UNPKG

ember-legacy-class-transform

Version:
337 lines (336 loc) 10.4 kB
import { populateBuiltins } from './syntax/functions'; import { Constants } from './environment/constants'; import { UNDEFINED_REFERENCE, ConditionalReference } from './references'; import { defaultManagers } from './dom/attribute-managers'; import { assert, ensureGuid, expect } from '@glimmer/util'; export class Scope { constructor( // the 0th slot is `self` slots, callerScope, // named arguments and blocks passed to a layout that uses eval evalScope, // locals in scope when the partial was invoked partialMap) { this.slots = slots; this.callerScope = callerScope; this.evalScope = evalScope; this.partialMap = partialMap; } static root(self, size = 0) { let refs = new Array(size + 1); for (let i = 0; i <= size; i++) { refs[i] = UNDEFINED_REFERENCE; } return new Scope(refs, null, null, null).init({ self }); } static sized(size = 0) { let refs = new Array(size + 1); for (let i = 0; i <= size; i++) { refs[i] = UNDEFINED_REFERENCE; } return new Scope(refs, null, null, null); } init({ self }) { this.slots[0] = self; return this; } getSelf() { return this.get(0); } getSymbol(symbol) { return this.get(symbol); } getBlock(symbol) { return this.get(symbol); } getEvalScope() { return this.evalScope; } getPartialMap() { return this.partialMap; } bind(symbol, value) { this.set(symbol, value); } bindSelf(self) { this.set(0, self); } bindSymbol(symbol, value) { this.set(symbol, value); } bindBlock(symbol, value) { this.set(symbol, value); } bindEvalScope(map) { this.evalScope = map; } bindPartialMap(map) { this.partialMap = map; } bindCallerScope(scope) { this.callerScope = scope; } getCallerScope() { return this.callerScope; } child() { return new Scope(this.slots.slice(), this.callerScope, this.evalScope, this.partialMap); } get(index) { if (index >= this.slots.length) { throw new RangeError(`BUG: cannot get $${index} from scope; length=${this.slots.length}`); } return this.slots[index]; } set(index, value) { if (index >= this.slots.length) { throw new RangeError(`BUG: cannot get $${index} from scope; length=${this.slots.length}`); } this.slots[index] = value; } } class Transaction { constructor() { this.scheduledInstallManagers = []; this.scheduledInstallModifiers = []; this.scheduledUpdateModifierManagers = []; this.scheduledUpdateModifiers = []; this.createdComponents = []; this.createdManagers = []; this.updatedComponents = []; this.updatedManagers = []; this.destructors = []; } didCreate(component, manager) { this.createdComponents.push(component); this.createdManagers.push(manager); } didUpdate(component, manager) { this.updatedComponents.push(component); this.updatedManagers.push(manager); } scheduleInstallModifier(modifier, manager) { this.scheduledInstallManagers.push(manager); this.scheduledInstallModifiers.push(modifier); } scheduleUpdateModifier(modifier, manager) { this.scheduledUpdateModifierManagers.push(manager); this.scheduledUpdateModifiers.push(modifier); } didDestroy(d) { this.destructors.push(d); } commit() { let { createdComponents, createdManagers } = this; for (let i = 0; i < createdComponents.length; i++) { let component = createdComponents[i]; let manager = createdManagers[i]; manager.didCreate(component); } let { updatedComponents, updatedManagers } = this; for (let i = 0; i < updatedComponents.length; i++) { let component = updatedComponents[i]; let manager = updatedManagers[i]; manager.didUpdate(component); } let { destructors } = this; for (let i = 0; i < destructors.length; i++) { destructors[i].destroy(); } let { scheduledInstallManagers, scheduledInstallModifiers } = this; for (let i = 0; i < scheduledInstallManagers.length; i++) { let manager = scheduledInstallManagers[i]; let modifier = scheduledInstallModifiers[i]; manager.install(modifier); } let { scheduledUpdateModifierManagers, scheduledUpdateModifiers } = this; for (let i = 0; i < scheduledUpdateModifierManagers.length; i++) { let manager = scheduledUpdateModifierManagers[i]; let modifier = scheduledUpdateModifiers[i]; manager.update(modifier); } } } export class Opcode { constructor(heap) { this.heap = heap; this.offset = 0; } get type() { return this.heap.getbyaddr(this.offset); } get op1() { return this.heap.getbyaddr(this.offset + 1); } get op2() { return this.heap.getbyaddr(this.offset + 2); } get op3() { return this.heap.getbyaddr(this.offset + 3); } } var TableSlotState; (function (TableSlotState) { TableSlotState[TableSlotState["Allocated"] = 0] = "Allocated"; TableSlotState[TableSlotState["Freed"] = 1] = "Freed"; TableSlotState[TableSlotState["Purged"] = 2] = "Purged"; TableSlotState[TableSlotState["Pointer"] = 3] = "Pointer"; })(TableSlotState || (TableSlotState = {})); export class Heap { constructor() { this.heap = []; this.offset = 0; this.handle = 0; /** * layout: * * - pointer into heap * - size * - freed (0 or 1) */ this.table = []; } push(item) { this.heap[this.offset++] = item; } getbyaddr(address) { return this.heap[address]; } setbyaddr(address, value) { this.heap[address] = value; } malloc() { this.table.push(this.offset, 0, 0); let handle = this.handle; this.handle += 3; return handle; } finishMalloc(handle) { let start = this.table[handle]; let finish = this.offset; this.table[handle + 1] = finish - start; } size() { return this.offset; } // It is illegal to close over this address, as compaction // may move it. However, it is legal to use this address // multiple times between compactions. getaddr(handle) { return this.table[handle]; } gethandle(address) { this.table.push(address, 0, TableSlotState.Pointer); let handle = this.handle; this.handle += 3; return handle; } sizeof(handle) { if (false) { return this.table[handle + 1]; } return -1; } free(handle) { this.table[handle + 2] = 1; } compact() { let compactedSize = 0; let { table, table: { length }, heap } = this; for (let i = 0; i < length; i += 3) { let offset = table[i]; let size = table[i + 1]; let state = table[i + 2]; if (state === TableSlotState.Purged) { continue; } else if (state === TableSlotState.Freed) { // transition to "already freed" // a good improvement would be to reuse // these slots table[i + 2] = 2; compactedSize += size; } else if (state === TableSlotState.Allocated) { for (let j = offset; j <= i + size; j++) { heap[j - compactedSize] = heap[j]; } table[i] = offset - compactedSize; } else if (state === TableSlotState.Pointer) { table[i] = offset - compactedSize; } } this.offset = this.offset - compactedSize; } } export class Program { constructor() { this.heap = new Heap(); this._opcode = new Opcode(this.heap); this.constants = new Constants(); } opcode(offset) { this._opcode.offset = offset; return this._opcode; } } export class Environment { constructor({ appendOperations, updateOperations }) { this._macros = null; this._transaction = null; this.program = new Program(); this.appendOperations = appendOperations; this.updateOperations = updateOperations; } toConditionalReference(reference) { return new ConditionalReference(reference); } getAppendOperations() { return this.appendOperations; } getDOM() { return this.updateOperations; } getIdentity(object) { return ensureGuid(object) + ''; } begin() { assert(!this._transaction, 'a glimmer transaction was begun, but one already exists. You may have a nested transaction'); this._transaction = new Transaction(); } get transaction() { return expect(this._transaction, 'must be in a transaction'); } didCreate(component, manager) { this.transaction.didCreate(component, manager); } didUpdate(component, manager) { this.transaction.didUpdate(component, manager); } scheduleInstallModifier(modifier, manager) { this.transaction.scheduleInstallModifier(modifier, manager); } scheduleUpdateModifier(modifier, manager) { this.transaction.scheduleUpdateModifier(modifier, manager); } didDestroy(d) { this.transaction.didDestroy(d); } commit() { let transaction = this.transaction; this._transaction = null; transaction.commit(); } attributeFor(element, attr, isTrusting, namespace) { return defaultManagers(element, attr, isTrusting, namespace === undefined ? null : namespace); } macros() { let macros = this._macros; if (!macros) { this._macros = macros = this.populateBuiltins(); } return macros; } populateBuiltins() { return populateBuiltins(); } } export default Environment;