aran
Version:
JavaScript instrumenter
322 lines (305 loc) • 8.21 kB
JavaScript
import { AranTypeError } from "../../../../error.mjs";
import { makeIntrinsicExpression } from "../../../node.mjs";
import {
findTree,
map,
flatSequence,
mapSequence,
zeroSequence,
} from "../../../../util/index.mjs";
import { forkMeta, nextMeta } from "../../../meta.mjs";
import {
listReifyInitializeEffect,
listReifyLateDeclareEffect,
listReifyWriteEffect,
listReifyWriteWriteSloppyFunctionEffect,
makeReifyDiscardExpression,
makeReifyReadExpression,
makeReifyTypeofExpression,
setupReifyBinding,
} from "./reify.mjs";
import {
listAlienInitializeEffect,
listAlienLateDeclareEffect,
listAlienWriteEffect,
listAlienWriteWriteSloppyFunctionEffect,
makeAlienDiscardExpression,
makeAlienReadExpression,
makeAlienTypeofExpression,
setupAlienBinding,
} from "./alien.mjs";
/**
* @type {(
* variable: import("estree-sentry").VariableName,
* ) => (
* binding: {
* variable: import("estree-sentry").VariableName,
* },
* ) => boolean}
*/
const compileMatch =
(variable1) =>
({ variable: variable2 }) =>
variable1 === variable2;
/**
* @type {(
* frame: import("./index.d.ts").RootFrame,
* root: import("../../../sort.d.ts").RootSort,
* ) => import("./index.d.ts").RootBind}
*/
export const hydrateRootFrame = (frame, root) => {
switch (frame.kind) {
case "reify": {
const { kind, bindings } = frame;
return { kind, root, bindings };
}
case "alien": {
const { kind, bindings } = frame;
return { kind, root, bindings };
}
default: {
throw new AranTypeError(frame);
}
}
};
///////////
// setup //
///////////
/**
* @type {import("../../api.d.ts").Setup<
* {
* bindings: [
* variable: import("estree-sentry").VariableName,
* kinds: import("./index.d.ts").RootKind[],
* ][],
* sort: import("../../../sort.d.ts").Sort,
* },
* (
* | import("../../../prelude/index.d.ts").ReifyExternalPrelude
* | import("../../../prelude/index.d.ts").PrefixPrelude
* | import("../../../prelude/index.d.ts").MetaDeclarationPrelude
* ),
* import("./index.d.ts").ReifyFrame,
* >}
*/
const setupReifyRootFrame = (hash, meta, { bindings, sort }) =>
mapSequence(
flatSequence(
map(bindings, (binding) =>
setupReifyBinding(hash, forkMeta((meta = nextMeta(meta))), {
binding,
sort,
}),
),
),
(bindings) => ({
type: "root",
kind: "reify",
bindings,
}),
);
/**
* @type {import("../../api.d.ts").Setup<
* {
* bindings: [
* variable: import("estree-sentry").VariableName,
* kinds: import("./index.d.ts").RootKind[],
* ][],
* },
* (
* | import("../../../prelude/index.d.ts").HeaderPrelude
* | import("../../../prelude/index.d.ts").PrefixPrelude
* | import("../../../prelude/index.d.ts").MetaDeclarationPrelude
* | import("../../../prelude/index.d.ts").WarningPrelude
* ),
* import("./index.d.ts").AlienFrame,
* >}
*/
const setupAlienRootFrame = (hash, meta, { bindings }) =>
mapSequence(
flatSequence(
map(bindings, (binding) =>
setupAlienBinding(hash, forkMeta((meta = nextMeta(meta))), { binding }),
),
),
(bindings) => ({
type: "root",
kind: "alien",
bindings,
}),
);
/**
* @type {import("../../api.d.ts").Setup<
* import("./index.d.ts").RawRootFrame,
* (
* | import("../../../prelude/index.d.ts").MetaDeclarationPrelude
* | import("../../../prelude/index.d.ts").HeaderPrelude
* | import("../../../prelude/index.d.ts").ReifyExternalPrelude
* | import("../../../prelude/index.d.ts").PrefixPrelude
* | import("../../../prelude/index.d.ts").WarningPrelude
* ),
* import("./index.d.ts").RootFrame,
* >}
*/
export const setupRootFrame = (
hash,
meta,
{ sort, global_declarative_record, bindings },
) => {
switch (global_declarative_record) {
case "builtin": {
return setupAlienRootFrame(hash, meta, { bindings });
}
case "emulate": {
return setupReifyRootFrame(hash, meta, { sort, bindings });
}
default: {
throw new AranTypeError(global_declarative_record);
}
}
};
//////////
// load //
//////////
/**
* @type {<X, W1, W2, O extends { variable: import("estree-sentry").VariableName }>(
* performReify: import("../../api.d.ts").Perform<import("./index.d.ts").ReifyMatch, O, W1, X>,
* performAlien: import("../../api.d.ts").Perform<import("./index.d.ts").AlienMatch, O, W2, X>,
* ) => import("../../api.d.ts").Perform<import("./index.d.ts").RootBind, O, W1 | W2, X>}
*/
const compileOperation =
(performReify, performAlien) => (hash, meta, bind, operation) => {
switch (bind.kind) {
case "reify": {
return performReify(
hash,
meta,
{
root: bind.root,
binding: findTree(bind.bindings, compileMatch(operation.variable)),
},
operation,
);
}
case "alien": {
return performAlien(
hash,
meta,
{
root: bind.root,
binding: findTree(bind.bindings, compileMatch(operation.variable)),
},
operation,
);
}
default: {
throw new AranTypeError(bind);
}
}
};
export const makeRootReadExpression = compileOperation(
makeReifyReadExpression,
makeAlienReadExpression,
);
export const makeRootTypeofExpression = compileOperation(
makeReifyTypeofExpression,
makeAlienTypeofExpression,
);
export const makeRootDiscardExpression = compileOperation(
makeReifyDiscardExpression,
makeAlienDiscardExpression,
);
export const listRootWriteEffect = compileOperation(
listReifyWriteEffect,
listAlienWriteEffect,
);
export const listRootWriteSloppyFunctionEffect = compileOperation(
listReifyWriteWriteSloppyFunctionEffect,
listAlienWriteWriteSloppyFunctionEffect,
);
export const listRootLateDeclareEffect = compileOperation(
listReifyLateDeclareEffect,
listAlienLateDeclareEffect,
);
/**
* @type {import("../../api.d.ts").Perform<
* import("./index.d.ts").RootBind,
* import("../index.d.ts").InitializeVariableOperation,
* import("../../../prelude/index.d.ts").MetaDeclarationPrelude,
* [
* import("../../../atom.d.ts").Effect[],
* import("./index.d.ts").RootFrame,
* ],
* >}
*/
export const listRootInitializeEffect = (hash, meta, bind, operation) => {
switch (bind.kind) {
case "reify": {
const { root, bindings } = bind;
return mapSequence(
listReifyInitializeEffect(
hash,
meta,
{
root,
binding: findTree(bindings, compileMatch(operation.variable)),
},
operation,
),
({ 0: value, 1: state }) => [
value,
{
type: "root",
kind: "reify",
bindings: [state, bindings],
},
],
);
}
case "alien": {
const { root, bindings } = bind;
return mapSequence(
listAlienInitializeEffect(
hash,
meta,
{
root,
binding: findTree(bindings, compileMatch(operation.variable)),
},
operation,
),
({ 0: value, 1: state }) => [
value,
{
type: "root",
kind: "alien",
bindings: [state, bindings],
},
],
);
}
default: {
throw new AranTypeError(bind);
}
}
};
/**
* This might not be correct for eval.local.root
* Because it might be inside a with statement.
* cf: wrong-this-parameter-in-with-in-eval
* @type {(
* hash: import("../../../hash.d.ts").Hash,
* meta: import("../../../meta.d.ts").Meta,
* bind: import("./index.d.ts").RootBind,
* operation: import("../index.d.ts").VariableOperation,
* ) => import("../../../../util/sequence.d.ts").Sequence<
* never,
* import("../../../atom.d.ts").Expression,
* >}
*/
export const makeRootReadAmbientThisExpression = (
hash,
_meta,
_bind,
_operation,
) => zeroSequence(makeIntrinsicExpression("undefined", hash));