scope.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.ValueScope = exports.ValueScopeName = exports.Scope = exports.varKinds = exports.UsedValueState = void 0;
  4. const code_1 = require("./code");
  5. class ValueError extends Error {
  6. constructor(name) {
  7. super(`CodeGen: "code" for ${name} not defined`);
  8. this.value = name.value;
  9. }
  10. }
  11. var UsedValueState;
  12. (function (UsedValueState) {
  13. UsedValueState[UsedValueState["Started"] = 0] = "Started";
  14. UsedValueState[UsedValueState["Completed"] = 1] = "Completed";
  15. })(UsedValueState || (exports.UsedValueState = UsedValueState = {}));
  16. exports.varKinds = {
  17. const: new code_1.Name("const"),
  18. let: new code_1.Name("let"),
  19. var: new code_1.Name("var"),
  20. };
  21. class Scope {
  22. constructor({ prefixes, parent } = {}) {
  23. this._names = {};
  24. this._prefixes = prefixes;
  25. this._parent = parent;
  26. }
  27. toName(nameOrPrefix) {
  28. return nameOrPrefix instanceof code_1.Name ? nameOrPrefix : this.name(nameOrPrefix);
  29. }
  30. name(prefix) {
  31. return new code_1.Name(this._newName(prefix));
  32. }
  33. _newName(prefix) {
  34. const ng = this._names[prefix] || this._nameGroup(prefix);
  35. return `${prefix}${ng.index++}`;
  36. }
  37. _nameGroup(prefix) {
  38. var _a, _b;
  39. if (((_b = (_a = this._parent) === null || _a === void 0 ? void 0 : _a._prefixes) === null || _b === void 0 ? void 0 : _b.has(prefix)) || (this._prefixes && !this._prefixes.has(prefix))) {
  40. throw new Error(`CodeGen: prefix "${prefix}" is not allowed in this scope`);
  41. }
  42. return (this._names[prefix] = { prefix, index: 0 });
  43. }
  44. }
  45. exports.Scope = Scope;
  46. class ValueScopeName extends code_1.Name {
  47. constructor(prefix, nameStr) {
  48. super(nameStr);
  49. this.prefix = prefix;
  50. }
  51. setValue(value, { property, itemIndex }) {
  52. this.value = value;
  53. this.scopePath = (0, code_1._) `.${new code_1.Name(property)}[${itemIndex}]`;
  54. }
  55. }
  56. exports.ValueScopeName = ValueScopeName;
  57. const line = (0, code_1._) `\n`;
  58. class ValueScope extends Scope {
  59. constructor(opts) {
  60. super(opts);
  61. this._values = {};
  62. this._scope = opts.scope;
  63. this.opts = { ...opts, _n: opts.lines ? line : code_1.nil };
  64. }
  65. get() {
  66. return this._scope;
  67. }
  68. name(prefix) {
  69. return new ValueScopeName(prefix, this._newName(prefix));
  70. }
  71. value(nameOrPrefix, value) {
  72. var _a;
  73. if (value.ref === undefined)
  74. throw new Error("CodeGen: ref must be passed in value");
  75. const name = this.toName(nameOrPrefix);
  76. const { prefix } = name;
  77. const valueKey = (_a = value.key) !== null && _a !== void 0 ? _a : value.ref;
  78. let vs = this._values[prefix];
  79. if (vs) {
  80. const _name = vs.get(valueKey);
  81. if (_name)
  82. return _name;
  83. }
  84. else {
  85. vs = this._values[prefix] = new Map();
  86. }
  87. vs.set(valueKey, name);
  88. const s = this._scope[prefix] || (this._scope[prefix] = []);
  89. const itemIndex = s.length;
  90. s[itemIndex] = value.ref;
  91. name.setValue(value, { property: prefix, itemIndex });
  92. return name;
  93. }
  94. getValue(prefix, keyOrRef) {
  95. const vs = this._values[prefix];
  96. if (!vs)
  97. return;
  98. return vs.get(keyOrRef);
  99. }
  100. scopeRefs(scopeName, values = this._values) {
  101. return this._reduceValues(values, (name) => {
  102. if (name.scopePath === undefined)
  103. throw new Error(`CodeGen: name "${name}" has no value`);
  104. return (0, code_1._) `${scopeName}${name.scopePath}`;
  105. });
  106. }
  107. scopeCode(values = this._values, usedValues, getCode) {
  108. return this._reduceValues(values, (name) => {
  109. if (name.value === undefined)
  110. throw new Error(`CodeGen: name "${name}" has no value`);
  111. return name.value.code;
  112. }, usedValues, getCode);
  113. }
  114. _reduceValues(values, valueCode, usedValues = {}, getCode) {
  115. let code = code_1.nil;
  116. for (const prefix in values) {
  117. const vs = values[prefix];
  118. if (!vs)
  119. continue;
  120. const nameSet = (usedValues[prefix] = usedValues[prefix] || new Map());
  121. vs.forEach((name) => {
  122. if (nameSet.has(name))
  123. return;
  124. nameSet.set(name, UsedValueState.Started);
  125. let c = valueCode(name);
  126. if (c) {
  127. const def = this.opts.es5 ? exports.varKinds.var : exports.varKinds.const;
  128. code = (0, code_1._) `${code}${def} ${name} = ${c};${this.opts._n}`;
  129. }
  130. else if ((c = getCode === null || getCode === void 0 ? void 0 : getCode(name))) {
  131. code = (0, code_1._) `${code}${c}${this.opts._n}`;
  132. }
  133. else {
  134. throw new ValueError(name);
  135. }
  136. nameSet.set(name, UsedValueState.Completed);
  137. });
  138. }
  139. return code;
  140. }
  141. }
  142. exports.ValueScope = ValueScope;
  143. //# sourceMappingURL=scope.js.map