UNPKG

aran

Version:
1,041 lines (1,011 loc) 28.2 kB
import { AranExecError, AranTypeError } from "../../../error.mjs"; import { EMPTY, concatX_, concat_, guard, map, EMPTY_SEQUENCE, bindSequence, initSequence, liftSequenceX, liftSequenceX_, liftSequence_X_, liftSequence_X__, liftSequence__X_, mapSequence, zeroSequence, } from "../../../util/index.mjs"; import { cacheConstant, cacheWritable, makeReadCacheExpression, makeWriteCacheEffect, } from "../../cache.mjs"; import { makeIsProperObjectExpression } from "../../helper.mjs"; import { makeBinaryExpression, makeGetExpression, makeThrowErrorExpression, } from "../../intrinsic.mjs"; import { makeApplyExpression, makeConditionalEffect, makeConditionalExpression, makeExpressionEffect, makeIntrinsicExpression, makePrimitiveExpression, makeReadExpression, makeWriteEffect, } from "../../node.mjs"; import { incorporateEffect, incorporateExpression, initSyntaxErrorExpression, makePrefixPrelude, } from "../../prelude/index.mjs"; import { forkMeta, nextMeta } from "../../meta.mjs"; /** * @type {( * routine: import("./index.d.ts").Routine, * ) => ( * | "illegal" * | "simple" * | "constructor" * | "constructor~" * | "constructor*" * )} */ const getResultKind = (routine) => { if (routine.intermediaries === null) { if (routine.type === "constructor") { return routine.derived ? "constructor*" : "constructor"; } else if (routine.type === "root" || routine.type === "method") { return "simple"; } else if (routine.type === "function") { return routine.asynchronous || routine.generator ? "simple" : "constructor~"; } else { throw new AranTypeError(routine); } } else { const intermediary = routine.intermediaries[0]; switch (intermediary) { case "arrow": { return "simple"; } case "eval.local.deep": { return "simple"; } case "static-block": { return "illegal"; } default: { throw new AranTypeError(intermediary); } } } }; /** * @type {( * routine: import("./index.d.ts").Routine, * ) => "illegal" | "program" | "closure"} */ const getOriginKind = (routine) => { if (routine.intermediaries === null) { return routine.type === "root" ? "program" : "closure"; } else { const intermediary = routine.intermediaries[0]; switch (intermediary) { case "arrow": { return "closure"; } case "eval.local.deep": { return "program"; } case "static-block": { return "illegal"; } default: { throw new AranTypeError(intermediary); } } } }; /** * @type {( * hash: import("../../hash.d.ts").Hash, * routine: import("./index.d.ts").ClosureRoutine, * ) => import("../../atom.d.ts").Expression} */ const makeThisExpression = (hash, routine) => routine.type === "constructor" && routine.derived ? makeConditionalExpression( makeReadExpression("this", hash), makeReadExpression("this", hash), makeThrowErrorExpression( "ReferenceError", "Cannot read 'this' before initialization", hash, ), hash, ) : makeReadExpression("this", hash); /** * @type {( * hash: import("../../hash.d.ts").Hash, * routine: ( * | import("./index.d.ts").MethodRoutine * | import("./index.d.ts").ConstructorRoutine * ), * ) => import("../../atom.d.ts").Expression} */ const makeSuperExpression = (hash, routine) => { if (routine.type === "method") { return makeApplyExpression( makeIntrinsicExpression("Reflect.getPrototypeOf", hash), makeIntrinsicExpression("undefined", hash), [makeReadCacheExpression(routine.proto, hash)], hash, ); } else if (routine.type === "constructor") { return makeApplyExpression( makeIntrinsicExpression("Reflect.getPrototypeOf", hash), makeIntrinsicExpression("undefined", hash), [ makeGetExpression( makeReadCacheExpression(routine.self, hash), makePrimitiveExpression("prototype", hash), hash, ), ], hash, ); } else { throw new AranTypeError(routine); } }; //////////// // extend // //////////// /** * @type {( * hash: import("../../hash.d.ts").Hash, * meta: import("../../meta.d.ts").Meta, * ) => import("../../../util/sequence.d.ts").Sequence< * import("../../prelude/index.d.ts").MetaDeclarationPrelude, * import("../../atom.d.ts").Effect[], * >} */ const listSetupThisConstructorEffect = (hash, meta) => liftSequenceX( concat_, liftSequence_X_( makeWriteEffect, "this", liftSequence__X_( makeApplyExpression, makeIntrinsicExpression("Object.create", hash), makeIntrinsicExpression("undefined", hash), liftSequenceX( concat_, incorporateExpression( mapSequence( cacheConstant( forkMeta((meta = nextMeta(meta))), makeGetExpression( makeReadExpression("new.target", hash), makePrimitiveExpression("prototype", hash), hash, ), hash, ), (prototype) => makeConditionalExpression( makeIsProperObjectExpression(hash, { value: prototype }), makeReadCacheExpression(prototype, hash), makeIntrinsicExpression("Object.prototype", hash), hash, ), ), hash, ), ), hash, ), hash, ), ); /** * @type {( * hash: import("../../hash.d.ts").Hash, * mode: "strict" | "sloppy", * ) => import("../../atom.d.ts").Effect[]} */ const listSetupThisMethodEffect = (hash, mode) => { if (mode === "strict") { return EMPTY; } else if (mode === "sloppy") { return [ makeWriteEffect( "this", makeConditionalExpression( makeBinaryExpression( "==", makeReadExpression("this", hash), makePrimitiveExpression(null, hash), hash, ), makeIntrinsicExpression("globalThis", hash), makeApplyExpression( makeIntrinsicExpression("Object", hash), makeIntrinsicExpression("undefined", hash), [makeReadExpression("this", hash)], hash, ), hash, ), hash, ), ]; } else { throw new AranTypeError(mode); } }; /** * @type {import("./index.d.ts").RootRoutine} */ export const INITIAL_ROUTINE = { type: "root", intermediaries: null, result: null, }; /** * @type {( * closure: Exclude<import("./index.d.ts").Closure, import("./index.d.ts").ArrowClosure>, * ) => import("./index.d.ts").Routine} */ export const makeClosureRoutine = (closure) => ({ ...closure, result: null, intermediaries: null, }); /** * @type {import("../api.d.ts").Extend< * import("./index.d.ts").Closure, * ( * | import("../../prelude/index.d.ts").PrefixPrelude * | import("../../prelude/index.d.ts").MetaDeclarationPrelude * ), * import("./index.d.ts").RoutineScope, * >} */ export const extendClosureRoutine = (hash, meta, closure, scope) => { switch (closure.type) { case "arrow": { return zeroSequence({ ...scope, routine: { ...scope.routine, intermediaries: ["arrow", scope.routine.intermediaries], result: null, }, }); } case "function": { if (closure.asynchronous || closure.generator) { return initSequence( map(listSetupThisMethodEffect(hash, scope.mode), makePrefixPrelude), { ...scope, routine: makeClosureRoutine(closure), }, ); } else { return bindSequence( liftSequence_X__( makeConditionalEffect, makeReadExpression("new.target", hash), listSetupThisConstructorEffect(hash, meta), listSetupThisMethodEffect(hash, scope.mode), hash, ), (setup) => initSequence([makePrefixPrelude(setup)], { ...scope, routine: makeClosureRoutine(closure), }), ); } } case "method": { return initSequence( map(listSetupThisMethodEffect(hash, scope.mode), makePrefixPrelude), { ...scope, routine: makeClosureRoutine(closure), }, ); } case "constructor": { return bindSequence( liftSequence_X__( makeConditionalEffect, makeReadExpression("new.target", hash), closure.derived ? EMPTY_SEQUENCE : liftSequenceX_( concatX_, listSetupThisConstructorEffect(hash, meta), makeConditionalEffect( makeReadCacheExpression(closure.field, hash), [ makeExpressionEffect( makeApplyExpression( makeReadCacheExpression(closure.field, hash), makeReadExpression("this", hash), [], hash, ), hash, ), ], EMPTY, hash, ), ), [ makeExpressionEffect( makeThrowErrorExpression( "TypeError", "constructor cannot be called as a method", hash, ), hash, ), ], hash, ), (setup) => initSequence([makePrefixPrelude(setup)], { ...scope, routine: makeClosureRoutine(closure), }), ); } default: { throw new AranTypeError(closure); } } }; /** * @type {import("../api.d.ts").Extend< * {}, * never, * import("./index.d.ts").RoutineScope, * >} */ export const extendStaticBlockRoutine = (_hash, _meta, _options, scope) => zeroSequence({ ...scope, routine: { ...scope.routine, intermediaries: ["static-block", scope.routine.intermediaries], }, }); /** * @type {<S extends import("./index.d.ts").RoutineScope>( * scope: S, * annotation: import("../../annotation/index.d.ts").Annotation, * ) => ( * & Omit<S, "annotation"> * & { annotation: import("../../annotation/index.d.ts").Annotation } * )} */ export const extendDeepEvalRoutine = (scope, annotation) => ({ ...scope, annotation, routine: { ...scope.routine, intermediaries: ["eval.local.deep", scope.routine.intermediaries], }, }); /** * @type {import("../api.d.ts").Extend< * {}, * import("../../prelude/index.d.ts").MetaDeclarationPrelude, * import("./index.d.ts").RoutineScope, * >} */ export const extendResultRoutine = (_hash, meta, _options, scope) => mapSequence( cacheWritable(forkMeta((meta = nextMeta(meta))), "undefined"), (result) => ({ ...scope, routine: { ...scope.routine, result, }, }), ); ////////// // load // ////////// /** * @type {import("../api.d.ts").PerformExpression< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").ReadThisOperation, * never, * >} */ export const makeReadThisExpression = ( hash, _meta, { root, routine }, _operation, ) => { if ( routine.type === "function" || routine.type === "method" || routine.type === "constructor" ) { return zeroSequence(makeThisExpression(hash, routine)); } else if (routine.type === "root") { if (root === "module") { return zeroSequence(makeIntrinsicExpression("undefined", hash)); } else if (root === "script" || root === "eval.global") { return zeroSequence(makeIntrinsicExpression("globalThis", hash)); } else if (root === "eval.local.root") { return zeroSequence(makeReadExpression("this", hash)); } else { throw new AranTypeError(root); } } else { throw new AranTypeError(routine); } }; /** * @type {import("../api.d.ts").PerformExpression< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").ReadNewTargetOperation, * import("../../prelude/index.d.ts").SyntaxErrorPrelude, * >} */ export const makeReadNewTargetExpression = ( hash, _meta, { root, routine }, _operation, ) => { if ( routine.type === "function" || routine.type === "method" || routine.type === "constructor" ) { return zeroSequence(makeReadExpression("new.target", hash)); } else if (routine.type === "root") { if (root === "script" || root === "module" || root === "eval.global") { return initSyntaxErrorExpression("Illegal 'new.target' read", hash); } else if (root === "eval.local.root") { return zeroSequence(makeReadExpression("new.target", hash)); } else { throw new AranTypeError(root); } } else { throw new AranTypeError(routine); } }; /** * @type {import("../api.d.ts").PerformExpression< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").ReadInputOperation, * import("../../prelude/index.d.ts").SyntaxErrorPrelude, * >} */ export const makeReadInputExpression = ( hash, _meta, { routine }, _operation, ) => { const { intermediaries } = routine; if (intermediaries === null) { if ( routine.type === "constructor" || routine.type === "function" || routine.type === "method" ) { return zeroSequence(makeReadExpression("function.arguments", hash)); } else if (routine.type === "root") { return initSyntaxErrorExpression( "Illegal 'function.arguments' read in root", hash, ); } else { throw new AranTypeError(routine); } } else { const intermediary = intermediaries[0]; if (intermediary === "arrow") { return zeroSequence(makeReadExpression("function.arguments", hash)); } else if ( intermediary === "eval.local.deep" || intermediary === "static-block" ) { return initSyntaxErrorExpression( `Illegal 'function.arguments' read in ${intermediary}`, hash, ); } else { throw new AranTypeError(intermediary); } } }; /** * @type {( * key: import("../../atom.d.ts").Expression, * ) => import("./index.d.ts").GetSuperOperation} */ export const makeGetSuperOperation = (key) => ({ key }); /** * @type {import("../api.d.ts").PerformExpression< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").GetSuperOperation, * import("../../prelude/index.d.ts").SyntaxErrorPrelude, * >} */ export const makeGetSuperExpression = ( hash, _meta, { root, routine }, operation, ) => { if (routine.type === "method" || routine.type === "constructor") { return zeroSequence( guard( routine.type === "constructor" && routine.derived, (node) => makeConditionalExpression( makeReadExpression("this", hash), node, makeThrowErrorExpression( "ReferenceError", "Cannot get `super` before calling `super`", hash, ), hash, ), makeApplyExpression( makeIntrinsicExpression("Reflect.get", hash), makeIntrinsicExpression("undefined", hash), [ makeSuperExpression(hash, routine), operation.key, makeReadExpression("this", hash), ], hash, ), ), ); } else if (routine.type === "function") { return initSyntaxErrorExpression("Illegal 'super' get", hash); } else if (routine.type === "root") { if (root === "script" || root === "module" || root === "eval.global") { return initSyntaxErrorExpression("Illegal 'super' get", hash); } else if (root === "eval.local.root") { return zeroSequence( makeApplyExpression( makeReadExpression("super.get", hash), makeIntrinsicExpression("undefined", hash), [operation.key], hash, ), ); } else { throw new AranTypeError(root); } } else { throw new AranTypeError(routine); } }; /** * @type {( * result: null | import("../../atom.d.ts").Expression, * ) => import("./index.d.ts").FinalizeResultOperation} */ export const makeFinalizeResultOperation = (result) => ({ result }); /** * @type {import("../api.d.ts").PerformExpression< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").FinalizeResultOperation, * never, * >} */ export const makeFinalizeResultExpression = ( hash, meta, { routine }, operation, ) => { const kind = getResultKind(routine); if (kind === "illegal") { throw new AranExecError("illegal finalize result operation", { routine, operation, }); } else if (kind === "simple") { return zeroSequence( operation.result ?? (routine.result === null ? makeIntrinsicExpression("undefined", hash) : makeReadCacheExpression(routine.result, hash)), ); } else { return incorporateExpression( mapSequence( /** * @type {import("../../../util/sequence.d.ts").Sequence< * import("../../prelude/index.d.ts").PrefixPrelude, * import("../../cache.d.ts").Cache, * >} */ ( operation.result === null ? routine.result === null ? cacheConstant( meta, makeIntrinsicExpression("undefined", hash), hash, ) : zeroSequence(routine.result) : cacheConstant(meta, operation.result, hash) ), (result) => { if (kind === "constructor") { return makeConditionalExpression( makeIsProperObjectExpression(hash, { value: result }), makeReadCacheExpression(result, hash), makeReadExpression("this", hash), hash, ); } else if (kind === "constructor~") { return makeConditionalExpression( makeReadExpression("new.target", hash), makeConditionalExpression( makeIsProperObjectExpression(hash, { value: result }), makeReadCacheExpression(result, hash), makeReadExpression("this", hash), hash, ), makeReadCacheExpression(result, hash), hash, ); } else if (kind === "constructor*") { return makeConditionalExpression( makeIsProperObjectExpression(hash, { value: result }), makeReadCacheExpression(result, hash), makeConditionalExpression( makeBinaryExpression( "===", makeReadCacheExpression(result, hash), makeIntrinsicExpression("undefined", hash), hash, ), makeConditionalExpression( makeReadExpression("this", hash), makeReadExpression("this", hash), makeThrowErrorExpression( "ReferenceError", "Derived constructors must call super before returning default value", hash, ), hash, ), makeThrowErrorExpression( "TypeError", "Derived constructors may only return object or undefined", hash, ), hash, ), hash, ); } else { throw new AranTypeError(kind); } }, ), hash, ); } }; /** * @type {import("../api.d.ts").PerformExpression< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").ReadResultOperation, * never, * >} */ export const makeReadResultExpression = ( hash, _meta, { routine }, _operation, ) => { if (routine.result === null) { return zeroSequence(makeIntrinsicExpression("undefined", hash)); } else { return zeroSequence(makeReadCacheExpression(routine.result, hash)); } }; ////////// // save // ////////// /** * @type {( * key: import("../../atom.d.ts").Expression, * value: import("../../atom.d.ts").Expression, * ) => import("./index.d.ts").SetSuperOperation} */ export const makeSetSuperOperation = (key, value) => ({ key, value }); /** * @type {import("../api.d.ts").PerformEffect< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").SetSuperOperation, * import("../../prelude/index.d.ts").SyntaxErrorPrelude * >} */ export const listSetSuperEffect = ( hash, _meta, { root, mode, routine }, operation, ) => { if (routine.type === "method" || routine.type === "constructor") { const perform = guard( routine.type === "constructor" && routine.derived, (node) => makeConditionalExpression( makeReadExpression("this", hash), node, makeThrowErrorExpression( "ReferenceError", "Cannot set `super` before calling `super`", hash, ), hash, ), makeApplyExpression( makeIntrinsicExpression("Reflect.set", hash), makeIntrinsicExpression("undefined", hash), [ makeSuperExpression(hash, routine), operation.key, operation.value, makeReadExpression("this", hash), ], hash, ), ); if (mode === "sloppy") { return zeroSequence(makeExpressionEffect(perform, hash)); } else if (mode === "strict") { return zeroSequence( makeConditionalEffect( perform, EMPTY, [ makeExpressionEffect( makeThrowErrorExpression( "TypeError", "Cannot assign super property", hash, ), hash, ), ], hash, ), ); } else { throw new AranTypeError(mode); } } else if (routine.type === "function") { return liftSequenceX_( makeExpressionEffect, initSyntaxErrorExpression("Illegal 'super' set", hash), hash, ); } else if (routine.type === "root") { if (root === "script" || root === "module" || root === "eval.global") { return liftSequenceX_( makeExpressionEffect, initSyntaxErrorExpression("Illegal 'super' set", hash), hash, ); } else if (root === "eval.local.root") { return zeroSequence( makeExpressionEffect( makeApplyExpression( makeReadExpression("super.set", hash), makeIntrinsicExpression("undefined", hash), [operation.key, operation.value], hash, ), hash, ), ); } else { throw new AranTypeError(root); } } else { throw new AranTypeError(routine); } }; /** * @type {( * input: import("../../atom.d.ts").Expression, * ) => import("./index.d.ts").CallSuperOperation} */ export const makeCallSuperOperation = (input) => ({ input }); /** * @type {import("../api.d.ts").PerformEffect< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").CallSuperOperation, * ( * | import("../../prelude/index.d.ts").SyntaxErrorPrelude * | import("../../prelude/index.d.ts").MetaDeclarationPrelude * ), * >} */ export const listCallSuperEffect = ( hash, meta, { root, routine }, operation, ) => { if (routine.type === "constructor") { if (routine.derived) { return incorporateEffect( mapSequence( cacheConstant( meta, makeApplyExpression( makeIntrinsicExpression("Reflect.construct", hash), makeIntrinsicExpression("undefined", hash), [ makeApplyExpression( makeIntrinsicExpression("Reflect.getPrototypeOf", hash), makeIntrinsicExpression("undefined", hash), [makeReadCacheExpression(routine.self, hash)], hash, ), operation.input, makeReadExpression("new.target", hash), ], hash, ), hash, ), (right) => makeConditionalEffect( makeReadExpression("this", hash), [ makeExpressionEffect( makeThrowErrorExpression( "ReferenceError", "Duplicate super call", hash, ), hash, ), ], [ makeWriteEffect( "this", makeReadCacheExpression(right, hash), hash, ), makeConditionalEffect( makeReadCacheExpression(routine.field, hash), [ makeExpressionEffect( makeApplyExpression( makeReadCacheExpression(routine.field, hash), makeReadExpression("this", hash), [], hash, ), hash, ), ], EMPTY, hash, ), ], hash, ), ), hash, ); } else { return liftSequenceX_( makeExpressionEffect, initSyntaxErrorExpression("Illegal 'super' call", hash), hash, ); } } else if (routine.type === "function" || routine.type === "method") { return liftSequenceX_( makeExpressionEffect, initSyntaxErrorExpression("Illegal 'super' call", hash), hash, ); } else if (routine.type === "root") { if (root === "script" || root === "module" || root === "eval.global") { return liftSequenceX_( makeExpressionEffect, initSyntaxErrorExpression("Illegal 'super' call", hash), hash, ); } else if (root === "eval.local.root") { return zeroSequence( makeExpressionEffect( makeApplyExpression( makeReadExpression("super.call", hash), makeIntrinsicExpression("undefined", hash), [operation.input], hash, ), hash, ), ); } else { throw new AranTypeError(root); } } else { throw new AranTypeError(routine); } }; /** * @type {( * origin: "closure" | "program", * result: import("../../atom.d.ts").Expression | null, * ) => import("./index.d.ts").UpdateResultOperation} */ export const makeUpdateResultOperation = (origin, result) => ({ origin, result, }); /** * @type {import("../api.d.ts").PerformEffect< * import("./index.d.ts").RoutineScope, * import("./index.d.ts").UpdateResultOperation, * import("../../prelude/index.d.ts").SyntaxErrorPrelude, * >} */ export const listUpdateResultEffect = (hash, _meta, { routine }, operation) => { if (getOriginKind(routine) !== operation.origin) { return liftSequenceX_( makeExpressionEffect, initSyntaxErrorExpression("Illegal 'result' update", hash), hash, ); } else { if (routine.result === null) { if (operation.result === null) { return EMPTY_SEQUENCE; } else { return zeroSequence(makeExpressionEffect(operation.result, hash)); } } else { return zeroSequence( makeWriteCacheEffect( routine.result, operation.result ?? makeIntrinsicExpression("undefined", hash), hash, ), ); } } };