@opencode/codemode 0.0.0-dev-19356 → 0.0.0-dev-19358

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ import { transpile } from "#transpile";
6
6
  import { toData } from "../data.js";
7
7
  import { ToolRuntime } from "../tool-runtime.js";
8
8
  import { normalizeError } from "./errors.js";
9
- import { InterpreterRuntimeError, isRecord } from "./model.js";
9
+ import { InterpreterRuntimeError } from "./model.js";
10
10
  import { PromiseRuntime } from "./promises.js";
11
11
  import { Interpreter } from "./runtime.js";
12
12
  export const executeProgram = (code, prepared, limits, hooks) => {
@@ -88,17 +88,13 @@ const parseProgram = (code) => {
88
88
  const bodyStart = transpiled.outputText.indexOf("{") + 1;
89
89
  const bodyEnd = transpiled.outputText.lastIndexOf("}");
90
90
  const executableCode = transpiled.outputText.slice(bodyStart, bodyEnd);
91
- const parsed = parse(executableCode, {
91
+ return parse(executableCode, {
92
92
  ecmaVersion: "latest",
93
93
  sourceType: "script",
94
94
  allowReturnOutsideFunction: true,
95
95
  allowAwaitOutsideFunction: true,
96
96
  locations: true,
97
97
  });
98
- if (!isRecord(parsed) || parsed.type !== "Program" || !Array.isArray(parsed.body)) {
99
- throw new InterpreterRuntimeError("Failed to parse script as a Program node.");
100
- }
101
- return parsed;
102
98
  };
103
99
  const utf8ByteLength = (value) => new TextEncoder().encode(value).byteLength;
104
100
  // Drop a replacement character produced by truncating inside a UTF-8 sequence.
@@ -1,24 +1,10 @@
1
+ import type { BlockStatement, Expression, Node, Pattern } from "acorn";
1
2
  import type { Effect } from "effect";
2
3
  import type { DiagnosticKind } from "../codemode.js";
3
4
  import type { SafeObject } from "../data.js";
4
5
  import type { Values } from "../values.js";
5
- export type SourcePosition = {
6
- line: number;
7
- column: number;
8
- };
9
- export type SourceLocation = {
10
- start: SourcePosition;
11
- end: SourcePosition;
12
- };
13
- export type AstNode = {
14
- type: string;
15
- loc?: SourceLocation;
16
- [key: string]: unknown;
17
- };
18
- export type ProgramNode = AstNode & {
19
- type: "Program";
20
- body: Array<AstNode>;
21
- };
6
+ /** Any parsed node; the interpreter narrows on `type` and reads `loc` for diagnostics. */
7
+ export type AstNode = Node;
22
8
  export type Binding = {
23
9
  mutable: boolean;
24
10
  value: unknown;
@@ -41,12 +27,12 @@ export type MemberReference = {
41
27
  key: PropertyKey;
42
28
  };
43
29
  export declare class CodeModeFunction {
44
- readonly parameters: ReadonlyArray<AstNode>;
45
- readonly body: AstNode;
30
+ readonly parameters: ReadonlyArray<Pattern>;
31
+ readonly body: BlockStatement | Expression;
46
32
  readonly capturedScopes: ReadonlyArray<Map<string, Binding>>;
47
33
  readonly async: boolean;
48
34
  readonly generator: boolean;
49
- constructor(parameters: ReadonlyArray<AstNode>, body: AstNode, capturedScopes: ReadonlyArray<Map<string, Binding>>, async: boolean, generator: boolean);
35
+ constructor(parameters: ReadonlyArray<Pattern>, body: BlockStatement | Expression, capturedScopes: ReadonlyArray<Map<string, Binding>>, async: boolean, generator: boolean);
50
36
  }
51
37
  export type GeneratorRequestKind = "next" | "return" | "throw";
52
38
  export declare class CodeModeGenerator {
@@ -138,12 +124,6 @@ export declare class InterpreterRuntimeError extends Error {
138
124
  }
139
125
  export declare const unsupportedSyntax: (kind: string, node: AstNode) => InterpreterRuntimeError;
140
126
  export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
141
- export declare const asNode: (value: unknown, context: string) => AstNode;
142
- export declare const getArray: (node: AstNode, key: string) => Array<unknown>;
143
- export declare const getString: (node: AstNode, key: string) => string;
144
- export declare const getBoolean: (node: AstNode, key: string) => boolean;
145
- export declare const getOptionalNode: (node: AstNode, key: string) => AstNode | undefined;
146
- export declare const getNode: (node: AstNode, key: string) => AstNode;
147
127
  export declare const sourceLocation: (node: AstNode) => {
148
128
  readonly line: number;
149
129
  readonly column: number;
@@ -143,37 +143,6 @@ export class InterpreterRuntimeError extends Error {
143
143
  }
144
144
  export const unsupportedSyntax = (kind, node) => new InterpreterRuntimeError(`Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
145
145
  export const isRecord = (value) => typeof value === "object" && value !== null;
146
- export const asNode = (value, context) => {
147
- if (!isRecord(value) || typeof value.type !== "string") {
148
- throw new InterpreterRuntimeError(`Invalid AST node while reading ${context}.`);
149
- }
150
- return value;
151
- };
152
- export const getArray = (node, key) => {
153
- const value = node[key];
154
- if (!Array.isArray(value))
155
- throw new InterpreterRuntimeError(`Expected '${key}' to be an array.`, node);
156
- return value;
157
- };
158
- export const getString = (node, key) => {
159
- const value = node[key];
160
- if (typeof value !== "string")
161
- throw new InterpreterRuntimeError(`Expected '${key}' to be a string.`, node);
162
- return value;
163
- };
164
- export const getBoolean = (node, key) => {
165
- const value = node[key];
166
- if (typeof value !== "boolean")
167
- throw new InterpreterRuntimeError(`Expected '${key}' to be a boolean.`, node);
168
- return value;
169
- };
170
- export const getOptionalNode = (node, key) => {
171
- const value = node[key];
172
- if (value === undefined || value === null)
173
- return undefined;
174
- return asNode(value, key);
175
- };
176
- export const getNode = (node, key) => asNode(node[key], key);
177
146
  export const sourceLocation = (node) => ({
178
147
  line: Math.max(1, (node.loc?.start.line ?? 2) - 1),
179
148
  column: Math.max(1, (node.loc?.start.column ?? 4) - 3),
@@ -1,5 +1,5 @@
1
+ import type { Program } from "acorn";
1
2
  import { Effect } from "effect";
2
- import { type ProgramNode } from "./model.js";
3
3
  import { PromiseRuntime } from "./promises.js";
4
4
  export declare class Interpreter<R> {
5
5
  private scopes;
@@ -12,7 +12,7 @@ export declare class Interpreter<R> {
12
12
  private generatorAsync;
13
13
  private readonly runner;
14
14
  constructor(executeTool: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, invokeSearch: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>, promises: PromiseRuntime<R>, logs?: Array<string>);
15
- run(program: ProgramNode): Effect.Effect<unknown, unknown, R>;
15
+ run(program: Program): Effect.Effect<unknown, unknown, R>;
16
16
  private createToolCallPromise;
17
17
  private createPromise;
18
18
  private settlePromise;
@@ -1,7 +1,7 @@
1
1
  import { Cause, Deferred, Effect, Exit } from "effect";
2
2
  import { isBlockedMember, ToolRuntimeError, toProgram } from "../data.js";
3
3
  import { ToolReference } from "../tool-runtime.js";
4
- import { AsyncIteratorSymbol, asNode, CodeModeFunction, CodeModeGenerator, CoercionFunction, ComputedValue, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, GeneratorMethodReference, GeneratorReturn, getArray, getBoolean, getNode, getOptionalNode, getString, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, JsonMethodReference, OptionalShortCircuit, PromiseCapabilityFunction, PromiseInstanceMethodReference, PromiseMethodReference, PromiseNamespace, ProgramThrow, SearchFunction, SymbolNamespace, unsupportedSyntax, UriFunction, } from "./model.js";
4
+ import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, CoercionFunction, ComputedValue, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, JsonMethodReference, OptionalShortCircuit, PromiseCapabilityFunction, PromiseInstanceMethodReference, PromiseMethodReference, PromiseNamespace, ProgramThrow, SearchFunction, SymbolNamespace, unsupportedSyntax, UriFunction, } from "./model.js";
5
5
  import { caughtErrorValue, constructAggregateErrorValue, constructErrorValue } from "./errors.js";
6
6
  import { arrayStatics, invokeArrayFrom, invokeGlobalMethod, invokeGroupBy, invokeIntrinsic, toPrimitive, } from "./methods.js";
7
7
  import { preserveConsumerError } from "./iterator.js";
@@ -40,18 +40,18 @@ const parseArrayIndex = (key) => {
40
40
  return index < MAX_ARRAY_LENGTH ? index : undefined;
41
41
  };
42
42
  const calleeDescription = (callee) => {
43
- if (callee.type === "Identifier")
44
- return getString(callee, "name");
45
- if (callee.type === "MemberExpression") {
46
- const object = getNode(callee, "object");
47
- const property = getNode(callee, "property");
48
- const key = callee.computed !== true && property.type === "Identifier"
49
- ? getString(property, "name")
43
+ if (callee?.type === "Identifier")
44
+ return callee.name;
45
+ if (callee?.type === "MemberExpression") {
46
+ const object = callee.object;
47
+ const property = callee.property;
48
+ const key = !callee.computed && property.type === "Identifier"
49
+ ? property.name
50
50
  : property.type === "Literal" && typeof property.value === "string"
51
51
  ? property.value
52
52
  : undefined;
53
53
  if (object.type === "Identifier" && key !== undefined)
54
- return `${getString(object, "name")}.${key}`;
54
+ return `${object.name}.${key}`;
55
55
  }
56
56
  return "The called value";
57
57
  };
@@ -90,24 +90,23 @@ const instanceofValue = (lhs, rhs, node) => {
90
90
  const collectPatternNames = (pattern, out = []) => {
91
91
  switch (pattern.type) {
92
92
  case "Identifier":
93
- out.push(getString(pattern, "name"));
93
+ out.push(pattern.name);
94
94
  break;
95
95
  case "AssignmentPattern":
96
- collectPatternNames(getNode(pattern, "left"), out);
96
+ collectPatternNames(pattern.left, out);
97
97
  break;
98
98
  case "RestElement":
99
- collectPatternNames(getNode(pattern, "argument"), out);
99
+ collectPatternNames(pattern.argument, out);
100
100
  break;
101
101
  case "ArrayPattern":
102
- for (const element of getArray(pattern, "elements")) {
102
+ for (const element of pattern.elements) {
103
103
  if (element !== null)
104
- collectPatternNames(asNode(element, "elements"), out);
104
+ collectPatternNames(element, out);
105
105
  }
106
106
  break;
107
107
  case "ObjectPattern":
108
- for (const property of getArray(pattern, "properties")) {
109
- const prop = asNode(property, "properties");
110
- collectPatternNames(prop.type === "RestElement" ? getNode(prop, "argument") : getNode(prop, "value"), out);
108
+ for (const prop of pattern.properties) {
109
+ collectPatternNames(prop.type === "RestElement" ? prop.argument : prop.value, out);
111
110
  }
112
111
  break;
113
112
  }
@@ -116,13 +115,13 @@ const collectPatternNames = (pattern, out = []) => {
116
115
  const loopDeclaration = (left, statement) => {
117
116
  if (left.type !== "VariableDeclaration")
118
117
  return undefined;
119
- const declarations = getArray(left, "declarations");
120
- if (declarations.length !== 1) {
118
+ const declaration = left.declarations.length === 1 ? left.declarations[0] : undefined;
119
+ if (declaration === undefined) {
121
120
  throw new InterpreterRuntimeError(`${statement} supports one declared binding.`, left);
122
121
  }
123
- const kind = getString(left, "kind");
122
+ const kind = left.kind;
124
123
  return {
125
- pattern: getNode(asNode(declarations[0], "declarations[0]"), "id"),
124
+ pattern: declaration.id,
126
125
  mutable: kind !== "const",
127
126
  lexical: kind !== "var",
128
127
  };
@@ -140,7 +139,7 @@ const copyIteratorSymbols = (source, target, consumed) => {
140
139
  Reflect.set(target, symbol, Reflect.get(source, symbol));
141
140
  }
142
141
  };
143
- const promiseResolutionNode = { type: "PromiseResolution" };
142
+ const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
144
143
  export class Interpreter {
145
144
  scopes;
146
145
  executeTool;
@@ -207,7 +206,7 @@ export class Interpreter {
207
206
  let value = undefined;
208
207
  for (const [index, statement] of program.body.entries()) {
209
208
  if (index === program.body.length - 1 && statement.type === "ExpressionStatement") {
210
- value = yield* self.evaluateExpression(getNode(statement, "expression"));
209
+ value = yield* self.evaluateExpression(statement.expression);
211
210
  break;
212
211
  }
213
212
  const result = yield* self.evaluateStatement(statement);
@@ -242,11 +241,11 @@ export class Interpreter {
242
241
  evaluateStatement(node) {
243
242
  switch (node.type) {
244
243
  case "ExpressionStatement":
245
- return Effect.as(this.evaluateExpression(getNode(node, "expression")), { kind: "none" });
244
+ return Effect.as(this.evaluateExpression(node.expression), { kind: "none" });
246
245
  case "VariableDeclaration":
247
246
  return Effect.map(this.evaluateVariableDeclaration(node), () => ({ kind: "none" }));
248
247
  case "ReturnStatement": {
249
- const argumentNode = getOptionalNode(node, "argument");
248
+ const argumentNode = node.argument;
250
249
  return argumentNode
251
250
  ? Effect.map(this.evaluateExpression(argumentNode), (value) => ({ kind: "return", value }))
252
251
  : Effect.succeed({ kind: "return", value: undefined });
@@ -289,11 +288,10 @@ export class Interpreter {
289
288
  this.scopes.push();
290
289
  const self = this;
291
290
  return Effect.gen(function* () {
292
- const body = getArray(node, "body");
291
+ const body = node.body;
293
292
  self.predeclareLexical(body);
294
293
  self.hoistFunctions(body);
295
- for (const statementValue of body) {
296
- const statement = asNode(statementValue, "body");
294
+ for (const statement of body) {
297
295
  const result = yield* self.evaluateStatement(statement);
298
296
  if (result.kind !== "none") {
299
297
  return result;
@@ -303,27 +301,24 @@ export class Interpreter {
303
301
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
304
302
  }
305
303
  createFunction(node) {
306
- return new CodeModeFunction(getArray(node, "params").map((parameter, index) => asNode(parameter, `params[${index}]`)), getNode(node, "body"), this.scopes.capture(), node.async === true, node.generator === true);
304
+ return new CodeModeFunction(node.params, node.body, this.scopes.capture(), node.async, node.generator);
307
305
  }
308
306
  hoistFunctions(statements) {
309
- for (const statementValue of statements) {
310
- if (!isRecord(statementValue) || statementValue.type !== "FunctionDeclaration")
307
+ for (const node of statements) {
308
+ if (node.type !== "FunctionDeclaration")
311
309
  continue;
312
- const node = statementValue;
313
- this.scopes.declare(getString(getNode(node, "id"), "name"), this.createFunction(node), true, node);
310
+ this.scopes.declare(node.id.name, this.createFunction(node), true, node);
314
311
  }
315
312
  }
316
313
  predeclareLexical(statements) {
317
- for (const statementValue of statements) {
318
- if (!isRecord(statementValue) || statementValue.type !== "VariableDeclaration")
314
+ for (const statement of statements) {
315
+ if (statement.type !== "VariableDeclaration")
319
316
  continue;
320
- const statement = statementValue;
321
- const kind = getString(statement, "kind");
317
+ const kind = statement.kind;
322
318
  if (kind === "var")
323
319
  continue;
324
- for (const declarationValue of getArray(statement, "declarations")) {
325
- const declaration = asNode(declarationValue, "declarations");
326
- for (const name of collectPatternNames(getNode(declaration, "id"))) {
320
+ for (const declaration of statement.declarations) {
321
+ for (const name of collectPatternNames(declaration.id)) {
327
322
  this.scopes.reserve(name, kind !== "const", declaration);
328
323
  }
329
324
  }
@@ -334,30 +329,27 @@ export class Interpreter {
334
329
  this.scopes.reserve(name, mutable, node);
335
330
  }
336
331
  evaluateIfStatement(node) {
337
- const testNode = getNode(node, "test");
338
- const consequentNode = getNode(node, "consequent");
339
- const alternateNode = getOptionalNode(node, "alternate");
340
- return Effect.flatMap(this.evaluateExpression(testNode), (test) => test
341
- ? this.evaluateStatement(consequentNode)
342
- : alternateNode
343
- ? this.evaluateStatement(alternateNode)
332
+ return Effect.flatMap(this.evaluateExpression(node.test), (test) => test
333
+ ? this.evaluateStatement(node.consequent)
334
+ : node.alternate
335
+ ? this.evaluateStatement(node.alternate)
344
336
  : Effect.succeed({ kind: "none" }));
345
337
  }
346
338
  evaluateSwitchStatement(node) {
347
339
  const self = this;
348
340
  return Effect.gen(function* () {
349
- const discriminant = yield* self.evaluateExpression(getNode(node, "discriminant"));
341
+ const discriminant = yield* self.evaluateExpression(node.discriminant);
350
342
  if (containsOpaqueReference(discriminant)) {
351
343
  throw new InterpreterRuntimeError("Switch discriminants must be data values.", node, "InvalidDataValue");
352
344
  }
353
345
  self.scopes.push();
354
346
  return yield* Effect.gen(function* () {
355
- const cases = getArray(node, "cases").map((value, index) => asNode(value, `cases[${index}]`));
356
- self.predeclareLexical(cases.flatMap((branch) => getArray(branch, "consequent")));
347
+ const cases = node.cases;
348
+ self.predeclareLexical(cases.flatMap((branch) => branch.consequent));
357
349
  let defaultIndex;
358
350
  let selected;
359
351
  for (const [index, branch] of cases.entries()) {
360
- const test = getOptionalNode(branch, "test");
352
+ const test = branch.test;
361
353
  if (!test) {
362
354
  defaultIndex = index;
363
355
  continue;
@@ -375,8 +367,8 @@ export class Interpreter {
375
367
  if (start === undefined)
376
368
  return { kind: "none" };
377
369
  for (let index = start; index < cases.length; index += 1) {
378
- for (const statementValue of getArray(cases[index], "consequent")) {
379
- const result = yield* self.evaluateStatement(asNode(statementValue, "consequent"));
370
+ for (const statement of cases[index].consequent) {
371
+ const result = yield* self.evaluateStatement(statement);
380
372
  if (result.kind === "break") {
381
373
  if (result.label === undefined)
382
374
  return { kind: "none" };
@@ -391,12 +383,10 @@ export class Interpreter {
391
383
  });
392
384
  }
393
385
  evaluateWhileStatement(node, labels) {
394
- const testNode = getNode(node, "test");
395
- const bodyNode = getNode(node, "body");
396
386
  const self = this;
397
387
  return Effect.gen(function* () {
398
- while (yield* self.evaluateExpression(testNode)) {
399
- const result = yield* self.evaluateStatement(bodyNode);
388
+ while (yield* self.evaluateExpression(node.test)) {
389
+ const result = yield* self.evaluateStatement(node.body);
400
390
  if (result.kind === "continue") {
401
391
  if (result.label !== undefined && !labels?.has(result.label))
402
392
  return result;
@@ -415,12 +405,10 @@ export class Interpreter {
415
405
  });
416
406
  }
417
407
  evaluateDoWhileStatement(node, labels) {
418
- const bodyNode = getNode(node, "body");
419
- const testNode = getNode(node, "test");
420
408
  const self = this;
421
409
  return Effect.gen(function* () {
422
410
  do {
423
- const result = yield* self.evaluateStatement(bodyNode);
411
+ const result = yield* self.evaluateStatement(node.body);
424
412
  if (result.kind === "continue") {
425
413
  if (result.label !== undefined && !labels?.has(result.label))
426
414
  return result;
@@ -434,7 +422,7 @@ export class Interpreter {
434
422
  if (result.kind === "return") {
435
423
  return result;
436
424
  }
437
- } while (yield* self.evaluateExpression(testNode));
425
+ } while (yield* self.evaluateExpression(node.test));
438
426
  return { kind: "none" };
439
427
  });
440
428
  }
@@ -442,11 +430,10 @@ export class Interpreter {
442
430
  this.scopes.push();
443
431
  const self = this;
444
432
  return Effect.gen(function* () {
445
- const initNode = getOptionalNode(node, "init");
446
- const testNode = getOptionalNode(node, "test");
447
- const updateNode = getOptionalNode(node, "update");
448
- const bodyNode = getNode(node, "body");
449
- if (initNode?.type === "VariableDeclaration" && getString(initNode, "kind") !== "var") {
433
+ const initNode = node.init;
434
+ const testNode = node.test;
435
+ const updateNode = node.update;
436
+ if (initNode?.type === "VariableDeclaration" && initNode.kind !== "var") {
450
437
  self.predeclareLexical([initNode]);
451
438
  }
452
439
  if (initNode) {
@@ -457,7 +444,7 @@ export class Interpreter {
457
444
  yield* self.evaluateExpression(initNode);
458
445
  }
459
446
  }
460
- const perIterationBindings = initNode?.type === "VariableDeclaration" && getString(initNode, "kind") !== "var"
447
+ const perIterationBindings = initNode?.type === "VariableDeclaration" && initNode.kind !== "var"
461
448
  ? Array.from(self.scopes.current().keys())
462
449
  : [];
463
450
  const nextIteration = () => {
@@ -469,7 +456,7 @@ export class Interpreter {
469
456
  };
470
457
  nextIteration();
471
458
  while (testNode ? yield* self.evaluateExpression(testNode) : true) {
472
- const result = yield* self.evaluateStatement(bodyNode);
459
+ const result = yield* self.evaluateStatement(node.body);
473
460
  if (result.kind === "return") {
474
461
  return result;
475
462
  }
@@ -492,8 +479,8 @@ export class Interpreter {
492
479
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
493
480
  }
494
481
  evaluateForOfStatement(node, labels) {
495
- const awaiting = getBoolean(node, "await");
496
- const left = getNode(node, "left");
482
+ const awaiting = node.await;
483
+ const left = node.left;
497
484
  const declared = loopDeclaration(left, "for...of");
498
485
  if (declared?.lexical)
499
486
  this.scopes.push();
@@ -501,8 +488,7 @@ export class Interpreter {
501
488
  return Effect.gen(function* () {
502
489
  if (declared?.lexical)
503
490
  self.predeclarePattern(declared.pattern, declared.mutable, left);
504
- const right = yield* self.evaluateExpression(getNode(node, "right"));
505
- const body = getNode(node, "body");
491
+ const right = yield* self.evaluateExpression(node.right);
506
492
  const iterator = yield* self.customIterator(right, node, awaiting);
507
493
  const cursor = iterator === undefined ? yield* self.syncIterator(right, node) : undefined;
508
494
  if (iterator === undefined && cursor === undefined) {
@@ -513,17 +499,10 @@ export class Interpreter {
513
499
  : awaiting
514
500
  ? Effect.andThen(cursor?.close ?? Effect.void, Effect.yieldNow)
515
501
  : (cursor?.close ?? Effect.void);
516
- let assignment;
517
- if (left.type !== "VariableDeclaration" &&
518
- (left.type === "Identifier" ||
519
- left.type === "MemberExpression" ||
520
- left.type === "ArrayPattern" ||
521
- left.type === "ObjectPattern")) {
522
- assignment = left;
523
- }
524
- else if (left.type !== "VariableDeclaration") {
502
+ if (left.type === "RestElement" || left.type === "AssignmentPattern") {
525
503
  throw new InterpreterRuntimeError("Unsupported for...of binding.", left);
526
504
  }
505
+ const assignment = left.type === "VariableDeclaration" ? undefined : left;
527
506
  const evaluateBody = (value) => Effect.gen(function* () {
528
507
  if (declared) {
529
508
  self.scopes.push();
@@ -534,7 +513,7 @@ export class Interpreter {
534
513
  else if (assignment) {
535
514
  yield* self.assignPattern(assignment, value, left);
536
515
  }
537
- return yield* self.evaluateStatement(body);
516
+ return yield* self.evaluateStatement(node.body);
538
517
  }).pipe(Effect.ensuring(Effect.sync(() => {
539
518
  if (declared)
540
519
  self.scopes.pop();
@@ -734,7 +713,7 @@ export class Interpreter {
734
713
  return undefined;
735
714
  }
736
715
  evaluateForInStatement(node, labels) {
737
- const left = getNode(node, "left");
716
+ const left = node.left;
738
717
  const declared = loopDeclaration(left, "for...in");
739
718
  if (declared?.lexical)
740
719
  this.scopes.push();
@@ -742,19 +721,15 @@ export class Interpreter {
742
721
  return Effect.gen(function* () {
743
722
  if (declared?.lexical)
744
723
  self.predeclarePattern(declared.pattern, declared.mutable, left);
745
- const right = yield* self.evaluateExpression(getNode(node, "right"));
746
- const body = getNode(node, "body");
724
+ const right = yield* self.evaluateExpression(node.right);
747
725
  const keys = self.enumerableKeys(right);
748
726
  if (keys === undefined) {
749
727
  throw new InterpreterRuntimeError("for...in requires a plain object, array, or tools reference. Use for...of for arrays/strings/Maps/Sets, or Object.keys(value) for a key list.", node);
750
728
  }
751
- let assignmentName;
752
- if (left.type === "Identifier") {
753
- assignmentName = getString(left, "name");
754
- }
755
- else if (left.type !== "VariableDeclaration") {
729
+ if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
756
730
  throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
757
731
  }
732
+ const assignmentName = left.type === "Identifier" ? left.name : undefined;
758
733
  for (const key of keys) {
759
734
  const result = yield* Effect.gen(function* () {
760
735
  if (declared) {
@@ -766,7 +741,7 @@ export class Interpreter {
766
741
  else if (assignmentName) {
767
742
  self.scopes.set(assignmentName, key, left);
768
743
  }
769
- return yield* self.evaluateStatement(body);
744
+ return yield* self.evaluateStatement(node.body);
770
745
  }).pipe(Effect.ensuring(Effect.sync(() => {
771
746
  if (declared)
772
747
  self.scopes.pop();
@@ -792,19 +767,17 @@ export class Interpreter {
792
767
  })));
793
768
  }
794
769
  evaluateBreakStatement(node) {
795
- const labelNode = getOptionalNode(node, "label");
796
- return labelNode ? { kind: "break", label: getString(labelNode, "name") } : { kind: "break" };
770
+ return node.label ? { kind: "break", label: node.label.name } : { kind: "break" };
797
771
  }
798
772
  evaluateContinueStatement(node) {
799
- const labelNode = getOptionalNode(node, "label");
800
- return labelNode ? { kind: "continue", label: getString(labelNode, "name") } : { kind: "continue" };
773
+ return node.label ? { kind: "continue", label: node.label.name } : { kind: "continue" };
801
774
  }
802
775
  evaluateLabeledStatement(node) {
803
776
  const labels = new Set();
804
777
  let body = node;
805
778
  while (body.type === "LabeledStatement") {
806
- labels.add(getString(getNode(body, "label"), "name"));
807
- body = getNode(body, "body");
779
+ labels.add(body.label.name);
780
+ body = body.body;
808
781
  }
809
782
  const evaluated = (() => {
810
783
  if (body.type === "WhileStatement")
@@ -824,13 +797,12 @@ export class Interpreter {
824
797
  : result);
825
798
  }
826
799
  evaluateThrowStatement(node) {
827
- const argument = getNode(node, "argument");
828
- return Effect.flatMap(this.evaluateExpression(argument), (value) => Effect.fail(new ProgramThrow(value)));
800
+ return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new ProgramThrow(value)));
829
801
  }
830
802
  evaluateTryStatement(node) {
831
- const body = getNode(node, "block");
832
- const handler = getOptionalNode(node, "handler");
833
- const finalizer = getOptionalNode(node, "finalizer");
803
+ const body = node.block;
804
+ const handler = node.handler;
805
+ const finalizer = node.finalizer;
834
806
  const self = this;
835
807
  const attempted = Effect.matchCauseEffect(this.evaluateStatement(body), {
836
808
  onFailure: (cause) => {
@@ -838,12 +810,12 @@ export class Interpreter {
838
810
  return Effect.failCause(cause);
839
811
  }
840
812
  const caught = caughtErrorValue(Cause.squash(cause));
841
- const parameter = getOptionalNode(handler, "param");
813
+ const parameter = handler.param;
842
814
  self.scopes.push();
843
815
  return Effect.gen(function* () {
844
816
  if (parameter)
845
817
  yield* self.declarePattern(parameter, caught, true, handler);
846
- return yield* self.evaluateStatement(getNode(handler, "body"));
818
+ return yield* self.evaluateStatement(handler.body);
847
819
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
848
820
  },
849
821
  onSuccess: Effect.succeed,
@@ -859,18 +831,16 @@ export class Interpreter {
859
831
  });
860
832
  }
861
833
  evaluateVariableDeclaration(node) {
862
- const kind = getString(node, "kind");
863
- const declarations = getArray(node, "declarations");
834
+ const kind = node.kind;
864
835
  const self = this;
865
836
  return Effect.gen(function* () {
866
- for (const declarationValue of declarations) {
867
- const declaration = asNode(declarationValue, "declarations");
837
+ for (const declaration of node.declarations) {
868
838
  if (declaration.type !== "VariableDeclarator") {
869
839
  throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
870
840
  }
871
- const init = getOptionalNode(declaration, "init");
841
+ const init = declaration.init;
872
842
  const value = init ? yield* self.evaluateExpression(init) : undefined;
873
- yield* self.declarePattern(getNode(declaration, "id"), value, kind !== "const", declaration, kind !== "var");
843
+ yield* self.declarePattern(declaration.id, value, kind !== "const", declaration, kind !== "var");
874
844
  }
875
845
  });
876
846
  }
@@ -878,7 +848,7 @@ export class Interpreter {
878
848
  const self = this;
879
849
  return Effect.gen(function* () {
880
850
  if (pattern.type === "Identifier") {
881
- const name = getString(pattern, "name");
851
+ const name = pattern.name;
882
852
  if (initialize)
883
853
  self.scopes.initialize(name, value, node);
884
854
  else
@@ -886,8 +856,8 @@ export class Interpreter {
886
856
  return;
887
857
  }
888
858
  if (pattern.type === "AssignmentPattern") {
889
- const resolved = value === undefined ? yield* self.evaluateExpression(getNode(pattern, "right")) : value;
890
- yield* self.declarePattern(getNode(pattern, "left"), resolved, mutable, node, initialize);
859
+ const resolved = value === undefined ? yield* self.evaluateExpression(pattern.right) : value;
860
+ yield* self.declarePattern(pattern.left, resolved, mutable, node, initialize);
891
861
  return;
892
862
  }
893
863
  if (pattern.type === "ObjectPattern") {
@@ -895,8 +865,7 @@ export class Interpreter {
895
865
  throw new InterpreterRuntimeError("Object destructuring requires a data object or array value.", pattern, "InvalidDataValue");
896
866
  }
897
867
  const consumed = new Set();
898
- for (const propertyValue of getArray(pattern, "properties")) {
899
- const property = asNode(propertyValue, "properties");
868
+ for (const property of pattern.properties) {
900
869
  if (property.type === "RestElement") {
901
870
  const rest = Object.create(null);
902
871
  for (const [key, item] of Object.entries(value)) {
@@ -904,7 +873,7 @@ export class Interpreter {
904
873
  rest[key] = item;
905
874
  }
906
875
  copyIteratorSymbols(value, rest, consumed);
907
- yield* self.declarePattern(getNode(property, "argument"), rest, mutable, property, initialize);
876
+ yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
908
877
  continue;
909
878
  }
910
879
  const key = yield* self.destructuringPropertyKey(property);
@@ -912,7 +881,7 @@ export class Interpreter {
912
881
  throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
913
882
  }
914
883
  consumed.add(typeof key === "symbol" ? key : String(key));
915
- yield* self.declarePattern(getNode(property, "value"), self.destructuringPropertyValue(value, key), mutable, property, initialize);
884
+ yield* self.declarePattern(property.value, self.destructuringPropertyValue(value, key), mutable, property, initialize);
916
885
  }
917
886
  return;
918
887
  }
@@ -926,7 +895,7 @@ export class Interpreter {
926
895
  const self = this;
927
896
  return Effect.gen(function* () {
928
897
  if (pattern.type === "Identifier") {
929
- self.scopes.set(getString(pattern, "name"), value, pattern);
898
+ self.scopes.set(pattern.name, value, pattern);
930
899
  return;
931
900
  }
932
901
  if (pattern.type === "MemberExpression") {
@@ -934,8 +903,8 @@ export class Interpreter {
934
903
  return;
935
904
  }
936
905
  if (pattern.type === "AssignmentPattern") {
937
- const resolved = value === undefined ? yield* self.evaluateExpression(getNode(pattern, "right")) : value;
938
- yield* self.assignPattern(getNode(pattern, "left"), resolved, node);
906
+ const resolved = value === undefined ? yield* self.evaluateExpression(pattern.right) : value;
907
+ yield* self.assignPattern(pattern.left, resolved, node);
939
908
  return;
940
909
  }
941
910
  if (pattern.type === "ObjectPattern") {
@@ -944,8 +913,7 @@ export class Interpreter {
944
913
  }
945
914
  const source = value;
946
915
  const consumed = new Set();
947
- for (const propertyValue of getArray(pattern, "properties")) {
948
- const property = asNode(propertyValue, "properties");
916
+ for (const property of pattern.properties) {
949
917
  if (property.type === "RestElement") {
950
918
  const rest = Object.create(null);
951
919
  for (const [key, item] of Object.entries(source)) {
@@ -953,7 +921,7 @@ export class Interpreter {
953
921
  rest[key] = item;
954
922
  }
955
923
  copyIteratorSymbols(source, rest, consumed);
956
- yield* self.assignPattern(getNode(property, "argument"), rest, property);
924
+ yield* self.assignPattern(property.argument, rest, property);
957
925
  continue;
958
926
  }
959
927
  const key = yield* self.destructuringPropertyKey(property);
@@ -961,7 +929,7 @@ export class Interpreter {
961
929
  throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
962
930
  }
963
931
  consumed.add(typeof key === "symbol" ? key : String(key));
964
- yield* self.assignPattern(getNode(property, "value"), self.destructuringPropertyValue(source, key), property);
932
+ yield* self.assignPattern(property.value, self.destructuringPropertyValue(source, key), property);
965
933
  }
966
934
  return;
967
935
  }
@@ -979,21 +947,19 @@ export class Interpreter {
979
947
  throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern).as("TypeError");
980
948
  }
981
949
  let done = false;
982
- for (const [index, item] of getArray(pattern, "elements").entries()) {
950
+ for (const element of pattern.elements) {
983
951
  if (done) {
984
- if (item === null)
952
+ if (element === null)
985
953
  continue;
986
- const element = asNode(item, `elements[${index}]`);
987
- yield* consume(element.type === "RestElement" ? getNode(element, "argument") : element, element.type === "RestElement" ? [] : undefined, element);
954
+ yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? [] : undefined, element);
988
955
  if (element.type === "RestElement")
989
956
  return;
990
957
  continue;
991
958
  }
992
959
  const step = yield* cursor.next;
993
960
  done = step.done;
994
- if (item === null)
961
+ if (element === null)
995
962
  continue;
996
- const element = asNode(item, `elements[${index}]`);
997
963
  if (element.type === "RestElement") {
998
964
  const rest = [];
999
965
  if (!step.done)
@@ -1004,7 +970,7 @@ export class Interpreter {
1004
970
  if (!done)
1005
971
  rest.push(next.value);
1006
972
  }
1007
- yield* consume(getNode(element, "argument"), rest, element);
973
+ yield* consume(element.argument, rest, element);
1008
974
  return;
1009
975
  }
1010
976
  const consumed = consume(element, step.done ? undefined : step.value, pattern);
@@ -1015,14 +981,18 @@ export class Interpreter {
1015
981
  });
1016
982
  }
1017
983
  destructuringPropertyKey(property) {
1018
- if (property.type !== "Property" || getString(property, "kind") !== "init") {
984
+ if (property.type !== "Property" || property.kind !== "init") {
1019
985
  throw new InterpreterRuntimeError("Unsupported object destructuring property.", property);
1020
986
  }
1021
- const keyNode = getNode(property, "key");
1022
- if (getBoolean(property, "computed")) {
987
+ const keyNode = property.key;
988
+ if (property.computed) {
1023
989
  return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value, keyNode));
1024
990
  }
1025
- return Effect.succeed(keyNode.type === "Identifier" ? getString(keyNode, "name") : String(keyNode.value));
991
+ if (keyNode.type === "Identifier")
992
+ return Effect.succeed(keyNode.name);
993
+ if (keyNode.type === "Literal")
994
+ return Effect.succeed(String(keyNode.value));
995
+ throw unsupportedSyntax(keyNode.type, keyNode);
1026
996
  }
1027
997
  destructuringPropertyValue(source, key) {
1028
998
  if (!Array.isArray(source))
@@ -1041,13 +1011,12 @@ export class Interpreter {
1041
1011
  switch (node.type) {
1042
1012
  case "Literal": {
1043
1013
  const regex = node.regex;
1044
- if (isRecord(regex) && typeof regex.pattern === "string") {
1045
- return Effect.sync(() => this.constructRegExp([regex.pattern, typeof regex.flags === "string" ? regex.flags : ""], node));
1046
- }
1014
+ if (regex)
1015
+ return Effect.sync(() => this.constructRegExp([regex.pattern, regex.flags], node));
1047
1016
  return Effect.sync(() => toProgram(node.value, "Literal"));
1048
1017
  }
1049
1018
  case "Identifier":
1050
- return Effect.sync(() => this.scopes.get(getString(node, "name"), node));
1019
+ return Effect.sync(() => this.scopes.get(node.name, node));
1051
1020
  case "BinaryExpression":
1052
1021
  return this.evaluateBinaryExpression(node);
1053
1022
  case "LogicalExpression":
@@ -1060,8 +1029,8 @@ export class Interpreter {
1060
1029
  const self = this;
1061
1030
  return Effect.gen(function* () {
1062
1031
  let result;
1063
- for (const expression of getArray(node, "expressions")) {
1064
- result = yield* self.evaluateExpression(asNode(expression, "expressions"));
1032
+ for (const expression of node.expressions) {
1033
+ result = yield* self.evaluateExpression(expression);
1065
1034
  }
1066
1035
  return result;
1067
1036
  });
@@ -1074,7 +1043,7 @@ export class Interpreter {
1074
1043
  case "MemberExpression":
1075
1044
  return this.readMember(node);
1076
1045
  case "ChainExpression":
1077
- return Effect.map(this.evaluateExpression(getNode(node, "expression")), (value) => value === OptionalShortCircuit ? undefined : value);
1046
+ return Effect.map(this.evaluateExpression(node.expression), (value) => value === OptionalShortCircuit ? undefined : value);
1078
1047
  case "ObjectExpression":
1079
1048
  return this.evaluateObjectExpression(node);
1080
1049
  case "ArrayExpression":
@@ -1087,7 +1056,7 @@ export class Interpreter {
1087
1056
  return this.evaluateUpdateExpression(node);
1088
1057
  case "AwaitExpression": {
1089
1058
  // Await always suspends, including for plain values.
1090
- return Effect.flatMap(this.evaluateExpression(getNode(node, "argument")), (value) => this.awaitValue(value, node));
1059
+ return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value, node));
1091
1060
  }
1092
1061
  case "YieldExpression":
1093
1062
  return this.evaluateYieldExpression(node);
@@ -1098,12 +1067,12 @@ export class Interpreter {
1098
1067
  }
1099
1068
  }
1100
1069
  evaluateNewExpression(node) {
1101
- const callee = getNode(node, "callee");
1070
+ const callee = node.callee;
1102
1071
  if (callee.type !== "Identifier") {
1103
1072
  throw unsupportedSyntax("NewExpression", node);
1104
1073
  }
1105
- const name = getString(callee, "name");
1106
- const argNodes = getArray(node, "arguments");
1074
+ const name = callee.name;
1075
+ const argNodes = node.arguments;
1107
1076
  const self = this;
1108
1077
  if (name === "Promise") {
1109
1078
  return Effect.flatMap(this.evaluateCallArguments(argNodes), (args) => constructPromise(self.runner, self.promises, args[0], node));
@@ -1303,11 +1272,14 @@ export class Interpreter {
1303
1272
  });
1304
1273
  }
1305
1274
  evaluateBinaryExpression(node) {
1306
- const operator = getString(node, "operator");
1275
+ const operator = node.operator;
1276
+ const left = node.left;
1277
+ if (left.type === "PrivateIdentifier")
1278
+ throw unsupportedSyntax(left.type, left);
1307
1279
  const self = this;
1308
1280
  return Effect.gen(function* () {
1309
- const lhs = yield* self.evaluateExpression(getNode(node, "left"));
1310
- const rhs = yield* self.evaluateExpression(getNode(node, "right"));
1281
+ const lhs = yield* self.evaluateExpression(left);
1282
+ const rhs = yield* self.evaluateExpression(node.right);
1311
1283
  if (operator === "instanceof")
1312
1284
  return instanceofValue(lhs, rhs, node);
1313
1285
  return toProgram(self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
@@ -1380,26 +1352,24 @@ export class Interpreter {
1380
1352
  }
1381
1353
  }
1382
1354
  evaluateLogicalExpression(node) {
1383
- const operator = getString(node, "operator");
1384
- return Effect.flatMap(this.evaluateExpression(getNode(node, "left")), (left) => {
1355
+ const operator = node.operator;
1356
+ return Effect.flatMap(this.evaluateExpression(node.left), (left) => {
1385
1357
  if (operator === "&&")
1386
- return left ? this.evaluateExpression(getNode(node, "right")) : Effect.succeed(left);
1358
+ return left ? this.evaluateExpression(node.right) : Effect.succeed(left);
1387
1359
  if (operator === "||")
1388
- return left ? Effect.succeed(left) : this.evaluateExpression(getNode(node, "right"));
1360
+ return left ? Effect.succeed(left) : this.evaluateExpression(node.right);
1389
1361
  if (operator === "??")
1390
- return left !== null && left !== undefined
1391
- ? Effect.succeed(left)
1392
- : this.evaluateExpression(getNode(node, "right"));
1362
+ return left !== null && left !== undefined ? Effect.succeed(left) : this.evaluateExpression(node.right);
1393
1363
  throw new InterpreterRuntimeError(`Unsupported logical operator '${operator}'.`, node);
1394
1364
  });
1395
1365
  }
1396
1366
  evaluateUnaryExpression(node) {
1397
- const operator = getString(node, "operator");
1398
- const argument = getNode(node, "argument");
1367
+ const operator = node.operator;
1368
+ const argument = node.argument;
1399
1369
  if (operator === "delete")
1400
1370
  return this.evaluateDeleteExpression(argument);
1401
1371
  // Undeclared names short-circuit, but declared TDZ bindings must still throw.
1402
- if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(getString(argument, "name"))) {
1372
+ if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(argument.name)) {
1403
1373
  return Effect.succeed("undefined");
1404
1374
  }
1405
1375
  return Effect.map(this.evaluateExpression(argument), (value) => {
@@ -1435,31 +1405,31 @@ export class Interpreter {
1435
1405
  });
1436
1406
  }
1437
1407
  evaluateAssignmentExpression(node) {
1438
- const left = getNode(node, "left");
1439
- const operator = getString(node, "operator");
1408
+ const left = node.left;
1409
+ const operator = node.operator;
1440
1410
  const self = this;
1441
1411
  return Effect.gen(function* () {
1442
1412
  if (operator === "??=" || operator === "||=" || operator === "&&=") {
1443
1413
  return yield* self.evaluateLogicalAssignment(node, left, operator);
1444
1414
  }
1445
1415
  if (operator === "=" && (left.type === "ObjectPattern" || left.type === "ArrayPattern")) {
1446
- const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1416
+ const rightValue = yield* self.evaluateExpression(node.right);
1447
1417
  yield* self.assignPattern(left, rightValue, node);
1448
1418
  return rightValue;
1449
1419
  }
1450
1420
  if (left.type === "Identifier") {
1451
- const name = getString(left, "name");
1421
+ const name = left.name;
1452
1422
  if (operator !== "=") {
1453
1423
  const current = self.scopes.get(name, left);
1454
- const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1424
+ const rightValue = yield* self.evaluateExpression(node.right);
1455
1425
  const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1456
1426
  return self.scopes.set(name, next, left);
1457
1427
  }
1458
- const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1428
+ const rightValue = yield* self.evaluateExpression(node.right);
1459
1429
  return self.scopes.set(name, rightValue, left);
1460
1430
  }
1461
1431
  if (left.type === "MemberExpression") {
1462
- return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(getNode(node, "right")), (rightValue) => {
1432
+ return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
1463
1433
  if (operator === "=")
1464
1434
  return { write: true, next: rightValue, result: rightValue };
1465
1435
  const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
@@ -1473,18 +1443,18 @@ export class Interpreter {
1473
1443
  const self = this;
1474
1444
  const shouldAssign = (current) => operator === "??=" ? current === null || current === undefined : operator === "||=" ? !current : Boolean(current);
1475
1445
  if (left.type === "Identifier") {
1476
- const name = getString(left, "name");
1446
+ const name = left.name;
1477
1447
  return Effect.gen(function* () {
1478
1448
  const current = self.scopes.get(name, left);
1479
1449
  if (!shouldAssign(current))
1480
1450
  return current;
1481
- const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1451
+ const rightValue = yield* self.evaluateExpression(node.right);
1482
1452
  return self.scopes.set(name, rightValue, left);
1483
1453
  });
1484
1454
  }
1485
1455
  if (left.type === "MemberExpression") {
1486
1456
  return self.modifyMember(left, (current) => shouldAssign(current)
1487
- ? Effect.map(self.evaluateExpression(getNode(node, "right")), (rightValue) => ({
1457
+ ? Effect.map(self.evaluateExpression(node.right), (rightValue) => ({
1488
1458
  write: true,
1489
1459
  next: rightValue,
1490
1460
  result: rightValue,
@@ -1494,9 +1464,9 @@ export class Interpreter {
1494
1464
  throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
1495
1465
  }
1496
1466
  evaluateUpdateExpression(node) {
1497
- const operator = getString(node, "operator");
1498
- const argument = getNode(node, "argument");
1499
- const prefix = getBoolean(node, "prefix");
1467
+ const operator = node.operator;
1468
+ const argument = node.argument;
1469
+ const prefix = node.prefix;
1500
1470
  const increment = operator === "++" ? 1 : operator === "--" ? -1 : undefined;
1501
1471
  if (increment === undefined) {
1502
1472
  throw new InterpreterRuntimeError(`Unsupported update operator '${operator}'.`, node);
@@ -1511,7 +1481,7 @@ export class Interpreter {
1511
1481
  };
1512
1482
  if (argument.type === "Identifier") {
1513
1483
  return Effect.sync(() => {
1514
- const name = getString(argument, "name");
1484
+ const name = argument.name;
1515
1485
  const current = operand(this.scopes.get(name, argument));
1516
1486
  const next = current + increment;
1517
1487
  this.scopes.set(name, next, argument);
@@ -1528,26 +1498,28 @@ export class Interpreter {
1528
1498
  throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
1529
1499
  }
1530
1500
  evaluateCallExpression(node) {
1531
- const callee = getNode(node, "callee");
1532
- const argNodes = getArray(node, "arguments");
1501
+ const callee = node.callee;
1533
1502
  const self = this;
1534
1503
  return Effect.gen(function* () {
1504
+ if (callee.type === "Super")
1505
+ throw unsupportedSyntax(callee.type, callee);
1535
1506
  const callable = yield* self.evaluateExpression(callee);
1536
1507
  if (callable === OptionalShortCircuit)
1537
1508
  return OptionalShortCircuit;
1538
- if ((callable === null || callable === undefined) && node.optional === true)
1509
+ if ((callable === null || callable === undefined) && node.optional)
1539
1510
  return OptionalShortCircuit;
1540
- const args = yield* self.evaluateCallArguments(argNodes);
1511
+ const args = yield* self.evaluateCallArguments(node.arguments);
1541
1512
  return yield* self.invokeCallable(callable, args, node, callee);
1542
1513
  });
1543
1514
  }
1544
1515
  // The single dispatch for every invocation: call expressions and callbacks share it.
1545
- invokeCallable(callable, args, node, callee = node) {
1516
+ invokeCallable(callable, args, node, callee) {
1546
1517
  const self = this;
1547
1518
  return Effect.gen(function* () {
1548
1519
  if (callable instanceof ToolReference) {
1549
- if (callable.path.length === 0)
1550
- throw new InterpreterRuntimeError("The tools root is not callable.", callee);
1520
+ if (callable.path.length === 0) {
1521
+ throw new InterpreterRuntimeError("The tools root is not callable.", callee ?? node);
1522
+ }
1551
1523
  return yield* self.createToolCallPromise(callable.path, args);
1552
1524
  }
1553
1525
  if (callable instanceof PromiseMethodReference) {
@@ -1638,9 +1610,9 @@ export class Interpreter {
1638
1610
  return undefined;
1639
1611
  }
1640
1612
  if (callable === undefined || callable === null) {
1641
- throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee).as("TypeError");
1613
+ throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
1642
1614
  }
1643
- throw new InterpreterRuntimeError("Only tools are callable here.", callee);
1615
+ throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
1644
1616
  });
1645
1617
  }
1646
1618
  invokeObjectMethodOnTools(name, ref, node) {
@@ -1659,10 +1631,9 @@ export class Interpreter {
1659
1631
  const self = this;
1660
1632
  return Effect.gen(function* () {
1661
1633
  const args = [];
1662
- for (const [index, arg] of argNodes.entries()) {
1663
- const argNode = asNode(arg, `arguments[${index}]`);
1634
+ for (const argNode of argNodes) {
1664
1635
  if (argNode.type === "SpreadElement") {
1665
- const spread = yield* self.evaluateExpression(getNode(argNode, "argument"));
1636
+ const spread = yield* self.evaluateExpression(argNode.argument);
1666
1637
  const cursor = yield* self.syncIterator(spread, argNode);
1667
1638
  if (cursor === undefined)
1668
1639
  throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode).as("TypeError");
@@ -1693,7 +1664,7 @@ export class Interpreter {
1693
1664
  }
1694
1665
  for (const [index, parameter] of fn.parameters.entries()) {
1695
1666
  if (parameter.type === "RestElement") {
1696
- yield* invocation.declarePattern(getNode(parameter, "argument"), args.slice(index), true, parameter, true);
1667
+ yield* invocation.declarePattern(parameter.argument, args.slice(index), true, parameter, true);
1697
1668
  break;
1698
1669
  }
1699
1670
  yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
@@ -1814,12 +1785,12 @@ export class Interpreter {
1814
1785
  return request;
1815
1786
  }
1816
1787
  evaluateYieldExpression(node) {
1817
- const argument = getOptionalNode(node, "argument");
1788
+ const argument = node.argument;
1818
1789
  const self = this;
1819
1790
  return Effect.gen(function* () {
1820
1791
  if (!self.generatorState)
1821
1792
  throw new InterpreterRuntimeError("yield is only valid inside a generator.", node);
1822
- if (node.delegate === true) {
1793
+ if (node.delegate) {
1823
1794
  const value = argument ? yield* self.evaluateExpression(argument) : undefined;
1824
1795
  return yield* self.delegateYield(value, node);
1825
1796
  }
@@ -1920,13 +1891,11 @@ export class Interpreter {
1920
1891
  }
1921
1892
  evaluateObjectExpression(node) {
1922
1893
  const objectValue = Object.create(null);
1923
- const properties = getArray(node, "properties");
1924
1894
  const self = this;
1925
1895
  return Effect.gen(function* () {
1926
- for (const propertyValue of properties) {
1927
- const property = asNode(propertyValue, "properties");
1896
+ for (const property of node.properties) {
1928
1897
  if (property.type === "SpreadElement") {
1929
- const spread = yield* self.evaluateExpression(getNode(property, "argument"));
1898
+ const spread = yield* self.evaluateExpression(property.argument);
1930
1899
  if (spread === null || spread === undefined || Values.isValue(spread))
1931
1900
  continue;
1932
1901
  if (typeof spread !== "object" || Array.isArray(spread) || isRuntimeReference(spread)) {
@@ -1940,21 +1909,16 @@ export class Interpreter {
1940
1909
  copyIteratorSymbols(spread, objectValue);
1941
1910
  continue;
1942
1911
  }
1943
- if (property.type !== "Property") {
1944
- throw new InterpreterRuntimeError("Only standard object properties are supported.", property);
1945
- }
1946
- if (getString(property, "kind") !== "init") {
1912
+ if (property.kind !== "init") {
1947
1913
  throw new InterpreterRuntimeError("Only init object properties are supported.", property);
1948
1914
  }
1949
- const keyNode = getNode(property, "key");
1950
- const valueNode = getNode(property, "value");
1951
- const computed = getBoolean(property, "computed");
1915
+ const keyNode = property.key;
1952
1916
  let key;
1953
- if (computed) {
1917
+ if (property.computed) {
1954
1918
  key = self.toPropertyKey(yield* self.evaluateExpression(keyNode), keyNode);
1955
1919
  }
1956
1920
  else if (keyNode.type === "Identifier") {
1957
- key = getString(keyNode, "name");
1921
+ key = keyNode.name;
1958
1922
  }
1959
1923
  else if (keyNode.type === "Literal") {
1960
1924
  key = self.toPropertyKey(keyNode.value, keyNode);
@@ -1965,25 +1929,23 @@ export class Interpreter {
1965
1929
  if (isBlockedMember(String(key))) {
1966
1930
  throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, keyNode);
1967
1931
  }
1968
- Reflect.set(objectValue, key, yield* self.evaluateExpression(valueNode));
1932
+ Reflect.set(objectValue, key, yield* self.evaluateExpression(property.value));
1969
1933
  }
1970
1934
  return objectValue;
1971
1935
  });
1972
1936
  }
1973
1937
  evaluateArrayExpression(node) {
1974
- const elements = getArray(node, "elements");
1975
1938
  const values = [];
1976
1939
  const self = this;
1977
1940
  return Effect.gen(function* () {
1978
- for (const elementValue of elements) {
1979
- if (elementValue === null) {
1941
+ for (const element of node.elements) {
1942
+ if (element === null) {
1980
1943
  // A literal elision is a real hole, like JS: extend length without an own index.
1981
1944
  values.length += 1;
1982
1945
  continue;
1983
1946
  }
1984
- const element = asNode(elementValue, "elements");
1985
1947
  if (element.type === "SpreadElement") {
1986
- const spread = yield* self.evaluateExpression(getNode(element, "argument"));
1948
+ const spread = yield* self.evaluateExpression(element.argument);
1987
1949
  const cursor = yield* self.syncIterator(spread, element);
1988
1950
  if (cursor === undefined)
1989
1951
  throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element).as("TypeError");
@@ -2002,20 +1964,20 @@ export class Interpreter {
2002
1964
  });
2003
1965
  }
2004
1966
  evaluateTemplateLiteral(node) {
2005
- const quasis = getArray(node, "quasis");
2006
- const expressions = getArray(node, "expressions");
1967
+ const quasis = node.quasis;
1968
+ const expressions = node.expressions;
2007
1969
  let output = "";
2008
1970
  const self = this;
2009
1971
  return Effect.gen(function* () {
2010
1972
  for (let index = 0; index < quasis.length; index += 1) {
2011
- const quasi = asNode(quasis[index], "quasis");
2012
- const rawValue = quasi.value;
2013
- if (!isRecord(rawValue) || typeof rawValue.cooked !== "string") {
1973
+ const quasi = quasis[index];
1974
+ // acorn only omits `cooked` for invalid escapes in tagged templates, which are unsupported.
1975
+ if (typeof quasi.value.cooked !== "string") {
2014
1976
  throw new InterpreterRuntimeError("Invalid template literal quasi.", quasi);
2015
1977
  }
2016
- output += rawValue.cooked;
1978
+ output += quasi.value.cooked;
2017
1979
  if (index < expressions.length) {
2018
- const raw = yield* self.evaluateExpression(asNode(expressions[index], "expressions"));
1980
+ const raw = yield* self.evaluateExpression(expressions[index]);
2019
1981
  output += coerceToString(toProgram(raw, "Template interpolation"));
2020
1982
  }
2021
1983
  }
@@ -2023,7 +1985,7 @@ export class Interpreter {
2023
1985
  });
2024
1986
  }
2025
1987
  evaluateConditionalExpression(node) {
2026
- return Effect.flatMap(this.evaluateExpression(getNode(node, "test")), (test) => this.evaluateExpression(getNode(node, test ? "consequent" : "alternate")));
1988
+ return Effect.flatMap(this.evaluateExpression(node.test), (test) => this.evaluateExpression(test ? node.consequent : node.alternate));
2027
1989
  }
2028
1990
  applyCompoundAssignment(operator, current, incoming, node) {
2029
1991
  if (!compoundOperators.has(operator)) {
@@ -2032,21 +1994,23 @@ export class Interpreter {
2032
1994
  return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
2033
1995
  }
2034
1996
  getMemberReference(node, operation = "read") {
2035
- const objectNode = getNode(node, "object");
2036
- const propertyNode = getNode(node, "property");
2037
- const computed = getBoolean(node, "computed");
2038
- const optional = node.optional === true;
1997
+ const objectNode = node.object;
1998
+ const propertyNode = node.property;
1999
+ if (objectNode.type === "Super")
2000
+ throw unsupportedSyntax(objectNode.type, objectNode);
2001
+ if (propertyNode.type === "PrivateIdentifier")
2002
+ throw unsupportedSyntax(propertyNode.type, propertyNode);
2039
2003
  const self = this;
2040
2004
  return Effect.gen(function* () {
2041
2005
  const objectValue = yield* self.evaluateExpression(objectNode);
2042
2006
  if (objectValue === OptionalShortCircuit)
2043
2007
  return OptionalShortCircuit;
2044
- if ((objectValue === null || objectValue === undefined) && optional)
2008
+ if ((objectValue === null || objectValue === undefined) && node.optional)
2045
2009
  return OptionalShortCircuit;
2046
- const key = computed
2010
+ const key = node.computed
2047
2011
  ? self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode)
2048
2012
  : propertyNode.type === "Identifier"
2049
- ? getString(propertyNode, "name")
2013
+ ? propertyNode.name
2050
2014
  : self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode);
2051
2015
  if (objectValue instanceof ToolReference) {
2052
2016
  if (typeof key !== "string") {
@@ -2234,7 +2198,7 @@ export class Interpreter {
2234
2198
  return this.modifyMember(node, () => Effect.succeed({ write: true, next: value, result: value }));
2235
2199
  }
2236
2200
  evaluateDeleteExpression(argument) {
2237
- const target = argument.type === "ChainExpression" ? getNode(argument, "expression") : argument;
2201
+ const target = argument.type === "ChainExpression" ? argument.expression : argument;
2238
2202
  if (target.type !== "MemberExpression") {
2239
2203
  throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
2240
2204
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@opencode/codemode",
4
- "version": "0.0.0-dev-19356",
4
+ "version": "0.0.0-dev-19358",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",