aran
Version:
JavaScript instrumenter
444 lines (413 loc) • 12.2 kB
TypeScript
import type { GetDefault, KeyOfUnion } from "../util/util.d.ts";
import type { DeclareHeader, ModuleHeader } from "./header.d.ts";
//////////
// Atom //
//////////
export type Atom = {
Label: string;
Variable: string;
Source: string;
Specifier: string;
Tag: unknown;
};
export type ResolvePartialAtom<atom extends Partial<Atom>> = {
Label: GetDefault<atom, "Label", string>;
Variable: GetDefault<atom, "Variable", string>;
Source: GetDefault<atom, "Source", string>;
Specifier: GetDefault<atom, "Specifier", string>;
Tag: GetDefault<atom, "Tag", string>;
};
///////////////
// Component //
///////////////
export type SyntaxPrimitive =
| null
| boolean
| number
| string
| { bigint: string };
export type RuntimePrimitive = null | boolean | number | string | bigint;
export type RegularIntrinsicRcord = {
// Symbol //
"Symbol": typeof Symbol;
"Symbol.unscopables": typeof Symbol.unscopables;
"Symbol.asyncIterator": typeof Symbol.asyncIterator;
"Symbol.iterator": typeof Symbol.iterator;
"Symbol.isConcatSpreadable": typeof Symbol.isConcatSpreadable;
"Symbol.toStringTag": typeof Symbol.toStringTag;
// String //
"String.prototype.concat": typeof String.prototype.concat;
// Object //
"Object": typeof Object;
"Object.hasOwn": typeof Object.prototype.hasOwnProperty;
"Object.create": typeof Object.create;
"Object.prototype": typeof Object.prototype;
"Object.assign": typeof Object.assign;
"Object.keys": typeof Object.keys;
"Object.freeze": typeof Object.freeze;
"Object.defineProperty": typeof Object.defineProperty;
"Object.setPrototypeOf": typeof Object.setPrototypeOf;
"Object.preventExtensions": typeof Object.preventExtensions;
// Array //
"Array.from": typeof Array.from;
"Array.of": typeof Array.of;
"Array.prototype.flat": typeof Array.prototype.flat;
"Array.prototype.values": typeof Array.prototype.values;
"Array.prototype.concat": typeof Array.prototype.concat;
"Array.prototype.includes": typeof Array.prototype.includes;
"Array.prototype.slice": typeof Array.prototype.slice;
"Array.prototype.fill": typeof Array.prototype.fill;
"Array.prototype.push": typeof Array.prototype.push;
// Function //
"Function.prototype": typeof Function.prototype;
// WeakMap //
"WeakMap": typeof WeakMap;
"WeakMap.prototype.has": typeof WeakMap.prototype.has;
"WeakMap.prototype.get": typeof WeakMap.prototype.get;
"WeakMap.prototype.set": typeof WeakMap.prototype.set;
// Map //
"Map": typeof Map;
"Map.prototype.has": typeof Map.prototype.has;
"Map.prototype.get": typeof Map.prototype.get;
"Map.prototype.set": typeof Map.prototype.set;
// WeakSet //
"WeakSet": typeof WeakSet;
"WeakSet.prototype.has": typeof WeakSet.prototype.has;
"WeakSet.prototype.add": typeof WeakSet.prototype.add;
// Reflect //
"Reflect.get": typeof Reflect.get;
"Reflect.has": typeof Reflect.has;
"Reflect.construct": typeof Reflect.construct;
"Reflect.apply": typeof Reflect.apply;
"Reflect.getPrototypeOf": typeof Reflect.getPrototypeOf;
"Reflect.ownKeys": typeof Reflect.ownKeys;
"Reflect.isExtensible": typeof Reflect.isExtensible;
"Reflect.set": typeof Reflect.set;
"Reflect.deleteProperty": typeof Reflect.deleteProperty;
"Reflect.setPrototypeOf": typeof Reflect.setPrototypeOf;
"Reflect.getOwnPropertyDescriptor": typeof Reflect.getOwnPropertyDescriptor;
"Reflect.preventExtensions": typeof Reflect.preventExtensions;
"Reflect.defineProperty": typeof Reflect.defineProperty;
// Number //
"Number": typeof Number;
"Number.NEGATIVE_INFINITY": typeof Number.NEGATIVE_INFINITY;
"Number.POSITIVE_INFINITY": typeof Number.POSITIVE_INFINITY;
// Others //
"Function": typeof Function;
"undefined": typeof undefined;
"globalThis": typeof globalThis;
"eval": typeof eval;
"Proxy": typeof Proxy;
"String": typeof String;
"RegExp": typeof RegExp;
"TypeError": typeof TypeError;
"ReferenceError": typeof ReferenceError;
"SyntaxError": typeof SyntaxError;
};
export type RegularIntrinsic = keyof RegularIntrinsicRcord;
export type AccessorIntrinsicRecord = {
"Symbol.prototype.description@get": (this: symbol) => string | undefined;
"Function.prototype.arguments@get": (this: Function) => void;
"Function.prototype.arguments@set": (this: Function, value: unknown) => void;
};
export type AccessorIntrinsic = keyof AccessorIntrinsicRecord;
export type ExtraIntrinsicRecord = {
"aran.global_object": typeof globalThis;
"aran.global_declarative_record": Record<string, unknown>;
"aran.deadzone_symbol": symbol;
"aran.transpileEvalCode": (
code: string,
situ: string,
hash: string | number,
) => Program<Atom>;
"aran.retropileEvalCode": (aran: Program<Atom>) => string;
"aran.declareGlobalVariable": (name: string) => void;
"aran.readGlobalVariable": (name: string) => unknown;
"aran.typeofGlobalVariable": (name: string) => string;
"aran.discardGlobalVariable": (name: string) => boolean;
"aran.writeGlobalVariableStrict": (name: string, value: unknown) => boolean;
"aran.writeGlobalVariableSloppy": (name: string, value: unknown) => boolean;
"aran.performUnaryOperation": (
operator: string,
argument: unknown,
) => unknown;
"aran.performBinaryOperation": (
operator: string,
left: unknown,
right: unknown,
) => unknown;
"aran.throwException": (value: unknown) => never;
"aran.getValueProperty": (object: unknown, key: unknown) => unknown;
// https://262.ecma-international.org/14.0#sec-topropertykey
"aran.toPropertyKey": (value: unknown) => string | symbol;
"aran.isConstructor": (value: unknown) => boolean;
"aran.toArgumentList": (
array: unknown[],
callee: Function | null,
) => ArrayLike<unknown>;
"aran.sliceObject": (
object: object,
exclusion: { [key in PropertyKey]: null },
) => object;
"aran.listForInKey": (object: unknown) => ArrayLike<string>;
"aran.listIteratorRest": <X>(
iterator: Iterator<X>,
next: (result: unknown) => IteratorResult<X>,
) => X[];
"aran.createObject": (prototype: object, ...entries: unknown[]) => unknown;
"aran.AsyncGeneratorFunction.prototype.prototype": AsyncGeneratorFunction["prototype"];
"aran.GeneratorFunction.prototype.prototype": GeneratorFunction["prototype"];
};
export type HeadlessClosureKind = "arrow" | "function" | "method";
export type HeadfulClosureKind = "generator";
export type ClosureKind = HeadlessClosureKind | HeadfulClosureKind;
export type AranIntrinsic = keyof ExtraIntrinsicRecord;
export type Intrinsic = RegularIntrinsic | AccessorIntrinsic | AranIntrinsic;
export type IntrinsicRecord = RegularIntrinsicRcord &
AccessorIntrinsicRecord &
ExtraIntrinsicRecord;
export type Parameter =
| "import"
| "import.meta"
| "this"
| "new.target"
// https://github.com/allenwb/ESideas/blob/HEAD/ES7MetaProps.md
| "function.arguments"
| "function.callee"
| "catch.error"
| "super.get"
| "super.set"
| "super.call"
| "private.check"
| "private.get"
| "private.has"
| "private.set"
| "scope.read"
| "scope.writeStrict"
| "scope.writeSloppy"
| "scope.typeof"
| "scope.discard";
//////////
// Node //
//////////
export type Program<atom extends Atom = Atom> =
| {
type: "Program";
kind: "module";
situ: "global";
head: ModuleHeader[];
body: HeadlessRoutineBlock<atom>;
tag: atom["Tag"];
}
| {
type: "Program";
kind: "script";
situ: "global";
head: DeclareHeader[];
body: HeadlessRoutineBlock<atom>;
tag: atom["Tag"];
}
| {
type: "Program";
kind: "eval";
situ: "global";
head: DeclareHeader[];
body: HeadlessRoutineBlock<atom>;
tag: atom["Tag"];
}
| {
type: "Program";
kind: "eval";
situ: "local.root";
head: DeclareHeader[];
body: HeadlessRoutineBlock<atom>;
tag: atom["Tag"];
}
| {
type: "Program";
kind: "eval";
situ: "local.deep";
head: [];
body: HeadlessRoutineBlock<atom>;
tag: atom["Tag"];
};
///////////
// Block //
///////////
export type SegmentBlock<atom extends Atom = Atom> = {
type: "SegmentBlock";
labels: atom["Label"][];
bindings: [atom["Variable"], Intrinsic][];
body: Statement<atom>[];
tag: atom["Tag"];
};
export type RoutineBlock<A extends Atom = Atom> = {
type: "RoutineBlock";
bindings: [A["Variable"], Intrinsic][];
head: Effect<A>[] | null;
body: Statement<A>[];
tail: Expression<A>;
tag: A["Tag"];
};
export type HeadlessRoutineBlock<atom extends Atom = Atom> =
RoutineBlock<atom> & {
head: null;
};
export type HeadfulRoutineBlock<atom extends Atom = Atom> =
RoutineBlock<atom> & {
head: Effect<atom>[];
};
export type Statement<atom extends Atom = Atom> =
| {
type: "EffectStatement";
inner: Effect<atom>;
tag: atom["Tag"];
}
| {
type: "BreakStatement";
label: atom["Label"];
tag: atom["Tag"];
}
| {
type: "DebuggerStatement";
tag: atom["Tag"];
}
| {
type: "BlockStatement";
body: SegmentBlock<atom>;
tag: atom["Tag"];
}
| {
type: "IfStatement";
test: Expression<atom>;
then: SegmentBlock<atom>;
else: SegmentBlock<atom>;
tag: atom["Tag"];
}
| {
type: "WhileStatement";
test: Expression<atom>;
body: SegmentBlock<atom>;
tag: atom["Tag"];
}
| {
type: "TryStatement";
try: SegmentBlock<atom>;
catch: SegmentBlock<atom>;
finally: SegmentBlock<atom>;
tag: atom["Tag"];
};
export type Effect<atom extends Atom = Atom> =
| {
type: "ExpressionEffect";
discard: Expression<atom>;
tag: atom["Tag"];
}
| {
type: "ConditionalEffect";
test: Expression<atom>;
positive: Effect<atom>[];
negative: Effect<atom>[];
tag: atom["Tag"];
}
| {
type: "WriteEffect";
variable: Parameter | atom["Variable"];
value: Expression<atom>;
tag: atom["Tag"];
}
| {
type: "ExportEffect";
export: atom["Specifier"];
value: Expression<atom>;
tag: atom["Tag"];
};
export type Expression<atom extends Atom = Atom> =
// Produce //
| {
type: "PrimitiveExpression";
primitive: SyntaxPrimitive;
tag: atom["Tag"];
}
| {
type: "IntrinsicExpression";
intrinsic: Intrinsic;
tag: atom["Tag"];
}
| {
type: "ImportExpression";
source: atom["Source"];
import: atom["Specifier"] | null;
tag: atom["Tag"];
}
| {
type: "ReadExpression";
variable: Parameter | atom["Variable"];
tag: atom["Tag"];
}
| {
type: "ClosureExpression";
kind: HeadlessClosureKind;
asynchronous: boolean;
body: HeadlessRoutineBlock<atom>;
tag: atom["Tag"];
}
| {
type: "ClosureExpression";
kind: HeadfulClosureKind;
asynchronous: boolean;
body: HeadfulRoutineBlock<atom>;
tag: atom["Tag"];
}
// Control //
| {
type: "AwaitExpression";
promise: Expression<atom>;
tag: atom["Tag"];
}
| {
type: "YieldExpression";
delegate: boolean;
item: Expression<atom>;
tag: atom["Tag"];
}
| {
type: "SequenceExpression";
head: Effect<atom>[];
tail: Expression<atom>;
tag: atom["Tag"];
}
| {
type: "ConditionalExpression";
test: Expression<atom>;
consequent: Expression<atom>;
alternate: Expression<atom>;
tag: atom["Tag"];
}
// Combine //
| {
type: "EvalExpression";
code: Expression<atom>;
tag: atom["Tag"];
}
| {
type: "ApplyExpression";
callee: Expression<atom>;
this: Expression<atom>;
arguments: Expression<atom>[];
tag: atom["Tag"];
}
| {
type: "ConstructExpression";
callee: Expression<atom>;
arguments: Expression<atom>[];
tag: atom["Tag"];
};
export type Node<A extends Atom = Atom> =
| Program<A>
| SegmentBlock<A>
| RoutineBlock<A>
| Statement<A>
| Effect<A>
| Expression<A>;
export type NodeKey = KeyOfUnion<Node<Atom>>;