| "use strict"; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| exports.ValueScope = exports.ValueScopeName = exports.Scope = exports.varKinds = exports.UsedValueState = void 0; |
| const code_1 = require("./code"); |
| class ValueError extends Error { |
| constructor(name) { |
| super(`CodeGen: "code" for ${name} not defined`); |
| this.value = name.value; |
| } |
| } |
| var UsedValueState; |
| (function (UsedValueState) { |
| UsedValueState[UsedValueState["Started"] = 0] = "Started"; |
| UsedValueState[UsedValueState["Completed"] = 1] = "Completed"; |
| })(UsedValueState = exports.UsedValueState || (exports.UsedValueState = {})); |
| exports.varKinds = { |
| const: new code_1.Name("const"), |
| let: new code_1.Name("let"), |
| var: new code_1.Name("var"), |
| }; |
| class Scope { |
| constructor({ prefixes, parent } = {}) { |
| this._names = {}; |
| this._prefixes = prefixes; |
| this._parent = parent; |
| } |
| toName(nameOrPrefix) { |
| return nameOrPrefix instanceof code_1.Name ? nameOrPrefix : this.name(nameOrPrefix); |
| } |
| name(prefix) { |
| return new code_1.Name(this._newName(prefix)); |
| } |
| _newName(prefix) { |
| const ng = this._names[prefix] || this._nameGroup(prefix); |
| return `${prefix}${ng.index++}`; |
| } |
| _nameGroup(prefix) { |
| var _a, _b; |
| 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))) { |
| throw new Error(`CodeGen: prefix "${prefix}" is not allowed in this scope`); |
| } |
| return (this._names[prefix] = { prefix, index: 0 }); |
| } |
| } |
| exports.Scope = Scope; |
| class ValueScopeName extends code_1.Name { |
| constructor(prefix, nameStr) { |
| super(nameStr); |
| this.prefix = prefix; |
| } |
| setValue(value, { property, itemIndex }) { |
| this.value = value; |
| this.scopePath = (0, code_1._) `.${new code_1.Name(property)}[${itemIndex}]`; |
| } |
| } |
| exports.ValueScopeName = ValueScopeName; |
| const line = (0, code_1._) `\n`; |
| class ValueScope extends Scope { |
| constructor(opts) { |
| super(opts); |
| this._values = {}; |
| this._scope = opts.scope; |
| this.opts = { ...opts, _n: opts.lines ? line : code_1.nil }; |
| } |
| get() { |
| return this._scope; |
| } |
| name(prefix) { |
| return new ValueScopeName(prefix, this._newName(prefix)); |
| } |
| value(nameOrPrefix, value) { |
| var _a; |
| if (value.ref === undefined) |
| throw new Error("CodeGen: ref must be passed in value"); |
| const name = this.toName(nameOrPrefix); |
| const { prefix } = name; |
| const valueKey = (_a = value.key) !== null && _a !== void 0 ? _a : value.ref; |
| let vs = this._values[prefix]; |
| if (vs) { |
| const _name = vs.get(valueKey); |
| if (_name) |
| return _name; |
| } |
| else { |
| vs = this._values[prefix] = new Map(); |
| } |
| vs.set(valueKey, name); |
| const s = this._scope[prefix] || (this._scope[prefix] = []); |
| const itemIndex = s.length; |
| s[itemIndex] = value.ref; |
| name.setValue(value, { property: prefix, itemIndex }); |
| return name; |
| } |
| getValue(prefix, keyOrRef) { |
| const vs = this._values[prefix]; |
| if (!vs) |
| return; |
| return vs.get(keyOrRef); |
| } |
| scopeRefs(scopeName, values = this._values) { |
| return this._reduceValues(values, (name) => { |
| if (name.scopePath === undefined) |
| throw new Error(`CodeGen: name "${name}" has no value`); |
| return (0, code_1._) `${scopeName}${name.scopePath}`; |
| }); |
| } |
| scopeCode(values = this._values, usedValues, getCode) { |
| return this._reduceValues(values, (name) => { |
| if (name.value === undefined) |
| throw new Error(`CodeGen: name "${name}" has no value`); |
| return name.value.code; |
| }, usedValues, getCode); |
| } |
| _reduceValues(values, valueCode, usedValues = {}, getCode) { |
| let code = code_1.nil; |
| for (const prefix in values) { |
| const vs = values[prefix]; |
| if (!vs) |
| continue; |
| const nameSet = (usedValues[prefix] = usedValues[prefix] || new Map()); |
| vs.forEach((name) => { |
| if (nameSet.has(name)) |
| return; |
| nameSet.set(name, UsedValueState.Started); |
| let c = valueCode(name); |
| if (c) { |
| const def = this.opts.es5 ? exports.varKinds.var : exports.varKinds.const; |
| code = (0, code_1._) `${code}${def} ${name} = ${c};${this.opts._n}`; |
| } |
| else if ((c = getCode === null || getCode === void 0 ? void 0 : getCode(name))) { |
| code = (0, code_1._) `${code}${c}${this.opts._n}`; |
| } |
| else { |
| throw new ValueError(name); |
| } |
| nameSet.set(name, UsedValueState.Completed); |
| }); |
| } |
| return code; |
| } |
| } |
| exports.ValueScope = ValueScope; |
| //# sourceMappingURL=scope.js.map |