UNPKG

ember-source

Version:

A JavaScript framework for creating ambitious web applications

1,526 lines (1,518 loc) 29.8 kB
import '@glimmer/util'; import { Op, MachineOp } from '@glimmer/vm'; /* This file is generated by build/debug.js */ function opcodeMetadata(op, isMachine) { let value = isMachine ? MACHINE_METADATA[op] : METADATA[op]; return value || null; } const METADATA = new Array(Op.Size).fill(null); const MACHINE_METADATA = new Array(Op.Size).fill(null); MACHINE_METADATA[MachineOp.PushFrame] = { name: 'PushFrame', mnemonic: 'pushf', before: null, stackChange: 2, ops: [], operands: 0, check: true }; MACHINE_METADATA[MachineOp.PopFrame] = { name: 'PopFrame', mnemonic: 'popf', before: null, stackChange: -2, ops: [], operands: 0, check: false }; MACHINE_METADATA[MachineOp.InvokeVirtual] = { name: 'InvokeVirtual', mnemonic: 'vcall', before: null, stackChange: -1, ops: [], operands: 0, check: true }; MACHINE_METADATA[MachineOp.InvokeStatic] = { name: 'InvokeStatic', mnemonic: 'scall', before: null, stackChange: 0, ops: [{ name: 'offset', type: 'u32' }], operands: 1, check: true }; MACHINE_METADATA[MachineOp.Jump] = { name: 'Jump', mnemonic: 'goto', before: null, stackChange: 0, ops: [{ name: 'to', type: 'u32' }], operands: 1, check: true }; MACHINE_METADATA[MachineOp.Return] = { name: 'Return', mnemonic: 'ret', before: null, stackChange: 0, ops: [], operands: 0, check: false }; MACHINE_METADATA[MachineOp.ReturnTo] = { name: 'ReturnTo', mnemonic: 'setra', before: null, stackChange: 0, ops: [{ name: 'offset', type: 'i32' }], operands: 1, check: true }; METADATA[Op.Helper] = { name: 'Helper', mnemonic: 'ncall', before: null, stackChange: null, ops: [{ name: 'helper', type: 'handle' }], operands: 1, check: true }; METADATA[Op.DynamicHelper] = { name: 'DynamicHelper', mnemonic: 'dynamiccall', before: null, stackChange: null, ops: [], operands: 0, check: true }; METADATA[Op.SetNamedVariables] = { name: 'SetNamedVariables', mnemonic: 'vsargs', before: null, stackChange: 0, ops: [{ name: 'register', type: 'u32' }], operands: 1, check: true }; METADATA[Op.SetBlocks] = { name: 'SetBlocks', mnemonic: 'vbblocks', before: null, stackChange: 0, ops: [{ name: 'register', type: 'u32' }], operands: 1, check: true }; METADATA[Op.SetVariable] = { name: 'SetVariable', mnemonic: 'sbvar', before: null, stackChange: -1, ops: [{ name: 'symbol', type: 'u32' }], operands: 1, check: true }; METADATA[Op.SetBlock] = { name: 'SetBlock', mnemonic: 'sblock', before: null, stackChange: -3, ops: [{ name: 'symbol', type: 'u32' }], operands: 1, check: true }; METADATA[Op.GetVariable] = { name: 'GetVariable', mnemonic: 'symload', before: null, stackChange: 1, ops: [{ name: 'symbol', type: 'u32' }], operands: 1, check: true }; METADATA[Op.GetProperty] = { name: 'GetProperty', mnemonic: 'getprop', before: null, stackChange: 0, ops: [{ name: 'property', type: 'str' }], operands: 1, check: true }; METADATA[Op.GetBlock] = { name: 'GetBlock', mnemonic: 'blockload', before: null, stackChange: 1, ops: [{ name: 'block', type: 'u32' }], operands: 1, check: true }; METADATA[Op.SpreadBlock] = { name: 'SpreadBlock', mnemonic: 'blockspread', before: null, stackChange: 2, ops: [], operands: 0, check: true }; METADATA[Op.HasBlock] = { name: 'HasBlock', mnemonic: 'hasblockload', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.HasBlockParams] = { name: 'HasBlockParams', mnemonic: 'hasparamsload', before: null, stackChange: -2, ops: [], operands: 0, check: true }; METADATA[Op.Concat] = { name: 'Concat', mnemonic: 'concat', before: null, stackChange: null, ops: [{ name: 'count', type: 'u32' }], operands: 1, check: true }; METADATA[Op.IfInline] = { name: 'IfInline', mnemonic: 'ifinline', before: null, stackChange: -2, ops: [{ name: 'count', type: 'u32' }], operands: 1, check: true }; METADATA[Op.Not] = { name: 'Not', mnemonic: 'not', before: null, stackChange: 0, ops: [{ name: 'count', type: 'u32' }], operands: 1, check: true }; METADATA[Op.Constant] = { name: 'Constant', mnemonic: 'rconstload', before: null, stackChange: 1, ops: [{ name: 'constant', type: 'unknown' }], operands: 1, check: true }; METADATA[Op.ConstantReference] = { name: 'ConstantReference', mnemonic: 'rconstrefload', before: null, stackChange: 1, ops: [{ name: 'constant', type: 'unknown' }], operands: 1, check: true }; METADATA[Op.Primitive] = { name: 'Primitive', mnemonic: 'pconstload', before: null, stackChange: 1, ops: [{ name: 'constant', type: 'primitive' }], operands: 1, check: true }; METADATA[Op.PrimitiveReference] = { name: 'PrimitiveReference', mnemonic: 'ptoref', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.ReifyU32] = { name: 'ReifyU32', mnemonic: 'reifyload', before: null, stackChange: 1, ops: [], operands: 0, check: true }; METADATA[Op.Dup] = { name: 'Dup', mnemonic: 'dup', before: null, stackChange: 1, ops: [{ name: 'register', type: 'u32' }, { name: 'offset', type: 'u32' }], operands: 2, check: true }; METADATA[Op.Pop] = { name: 'Pop', mnemonic: 'pop', before: null, stackChange: 0, ops: [{ name: 'count', type: 'u32' }], operands: 1, check: false }; METADATA[Op.Load] = { name: 'Load', mnemonic: 'put', before: null, stackChange: -1, ops: [{ name: 'register', type: 'u32' }], operands: 1, check: true }; METADATA[Op.Fetch] = { name: 'Fetch', mnemonic: 'regload', before: null, stackChange: 1, ops: [{ name: 'register', type: 'u32' }], operands: 1, check: true }; METADATA[Op.RootScope] = { name: 'RootScope', mnemonic: 'rscopepush', before: null, stackChange: 0, ops: [{ name: 'symbols', type: 'u32' }], operands: 1, check: true }; METADATA[Op.VirtualRootScope] = { name: 'VirtualRootScope', mnemonic: 'vrscopepush', before: null, stackChange: 0, ops: [{ name: 'register', type: 'u32' }], operands: 1, check: true }; METADATA[Op.ChildScope] = { name: 'ChildScope', mnemonic: 'cscopepush', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.PopScope] = { name: 'PopScope', mnemonic: 'scopepop', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.Text] = { name: 'Text', mnemonic: 'apnd_text', before: null, stackChange: 0, ops: [{ name: 'contents', type: 'str' }], operands: 1, check: true }; METADATA[Op.Comment] = { name: 'Comment', mnemonic: 'apnd_comment', before: null, stackChange: 0, ops: [{ name: 'contents', type: 'str' }], operands: 1, check: true }; METADATA[Op.AppendHTML] = { name: 'AppendHTML', mnemonic: 'apnd_dynhtml', before: null, stackChange: -1, ops: [], operands: 0, check: true }; METADATA[Op.AppendSafeHTML] = { name: 'AppendSafeHTML', mnemonic: 'apnd_dynshtml', before: null, stackChange: -1, ops: [], operands: 0, check: true }; METADATA[Op.AppendDocumentFragment] = { name: 'AppendDocumentFragment', mnemonic: 'apnd_dynfrag', before: null, stackChange: -1, ops: [], operands: 0, check: true }; METADATA[Op.AppendNode] = { name: 'AppendNode', mnemonic: 'apnd_dynnode', before: null, stackChange: -1, ops: [], operands: 0, check: true }; METADATA[Op.AppendText] = { name: 'AppendText', mnemonic: 'apnd_dyntext', before: null, stackChange: -1, ops: [], operands: 0, check: true }; METADATA[Op.OpenElement] = { name: 'OpenElement', mnemonic: 'apnd_tag', before: null, stackChange: 0, ops: [{ name: 'tag', type: 'str' }], operands: 1, check: true }; METADATA[Op.OpenDynamicElement] = { name: 'OpenDynamicElement', mnemonic: 'apnd_dyntag', before: null, stackChange: -1, ops: [], operands: 0, check: true }; METADATA[Op.PushRemoteElement] = { name: 'PushRemoteElement', mnemonic: 'apnd_remotetag', before: null, stackChange: -3, ops: [], operands: 0, check: true }; METADATA[Op.StaticAttr] = { name: 'StaticAttr', mnemonic: 'apnd_attr', before: null, stackChange: 0, ops: [{ name: 'name', type: 'str' }, { name: 'value', type: 'str' }, { name: 'namespace', type: 'option-str' }], operands: 3, check: true }; METADATA[Op.DynamicAttr] = { name: 'DynamicAttr', mnemonic: 'apnd_dynattr', before: null, stackChange: -1, ops: [{ name: 'name', type: 'str' }, { name: 'trusting', type: 'bool' }, { name: 'namespace', type: 'option-str' }], operands: 3, check: true }; METADATA[Op.ComponentAttr] = { name: 'ComponentAttr', mnemonic: 'apnd_cattr', before: null, stackChange: -1, ops: [{ name: 'name', type: 'str' }, { name: 'trusting', type: 'bool' }, { name: 'namespace', type: 'option-str' }], operands: 3, check: true }; METADATA[Op.FlushElement] = { name: 'FlushElement', mnemonic: 'apnd_flushtag', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.CloseElement] = { name: 'CloseElement', mnemonic: 'apnd_closetag', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.PopRemoteElement] = { name: 'PopRemoteElement', mnemonic: 'apnd_closeremotetag', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.Modifier] = { name: 'Modifier', mnemonic: 'apnd_modifier', before: null, stackChange: -1, ops: [{ name: 'helper', type: 'handle' }], operands: 1, check: true }; METADATA[Op.BindDynamicScope] = { name: 'BindDynamicScope', mnemonic: 'setdynscope', before: null, stackChange: null, ops: [{ name: 'names', type: 'str-array' }], operands: 1, check: true }; METADATA[Op.PushDynamicScope] = { name: 'PushDynamicScope', mnemonic: 'dynscopepush', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.PopDynamicScope] = { name: 'PopDynamicScope', mnemonic: 'dynscopepop', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.CompileBlock] = { name: 'CompileBlock', mnemonic: 'cmpblock', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.PushBlockScope] = { name: 'PushBlockScope', mnemonic: 'scopeload', before: null, stackChange: 1, ops: [{ name: 'scope', type: 'scope' }], operands: 1, check: true }; METADATA[Op.PushSymbolTable] = { name: 'PushSymbolTable', mnemonic: 'dsymload', before: null, stackChange: 1, ops: [{ name: 'table', type: 'symbol-table' }], operands: 1, check: true }; METADATA[Op.InvokeYield] = { name: 'InvokeYield', mnemonic: 'invokeyield', before: null, stackChange: null, ops: [], operands: 0, check: true }; METADATA[Op.JumpIf] = { name: 'JumpIf', mnemonic: 'iftrue', before: null, stackChange: -1, ops: [{ name: 'to', type: 'u32' }], operands: 1, check: true }; METADATA[Op.JumpUnless] = { name: 'JumpUnless', mnemonic: 'iffalse', before: null, stackChange: -1, ops: [{ name: 'to', type: 'u32' }], operands: 1, check: true }; METADATA[Op.JumpEq] = { name: 'JumpEq', mnemonic: 'ifeq', before: null, stackChange: 0, ops: [{ name: 'to', type: 'i32' }, { name: 'comparison', type: 'i32' }], operands: 2, check: true }; METADATA[Op.AssertSame] = { name: 'AssertSame', mnemonic: 'assert_eq', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.Enter] = { name: 'Enter', mnemonic: 'blk_start', before: null, stackChange: 0, ops: [{ name: 'args', type: 'u32' }], operands: 1, check: true }; METADATA[Op.Exit] = { name: 'Exit', mnemonic: 'blk_end', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.ToBoolean] = { name: 'ToBoolean', mnemonic: 'anytobool', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.EnterList] = { name: 'EnterList', mnemonic: 'list_start', before: null, stackChange: null, ops: [{ name: 'address', type: 'u32' }, { name: 'address', type: 'u32' }], operands: 2, check: true }; METADATA[Op.ExitList] = { name: 'ExitList', mnemonic: 'list_end', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.Iterate] = { name: 'Iterate', mnemonic: 'iter', before: null, stackChange: 0, ops: [{ name: 'end', type: 'u32' }], operands: 1, check: false }; METADATA[Op.Main] = { name: 'Main', mnemonic: 'main', before: null, stackChange: -2, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.ContentType] = { name: 'ContentType', mnemonic: 'ctload', before: null, stackChange: 1, ops: [], operands: 0, check: true }; METADATA[Op.DynamicContentType] = { name: 'DynamicContentType', mnemonic: 'dctload', before: null, stackChange: 1, ops: [], operands: 0, check: true }; METADATA[Op.Curry] = { name: 'Curry', mnemonic: 'curry', before: null, stackChange: null, ops: [{ name: 'type', type: 'u32' }, { name: 'is-strict', type: 'bool' }], operands: 2, check: true }; METADATA[Op.PushComponentDefinition] = { name: 'PushComponentDefinition', mnemonic: 'cmload', before: null, stackChange: 1, ops: [{ name: 'spec', type: 'handle' }], operands: 1, check: true }; METADATA[Op.PushDynamicComponentInstance] = { name: 'PushDynamicComponentInstance', mnemonic: 'dciload', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.ResolveDynamicComponent] = { name: 'ResolveDynamicComponent', mnemonic: 'cdload', before: null, stackChange: 0, ops: [{ name: 'owner', type: 'owner' }], operands: 1, check: true }; METADATA[Op.PushArgs] = { name: 'PushArgs', mnemonic: 'argsload', before: null, stackChange: null, ops: [{ name: 'names', type: 'str-array' }, { name: 'block-names', type: 'str-array' }, { name: 'flags', type: 'u32' }], operands: 3, check: true }; METADATA[Op.PushEmptyArgs] = { name: 'PushEmptyArgs', mnemonic: 'emptyargsload', before: null, stackChange: 1, ops: [], operands: 0, check: true }; METADATA[Op.PopArgs] = { name: 'PopArgs', mnemonic: 'argspop', before: null, stackChange: null, ops: [], operands: 0, check: true }; METADATA[Op.PrepareArgs] = { name: 'PrepareArgs', mnemonic: 'argsprep', before: null, stackChange: 0, ops: [{ name: 'state', type: 'register' }], operands: 1, check: false }; METADATA[Op.CaptureArgs] = { name: 'CaptureArgs', mnemonic: 'argscapture', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.CreateComponent] = { name: 'CreateComponent', mnemonic: 'comp_create', before: null, stackChange: 0, ops: [{ name: 'flags', type: 'u32' }, { name: 'state', type: 'register' }], operands: 2, check: true }; METADATA[Op.RegisterComponentDestructor] = { name: 'RegisterComponentDestructor', mnemonic: 'comp_dest', before: null, stackChange: 0, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.PutComponentOperations] = { name: 'PutComponentOperations', mnemonic: 'comp_elops', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.GetComponentSelf] = { name: 'GetComponentSelf', mnemonic: 'comp_selfload', before: null, stackChange: 1, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.GetComponentTagName] = { name: 'GetComponentTagName', mnemonic: 'comp_tagload', before: null, stackChange: 1, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.GetComponentLayout] = { name: 'GetComponentLayout', mnemonic: 'comp_layoutload', before: null, stackChange: 2, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.BindEvalScope] = { name: 'BindEvalScope', mnemonic: 'eval_scope', before: null, stackChange: 0, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.SetupForEval] = { name: 'SetupForEval', mnemonic: 'eval_setup', before: null, stackChange: 0, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.PopulateLayout] = { name: 'PopulateLayout', mnemonic: 'comp_layoutput', before: null, stackChange: -2, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.InvokeComponentLayout] = { name: 'InvokeComponentLayout', mnemonic: 'comp_invokelayout', before: null, stackChange: 0, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.BeginComponentTransaction] = { name: 'BeginComponentTransaction', mnemonic: 'comp_begin', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.CommitComponentTransaction] = { name: 'CommitComponentTransaction', mnemonic: 'comp_commit', before: null, stackChange: 0, ops: [], operands: 0, check: true }; METADATA[Op.DidCreateElement] = { name: 'DidCreateElement', mnemonic: 'comp_created', before: null, stackChange: 0, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.DidRenderLayout] = { name: 'DidRenderLayout', mnemonic: 'comp_rendered', before: null, stackChange: 0, ops: [{ name: 'state', type: 'register' }], operands: 1, check: true }; METADATA[Op.ResolveMaybeLocal] = { name: 'ResolveMaybeLocal', mnemonic: 'eval_varload', before: null, stackChange: 1, ops: [{ name: 'local', type: 'str' }], operands: 1, check: true }; METADATA[Op.Debugger] = { name: 'Debugger', mnemonic: 'debugger', before: null, stackChange: 0, ops: [{ name: 'symbols', type: 'str-array' }, { name: 'debugInfo', type: 'array' }], operands: 2, check: true }; function debugSlice(context, start, end) { } function logOpcode(type, params) { } function debug(c, op, isMachine) { return undefined; } // TODO: How do these map onto constant and machine types? const OPERAND_TYPES = ['u32', 'i32', 'owner', 'handle', 'str', 'option-str', 'array', 'str-array', 'bool', 'primitive', 'register', 'unknown', 'symbol-table', 'scope']; function isOperandType(s) { return OPERAND_TYPES.indexOf(s) !== -1; } function normalize(key, input) { let name; if (input.format === undefined) { throw new Error(`Missing format in ${JSON.stringify(input)}`); } if (Array.isArray(input.format)) { name = input.format[0]; } else { name = input.format; } let ops = Array.isArray(input.format) ? operands(input.format.slice(1)) : []; return { name, mnemonic: key, before: null, stackChange: stackChange(input['operand-stack']), ops, operands: ops.length, check: input.skip === true ? false : true }; } function stackChange(stack) { if (stack === undefined) { return 0; } let before = stack[0]; let after = stack[1]; if (hasRest(before) || hasRest(after)) { return null; } return after.length - before.length; } function hasRest(input) { if (!Array.isArray(input)) { throw new Error(`Unexpected stack entry: ${JSON.stringify(input)}`); } return input.some(s => s.slice(-3) === '...'); } function operands(input) { if (!Array.isArray(input)) { throw new Error(`Expected operands array, got ${JSON.stringify(input)}`); } return input.map(op); } function op(input) { let [name, type] = input.split(':'); if (isOperandType(type)) { return { name, type }; } else { throw new Error(`Expected operand, found ${JSON.stringify(input)}`); } } function normalizeAll(parsed) { let machine = normalizeParsed(parsed.machine); let syscall = normalizeParsed(parsed.syscall); return { machine, syscall }; } function normalizeParsed(parsed) { let out = Object.create(null); for (const [key, value] of Object.entries(parsed)) { out[key] = normalize(key, value); } return out; } function buildEnum(name, parsed, offset, max) { let e = [`export enum ${name} {`]; let last; Object.values(parsed).forEach((value, i) => { e.push(` ${value.name} = ${offset + i},`); last = i; }); e.push(` Size = ${last + offset + 1},`); e.push('}'); let enumString = e.join('\n'); let predicate; if (max) { predicate = strip` export function is${name}(value: number): value is ${name} { return value >= ${offset} && value <= ${max}; } `; } else { predicate = strip` export function is${name}(value: number): value is ${name} { return value >= ${offset}; } `; } return { enumString, predicate }; } function strip(strings, ...args) { let out = ''; for (let i = 0; i < strings.length; i++) { let string = strings[i]; let dynamic = args[i] !== undefined ? String(args[i]) : ''; out += `${string}${dynamic}`; } // eslint-disable-next-line regexp/no-super-linear-backtracking out = /^\s*?\n?([\s\S]*?)\s*$/u.exec(out)[1]; let min = Number.MAX_SAFE_INTEGER; for (let line of out.split('\n')) { let leading = /^\s*/u.exec(line)[0].length; min = Math.min(min, leading); } let stripped = ''; for (let line of out.split('\n')) { stripped += line.slice(min) + '\n'; } return stripped; } const META_KIND = ['METADATA', 'MACHINE_METADATA']; function buildSingleMeta(kind, all, key) { let e = kind === 'MACHINE_METADATA' ? 'MachineOp' : 'Op'; return `${kind}[${e}.${all[key].name}] = ${stringify(all[key], 0)};`; } function stringify(o, pad) { if (typeof o !== 'object' || o === null) { if (typeof o === 'string') { return `'${o}'`; } return JSON.stringify(o); } if (Array.isArray(o)) { return `[${o.map(v => stringify(v, pad)).join(', ')}]`; } let out = ['{']; for (let key of Object.keys(o)) { out.push(`${' '.repeat(pad + 2)}${key}: ${stringify(o[key], pad + 2)},`); } out.push(`${' '.repeat(pad)}}`); return out.join('\n'); } function buildMetas(kind, all) { let out = []; for (let key of Object.keys(all)) { out.push(buildSingleMeta(kind, all, key)); } return out.join('\n\n'); } function wrap(checker) { class Wrapped { validate(value) { return checker().validate(value); } expected() { return checker().expected(); } } return new Wrapped(); } class TypeofChecker { constructor(expectedType) { this.expectedType = expectedType; } validate(value) { return typeof value === this.expectedType; } expected() { return `typeof ${this.expectedType}`; } } class PrimitiveChecker { validate(value) { return typeof value !== 'string' || typeof value === 'number' || typeof value === 'string' || value === undefined || value === null; } expected() { return `a primitive`; } } class NullChecker { validate(value) { return value === null; } expected() { return `null`; } } class UndefinedChecker { validate(value) { return value === undefined; } expected() { return `undefined`; } } class InstanceofChecker { constructor(Class) { this.Class = Class; } validate(value) { return value ? value instanceof this.Class : false; } expected() { return `an instance of ${this.Class.name}`; } } class OptionChecker { constructor(checker, emptyValue) { this.checker = checker; this.emptyValue = emptyValue; } validate(value) { if (value === this.emptyValue) return true; return this.checker.validate(value); } expected() { return `${this.checker.expected()} or null`; } } class MaybeChecker { constructor(checker) { this.checker = checker; } validate(value) { if (value === null || value === undefined) return true; return this.checker.validate(value); } expected() { return `${this.checker.expected()} or null or undefined`; } } class OrChecker { constructor(left, right) { this.left = left; this.right = right; } validate(value) { return this.left.validate(value) || this.right.validate(value); } expected() { return `${this.left.expected()} or ${this.right.expected()}`; } } class ExactValueChecker { constructor(value, desc) { this.value = value; this.desc = desc; } validate(obj) { return obj === this.value; } expected() { return this.desc; } } class PropertyChecker { constructor(checkers) { this.checkers = checkers; } validate(obj) { if (typeof obj !== 'object') return false; if (obj === null || obj === undefined) return false; return Object.entries(this.checkers).every(([k, checker]) => k in obj ? checker.validate(obj[k]) : false); } expected() { let pairs = Object.entries(this.checkers).map(([k, checker]) => { return `${k}: ${checker.expected()}`; }); return `{ ${pairs.join(',')} }`; } } class ArrayChecker { constructor(checker) { this.checker = checker; } validate(obj) { if (obj === null || obj === undefined) return false; if (!Array.isArray(obj)) return false; return obj.every(item => this.checker.validate(item)); } expected() { return `Array<${this.checker.expected()}>`; } } class DictChecker { constructor(checker) { this.checker = checker; } validate(value) { let isDict = typeof value === 'object' && value !== null && Object.getPrototypeOf(value) === null; if (!isDict) return false; let { checker } = this; for (let key in value) { if (!checker.validate(value[key])) { return false; } } return true; } expected() { return `a primitive`; } } class OpaqueChecker { type; validate(_obj) { return true; } expected() { return `any`; } } class ObjectChecker { validate(obj) { return typeof obj === 'function' || typeof obj === 'object' && obj !== null; } expected() { return `an object or function (valid WeakMap key)`; } } class SafeStringChecker { validate(value) { return typeof value === 'object' && value !== null && typeof value.toHTML === 'function'; } expected() { return `SafeString`; } } function CheckInstanceof(Class) { return new InstanceofChecker(Class); } function CheckOption(checker) { return new OptionChecker(checker, null); } function CheckMaybe(checker) { return new MaybeChecker(checker); } function CheckInterface(obj) { return new PropertyChecker(obj); } function CheckArray(obj) { return new ArrayChecker(obj); } function CheckDict(obj) { return new DictChecker(obj); } function defaultMessage(value, expected) { return `Got ${value}, expected:\n${expected}`; } function check(value, checker, message = defaultMessage) { if (typeof checker === 'function') { checker(value); return value; } if (checker.validate(value)) { return value; } else { throw new Error(message(value, checker.expected())); } } let size = 0; function recordStackSize(sp) { size = sp; } function expectStackChange(stack, expected, name) { let actual = stack.sp - size; if (actual === expected) return; throw new Error(`Expected stack to change by ${expected}, but it changed by ${actual} in ${name}`); } const CheckPrimitive = new PrimitiveChecker(); const CheckFunction = new TypeofChecker('function'); const CheckNumber = new TypeofChecker('number'); const CheckBoolean = new TypeofChecker('boolean'); const CheckHandle = CheckNumber; const CheckString = new TypeofChecker('string'); const CheckNull = new NullChecker(); const CheckUndefined = new UndefinedChecker(); const CheckUnknown = new OpaqueChecker(); const CheckSafeString = new SafeStringChecker(); const CheckObject = new ObjectChecker(); function CheckOr(left, right) { return new OrChecker(left, right); } function CheckValue(value, desc = String(value)) { return new ExactValueChecker(value, desc); } const CheckBlockSymbolTable = CheckInterface({ parameters: CheckArray(CheckNumber) }); const CheckProgramSymbolTable = CheckInterface({ hasEval: CheckBoolean, symbols: CheckArray(CheckString) }); const CheckElement = CheckInterface({ nodeType: CheckValue(1), tagName: CheckString, nextSibling: CheckUnknown }); const CheckDocumentFragment = CheckInterface({ nodeType: CheckValue(11), nextSibling: CheckUnknown }); const CheckNode = CheckInterface({ nodeType: CheckNumber, nextSibling: CheckUnknown }); export { CheckArray, CheckBlockSymbolTable, CheckBoolean, CheckDict, CheckDocumentFragment, CheckElement, CheckFunction, CheckHandle, CheckInstanceof, CheckInterface, CheckMaybe, CheckNode, CheckNull, CheckNumber, CheckObject, CheckOption, CheckOr, CheckPrimitive, CheckProgramSymbolTable, CheckSafeString, CheckString, CheckUndefined, CheckUnknown, CheckValue, META_KIND, OPERAND_TYPES, buildEnum, buildMetas, buildSingleMeta, check, debug, debugSlice, expectStackChange, logOpcode, normalize, normalizeAll, normalizeParsed, opcodeMetadata, recordStackSize, strip, wrap };