jslike 1.3.0 → 1.4.0

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.
@@ -828,10 +828,10 @@ var pp$8 = Parser.prototype;
828
828
  // to its body instead of creating a new node.
829
829
 
830
830
  pp$8.parseTopLevel = function(node) {
831
- var exports = Object.create(null);
831
+ var exports$1 = Object.create(null);
832
832
  if (!node.body) { node.body = []; }
833
833
  while (this.type !== types$1.eof) {
834
- var stmt = this.parseStatement(null, true, exports);
834
+ var stmt = this.parseStatement(null, true, exports$1);
835
835
  node.body.push(stmt);
836
836
  }
837
837
  if (this.inModule)
@@ -938,7 +938,7 @@ pp$8.isUsing = function(isFor) {
938
938
  // `if (foo) /blah/.exec(foo)`, where looking at the previous token
939
939
  // does not help.
940
940
 
941
- pp$8.parseStatement = function(context, topLevel, exports) {
941
+ pp$8.parseStatement = function(context, topLevel, exports$1) {
942
942
  var starttype = this.type, node = this.startNode(), kind;
943
943
 
944
944
  if (this.isLet(context)) {
@@ -993,7 +993,7 @@ pp$8.parseStatement = function(context, topLevel, exports) {
993
993
  if (!this.inModule)
994
994
  { this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'"); }
995
995
  }
996
- return starttype === types$1._import ? this.parseImport(node) : this.parseExport(node, exports)
996
+ return starttype === types$1._import ? this.parseImport(node) : this.parseExport(node, exports$1)
997
997
 
998
998
  // If the statement does not start with a statement keyword or a
999
999
  // brace, it's an ExpressionStatement or LabeledStatement. We
@@ -1749,11 +1749,11 @@ function checkKeyName(node, name) {
1749
1749
 
1750
1750
  // Parses module export declaration.
1751
1751
 
1752
- pp$8.parseExportAllDeclaration = function(node, exports) {
1752
+ pp$8.parseExportAllDeclaration = function(node, exports$1) {
1753
1753
  if (this.options.ecmaVersion >= 11) {
1754
1754
  if (this.eatContextual("as")) {
1755
1755
  node.exported = this.parseModuleExportName();
1756
- this.checkExport(exports, node.exported, this.lastTokStart);
1756
+ this.checkExport(exports$1, node.exported, this.lastTokStart);
1757
1757
  } else {
1758
1758
  node.exported = null;
1759
1759
  }
@@ -1767,14 +1767,14 @@ pp$8.parseExportAllDeclaration = function(node, exports) {
1767
1767
  return this.finishNode(node, "ExportAllDeclaration")
1768
1768
  };
1769
1769
 
1770
- pp$8.parseExport = function(node, exports) {
1770
+ pp$8.parseExport = function(node, exports$1) {
1771
1771
  this.next();
1772
1772
  // export * from '...'
1773
1773
  if (this.eat(types$1.star)) {
1774
- return this.parseExportAllDeclaration(node, exports)
1774
+ return this.parseExportAllDeclaration(node, exports$1)
1775
1775
  }
1776
1776
  if (this.eat(types$1._default)) { // export default ...
1777
- this.checkExport(exports, "default", this.lastTokStart);
1777
+ this.checkExport(exports$1, "default", this.lastTokStart);
1778
1778
  node.declaration = this.parseExportDefaultDeclaration();
1779
1779
  return this.finishNode(node, "ExportDefaultDeclaration")
1780
1780
  }
@@ -1782,16 +1782,16 @@ pp$8.parseExport = function(node, exports) {
1782
1782
  if (this.shouldParseExportStatement()) {
1783
1783
  node.declaration = this.parseExportDeclaration(node);
1784
1784
  if (node.declaration.type === "VariableDeclaration")
1785
- { this.checkVariableExport(exports, node.declaration.declarations); }
1785
+ { this.checkVariableExport(exports$1, node.declaration.declarations); }
1786
1786
  else
1787
- { this.checkExport(exports, node.declaration.id, node.declaration.id.start); }
1787
+ { this.checkExport(exports$1, node.declaration.id, node.declaration.id.start); }
1788
1788
  node.specifiers = [];
1789
1789
  node.source = null;
1790
1790
  if (this.options.ecmaVersion >= 16)
1791
1791
  { node.attributes = []; }
1792
1792
  } else { // export { x, y as z } [from '...']
1793
1793
  node.declaration = null;
1794
- node.specifiers = this.parseExportSpecifiers(exports);
1794
+ node.specifiers = this.parseExportSpecifiers(exports$1);
1795
1795
  if (this.eatContextual("from")) {
1796
1796
  if (this.type !== types$1.string) { this.unexpected(); }
1797
1797
  node.source = this.parseExprAtom();
@@ -1841,47 +1841,47 @@ pp$8.parseExportDefaultDeclaration = function() {
1841
1841
  }
1842
1842
  };
1843
1843
 
1844
- pp$8.checkExport = function(exports, name, pos) {
1845
- if (!exports) { return }
1844
+ pp$8.checkExport = function(exports$1, name, pos) {
1845
+ if (!exports$1) { return }
1846
1846
  if (typeof name !== "string")
1847
1847
  { name = name.type === "Identifier" ? name.name : name.value; }
1848
- if (hasOwn(exports, name))
1848
+ if (hasOwn(exports$1, name))
1849
1849
  { this.raiseRecoverable(pos, "Duplicate export '" + name + "'"); }
1850
- exports[name] = true;
1850
+ exports$1[name] = true;
1851
1851
  };
1852
1852
 
1853
- pp$8.checkPatternExport = function(exports, pat) {
1853
+ pp$8.checkPatternExport = function(exports$1, pat) {
1854
1854
  var type = pat.type;
1855
1855
  if (type === "Identifier")
1856
- { this.checkExport(exports, pat, pat.start); }
1856
+ { this.checkExport(exports$1, pat, pat.start); }
1857
1857
  else if (type === "ObjectPattern")
1858
1858
  { for (var i = 0, list = pat.properties; i < list.length; i += 1)
1859
1859
  {
1860
1860
  var prop = list[i];
1861
1861
 
1862
- this.checkPatternExport(exports, prop);
1862
+ this.checkPatternExport(exports$1, prop);
1863
1863
  } }
1864
1864
  else if (type === "ArrayPattern")
1865
1865
  { for (var i$1 = 0, list$1 = pat.elements; i$1 < list$1.length; i$1 += 1) {
1866
1866
  var elt = list$1[i$1];
1867
1867
 
1868
- if (elt) { this.checkPatternExport(exports, elt); }
1868
+ if (elt) { this.checkPatternExport(exports$1, elt); }
1869
1869
  } }
1870
1870
  else if (type === "Property")
1871
- { this.checkPatternExport(exports, pat.value); }
1871
+ { this.checkPatternExport(exports$1, pat.value); }
1872
1872
  else if (type === "AssignmentPattern")
1873
- { this.checkPatternExport(exports, pat.left); }
1873
+ { this.checkPatternExport(exports$1, pat.left); }
1874
1874
  else if (type === "RestElement")
1875
- { this.checkPatternExport(exports, pat.argument); }
1875
+ { this.checkPatternExport(exports$1, pat.argument); }
1876
1876
  };
1877
1877
 
1878
- pp$8.checkVariableExport = function(exports, decls) {
1879
- if (!exports) { return }
1878
+ pp$8.checkVariableExport = function(exports$1, decls) {
1879
+ if (!exports$1) { return }
1880
1880
  for (var i = 0, list = decls; i < list.length; i += 1)
1881
1881
  {
1882
1882
  var decl = list[i];
1883
1883
 
1884
- this.checkPatternExport(exports, decl.id);
1884
+ this.checkPatternExport(exports$1, decl.id);
1885
1885
  }
1886
1886
  };
1887
1887
 
@@ -1896,13 +1896,13 @@ pp$8.shouldParseExportStatement = function() {
1896
1896
 
1897
1897
  // Parses a comma-separated list of module exports.
1898
1898
 
1899
- pp$8.parseExportSpecifier = function(exports) {
1899
+ pp$8.parseExportSpecifier = function(exports$1) {
1900
1900
  var node = this.startNode();
1901
1901
  node.local = this.parseModuleExportName();
1902
1902
 
1903
1903
  node.exported = this.eatContextual("as") ? this.parseModuleExportName() : node.local;
1904
1904
  this.checkExport(
1905
- exports,
1905
+ exports$1,
1906
1906
  node.exported,
1907
1907
  node.exported.start
1908
1908
  );
@@ -1910,7 +1910,7 @@ pp$8.parseExportSpecifier = function(exports) {
1910
1910
  return this.finishNode(node, "ExportSpecifier")
1911
1911
  };
1912
1912
 
1913
- pp$8.parseExportSpecifiers = function(exports) {
1913
+ pp$8.parseExportSpecifiers = function(exports$1) {
1914
1914
  var nodes = [], first = true;
1915
1915
  // export { x, y as z } [from '...']
1916
1916
  this.expect(types$1.braceL);
@@ -1920,7 +1920,7 @@ pp$8.parseExportSpecifiers = function(exports) {
1920
1920
  if (this.afterTrailingComma(types$1.braceR)) { break }
1921
1921
  } else { first = false; }
1922
1922
 
1923
- nodes.push(this.parseExportSpecifier(exports));
1923
+ nodes.push(this.parseExportSpecifier(exports$1));
1924
1924
  }
1925
1925
  return nodes
1926
1926
  };
@@ -6218,24 +6218,3259 @@ Parser.acorn = {
6218
6218
  //
6219
6219
  // [estree]: https://github.com/estree/estree
6220
6220
 
6221
- function parse(input, options) {
6221
+ function parse$1(input, options) {
6222
6222
  return Parser.parse(input, options)
6223
6223
  }
6224
6224
 
6225
- // This function tries to parse a single expression at a given
6226
- // offset in a string. Useful for parsing mixed-language formats
6227
- // that embed JavaScript expressions.
6225
+ // Runtime Environment for variable scoping and storage
6228
6226
 
6229
- function parseExpressionAt(input, pos, options) {
6230
- return Parser.parseExpressionAt(input, pos, options)
6227
+ class Environment {
6228
+ constructor(parent = null) {
6229
+ this.parent = parent;
6230
+ this.vars = new Map();
6231
+ this.consts = new Set(); // Track const variables
6232
+ }
6233
+
6234
+ define(name, value, isConst = false) {
6235
+ if (this.vars.has(name)) {
6236
+ throw new Error(`Variable '${name}' already declared`);
6237
+ }
6238
+ this.vars.set(name, value);
6239
+ if (isConst) {
6240
+ this.consts.add(name);
6241
+ }
6242
+ return value;
6243
+ }
6244
+
6245
+ get(name) {
6246
+ if (this.vars.has(name)) {
6247
+ return this.vars.get(name);
6248
+ }
6249
+ if (this.parent) {
6250
+ return this.parent.get(name);
6251
+ }
6252
+ throw new ReferenceError(`Variable "${name}" is not defined`);
6253
+ }
6254
+
6255
+ set(name, value) {
6256
+ if (this.vars.has(name)) {
6257
+ // Check if trying to reassign a const variable
6258
+ if (this.consts.has(name)) {
6259
+ throw new TypeError(`Cannot reassign const variable '${name}'`);
6260
+ }
6261
+ this.vars.set(name, value);
6262
+ return value;
6263
+ }
6264
+ if (this.parent) {
6265
+ return this.parent.set(name, value);
6266
+ }
6267
+ throw new ReferenceError(`Variable "${name}" is not defined`);
6268
+ }
6269
+
6270
+ has(name) {
6271
+ return this.vars.has(name) || (this.parent ? this.parent.has(name) : false);
6272
+ }
6273
+
6274
+ // For let/const block scoping
6275
+ extend() {
6276
+ return new Environment(this);
6277
+ }
6278
+ }
6279
+
6280
+ // Special control flow signals
6281
+ class ReturnValue {
6282
+ constructor(value) {
6283
+ this.value = value;
6284
+ }
6285
+ }
6286
+
6287
+ class BreakSignal {
6288
+ constructor() {}
6289
+ }
6290
+
6291
+ class ContinueSignal {
6292
+ constructor() {}
6293
+ }
6294
+
6295
+ class ThrowSignal {
6296
+ constructor(value) {
6297
+ this.value = value;
6298
+ }
6299
+ }
6300
+
6301
+ /**
6302
+ * Enhanced error classes for better developer experience
6303
+ */
6304
+
6305
+ // Simple Levenshtein distance for "did you mean" suggestions
6306
+ function levenshteinDistance(a, b) {
6307
+ const matrix = [];
6308
+
6309
+ for (let i = 0; i <= b.length; i++) {
6310
+ matrix[i] = [i];
6311
+ }
6312
+
6313
+ for (let j = 0; j <= a.length; j++) {
6314
+ matrix[0][j] = j;
6315
+ }
6316
+
6317
+ for (let i = 1; i <= b.length; i++) {
6318
+ for (let j = 1; j <= a.length; j++) {
6319
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
6320
+ matrix[i][j] = matrix[i - 1][j - 1];
6321
+ } else {
6322
+ matrix[i][j] = Math.min(
6323
+ matrix[i - 1][j - 1] + 1,
6324
+ matrix[i][j - 1] + 1,
6325
+ matrix[i - 1][j] + 1
6326
+ );
6327
+ }
6328
+ }
6329
+ }
6330
+
6331
+ return matrix[b.length][a.length];
6332
+ }
6333
+
6334
+ // Find similar strings for suggestions
6335
+ function findSimilar(target, candidates, maxDistance = 3) {
6336
+ const suggestions = [];
6337
+
6338
+ for (const candidate of candidates) {
6339
+ const distance = levenshteinDistance(target.toLowerCase(), candidate.toLowerCase());
6340
+ if (distance <= maxDistance && distance > 0) {
6341
+ suggestions.push({ name: candidate, distance });
6342
+ }
6343
+ }
6344
+
6345
+ return suggestions
6346
+ .sort((a, b) => a.distance - b.distance)
6347
+ .slice(0, 3)
6348
+ .map(s => s.name);
6349
+ }
6350
+
6351
+ // Get available methods/properties on an object
6352
+ function getAvailableMethods(obj) {
6353
+ if (obj === null || obj === undefined) return [];
6354
+
6355
+ const methods = new Set();
6356
+
6357
+ // Get own properties
6358
+ Object.getOwnPropertyNames(obj).forEach(name => {
6359
+ if (typeof obj[name] === 'function') {
6360
+ methods.add(name);
6361
+ }
6362
+ });
6363
+
6364
+ // Get prototype methods
6365
+ let proto = Object.getPrototypeOf(obj);
6366
+ while (proto && proto !== Object.prototype) {
6367
+ Object.getOwnPropertyNames(proto).forEach(name => {
6368
+ if (typeof proto[name] === 'function' && name !== 'constructor') {
6369
+ methods.add(name);
6370
+ }
6371
+ });
6372
+ proto = Object.getPrototypeOf(proto);
6373
+ }
6374
+
6375
+ return Array.from(methods).sort();
6376
+ }
6377
+
6378
+ class EnhancedTypeError extends TypeError {
6379
+ constructor(message, context = {}) {
6380
+ super(message);
6381
+ this.name = 'TypeError';
6382
+ this.objectName = context.objectName || 'object';
6383
+ this.methodName = context.methodName || 'method';
6384
+ this.objectValue = context.objectValue;
6385
+ this.availableMethods = context.availableMethods || [];
6386
+ this.suggestions = context.suggestions || [];
6387
+ }
6388
+
6389
+ getFormattedMessage() {
6390
+ let formatted = this.message;
6391
+
6392
+ // Add available methods
6393
+ if (this.availableMethods.length > 0) {
6394
+ const methodList = this.availableMethods.slice(0, 10).join(', ');
6395
+ const more = this.availableMethods.length > 10
6396
+ ? ` (and ${this.availableMethods.length - 10} more)`
6397
+ : '';
6398
+ formatted += `\n\nAvailable methods on '${this.objectName}': ${methodList}${more}`;
6399
+ }
6400
+
6401
+ // Add suggestions
6402
+ if (this.suggestions.length > 0) {
6403
+ formatted += `\n\nDid you mean: ${this.suggestions.join(', ')}?`;
6404
+ }
6405
+
6406
+ return formatted;
6407
+ }
6408
+ }
6409
+
6410
+ function createMethodNotFoundError(objectName, methodName, objectValue) {
6411
+ const availableMethods = getAvailableMethods(objectValue);
6412
+ const suggestions = findSimilar(methodName, availableMethods);
6413
+
6414
+ const message = `TypeError when calling method '${methodName}' on object '${objectName}': ` +
6415
+ `Expected: function, Received: undefined`;
6416
+
6417
+ return new EnhancedTypeError(message, {
6418
+ objectName,
6419
+ methodName,
6420
+ objectValue,
6421
+ availableMethods,
6422
+ suggestions
6423
+ });
6424
+ }
6425
+
6426
+ class Interpreter {
6427
+ constructor(globalEnv, options = {}) {
6428
+ this.globalEnv = globalEnv;
6429
+ this.moduleResolver = options.moduleResolver;
6430
+ this.moduleCache = new Map(); // Cache loaded modules
6431
+ this.moduleExports = {}; // Track exports in current module
6432
+ this.abortSignal = options.abortSignal;
6433
+ }
6434
+
6435
+ // Check if execution should be aborted
6436
+ checkAbortSignal() {
6437
+ if (this.abortSignal && this.abortSignal.aborted) {
6438
+ const error = new Error('The operation was aborted');
6439
+ error.name = 'AbortError';
6440
+ throw error;
6441
+ }
6442
+ }
6443
+
6444
+ // Async evaluation for async functions - handles await expressions
6445
+ async evaluateAsync(node, env) {
6446
+ if (!node) return undefined;
6447
+
6448
+ // Check for abort signal before evaluating
6449
+ this.checkAbortSignal();
6450
+
6451
+ // Handle await expressions by actually awaiting the promise
6452
+ if (node.type === 'AwaitExpression') {
6453
+ const promise = await this.evaluateAsync(node.argument, env);
6454
+ return await promise;
6455
+ }
6456
+
6457
+ // For block statements, evaluate each statement async
6458
+ if (node.type === 'BlockStatement') {
6459
+ const blockEnv = new Environment(env);
6460
+ let result = undefined;
6461
+ for (const statement of node.body) {
6462
+ result = await this.evaluateAsync(statement, blockEnv);
6463
+ if (result instanceof ReturnValue || result instanceof ThrowSignal ||
6464
+ result instanceof BreakSignal || result instanceof ContinueSignal) {
6465
+ return result;
6466
+ }
6467
+ }
6468
+ return result;
6469
+ }
6470
+
6471
+ // For expression statements, evaluate the expression async
6472
+ if (node.type === 'ExpressionStatement') {
6473
+ return await this.evaluateAsync(node.expression, env);
6474
+ }
6475
+
6476
+ // For variable declarations with await in init
6477
+ if (node.type === 'VariableDeclaration') {
6478
+ for (const declarator of node.declarations) {
6479
+ const value = declarator.init
6480
+ ? await this.evaluateAsync(declarator.init, env)
6481
+ : undefined;
6482
+
6483
+ const isConst = node.kind === 'const';
6484
+ if (declarator.id.type === 'Identifier') {
6485
+ env.define(declarator.id.name, value, isConst);
6486
+ } else if (declarator.id.type === 'ObjectPattern') {
6487
+ this.bindObjectPattern(declarator.id, value, env, isConst);
6488
+ } else if (declarator.id.type === 'ArrayPattern') {
6489
+ this.bindArrayPattern(declarator.id, value, env, isConst);
6490
+ }
6491
+ }
6492
+ return undefined;
6493
+ }
6494
+
6495
+ // For Program nodes (evaluate all statements async)
6496
+ if (node.type === 'Program') {
6497
+ let result = undefined;
6498
+ for (const statement of node.body) {
6499
+ result = await this.evaluateAsync(statement, env);
6500
+ // Handle top-level return and throw
6501
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
6502
+ return result;
6503
+ }
6504
+ }
6505
+ return result;
6506
+ }
6507
+
6508
+ // For import declarations (always async)
6509
+ if (node.type === 'ImportDeclaration') {
6510
+ return await this.evaluateImportDeclaration(node, env);
6511
+ }
6512
+
6513
+ // For export declarations
6514
+ if (node.type === 'ExportNamedDeclaration') {
6515
+ return this.evaluateExportNamedDeclaration(node, env);
6516
+ }
6517
+
6518
+ if (node.type === 'ExportDefaultDeclaration') {
6519
+ return this.evaluateExportDefaultDeclaration(node, env);
6520
+ }
6521
+
6522
+ // For return statements with await
6523
+ if (node.type === 'ReturnStatement') {
6524
+ const value = node.argument ? await this.evaluateAsync(node.argument, env) : undefined;
6525
+ return new ReturnValue(value);
6526
+ }
6527
+
6528
+ // For binary/unary expressions that might contain awaits
6529
+ if (node.type === 'BinaryExpression') {
6530
+ const left = await this.evaluateAsync(node.left, env);
6531
+ const right = await this.evaluateAsync(node.right, env);
6532
+ return this.evaluateBinaryExpressionValues(node.operator, left, right);
6533
+ }
6534
+
6535
+ // For call expressions (might be calling async functions)
6536
+ if (node.type === 'CallExpression') {
6537
+ let thisContext = undefined;
6538
+ let callee;
6539
+ let objectName = null;
6540
+ let methodName = null;
6541
+
6542
+ if (node.callee.type === 'MemberExpression') {
6543
+ thisContext = await this.evaluateAsync(node.callee.object, env);
6544
+ const prop = node.callee.computed
6545
+ ? await this.evaluateAsync(node.callee.property, env)
6546
+ : node.callee.property.name;
6547
+ callee = thisContext[prop];
6548
+
6549
+ // Capture names for enhanced error messages
6550
+ methodName = prop;
6551
+ objectName = this.getExpressionName(node.callee.object);
6552
+ } else {
6553
+ callee = await this.evaluateAsync(node.callee, env);
6554
+ }
6555
+
6556
+ // Handle optional call - if optional and callee is null/undefined, return undefined
6557
+ if (node.optional && (callee === null || callee === undefined)) {
6558
+ return undefined;
6559
+ }
6560
+
6561
+ const args = [];
6562
+ for (const arg of node.arguments) {
6563
+ args.push(await this.evaluateAsync(arg, env));
6564
+ }
6565
+
6566
+ if (typeof callee === 'function') {
6567
+ if (thisContext !== undefined) {
6568
+ return await callee.call(thisContext, ...args);
6569
+ }
6570
+ return await callee(...args);
6571
+ } else if (callee && callee.__isFunction) {
6572
+ return await this.callUserFunction(callee, args, env, thisContext);
6573
+ }
6574
+
6575
+ // Throw enhanced error for member expression calls
6576
+ if (objectName && methodName) {
6577
+ throw createMethodNotFoundError(objectName, methodName, thisContext);
6578
+ }
6579
+
6580
+ throw new TypeError(`${node.callee.name || 'Expression'} is not a function`);
6581
+ }
6582
+
6583
+ // For chain expressions (optional chaining)
6584
+ if (node.type === 'ChainExpression') {
6585
+ return await this.evaluateAsync(node.expression, env);
6586
+ }
6587
+
6588
+ // For member expressions in async context
6589
+ if (node.type === 'MemberExpression') {
6590
+ const obj = await this.evaluateAsync(node.object, env);
6591
+
6592
+ // Handle optional chaining
6593
+ if (node.optional && (obj === null || obj === undefined)) {
6594
+ return undefined;
6595
+ }
6596
+
6597
+ if (obj === null || obj === undefined) {
6598
+ throw new TypeError(`Cannot read property of ${obj}`);
6599
+ }
6600
+
6601
+ const prop = node.computed
6602
+ ? await this.evaluateAsync(node.property, env)
6603
+ : node.property.name;
6604
+
6605
+ return obj[prop];
6606
+ }
6607
+
6608
+ // For template literals with await expressions
6609
+ if (node.type === 'TemplateLiteral') {
6610
+ let result = '';
6611
+ for (let i = 0; i < node.quasis.length; i++) {
6612
+ result += node.quasis[i].value.cooked || node.quasis[i].value.raw;
6613
+ if (i < node.expressions.length) {
6614
+ const exprValue = await this.evaluateAsync(node.expressions[i], env);
6615
+ result += String(exprValue);
6616
+ }
6617
+ }
6618
+ return result;
6619
+ }
6620
+
6621
+ // For logical expressions with async operands (await support)
6622
+ if (node.type === 'LogicalExpression') {
6623
+ const left = await this.evaluateAsync(node.left, env);
6624
+
6625
+ if (node.operator === '&&') {
6626
+ return left ? await this.evaluateAsync(node.right, env) : left;
6627
+ } else if (node.operator === '||') {
6628
+ return left ? left : await this.evaluateAsync(node.right, env);
6629
+ } else if (node.operator === '??') {
6630
+ return left !== null && left !== undefined ? left : await this.evaluateAsync(node.right, env);
6631
+ }
6632
+
6633
+ throw new Error(`Unknown logical operator: ${node.operator}`);
6634
+ }
6635
+
6636
+ // For try-catch-finally with async operations
6637
+ if (node.type === 'TryStatement') {
6638
+ let result;
6639
+
6640
+ try {
6641
+ result = await this.evaluateAsync(node.block, env);
6642
+
6643
+ if (result instanceof ThrowSignal) {
6644
+ throw result.value;
6645
+ }
6646
+ } catch (error) {
6647
+ if (node.handler) {
6648
+ const catchEnv = new Environment(env);
6649
+ if (node.handler.param) {
6650
+ catchEnv.define(node.handler.param.name, error);
6651
+ }
6652
+ result = await this.evaluateAsync(node.handler.body, catchEnv);
6653
+ } else {
6654
+ throw error;
6655
+ }
6656
+ } finally {
6657
+ if (node.finalizer) {
6658
+ const finalResult = await this.evaluateAsync(node.finalizer, env);
6659
+ // If finally block throws or returns, it overrides the try/catch result
6660
+ if (finalResult instanceof ThrowSignal || finalResult instanceof ReturnValue) {
6661
+ return finalResult;
6662
+ }
6663
+ }
6664
+ }
6665
+
6666
+ return result;
6667
+ }
6668
+
6669
+ // For new expressions (async constructors)
6670
+ if (node.type === 'NewExpression') {
6671
+ const result = this.evaluateNewExpression(node, env);
6672
+ // If it's a promise, await it
6673
+ if (result && typeof result.then === 'function') {
6674
+ return await result;
6675
+ }
6676
+ return result;
6677
+ }
6678
+
6679
+ // For ForStatement with async body
6680
+ if (node.type === 'ForStatement') {
6681
+ const forEnv = new Environment(env);
6682
+ if (node.init) {
6683
+ await this.evaluateAsync(node.init, forEnv);
6684
+ }
6685
+ while (!node.test || await this.evaluateAsync(node.test, forEnv)) {
6686
+ const result = await this.evaluateAsync(node.body, forEnv);
6687
+ if (result instanceof BreakSignal) {
6688
+ break;
6689
+ }
6690
+ if (result instanceof ContinueSignal) {
6691
+ if (node.update) {
6692
+ await this.evaluateAsync(node.update, forEnv);
6693
+ }
6694
+ continue;
6695
+ }
6696
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
6697
+ return result;
6698
+ }
6699
+ if (node.update) {
6700
+ await this.evaluateAsync(node.update, forEnv);
6701
+ }
6702
+ }
6703
+ return undefined;
6704
+ }
6705
+
6706
+ // For ForOfStatement with async body
6707
+ if (node.type === 'ForOfStatement') {
6708
+ const forEnv = new Environment(env);
6709
+ const iterable = await this.evaluateAsync(node.right, forEnv);
6710
+ const declarator = node.left.declarations[0];
6711
+ const isConst = node.left.kind === 'const';
6712
+
6713
+ for (const value of iterable) {
6714
+ const iterEnv = forEnv.extend();
6715
+ if (declarator.id.type === 'Identifier') {
6716
+ iterEnv.define(declarator.id.name, value, isConst);
6717
+ } else if (declarator.id.type === 'ArrayPattern') {
6718
+ this.bindArrayPattern(declarator.id, value, iterEnv, isConst);
6719
+ } else if (declarator.id.type === 'ObjectPattern') {
6720
+ this.bindObjectPattern(declarator.id, value, iterEnv, isConst);
6721
+ }
6722
+ const result = await this.evaluateAsync(node.body, iterEnv);
6723
+ if (result instanceof BreakSignal) {
6724
+ break;
6725
+ }
6726
+ if (result instanceof ContinueSignal) {
6727
+ continue;
6728
+ }
6729
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
6730
+ return result;
6731
+ }
6732
+ }
6733
+ return undefined;
6734
+ }
6735
+
6736
+ // For ForInStatement with async body
6737
+ if (node.type === 'ForInStatement') {
6738
+ const forEnv = new Environment(env);
6739
+ const obj = await this.evaluateAsync(node.right, forEnv);
6740
+ if (obj === null || obj === undefined) {
6741
+ throw new TypeError(`Cannot use 'in' operator to iterate over ${obj}`);
6742
+ }
6743
+ const varName = node.left.declarations[0].id.name;
6744
+ forEnv.define(varName, undefined);
6745
+
6746
+ for (const key in obj) {
6747
+ forEnv.set(varName, key);
6748
+ const result = await this.evaluateAsync(node.body, forEnv);
6749
+ if (result instanceof BreakSignal) {
6750
+ break;
6751
+ }
6752
+ if (result instanceof ContinueSignal) {
6753
+ continue;
6754
+ }
6755
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
6756
+ return result;
6757
+ }
6758
+ }
6759
+ return undefined;
6760
+ }
6761
+
6762
+ // For WhileStatement with async body
6763
+ if (node.type === 'WhileStatement') {
6764
+ while (await this.evaluateAsync(node.test, env)) {
6765
+ const result = await this.evaluateAsync(node.body, env);
6766
+ if (result instanceof BreakSignal) {
6767
+ break;
6768
+ }
6769
+ if (result instanceof ContinueSignal) {
6770
+ continue;
6771
+ }
6772
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
6773
+ return result;
6774
+ }
6775
+ }
6776
+ return undefined;
6777
+ }
6778
+
6779
+ // For DoWhileStatement with async body
6780
+ if (node.type === 'DoWhileStatement') {
6781
+ do {
6782
+ const result = await this.evaluateAsync(node.body, env);
6783
+ if (result instanceof BreakSignal) {
6784
+ break;
6785
+ }
6786
+ if (result instanceof ContinueSignal) {
6787
+ continue;
6788
+ }
6789
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
6790
+ return result;
6791
+ }
6792
+ } while (await this.evaluateAsync(node.test, env));
6793
+ return undefined;
6794
+ }
6795
+
6796
+ // For IfStatement with async branches
6797
+ if (node.type === 'IfStatement') {
6798
+ const test = await this.evaluateAsync(node.test, env);
6799
+ if (test) {
6800
+ return await this.evaluateAsync(node.consequent, env);
6801
+ } else if (node.alternate) {
6802
+ return await this.evaluateAsync(node.alternate, env);
6803
+ }
6804
+ return undefined;
6805
+ }
6806
+
6807
+ // For SwitchStatement with async cases
6808
+ if (node.type === 'SwitchStatement') {
6809
+ const discriminant = await this.evaluateAsync(node.discriminant, env);
6810
+ let matched = false;
6811
+
6812
+ for (const switchCase of node.cases) {
6813
+ if (!matched && switchCase.test) {
6814
+ const testValue = await this.evaluateAsync(switchCase.test, env);
6815
+ if (testValue === discriminant) {
6816
+ matched = true;
6817
+ }
6818
+ } else if (!switchCase.test) {
6819
+ matched = true;
6820
+ }
6821
+
6822
+ if (matched) {
6823
+ for (const statement of switchCase.consequent) {
6824
+ const result = await this.evaluateAsync(statement, env);
6825
+ if (result instanceof BreakSignal) {
6826
+ return undefined;
6827
+ }
6828
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
6829
+ return result;
6830
+ }
6831
+ }
6832
+ }
6833
+ }
6834
+ return undefined;
6835
+ }
6836
+
6837
+ // For ConditionalExpression (ternary) with async operands
6838
+ if (node.type === 'ConditionalExpression') {
6839
+ const test = await this.evaluateAsync(node.test, env);
6840
+ return test
6841
+ ? await this.evaluateAsync(node.consequent, env)
6842
+ : await this.evaluateAsync(node.alternate, env);
6843
+ }
6844
+
6845
+ // For AssignmentExpression with async value
6846
+ if (node.type === 'AssignmentExpression') {
6847
+ const value = await this.evaluateAsync(node.right, env);
6848
+
6849
+ if (node.left.type === 'Identifier') {
6850
+ const name = node.left.name;
6851
+ if (node.operator === '=') {
6852
+ if (env.has(name)) {
6853
+ env.set(name, value);
6854
+ } else {
6855
+ env.define(name, value);
6856
+ }
6857
+ return value;
6858
+ } else {
6859
+ const current = env.get(name);
6860
+ const newValue = this.applyCompoundAssignment(node.operator, current, value);
6861
+ env.set(name, newValue);
6862
+ return newValue;
6863
+ }
6864
+ } else if (node.left.type === 'MemberExpression') {
6865
+ const obj = await this.evaluateAsync(node.left.object, env);
6866
+ const prop = node.left.computed
6867
+ ? await this.evaluateAsync(node.left.property, env)
6868
+ : node.left.property.name;
6869
+
6870
+ if (node.operator === '=') {
6871
+ obj[prop] = value;
6872
+ return value;
6873
+ } else {
6874
+ const newValue = this.applyCompoundAssignment(node.operator, obj[prop], value);
6875
+ obj[prop] = newValue;
6876
+ return newValue;
6877
+ }
6878
+ }
6879
+ throw new Error('Invalid assignment target');
6880
+ }
6881
+
6882
+ // For UnaryExpression with async argument
6883
+ if (node.type === 'UnaryExpression') {
6884
+ if (node.operator === 'delete' && node.argument.type === 'MemberExpression') {
6885
+ const obj = await this.evaluateAsync(node.argument.object, env);
6886
+ const prop = node.argument.computed
6887
+ ? await this.evaluateAsync(node.argument.property, env)
6888
+ : node.argument.property.name;
6889
+ return delete obj[prop];
6890
+ }
6891
+ const argument = await this.evaluateAsync(node.argument, env);
6892
+ switch (node.operator) {
6893
+ case '+': return +argument;
6894
+ case '-': return -argument;
6895
+ case '!': return !argument;
6896
+ case '~': return ~argument;
6897
+ case 'typeof':
6898
+ if (argument && argument.__isFunction) {
6899
+ return 'function';
6900
+ }
6901
+ return typeof argument;
6902
+ case 'void': return undefined;
6903
+ case 'delete': return true;
6904
+ default:
6905
+ throw new Error(`Unknown unary operator: ${node.operator}`);
6906
+ }
6907
+ }
6908
+
6909
+ // For UpdateExpression with async member access
6910
+ if (node.type === 'UpdateExpression') {
6911
+ if (node.argument.type === 'Identifier') {
6912
+ const name = node.argument.name;
6913
+ const current = env.get(name);
6914
+ const numericCurrent = (current === null || current === undefined) ? 0 : Number(current);
6915
+ const newValue = node.operator === '++' ? numericCurrent + 1 : numericCurrent - 1;
6916
+ env.set(name, newValue);
6917
+ return node.prefix ? newValue : numericCurrent;
6918
+ } else if (node.argument.type === 'MemberExpression') {
6919
+ const obj = await this.evaluateAsync(node.argument.object, env);
6920
+ if (obj === null || obj === undefined) {
6921
+ throw new TypeError(
6922
+ `Cannot read properties of ${obj} (reading '${
6923
+ node.argument.computed
6924
+ ? await this.evaluateAsync(node.argument.property, env)
6925
+ : node.argument.property.name
6926
+ }')`
6927
+ );
6928
+ }
6929
+ const prop = node.argument.computed
6930
+ ? await this.evaluateAsync(node.argument.property, env)
6931
+ : node.argument.property.name;
6932
+ let current = obj[prop];
6933
+ const numericCurrent = (current === null || current === undefined) ? 0 : Number(current);
6934
+ const newValue = node.operator === '++' ? numericCurrent + 1 : numericCurrent - 1;
6935
+ obj[prop] = newValue;
6936
+ return node.prefix ? newValue : numericCurrent;
6937
+ }
6938
+ throw new Error('Invalid update expression target');
6939
+ }
6940
+
6941
+ // For ArrayExpression with async elements
6942
+ if (node.type === 'ArrayExpression') {
6943
+ const result = [];
6944
+ for (const elem of node.elements) {
6945
+ if (!elem) {
6946
+ result.push(undefined);
6947
+ } else if (elem.type === 'SpreadElement') {
6948
+ const spreadValue = await this.evaluateAsync(elem.argument, env);
6949
+ if (Array.isArray(spreadValue)) {
6950
+ result.push(...spreadValue);
6951
+ } else if (typeof spreadValue[Symbol.iterator] === 'function') {
6952
+ result.push(...spreadValue);
6953
+ } else {
6954
+ throw new TypeError('Spread syntax requires an iterable');
6955
+ }
6956
+ } else {
6957
+ result.push(await this.evaluateAsync(elem, env));
6958
+ }
6959
+ }
6960
+ return result;
6961
+ }
6962
+
6963
+ // For ObjectExpression with async values
6964
+ if (node.type === 'ObjectExpression') {
6965
+ const obj = {};
6966
+ for (const prop of node.properties) {
6967
+ if (prop.type === 'SpreadElement') {
6968
+ const spreadValue = await this.evaluateAsync(prop.argument, env);
6969
+ if (typeof spreadValue === 'object' && spreadValue !== null) {
6970
+ Object.assign(obj, spreadValue);
6971
+ }
6972
+ } else {
6973
+ const key = prop.key.type === 'Identifier' && !prop.computed
6974
+ ? prop.key.name
6975
+ : await this.evaluateAsync(prop.key, env);
6976
+ const value = prop.value ? await this.evaluateAsync(prop.value, env) : env.get(key);
6977
+ if (prop.method && prop.value.type === 'FunctionExpression') {
6978
+ obj[key] = (...args) => {
6979
+ const funcValue = this.evaluate(prop.value, env);
6980
+ return this.callUserFunction(funcValue, args, env);
6981
+ };
6982
+ } else {
6983
+ obj[key] = value;
6984
+ }
6985
+ }
6986
+ }
6987
+ return obj;
6988
+ }
6989
+
6990
+ // For SequenceExpression with async expressions
6991
+ if (node.type === 'SequenceExpression') {
6992
+ let result;
6993
+ for (const expr of node.expressions) {
6994
+ result = await this.evaluateAsync(expr, env);
6995
+ }
6996
+ return result;
6997
+ }
6998
+
6999
+ // For ThrowStatement with async argument
7000
+ if (node.type === 'ThrowStatement') {
7001
+ return new ThrowSignal(await this.evaluateAsync(node.argument, env));
7002
+ }
7003
+
7004
+ // For FunctionDeclaration - define in environment
7005
+ if (node.type === 'FunctionDeclaration') {
7006
+ return this.evaluateFunctionDeclaration(node, env);
7007
+ }
7008
+
7009
+ // For FunctionExpression/ArrowFunctionExpression - create function
7010
+ if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
7011
+ return this.evaluateFunctionExpression(node, env);
7012
+ }
7013
+
7014
+ // For ClassDeclaration
7015
+ if (node.type === 'ClassDeclaration') {
7016
+ return this.evaluateClassDeclaration(node, env);
7017
+ }
7018
+
7019
+ // For ClassExpression
7020
+ if (node.type === 'ClassExpression') {
7021
+ return this.evaluateClassExpression(node, env);
7022
+ }
7023
+
7024
+ // Only leaf nodes should fall through to sync evaluate
7025
+ // These have no sub-expressions that could contain await
7026
+ if (['Literal', 'Identifier', 'BreakStatement', 'ContinueStatement',
7027
+ 'EmptyStatement', 'ThisExpression', 'Super'].includes(node.type)) {
7028
+ return this.evaluate(node, env);
7029
+ }
7030
+
7031
+ // Safety check - if we get here, we missed a node type
7032
+ throw new Error(`Unhandled node type in evaluateAsync: ${node.type}`);
7033
+ }
7034
+
7035
+ evaluate(node, env) {
7036
+ if (!node) return undefined;
7037
+
7038
+ // Check for abort signal before evaluating
7039
+ this.checkAbortSignal();
7040
+
7041
+ switch (node.type) {
7042
+ case 'Program':
7043
+ return this.evaluateProgram(node, env);
7044
+
7045
+ case 'Literal':
7046
+ // Handle regex literals
7047
+ if (node.regex) {
7048
+ return new RegExp(node.regex.pattern, node.regex.flags);
7049
+ }
7050
+ return node.value;
7051
+
7052
+ case 'Identifier':
7053
+ return env.get(node.name);
7054
+
7055
+ case 'BinaryExpression':
7056
+ return this.evaluateBinaryExpression(node, env);
7057
+
7058
+ case 'UnaryExpression':
7059
+ return this.evaluateUnaryExpression(node, env);
7060
+
7061
+ case 'UpdateExpression':
7062
+ return this.evaluateUpdateExpression(node, env);
7063
+
7064
+ case 'AwaitExpression':
7065
+ return this.evaluateAwaitExpression(node, env);
7066
+
7067
+ case 'AssignmentExpression':
7068
+ return this.evaluateAssignmentExpression(node, env);
7069
+
7070
+ case 'LogicalExpression':
7071
+ return this.evaluateLogicalExpression(node, env);
7072
+
7073
+ case 'ConditionalExpression':
7074
+ return this.evaluateConditionalExpression(node, env);
7075
+
7076
+ case 'CallExpression':
7077
+ return this.evaluateCallExpression(node, env);
7078
+
7079
+ case 'MemberExpression':
7080
+ return this.evaluateMemberExpression(node, env);
7081
+
7082
+ case 'ChainExpression':
7083
+ return this.evaluateChainExpression(node, env);
7084
+
7085
+ case 'ArrayExpression':
7086
+ return this.evaluateArrayExpression(node, env);
7087
+
7088
+ case 'ObjectExpression':
7089
+ return this.evaluateObjectExpression(node, env);
7090
+
7091
+ case 'FunctionExpression':
7092
+ case 'ArrowFunctionExpression':
7093
+ return this.evaluateFunctionExpression(node, env);
7094
+
7095
+ case 'NewExpression':
7096
+ return this.evaluateNewExpression(node, env);
7097
+
7098
+ case 'ThisExpression':
7099
+ return this.evaluateThisExpression(node, env);
7100
+
7101
+ case 'Super':
7102
+ return this.evaluateSuperExpression(node, env);
7103
+
7104
+ case 'SequenceExpression':
7105
+ return this.evaluateSequenceExpression(node, env);
7106
+
7107
+ case 'VariableDeclaration':
7108
+ return this.evaluateVariableDeclaration(node, env);
7109
+
7110
+ case 'FunctionDeclaration':
7111
+ return this.evaluateFunctionDeclaration(node, env);
7112
+
7113
+ case 'ImportDeclaration':
7114
+ return this.evaluateImportDeclaration(node, env);
7115
+
7116
+ case 'ExportNamedDeclaration':
7117
+ return this.evaluateExportNamedDeclaration(node, env);
7118
+
7119
+ case 'ExportDefaultDeclaration':
7120
+ return this.evaluateExportDefaultDeclaration(node, env);
7121
+
7122
+ case 'BlockStatement':
7123
+ return this.evaluateBlockStatement(node, env);
7124
+
7125
+ case 'ExpressionStatement':
7126
+ return this.evaluate(node.expression, env);
7127
+
7128
+ case 'ReturnStatement':
7129
+ return new ReturnValue(node.argument ? this.evaluate(node.argument, env) : undefined);
7130
+
7131
+ case 'IfStatement':
7132
+ return this.evaluateIfStatement(node, env);
7133
+
7134
+ case 'WhileStatement':
7135
+ return this.evaluateWhileStatement(node, env);
7136
+
7137
+ case 'DoWhileStatement':
7138
+ return this.evaluateDoWhileStatement(node, env);
7139
+
7140
+ case 'ForStatement':
7141
+ return this.evaluateForStatement(node, env);
7142
+
7143
+ case 'ForInStatement':
7144
+ return this.evaluateForInStatement(node, env);
7145
+
7146
+ case 'ForOfStatement':
7147
+ return this.evaluateForOfStatement(node, env);
7148
+
7149
+ case 'BreakStatement':
7150
+ return new BreakSignal();
7151
+
7152
+ case 'ContinueStatement':
7153
+ return new ContinueSignal();
7154
+
7155
+ case 'ThrowStatement':
7156
+ return new ThrowSignal(this.evaluate(node.argument, env));
7157
+
7158
+ case 'TryStatement':
7159
+ return this.evaluateTryStatement(node, env);
7160
+
7161
+ case 'SwitchStatement':
7162
+ return this.evaluateSwitchStatement(node, env);
7163
+
7164
+ case 'EmptyStatement':
7165
+ return undefined;
7166
+
7167
+ // ES6+ Features
7168
+ case 'TemplateLiteral':
7169
+ return this.evaluateTemplateLiteral(node, env);
7170
+
7171
+ case 'ClassDeclaration':
7172
+ return this.evaluateClassDeclaration(node, env);
7173
+
7174
+ case 'ClassExpression':
7175
+ return this.evaluateClassExpression(node, env);
7176
+
7177
+ case 'MethodDefinition':
7178
+ return this.evaluateMethodDefinition(node, env);
7179
+
7180
+ case 'SpreadElement':
7181
+ return this.evaluateSpreadElement(node, env);
7182
+
7183
+ case 'RestElement':
7184
+ return this.evaluateRestElement(node, env);
7185
+
7186
+ case 'ObjectPattern':
7187
+ return this.evaluateObjectPattern(node, env);
7188
+
7189
+ case 'ArrayPattern':
7190
+ return this.evaluateArrayPattern(node, env);
7191
+
7192
+ case 'AssignmentPattern':
7193
+ return this.evaluateAssignmentPattern(node, env);
7194
+
7195
+ case 'Property':
7196
+ return this.evaluateProperty(node, env);
7197
+
7198
+ default:
7199
+ throw new Error(`Unknown node type: ${node.type}`);
7200
+ }
7201
+ }
7202
+
7203
+ evaluateProgram(node, env) {
7204
+ let result = undefined;
7205
+ for (let i = 0; i < node.body.length; i++) {
7206
+ const statement = node.body[i];
7207
+ const isLast = i === node.body.length - 1;
7208
+
7209
+ // Special case: Last statement is a BlockStatement that looks like object literal
7210
+ // Handle both shorthand { x, y } and full syntax { key: value, key2: value2 }
7211
+ if (isLast && statement.type === 'BlockStatement') {
7212
+ const objLiteral = this.tryConvertBlockToObjectLiteral(statement, env);
7213
+ if (objLiteral !== null) {
7214
+ return objLiteral;
7215
+ }
7216
+ }
7217
+
7218
+ const statementResult = this.evaluate(statement, env);
7219
+ if (statementResult instanceof ReturnValue || statementResult instanceof ThrowSignal) {
7220
+ return statementResult;
7221
+ }
7222
+ result = statementResult;
7223
+ }
7224
+ return result;
7225
+ }
7226
+
7227
+ // Try to convert a BlockStatement to an object literal
7228
+ // Returns null if the block doesn't look like an object literal
7229
+ tryConvertBlockToObjectLiteral(block, env) {
7230
+ if (block.body.length === 0) return null;
7231
+
7232
+ // Check if it's shorthand syntax: { x, y }
7233
+ if (block.body.length === 1 && block.body[0].type === 'ExpressionStatement') {
7234
+ const expr = block.body[0].expression;
7235
+
7236
+ // SequenceExpression of Identifiers: { x, y, z }
7237
+ if (expr.type === 'SequenceExpression' &&
7238
+ expr.expressions.every(e => e.type === 'Identifier')) {
7239
+ const obj = {};
7240
+ for (const identifier of expr.expressions) {
7241
+ obj[identifier.name] = env.get(identifier.name);
7242
+ }
7243
+ return obj;
7244
+ }
7245
+
7246
+ // Single Identifier: { x }
7247
+ if (expr.type === 'Identifier') {
7248
+ const obj = {};
7249
+ obj[expr.name] = env.get(expr.name);
7250
+ return obj;
7251
+ }
7252
+ }
7253
+
7254
+ // Check if it's labeled statements that look like object properties
7255
+ // Example: { first: first(arr), last: last(arr) }
7256
+ // This gets parsed as LabeledStatements in script mode
7257
+ const allLabeled = block.body.every(stmt => stmt.type === 'LabeledStatement');
7258
+ if (!allLabeled) return null;
7259
+
7260
+ // Convert labeled statements to object properties
7261
+ const obj = {};
7262
+ for (const stmt of block.body) {
7263
+ const label = stmt.label.name;
7264
+
7265
+ // The body of LabeledStatement should be ExpressionStatement
7266
+ if (stmt.body.type !== 'ExpressionStatement') {
7267
+ return null; // Not an object literal pattern
7268
+ }
7269
+
7270
+ const value = this.evaluate(stmt.body.expression, env);
7271
+ obj[label] = value;
7272
+ }
7273
+
7274
+ return obj;
7275
+ }
7276
+
7277
+ evaluateBinaryExpression(node, env) {
7278
+ const left = this.evaluate(node.left, env);
7279
+ const right = this.evaluate(node.right, env);
7280
+ return this.evaluateBinaryExpressionValues(node.operator, left, right);
7281
+ }
7282
+
7283
+ evaluateBinaryExpressionValues(operator, left, right) {
7284
+ switch (operator) {
7285
+ case '+': return left + right;
7286
+ case '-': return left - right;
7287
+ case '*': return left * right;
7288
+ case '/': return left / right;
7289
+ case '%': return left % right;
7290
+ case '**': return left ** right;
7291
+ case '<': return left < right;
7292
+ case '>': return left > right;
7293
+ case '<=': return left <= right;
7294
+ case '>=': return left >= right;
7295
+ case '==': return left == right;
7296
+ case '!=': return left != right;
7297
+ case '===': return left === right;
7298
+ case '!==': return left !== right;
7299
+ case '&': return left & right;
7300
+ case '|': return left | right;
7301
+ case '^': return left ^ right;
7302
+ case '<<': return left << right;
7303
+ case '>>': return left >> right;
7304
+ case '>>>': return left >>> right;
7305
+ case 'in': {
7306
+ // Check right operand is not null/undefined
7307
+ if (right === null || right === undefined) {
7308
+ throw new TypeError(
7309
+ 'Cannot use "in" operator to search for property in null or undefined'
7310
+ );
7311
+ }
7312
+ // Coerce left operand to string/symbol for property key
7313
+ const key = String(left);
7314
+ return key in Object(right);
7315
+ }
7316
+ case 'instanceof': {
7317
+ // Check right operand is a constructor function or JSLike function
7318
+ if (typeof right !== 'function' && !(right && right.__isFunction)) {
7319
+ throw new TypeError(
7320
+ 'Right-hand side of instanceof is not a constructor'
7321
+ );
7322
+ }
7323
+ // Primitives (null/undefined) always return false
7324
+ if (left === null || left === undefined) {
7325
+ return false;
7326
+ }
7327
+ // Special case: check if left is a JSLike function and right is Function constructor
7328
+ if (right === Function && left && left.__isFunction) {
7329
+ return true;
7330
+ }
7331
+ // Use JavaScript's instanceof for native objects
7332
+ if (typeof right === 'function') {
7333
+ return left instanceof right;
7334
+ }
7335
+ // For JSLike functions, check prototype chain
7336
+ return false;
7337
+ }
7338
+ default:
7339
+ throw new Error(`Unknown binary operator: ${operator}`);
7340
+ }
7341
+ }
7342
+
7343
+ evaluateUnaryExpression(node, env) {
7344
+ const argument = this.evaluate(node.argument, env);
7345
+
7346
+ switch (node.operator) {
7347
+ case '+': return +argument;
7348
+ case '-': return -argument;
7349
+ case '!': return !argument;
7350
+ case '~': return ~argument;
7351
+ case 'typeof':
7352
+ // JSLike functions should report as 'function'
7353
+ if (argument && argument.__isFunction) {
7354
+ return 'function';
7355
+ }
7356
+ return typeof argument;
7357
+ case 'void': return undefined;
7358
+ case 'delete':
7359
+ if (node.argument.type === 'MemberExpression') {
7360
+ const obj = this.evaluate(node.argument.object, env);
7361
+ const prop = node.argument.computed
7362
+ ? this.evaluate(node.argument.property, env)
7363
+ : node.argument.property.name;
7364
+ return delete obj[prop];
7365
+ }
7366
+ return true;
7367
+ default:
7368
+ throw new Error(`Unknown unary operator: ${node.operator}`);
7369
+ }
7370
+ }
7371
+
7372
+ evaluateUpdateExpression(node, env) {
7373
+ if (node.argument.type === 'Identifier') {
7374
+ const name = node.argument.name;
7375
+ const current = env.get(name);
7376
+ // Wang feature: treat null/undefined as 0 for increment/decrement
7377
+ const numericCurrent = (current === null || current === undefined) ? 0 : Number(current);
7378
+ const newValue = node.operator === '++' ? numericCurrent + 1 : numericCurrent - 1;
7379
+ env.set(name, newValue);
7380
+ return node.prefix ? newValue : numericCurrent;
7381
+ } else if (node.argument.type === 'MemberExpression') {
7382
+ const obj = this.evaluate(node.argument.object, env);
7383
+
7384
+ // Check for null/undefined object
7385
+ if (obj === null || obj === undefined) {
7386
+ throw new TypeError(
7387
+ `Cannot read properties of ${obj} (reading '${
7388
+ node.argument.computed
7389
+ ? this.evaluate(node.argument.property, env)
7390
+ : node.argument.property.name
7391
+ }')`
7392
+ );
7393
+ }
7394
+
7395
+ const prop = node.argument.computed
7396
+ ? this.evaluate(node.argument.property, env)
7397
+ : node.argument.property.name;
7398
+
7399
+ // Get current value and convert to number
7400
+ let current = obj[prop];
7401
+ // Wang feature: treat null/undefined as 0 for increment/decrement
7402
+ const numericCurrent = (current === null || current === undefined) ? 0 : Number(current);
7403
+ const newValue = node.operator === '++' ? numericCurrent + 1 : numericCurrent - 1;
7404
+ obj[prop] = newValue;
7405
+
7406
+ return node.prefix ? newValue : numericCurrent;
7407
+ }
7408
+ throw new Error('Invalid update expression target');
7409
+ }
7410
+
7411
+ evaluateAwaitExpression(node, env) {
7412
+ // Evaluate the argument (should be a Promise)
7413
+ const promise = this.evaluate(node.argument, env);
7414
+
7415
+ // Return the promise - the caller must handle it
7416
+ // This is a simplified implementation that relies on the runtime being async
7417
+ return promise;
7418
+ }
7419
+
7420
+ evaluateAssignmentExpression(node, env) {
7421
+ const value = this.evaluate(node.right, env);
7422
+
7423
+ if (node.left.type === 'Identifier') {
7424
+ const name = node.left.name;
7425
+
7426
+ if (node.operator === '=') {
7427
+ if (env.has(name)) {
7428
+ env.set(name, value);
7429
+ } else {
7430
+ env.define(name, value);
7431
+ }
7432
+ return value;
7433
+ } else {
7434
+ const current = env.get(name);
7435
+ const newValue = this.applyCompoundAssignment(node.operator, current, value);
7436
+ env.set(name, newValue);
7437
+ return newValue;
7438
+ }
7439
+ } else if (node.left.type === 'MemberExpression') {
7440
+ const obj = this.evaluate(node.left.object, env);
7441
+ const prop = node.left.computed
7442
+ ? this.evaluate(node.left.property, env)
7443
+ : node.left.property.name;
7444
+
7445
+ if (node.operator === '=') {
7446
+ obj[prop] = value;
7447
+ return value;
7448
+ } else {
7449
+ const newValue = this.applyCompoundAssignment(node.operator, obj[prop], value);
7450
+ obj[prop] = newValue;
7451
+ return newValue;
7452
+ }
7453
+ }
7454
+
7455
+ throw new Error('Invalid assignment target');
7456
+ }
7457
+
7458
+ applyCompoundAssignment(operator, left, right) {
7459
+ // For numeric operators, coerce undefined to 0 (like JavaScript does for += with numbers)
7460
+ // But keep undefined for string concatenation
7461
+ const isNumericOp = operator !== '+=';
7462
+ const leftVal = (isNumericOp && left === undefined) ? 0 : left;
7463
+
7464
+ switch (operator) {
7465
+ case '+=':
7466
+ // Special case: undefined + number should coerce undefined to 0
7467
+ if (left === undefined && typeof right === 'number') {
7468
+ return 0 + right;
7469
+ }
7470
+ return left + right;
7471
+ case '-=': return leftVal - right;
7472
+ case '*=': return leftVal * right;
7473
+ case '/=': return leftVal / right;
7474
+ case '%=': return leftVal % right;
7475
+ default: throw new Error(`Unknown assignment operator: ${operator}`);
7476
+ }
7477
+ }
7478
+
7479
+ evaluateLogicalExpression(node, env) {
7480
+ const left = this.evaluate(node.left, env);
7481
+
7482
+ if (node.operator === '&&') {
7483
+ return left ? this.evaluate(node.right, env) : left;
7484
+ } else if (node.operator === '||') {
7485
+ return left ? left : this.evaluate(node.right, env);
7486
+ } else if (node.operator === '??') {
7487
+ return left !== null && left !== undefined ? left : this.evaluate(node.right, env);
7488
+ }
7489
+
7490
+ throw new Error(`Unknown logical operator: ${node.operator}`);
7491
+ }
7492
+
7493
+ evaluateConditionalExpression(node, env) {
7494
+ const test = this.evaluate(node.test, env);
7495
+ return test
7496
+ ? this.evaluate(node.consequent, env)
7497
+ : this.evaluate(node.alternate, env);
7498
+ }
7499
+
7500
+ evaluateCallExpression(node, env) {
7501
+ // Determine thisContext for method calls
7502
+ let thisContext = undefined;
7503
+ let callee;
7504
+ let objectName = null;
7505
+ let methodName = null;
7506
+
7507
+ if (node.callee.type === 'MemberExpression') {
7508
+ // For method calls like obj.method(), set this to obj
7509
+ thisContext = this.evaluate(node.callee.object, env);
7510
+ const prop = node.callee.computed
7511
+ ? this.evaluate(node.callee.property, env)
7512
+ : node.callee.property.name;
7513
+ callee = thisContext[prop];
7514
+
7515
+ // Capture names for enhanced error messages
7516
+ methodName = prop;
7517
+ objectName = this.getExpressionName(node.callee.object);
7518
+ } else {
7519
+ callee = this.evaluate(node.callee, env);
7520
+ }
7521
+
7522
+ // Handle optional call - if optional and callee is null/undefined, return undefined
7523
+ if (node.optional && (callee === null || callee === undefined)) {
7524
+ return undefined;
7525
+ }
7526
+
7527
+ const args = node.arguments.map(arg => this.evaluate(arg, env));
7528
+
7529
+ if (typeof callee === 'function') {
7530
+ // Native JavaScript function or class method
7531
+ if (thisContext !== undefined) {
7532
+ return callee.call(thisContext, ...args);
7533
+ }
7534
+ return callee(...args);
7535
+ } else if (callee && callee.__isFunction) {
7536
+ // User-defined function - pass thisContext
7537
+ return this.callUserFunction(callee, args, env, thisContext);
7538
+ }
7539
+
7540
+ // Throw enhanced error for member expression calls
7541
+ if (objectName && methodName) {
7542
+ throw createMethodNotFoundError(objectName, methodName, thisContext);
7543
+ }
7544
+
7545
+ throw new TypeError(`${node.callee.name || 'Expression'} is not a function`);
7546
+ }
7547
+
7548
+ // Helper to get a readable name for an expression (for error messages)
7549
+ getExpressionName(node) {
7550
+ if (!node) return 'object';
7551
+
7552
+ switch (node.type) {
7553
+ case 'Identifier':
7554
+ return node.name;
7555
+ case 'ThisExpression':
7556
+ return 'this';
7557
+ case 'MemberExpression':
7558
+ const objName = this.getExpressionName(node.object);
7559
+ const propName = node.computed ? '[...]' : node.property.name;
7560
+ return `${objName}.${propName}`;
7561
+ default:
7562
+ return 'object';
7563
+ }
7564
+ }
7565
+
7566
+ callUserFunction(func, args, callingEnv, thisContext = undefined) {
7567
+ // Extract metadata if function is wrapped
7568
+ const metadata = func.__metadata || func;
7569
+ const funcEnv = new Environment(metadata.closure);
7570
+
7571
+ // Bind 'this' if provided (for method calls)
7572
+ if (thisContext !== undefined) {
7573
+ funcEnv.define('this', thisContext);
7574
+ }
7575
+
7576
+ // Bind parameters
7577
+ for (let i = 0; i < metadata.params.length; i++) {
7578
+ const param = metadata.params[i];
7579
+
7580
+ if (param.type === 'Identifier') {
7581
+ // Simple parameter: function(x)
7582
+ funcEnv.define(param.name, args[i]);
7583
+ } else if (param.type === 'AssignmentPattern') {
7584
+ // Default parameter: function(x = defaultValue)
7585
+ const value = args[i] !== undefined ? args[i] : this.evaluate(param.right, funcEnv);
7586
+ funcEnv.define(param.left.name, value);
7587
+ } else if (param.type === 'RestElement') {
7588
+ // Rest parameter: function(...rest)
7589
+ funcEnv.define(param.argument.name, args.slice(i));
7590
+ break; // Rest element must be last
7591
+ } else if (param.type === 'ObjectPattern') {
7592
+ // Destructuring parameter: function({a, b})
7593
+ this.bindObjectPattern(param, args[i], funcEnv);
7594
+ } else if (param.type === 'ArrayPattern') {
7595
+ // Array destructuring parameter: function([a, b])
7596
+ this.bindArrayPattern(param, args[i], funcEnv);
7597
+ } else {
7598
+ // Fallback for simple parameter names
7599
+ funcEnv.define(param.name, args[i]);
7600
+ }
7601
+ }
7602
+
7603
+ // Execute function body
7604
+ // If async, use async evaluation and return a promise
7605
+ if (metadata.async) {
7606
+ return (async () => {
7607
+ if (metadata.expression) {
7608
+ // Arrow function with expression body
7609
+ const result = await this.evaluateAsync(metadata.body, funcEnv);
7610
+ // If the result is a ThrowSignal, throw the error
7611
+ if (result instanceof ThrowSignal) {
7612
+ throw result.value;
7613
+ }
7614
+ return result;
7615
+ } else {
7616
+ // Block statement body
7617
+ const result = await this.evaluateAsync(metadata.body, funcEnv);
7618
+ if (result instanceof ReturnValue) {
7619
+ return result.value;
7620
+ }
7621
+ // If the result is a ThrowSignal, throw the error
7622
+ if (result instanceof ThrowSignal) {
7623
+ throw result.value;
7624
+ }
7625
+ return undefined;
7626
+ }
7627
+ })();
7628
+ } else {
7629
+ // Synchronous evaluation for non-async functions
7630
+ if (metadata.expression) {
7631
+ const result = this.evaluate(metadata.body, funcEnv);
7632
+ // If the result is a ThrowSignal, throw the error
7633
+ if (result instanceof ThrowSignal) {
7634
+ throw result.value;
7635
+ }
7636
+ return result;
7637
+ } else {
7638
+ const result = this.evaluate(metadata.body, funcEnv);
7639
+ if (result instanceof ReturnValue) {
7640
+ return result.value;
7641
+ }
7642
+ // If the result is a ThrowSignal, throw the error
7643
+ if (result instanceof ThrowSignal) {
7644
+ throw result.value;
7645
+ }
7646
+ return undefined;
7647
+ }
7648
+ }
7649
+ }
7650
+
7651
+ evaluateMemberExpression(node, env) {
7652
+ const obj = this.evaluate(node.object, env);
7653
+
7654
+ // Handle optional chaining - if optional and obj is null/undefined, return undefined
7655
+ if (node.optional && (obj === null || obj === undefined)) {
7656
+ return undefined;
7657
+ }
7658
+
7659
+ if (obj === null || obj === undefined) {
7660
+ throw new TypeError(`Cannot read property of ${obj}`);
7661
+ }
7662
+
7663
+ const prop = node.computed
7664
+ ? this.evaluate(node.property, env)
7665
+ : node.property.name;
7666
+
7667
+ return obj[prop];
7668
+ }
7669
+
7670
+ evaluateChainExpression(node, env) {
7671
+ // ChainExpression is a wrapper for optional chaining expressions
7672
+ // It contains the actual expression (MemberExpression or CallExpression with optional: true)
7673
+ // We just evaluate the inner expression, which will handle the optional logic
7674
+ return this.evaluate(node.expression, env);
7675
+ }
7676
+
7677
+ evaluateArrayExpression(node, env) {
7678
+ const result = [];
7679
+ for (const elem of node.elements) {
7680
+ if (!elem) {
7681
+ // Hole in array [1, , 3]
7682
+ result.push(undefined);
7683
+ } else if (elem.type === 'SpreadElement') {
7684
+ // Spread syntax [...arr]
7685
+ const spreadValue = this.evaluate(elem.argument, env);
7686
+ if (Array.isArray(spreadValue)) {
7687
+ result.push(...spreadValue);
7688
+ } else if (typeof spreadValue[Symbol.iterator] === 'function') {
7689
+ result.push(...spreadValue);
7690
+ } else {
7691
+ throw new TypeError('Spread syntax requires an iterable');
7692
+ }
7693
+ } else {
7694
+ result.push(this.evaluate(elem, env));
7695
+ }
7696
+ }
7697
+ return result;
7698
+ }
7699
+
7700
+ evaluateObjectExpression(node, env) {
7701
+ const obj = {};
7702
+ for (const prop of node.properties) {
7703
+ if (prop.type === 'SpreadElement') {
7704
+ // Object spread {...other}
7705
+ const spreadValue = this.evaluate(prop.argument, env);
7706
+ if (typeof spreadValue === 'object' && spreadValue !== null) {
7707
+ Object.assign(obj, spreadValue);
7708
+ }
7709
+ } else {
7710
+ // Regular property or shorthand
7711
+ const key = prop.key.type === 'Identifier' && !prop.computed
7712
+ ? prop.key.name
7713
+ : this.evaluate(prop.key, env);
7714
+
7715
+ // Handle shorthand properties {x} => {x: x}
7716
+ const value = prop.value ? this.evaluate(prop.value, env) : env.get(key);
7717
+
7718
+ // Handle method shorthand: method() {}
7719
+ if (prop.method && prop.value.type === 'FunctionExpression') {
7720
+ obj[key] = (...args) => {
7721
+ const funcValue = this.evaluate(prop.value, env);
7722
+ return this.callUserFunction(funcValue, args, env);
7723
+ };
7724
+ } else {
7725
+ obj[key] = value;
7726
+ }
7727
+ }
7728
+ }
7729
+ return obj;
7730
+ }
7731
+
7732
+ evaluateFunctionExpression(node, env) {
7733
+ const funcMetadata = {
7734
+ __isFunction: true,
7735
+ params: node.params,
7736
+ body: node.body,
7737
+ closure: env,
7738
+ expression: node.type === 'ArrowFunctionExpression' && node.expression,
7739
+ async: node.async || false
7740
+ };
7741
+
7742
+ // Wrap in actual JavaScript function so it can be called by native code
7743
+ const interpreter = this;
7744
+
7745
+ // Create async or sync wrapper based on function type
7746
+ // Note: using regular function (not arrow) to capture 'this' for method calls
7747
+ const wrappedFunc = funcMetadata.async
7748
+ ? async function(...args) {
7749
+ return await interpreter.callUserFunction(funcMetadata, args, funcMetadata.closure, this);
7750
+ }
7751
+ : function(...args) {
7752
+ return interpreter.callUserFunction(funcMetadata, args, funcMetadata.closure, this);
7753
+ };
7754
+
7755
+ // Preserve metadata for JSLike's internal use
7756
+ wrappedFunc.__isFunction = true;
7757
+ wrappedFunc.__metadata = funcMetadata;
7758
+
7759
+ return wrappedFunc;
7760
+ }
7761
+
7762
+ evaluateNewExpression(node, env) {
7763
+ const constructor = this.evaluate(node.callee, env);
7764
+ const args = node.arguments.map(arg => this.evaluate(arg, env));
7765
+
7766
+ // Handle user-defined functions (including async and arrow functions)
7767
+ if (constructor && constructor.__isFunction) {
7768
+ const result = this.callUserFunction(constructor, args, env);
7769
+ // If result is a promise (async function), return it directly
7770
+ // The async context will handle it
7771
+ if (result && typeof result.then === 'function') {
7772
+ return result.then(res => {
7773
+ if (res && typeof res === 'object') {
7774
+ return res;
7775
+ }
7776
+ return {};
7777
+ });
7778
+ }
7779
+ // If the function returns an object, use it; otherwise create a new object
7780
+ if (result && typeof result === 'object') {
7781
+ return result;
7782
+ }
7783
+ // For arrow/async functions that don't return an object, create one
7784
+ return {};
7785
+ }
7786
+
7787
+ if (typeof constructor === 'function') {
7788
+ // For native functions and classes, try to construct
7789
+ // Arrow functions and async functions can't be constructed with 'new' in JavaScript,
7790
+ // but if they return an object, we can use that
7791
+ try {
7792
+ return new constructor(...args);
7793
+ } catch (err) {
7794
+ // If construction fails (e.g., arrow function, async function),
7795
+ // try calling it normally and see if it returns an object
7796
+ if (err.message && err.message.includes('not a constructor')) {
7797
+ const result = constructor(...args);
7798
+ // If result is a promise, handle it
7799
+ if (result && typeof result.then === 'function') {
7800
+ return result.then(res => {
7801
+ if (res && typeof res === 'object') {
7802
+ return res;
7803
+ }
7804
+ throw new TypeError(`Type mismatch in new expression: ${node.callee.name || 'Expression'} is not a constructor`);
7805
+ });
7806
+ }
7807
+ if (result && typeof result === 'object') {
7808
+ return result;
7809
+ }
7810
+ throw new TypeError(`Type mismatch in new expression: ${node.callee.name || 'Expression'} is not a constructor`);
7811
+ }
7812
+ throw err;
7813
+ }
7814
+ }
7815
+
7816
+ throw new TypeError(`Type mismatch in new expression: ${node.callee.name || 'Expression'} is not a constructor`);
7817
+ }
7818
+
7819
+ evaluateThisExpression(node, env) {
7820
+ try {
7821
+ return env.get('this');
7822
+ } catch (e) {
7823
+ // 'this' not defined in current scope
7824
+ return undefined;
7825
+ }
7826
+ }
7827
+
7828
+ evaluateSuperExpression(node, env) {
7829
+ // Super is used in class methods to access parent class
7830
+ try {
7831
+ return env.get('super');
7832
+ } catch (e) {
7833
+ throw new ReferenceError("'super' keyword is unexpected here");
7834
+ }
7835
+ }
7836
+
7837
+ evaluateSequenceExpression(node, env) {
7838
+ let result;
7839
+ for (const expr of node.expressions) {
7840
+ result = this.evaluate(expr, env);
7841
+ }
7842
+ return result;
7843
+ }
7844
+
7845
+ evaluateVariableDeclaration(node, env) {
7846
+ const isConst = node.kind === 'const';
7847
+
7848
+ for (const declarator of node.declarations) {
7849
+ const value = declarator.init
7850
+ ? this.evaluate(declarator.init, env)
7851
+ : undefined;
7852
+
7853
+ // Handle destructuring patterns
7854
+ if (declarator.id.type === 'ObjectPattern') {
7855
+ this.bindObjectPattern(declarator.id, value, env, isConst);
7856
+ } else if (declarator.id.type === 'ArrayPattern') {
7857
+ this.bindArrayPattern(declarator.id, value, env, isConst);
7858
+ } else {
7859
+ env.define(declarator.id.name, value, isConst);
7860
+ }
7861
+ }
7862
+ return undefined;
7863
+ }
7864
+
7865
+ bindObjectPattern(pattern, value, env, isConst = false) {
7866
+ if (value === null || value === undefined) {
7867
+ throw new TypeError('Cannot destructure undefined or null');
7868
+ }
7869
+
7870
+ for (const prop of pattern.properties) {
7871
+ if (prop.type === 'RestElement') {
7872
+ // Handle rest properties {...rest}
7873
+ const assignedKeys = pattern.properties
7874
+ .filter(p => p.type !== 'RestElement')
7875
+ .map(p => p.key.name || p.key.value);
7876
+ const restObj = {};
7877
+ for (const key in value) {
7878
+ if (!assignedKeys.includes(key)) {
7879
+ restObj[key] = value[key];
7880
+ }
7881
+ }
7882
+ env.define(prop.argument.name, restObj, isConst);
7883
+ } else {
7884
+ const key = prop.key.name || prop.key.value;
7885
+ const propValue = value[key];
7886
+
7887
+ if (prop.value.type === 'Identifier') {
7888
+ env.define(prop.value.name, propValue, isConst);
7889
+ } else if (prop.value.type === 'AssignmentPattern') {
7890
+ // Handle default values
7891
+ const finalValue = propValue !== undefined
7892
+ ? propValue
7893
+ : this.evaluate(prop.value.right, env);
7894
+ env.define(prop.value.left.name, finalValue, isConst);
7895
+ } else if (prop.value.type === 'ObjectPattern') {
7896
+ this.bindObjectPattern(prop.value, propValue, env, isConst);
7897
+ } else if (prop.value.type === 'ArrayPattern') {
7898
+ this.bindArrayPattern(prop.value, propValue, env, isConst);
7899
+ }
7900
+ }
7901
+ }
7902
+ }
7903
+
7904
+ bindArrayPattern(pattern, value, env, isConst = false) {
7905
+ if (!Array.isArray(value)) {
7906
+ throw new TypeError('Cannot destructure non-iterable');
7907
+ }
7908
+
7909
+ for (let i = 0; i < pattern.elements.length; i++) {
7910
+ const element = pattern.elements[i];
7911
+ if (!element) continue; // Hole in pattern [a, , c]
7912
+
7913
+ if (element.type === 'RestElement') {
7914
+ // Handle rest elements [...rest]
7915
+ const restValues = value.slice(i);
7916
+ env.define(element.argument.name, restValues, isConst);
7917
+ break;
7918
+ } else if (element.type === 'Identifier') {
7919
+ env.define(element.name, value[i], isConst);
7920
+ } else if (element.type === 'AssignmentPattern') {
7921
+ // Handle default values
7922
+ const finalValue = value[i] !== undefined
7923
+ ? value[i]
7924
+ : this.evaluate(element.right, env);
7925
+ env.define(element.left.name, finalValue, isConst);
7926
+ } else if (element.type === 'ObjectPattern') {
7927
+ this.bindObjectPattern(element, value[i], env, isConst);
7928
+ } else if (element.type === 'ArrayPattern') {
7929
+ this.bindArrayPattern(element, value[i], env, isConst);
7930
+ }
7931
+ }
7932
+ }
7933
+
7934
+ evaluateFunctionDeclaration(node, env) {
7935
+ const funcMetadata = {
7936
+ __isFunction: true,
7937
+ params: node.params,
7938
+ body: node.body,
7939
+ closure: env,
7940
+ expression: false,
7941
+ async: node.async || false
7942
+ };
7943
+
7944
+ // Wrap in actual JavaScript function so it can be called by native code
7945
+ const interpreter = this;
7946
+
7947
+ // Create async or sync wrapper based on function type
7948
+ // Note: using regular function (not arrow) to capture 'this' for method calls
7949
+ const wrappedFunc = funcMetadata.async
7950
+ ? async function(...args) {
7951
+ return await interpreter.callUserFunction(funcMetadata, args, funcMetadata.closure, this);
7952
+ }
7953
+ : function(...args) {
7954
+ return interpreter.callUserFunction(funcMetadata, args, funcMetadata.closure, this);
7955
+ };
7956
+
7957
+ // Preserve metadata for JSLike's internal use
7958
+ wrappedFunc.__isFunction = true;
7959
+ wrappedFunc.__metadata = funcMetadata;
7960
+
7961
+ env.define(node.id.name, wrappedFunc);
7962
+ return undefined;
7963
+ }
7964
+
7965
+ async evaluateImportDeclaration(node, env) {
7966
+ // Get module path from import source
7967
+ const modulePath = node.source.value;
7968
+
7969
+ // Check if module resolver is configured
7970
+ if (!this.moduleResolver) {
7971
+ throw new Error('Module resolver not configured - cannot import modules');
7972
+ }
7973
+
7974
+ // Check if module is already cached
7975
+ let moduleExports;
7976
+ if (this.moduleCache.has(modulePath)) {
7977
+ moduleExports = this.moduleCache.get(modulePath);
7978
+ } else {
7979
+ // Resolve and load module code
7980
+ const resolution = await this.moduleResolver.resolve(modulePath);
7981
+ if (!resolution) {
7982
+ throw new Error(`Cannot find module '${modulePath}'`);
7983
+ }
7984
+
7985
+ // Handle both old (string) and new (ModuleResolution) formats
7986
+ const moduleCode = typeof resolution === 'string' ? resolution : resolution.code;
7987
+
7988
+ // Parse and execute module in its own environment
7989
+ const moduleAst = parse$1(moduleCode, {
7990
+ ecmaVersion: 2020,
7991
+ sourceType: 'module',
7992
+ locations: false
7993
+ });
7994
+ const moduleEnv = new Environment(this.globalEnv);
7995
+
7996
+ // Create a new interpreter for the module with shared module cache
7997
+ const moduleInterpreter = new Interpreter(this.globalEnv, {
7998
+ moduleResolver: this.moduleResolver
7999
+ });
8000
+ moduleInterpreter.moduleCache = this.moduleCache; // Share cache
8001
+
8002
+ // Execute module and collect exports
8003
+ await moduleInterpreter.evaluateAsync(moduleAst, moduleEnv);
8004
+
8005
+ // Cache the module exports
8006
+ moduleExports = moduleInterpreter.moduleExports;
8007
+ this.moduleCache.set(modulePath, moduleExports);
8008
+ }
8009
+
8010
+ // Import specified bindings into current environment
8011
+ for (const specifier of node.specifiers) {
8012
+ if (specifier.type === 'ImportSpecifier') {
8013
+ // Named import: import { foo, bar } from "module"
8014
+ const importedName = specifier.imported.name;
8015
+ const localName = specifier.local.name;
8016
+
8017
+ if (!(importedName in moduleExports)) {
8018
+ throw new Error(`Module '${modulePath}' has no export '${importedName}'`);
8019
+ }
8020
+
8021
+ env.define(localName, moduleExports[importedName]);
8022
+ } else if (specifier.type === 'ImportDefaultSpecifier') {
8023
+ // Default import: import foo from "module"
8024
+ const localName = specifier.local.name;
8025
+
8026
+ if (!('default' in moduleExports)) {
8027
+ throw new Error(`Module '${modulePath}' has no default export`);
8028
+ }
8029
+
8030
+ env.define(localName, moduleExports.default);
8031
+ } else if (specifier.type === 'ImportNamespaceSpecifier') {
8032
+ // Namespace import: import * as foo from "module"
8033
+ const localName = specifier.local.name;
8034
+ env.define(localName, moduleExports);
8035
+ }
8036
+ }
8037
+
8038
+ return undefined;
8039
+ }
8040
+
8041
+ evaluateExportNamedDeclaration(node, env) {
8042
+ // Handle export with declaration: export function foo() {} or export const x = 42
8043
+ if (node.declaration) {
8044
+ const result = this.evaluate(node.declaration, env);
8045
+
8046
+ // Register exported names
8047
+ if (node.declaration.type === 'FunctionDeclaration') {
8048
+ // export function foo() {}
8049
+ const name = node.declaration.id.name;
8050
+ this.moduleExports[name] = env.get(name);
8051
+ } else if (node.declaration.type === 'VariableDeclaration') {
8052
+ // export const x = 42, y = 10
8053
+ for (const declarator of node.declaration.declarations) {
8054
+ const name = declarator.id.name;
8055
+ this.moduleExports[name] = env.get(name);
8056
+ }
8057
+ } else if (node.declaration.type === 'ClassDeclaration') {
8058
+ // export class Foo {}
8059
+ const name = node.declaration.id.name;
8060
+ this.moduleExports[name] = env.get(name);
8061
+ }
8062
+
8063
+ return result;
8064
+ }
8065
+
8066
+ // Handle export list: export { foo, bar }
8067
+ if (node.specifiers && node.specifiers.length > 0) {
8068
+ for (const specifier of node.specifiers) {
8069
+ const exportedName = specifier.exported.name;
8070
+ const localName = specifier.local.name;
8071
+ this.moduleExports[exportedName] = env.get(localName);
8072
+ }
8073
+ }
8074
+
8075
+ return undefined;
8076
+ }
8077
+
8078
+ evaluateExportDefaultDeclaration(node, env) {
8079
+ // Evaluate the default export expression/declaration
8080
+ let value;
8081
+
8082
+ if (node.declaration.type === 'FunctionDeclaration' || node.declaration.type === 'ClassDeclaration') {
8083
+ // export default function foo() {} or export default class Foo {}
8084
+ value = this.evaluate(node.declaration, env);
8085
+ // If it has a name, it's also defined in the environment
8086
+ if (node.declaration.id) {
8087
+ value = env.get(node.declaration.id.name);
8088
+ }
8089
+ } else {
8090
+ // export default expression
8091
+ value = this.evaluate(node.declaration, env);
8092
+ }
8093
+
8094
+ // Register as default export
8095
+ this.moduleExports.default = value;
8096
+
8097
+ return undefined;
8098
+ }
8099
+
8100
+ evaluateBlockStatement(node, env) {
8101
+ const blockEnv = new Environment(env);
8102
+ let result;
8103
+
8104
+ for (const statement of node.body) {
8105
+ result = this.evaluate(statement, blockEnv);
8106
+ if (result instanceof ReturnValue ||
8107
+ result instanceof BreakSignal ||
8108
+ result instanceof ContinueSignal ||
8109
+ result instanceof ThrowSignal) {
8110
+ return result;
8111
+ }
8112
+ }
8113
+
8114
+ return result;
8115
+ }
8116
+
8117
+ evaluateIfStatement(node, env) {
8118
+ const test = this.evaluate(node.test, env);
8119
+
8120
+ if (test) {
8121
+ return this.evaluate(node.consequent, env);
8122
+ } else if (node.alternate) {
8123
+ return this.evaluate(node.alternate, env);
8124
+ }
8125
+
8126
+ return undefined;
8127
+ }
8128
+
8129
+ evaluateWhileStatement(node, env) {
8130
+ let result;
8131
+
8132
+ while (this.evaluate(node.test, env)) {
8133
+ result = this.evaluate(node.body, env);
8134
+
8135
+ if (result instanceof BreakSignal) {
8136
+ break;
8137
+ }
8138
+ if (result instanceof ContinueSignal) {
8139
+ continue;
8140
+ }
8141
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
8142
+ return result;
8143
+ }
8144
+ }
8145
+
8146
+ return undefined;
8147
+ }
8148
+
8149
+ evaluateDoWhileStatement(node, env) {
8150
+ let result;
8151
+
8152
+ do {
8153
+ result = this.evaluate(node.body, env);
8154
+
8155
+ if (result instanceof BreakSignal) {
8156
+ break;
8157
+ }
8158
+ if (result instanceof ContinueSignal) {
8159
+ continue;
8160
+ }
8161
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
8162
+ return result;
8163
+ }
8164
+ } while (this.evaluate(node.test, env));
8165
+
8166
+ return undefined;
8167
+ }
8168
+
8169
+ evaluateForStatement(node, env) {
8170
+ const forEnv = new Environment(env);
8171
+ let result;
8172
+
8173
+ if (node.init) {
8174
+ this.evaluate(node.init, forEnv);
8175
+ }
8176
+
8177
+ while (!node.test || this.evaluate(node.test, forEnv)) {
8178
+ result = this.evaluate(node.body, forEnv);
8179
+
8180
+ if (result instanceof BreakSignal) {
8181
+ break;
8182
+ }
8183
+ if (result instanceof ContinueSignal) {
8184
+ if (node.update) {
8185
+ this.evaluate(node.update, forEnv);
8186
+ }
8187
+ continue;
8188
+ }
8189
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
8190
+ return result;
8191
+ }
8192
+
8193
+ if (node.update) {
8194
+ this.evaluate(node.update, forEnv);
8195
+ }
8196
+ }
8197
+
8198
+ return undefined;
8199
+ }
8200
+
8201
+ evaluateForInStatement(node, env) {
8202
+ const forEnv = new Environment(env);
8203
+ const obj = this.evaluate(node.right, forEnv);
8204
+ let result;
8205
+
8206
+ // Check for null or undefined - JavaScript throws TypeError
8207
+ if (obj === null || obj === undefined) {
8208
+ throw new TypeError(`Cannot use 'in' operator to iterate over ${obj}`);
8209
+ }
8210
+
8211
+ // Get the variable name from the declaration
8212
+ const varName = node.left.declarations[0].id.name;
8213
+
8214
+ // Define the variable once before the loop
8215
+ forEnv.define(varName, undefined);
8216
+
8217
+ for (const key in obj) {
8218
+ // Update the variable value for each iteration
8219
+ forEnv.set(varName, key);
8220
+ result = this.evaluate(node.body, forEnv);
8221
+
8222
+ if (result instanceof BreakSignal) {
8223
+ break;
8224
+ }
8225
+ if (result instanceof ContinueSignal) {
8226
+ continue;
8227
+ }
8228
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
8229
+ return result;
8230
+ }
8231
+ }
8232
+
8233
+ return undefined;
8234
+ }
8235
+
8236
+ evaluateForOfStatement(node, env) {
8237
+ const forEnv = new Environment(env);
8238
+ const iterable = this.evaluate(node.right, forEnv);
8239
+ let result;
8240
+
8241
+ const declarator = node.left.declarations[0];
8242
+ const isConst = node.left.kind === 'const';
8243
+
8244
+ for (const value of iterable) {
8245
+ // Create a new child environment for each iteration to handle const properly
8246
+ const iterEnv = forEnv.extend();
8247
+
8248
+ // Bind the value using the appropriate pattern
8249
+ if (declarator.id.type === 'Identifier') {
8250
+ iterEnv.define(declarator.id.name, value, isConst);
8251
+ } else if (declarator.id.type === 'ArrayPattern') {
8252
+ this.bindArrayPattern(declarator.id, value, iterEnv, isConst);
8253
+ } else if (declarator.id.type === 'ObjectPattern') {
8254
+ this.bindObjectPattern(declarator.id, value, iterEnv, isConst);
8255
+ }
8256
+
8257
+ result = this.evaluate(node.body, iterEnv);
8258
+
8259
+ if (result instanceof BreakSignal) {
8260
+ break;
8261
+ }
8262
+ if (result instanceof ContinueSignal) {
8263
+ continue;
8264
+ }
8265
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
8266
+ return result;
8267
+ }
8268
+ }
8269
+
8270
+ return undefined;
8271
+ }
8272
+
8273
+ evaluateTryStatement(node, env) {
8274
+ let result;
8275
+
8276
+ try {
8277
+ result = this.evaluate(node.block, env);
8278
+
8279
+ if (result instanceof ThrowSignal) {
8280
+ throw result.value;
8281
+ }
8282
+ } catch (error) {
8283
+ if (node.handler) {
8284
+ const catchEnv = new Environment(env);
8285
+ if (node.handler.param) {
8286
+ catchEnv.define(node.handler.param.name, error);
8287
+ }
8288
+ result = this.evaluate(node.handler.body, catchEnv);
8289
+ } else {
8290
+ throw error;
8291
+ }
8292
+ } finally {
8293
+ if (node.finalizer) {
8294
+ const finalResult = this.evaluate(node.finalizer, env);
8295
+ // If finally block throws or returns, it overrides the try/catch result
8296
+ if (finalResult instanceof ThrowSignal || finalResult instanceof ReturnValue) {
8297
+ return finalResult;
8298
+ }
8299
+ }
8300
+ }
8301
+
8302
+ return result;
8303
+ }
8304
+
8305
+ evaluateSwitchStatement(node, env) {
8306
+ const discriminant = this.evaluate(node.discriminant, env);
8307
+ let matched = false;
8308
+ let result;
8309
+
8310
+ for (const switchCase of node.cases) {
8311
+ // Check if this case matches (or if we're in fall-through mode)
8312
+ if (!matched && switchCase.test) {
8313
+ const testValue = this.evaluate(switchCase.test, env);
8314
+ if (testValue === discriminant) {
8315
+ matched = true;
8316
+ }
8317
+ } else if (!switchCase.test) {
8318
+ // Default case
8319
+ matched = true;
8320
+ }
8321
+
8322
+ // Execute consequent if matched
8323
+ if (matched) {
8324
+ for (const statement of switchCase.consequent) {
8325
+ result = this.evaluate(statement, env);
8326
+
8327
+ if (result instanceof BreakSignal) {
8328
+ return undefined;
8329
+ }
8330
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
8331
+ return result;
8332
+ }
8333
+ }
8334
+ }
8335
+ }
8336
+
8337
+ return undefined;
8338
+ }
8339
+
8340
+ // ===== ES6+ Feature Implementations =====
8341
+
8342
+ evaluateTemplateLiteral(node, env) {
8343
+ let result = '';
8344
+ for (let i = 0; i < node.quasis.length; i++) {
8345
+ result += node.quasis[i].value.cooked || node.quasis[i].value.raw;
8346
+ if (i < node.expressions.length) {
8347
+ const exprValue = this.evaluate(node.expressions[i], env);
8348
+ result += String(exprValue);
8349
+ }
8350
+ }
8351
+ return result;
8352
+ }
8353
+
8354
+ evaluateClassDeclaration(node, env) {
8355
+ const className = node.id.name;
8356
+ const classFunc = this.createClass(node, env);
8357
+ env.define(className, classFunc);
8358
+ return undefined;
8359
+ }
8360
+
8361
+ evaluateClassExpression(node, env) {
8362
+ return this.createClass(node, env);
8363
+ }
8364
+
8365
+ createClass(node, env) {
8366
+ const className = node.id ? node.id.name : 'AnonymousClass';
8367
+ const superClass = node.superClass ? this.evaluate(node.superClass, env) : null;
8368
+ const interpreter = this; // Capture interpreter reference
8369
+
8370
+ // Find constructor
8371
+ let constructor = null;
8372
+ const methods = {};
8373
+ const staticMethods = {};
8374
+
8375
+ for (const member of node.body.body) {
8376
+ if (member.type === 'MethodDefinition') {
8377
+ const methodName = member.key.name || member.key.value;
8378
+ const methodFunc = this.createMethodFunction(member.value, env, className);
8379
+
8380
+ if (member.kind === 'constructor') {
8381
+ constructor = methodFunc;
8382
+ } else if (member.static) {
8383
+ staticMethods[methodName] = methodFunc;
8384
+ } else {
8385
+ methods[methodName] = methodFunc;
8386
+ }
8387
+ }
8388
+ }
8389
+
8390
+ // Create class constructor function
8391
+ const classConstructor = function(...args) {
8392
+ // Create instance
8393
+ const instance = Object.create(classConstructor.prototype);
8394
+
8395
+ // Call constructor - super() must be called explicitly inside constructor
8396
+ if (constructor) {
8397
+ const result = interpreter.callMethodFunction(constructor, instance, args, env, superClass);
8398
+ // Only use the returned object if it's an explicit return of an object (not the instance)
8399
+ if (result && result.__explicitReturn && result.value && typeof result.value === 'object' && result.value !== instance) {
8400
+ return result.value;
8401
+ }
8402
+ } else if (superClass) {
8403
+ // If no constructor defined but has superClass, implicitly call super()
8404
+ // Call the superClass constructor properly - it's a classConstructor function
8405
+ superClass.call(instance, ...args);
8406
+ }
8407
+
8408
+ return instance;
8409
+ };
8410
+
8411
+ // Store the constructor method on the classConstructor for super() to access
8412
+ if (constructor) {
8413
+ classConstructor.__constructor = constructor;
8414
+ }
8415
+
8416
+ // Set up prototype chain
8417
+ if (superClass) {
8418
+ classConstructor.prototype = Object.create(superClass.prototype);
8419
+ classConstructor.prototype.constructor = classConstructor;
8420
+ }
8421
+
8422
+ // Add methods to prototype
8423
+ for (const [name, method] of Object.entries(methods)) {
8424
+ classConstructor.prototype[name] = function(...args) {
8425
+ const result = interpreter.callMethodFunction(method, this, args, env);
8426
+ // Unwrap explicit return marker
8427
+ if (result && result.__explicitReturn) {
8428
+ return result.value;
8429
+ }
8430
+ return result;
8431
+ };
8432
+ }
8433
+
8434
+ // Add static methods
8435
+ for (const [name, method] of Object.entries(staticMethods)) {
8436
+ classConstructor[name] = function(...args) {
8437
+ const result = interpreter.callMethodFunction(method, classConstructor, args, env);
8438
+ // Unwrap explicit return marker
8439
+ if (result && result.__explicitReturn) {
8440
+ return result.value;
8441
+ }
8442
+ return result;
8443
+ };
8444
+ }
8445
+
8446
+ classConstructor.__className = className;
8447
+ return classConstructor;
8448
+ }
8449
+
8450
+ createMethodFunction(funcNode, env, className) {
8451
+ const func = {
8452
+ __isFunction: true,
8453
+ __params: funcNode.params,
8454
+ __body: funcNode.body,
8455
+ __env: env,
8456
+ __className: className
8457
+ };
8458
+ return func;
8459
+ }
8460
+
8461
+ callMethodFunction(methodFunc, thisContext, args, env, superClass = null) {
8462
+ const funcEnv = new Environment(methodFunc.__env || env);
8463
+
8464
+ // Bind 'this'
8465
+ funcEnv.define('this', thisContext);
8466
+
8467
+ // Bind 'super' if superClass exists
8468
+ if (superClass) {
8469
+ // Create a super function that calls the parent constructor
8470
+ const superFunc = (...superArgs) => {
8471
+ // Call the parent constructor method if it exists
8472
+ if (superClass.__constructor) {
8473
+ this.callMethodFunction(superClass.__constructor, thisContext, superArgs, env, null);
8474
+ }
8475
+ // Otherwise, call superClass as a regular constructor (for native/external classes)
8476
+ else {
8477
+ // For native constructors like Error, we need to use Reflect.construct
8478
+ // to properly initialize the instance properties
8479
+ const tempInstance = Reflect.construct(superClass, superArgs, thisContext.constructor);
8480
+ // Copy properties from the temp instance to our thisContext
8481
+ Object.getOwnPropertyNames(tempInstance).forEach(name => {
8482
+ thisContext[name] = tempInstance[name];
8483
+ });
8484
+ }
8485
+ return undefined;
8486
+ };
8487
+ // Store both the function and mark it as super
8488
+ superFunc.__isSuperConstructor = true;
8489
+ superFunc.__superClass = superClass;
8490
+ funcEnv.define('super', superFunc);
8491
+ }
8492
+
8493
+ // Bind parameters
8494
+ for (let i = 0; i < methodFunc.__params.length; i++) {
8495
+ const param = methodFunc.__params[i];
8496
+
8497
+ if (param.type === 'Identifier') {
8498
+ // Simple parameter: function(x)
8499
+ funcEnv.define(param.name, args[i]);
8500
+ } else if (param.type === 'AssignmentPattern') {
8501
+ // Default parameter: function(x = defaultValue)
8502
+ const value = args[i] !== undefined ? args[i] : this.evaluate(param.right, funcEnv);
8503
+ funcEnv.define(param.left.name, value);
8504
+ } else if (param.type === 'RestElement') {
8505
+ // Rest parameter: function(...rest)
8506
+ funcEnv.define(param.argument.name, args.slice(i));
8507
+ break; // Rest element must be last
8508
+ } else if (param.type === 'ObjectPattern') {
8509
+ // Destructuring parameter: function({a, b})
8510
+ this.bindObjectPattern(param, args[i], funcEnv);
8511
+ } else if (param.type === 'ArrayPattern') {
8512
+ // Array destructuring parameter: function([a, b])
8513
+ this.bindArrayPattern(param, args[i], funcEnv);
8514
+ } else {
8515
+ // Fallback for simple parameter names
8516
+ funcEnv.define(param.name, args[i]);
8517
+ }
8518
+ }
8519
+
8520
+ const result = this.evaluate(methodFunc.__body, funcEnv);
8521
+
8522
+ if (result instanceof ReturnValue) {
8523
+ // Mark that this was an explicit return for constructor handling
8524
+ return { __explicitReturn: true, value: result.value };
8525
+ }
8526
+
8527
+ // If the result is a ThrowSignal, throw the error
8528
+ if (result instanceof ThrowSignal) {
8529
+ throw result.value;
8530
+ }
8531
+
8532
+ // Return implicit result (for arrow function expressions)
8533
+ return result;
8534
+ }
8535
+
8536
+ evaluateMethodDefinition(node, env) {
8537
+ // This is handled by class creation
8538
+ return undefined;
8539
+ }
8540
+
8541
+ evaluateSpreadElement(node, env) {
8542
+ const arg = this.evaluate(node.argument, env);
8543
+ if (Array.isArray(arg)) {
8544
+ return { __spread: true, __values: arg };
8545
+ }
8546
+ if (typeof arg === 'object' && arg !== null) {
8547
+ return { __spread: true, __values: Object.entries(arg) };
8548
+ }
8549
+ throw new TypeError('Spread syntax requires an iterable');
8550
+ }
8551
+
8552
+ evaluateRestElement(node, env) {
8553
+ // Handled during parameter binding
8554
+ return undefined;
8555
+ }
8556
+
8557
+ evaluateObjectPattern(node, env) {
8558
+ // Handled during destructuring
8559
+ return undefined;
8560
+ }
8561
+
8562
+ evaluateArrayPattern(node, env) {
8563
+ // Handled during destructuring
8564
+ return undefined;
8565
+ }
8566
+
8567
+ evaluateAssignmentPattern(node, env) {
8568
+ // Handled during parameter binding with defaults
8569
+ return undefined;
8570
+ }
8571
+
8572
+ evaluateProperty(node, env) {
8573
+ // Already handled in evaluateObjectExpression
8574
+ return undefined;
8575
+ }
8576
+ }
8577
+
8578
+ // Built-in global objects and functions
8579
+
8580
+ function createGlobalEnvironment(env) {
8581
+ // Global objects (only those not already defined below)
8582
+ env.define('Date', Date);
8583
+
8584
+ // console object
8585
+ env.define('console', {
8586
+ log: (...args) => {
8587
+ console.log(...args);
8588
+ return undefined;
8589
+ },
8590
+ error: (...args) => {
8591
+ console.error(...args);
8592
+ return undefined;
8593
+ },
8594
+ warn: (...args) => {
8595
+ console.warn(...args);
8596
+ return undefined;
8597
+ },
8598
+ info: (...args) => {
8599
+ console.info(...args);
8600
+ return undefined;
8601
+ },
8602
+ dir: (...args) => {
8603
+ console.dir(...args);
8604
+ return undefined;
8605
+ }
8606
+ });
8607
+
8608
+ // Math object
8609
+ env.define('Math', {
8610
+ PI: Math.PI,
8611
+ E: Math.E,
8612
+ abs: Math.abs,
8613
+ acos: Math.acos,
8614
+ asin: Math.asin,
8615
+ atan: Math.atan,
8616
+ atan2: Math.atan2,
8617
+ ceil: Math.ceil,
8618
+ cos: Math.cos,
8619
+ exp: Math.exp,
8620
+ floor: Math.floor,
8621
+ log: Math.log,
8622
+ max: Math.max,
8623
+ min: Math.min,
8624
+ pow: Math.pow,
8625
+ random: Math.random,
8626
+ round: Math.round,
8627
+ sin: Math.sin,
8628
+ sqrt: Math.sqrt,
8629
+ tan: Math.tan,
8630
+ trunc: Math.trunc
8631
+ });
8632
+
8633
+ // Global values
8634
+ env.define('undefined', undefined);
8635
+
8636
+ // Global functions
8637
+ env.define('parseInt', parseInt);
8638
+ env.define('parseFloat', parseFloat);
8639
+ env.define('isNaN', isNaN);
8640
+ env.define('isFinite', isFinite);
8641
+
8642
+ // Array constructor
8643
+ env.define('Array', Array);
8644
+
8645
+ // Object constructor
8646
+ env.define('Object', Object);
8647
+
8648
+ // String constructor
8649
+ env.define('String', String);
8650
+
8651
+ // Number constructor
8652
+ env.define('Number', Number);
8653
+
8654
+ // Boolean constructor
8655
+ env.define('Boolean', Boolean);
8656
+
8657
+ // Function constructor
8658
+ env.define('Function', Function);
8659
+
8660
+ // RegExp constructor
8661
+ env.define('RegExp', RegExp);
8662
+
8663
+ // Symbol constructor
8664
+ env.define('Symbol', Symbol);
8665
+
8666
+ // Map and Set constructors
8667
+ env.define('Map', Map);
8668
+ env.define('Set', Set);
8669
+ env.define('WeakMap', WeakMap);
8670
+ env.define('WeakSet', WeakSet);
8671
+
8672
+ // JSON object
8673
+ env.define('JSON', {
8674
+ parse: JSON.parse,
8675
+ stringify: JSON.stringify
8676
+ });
8677
+
8678
+ // setTimeout, setInterval (basic implementations)
8679
+ env.define('setTimeout', setTimeout);
8680
+ env.define('setInterval', setInterval);
8681
+ env.define('clearTimeout', clearTimeout);
8682
+ env.define('clearInterval', clearInterval);
8683
+
8684
+ // Promise
8685
+ env.define('Promise', Promise);
8686
+
8687
+ // Error constructors
8688
+ env.define('Error', Error);
8689
+ env.define('TypeError', TypeError);
8690
+ env.define('ReferenceError', ReferenceError);
8691
+ env.define('SyntaxError', SyntaxError);
8692
+ env.define('RangeError', RangeError);
8693
+
8694
+ // Global console functions (shortcuts for console.log/warn/error)
8695
+ env.define('log', (...args) => {
8696
+ console.log(...args);
8697
+ return undefined;
8698
+ });
8699
+ env.define('warn', (...args) => {
8700
+ console.warn(...args);
8701
+ return undefined;
8702
+ });
8703
+ env.define('error', (...args) => {
8704
+ console.error(...args);
8705
+ return undefined;
8706
+ });
8707
+
8708
+ // Wang Standard Library - Array Operations
8709
+ env.define('sort_by', (array, keyOrFn) => {
8710
+ const arr = [...array];
8711
+ if (typeof keyOrFn === 'function') {
8712
+ return arr.sort((a, b) => {
8713
+ const aVal = keyOrFn(a);
8714
+ const bVal = keyOrFn(b);
8715
+ return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
8716
+ });
8717
+ } else {
8718
+ return arr.sort((a, b) => {
8719
+ const aVal = a[keyOrFn];
8720
+ const bVal = b[keyOrFn];
8721
+ return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
8722
+ });
8723
+ }
8724
+ });
8725
+
8726
+ env.define('reverse', (array) => {
8727
+ return [...array].reverse();
8728
+ });
8729
+
8730
+ env.define('unique', (array) => {
8731
+ return [...new Set(array)];
8732
+ });
8733
+
8734
+ env.define('unique_by', (array, key) => {
8735
+ const seen = new Set();
8736
+ return array.filter(item => {
8737
+ const val = item[key];
8738
+ if (seen.has(val)) return false;
8739
+ seen.add(val);
8740
+ return true;
8741
+ });
8742
+ });
8743
+
8744
+ env.define('group_by', (array, key) => {
8745
+ return array.reduce((groups, item) => {
8746
+ const groupKey = item[key];
8747
+ if (!groups[groupKey]) groups[groupKey] = [];
8748
+ groups[groupKey].push(item);
8749
+ return groups;
8750
+ }, {});
8751
+ });
8752
+
8753
+ env.define('chunk', (array, size) => {
8754
+ const chunks = [];
8755
+ for (let i = 0; i < array.length; i += size) {
8756
+ chunks.push(array.slice(i, i + size));
8757
+ }
8758
+ return chunks;
8759
+ });
8760
+
8761
+ env.define('flatten', (array, depth = 1) => {
8762
+ return array.flat(depth);
8763
+ });
8764
+
8765
+ env.define('first', (array, n) => {
8766
+ if (n === undefined) return array[0];
8767
+ return array.slice(0, n);
8768
+ });
8769
+
8770
+ env.define('last', (array, n) => {
8771
+ if (n === undefined) return array[array.length - 1];
8772
+ return array.slice(-n);
8773
+ });
8774
+
8775
+ env.define('take', (array, n) => {
8776
+ return array.slice(0, n);
8777
+ });
8778
+
8779
+ env.define('drop', (array, n) => {
8780
+ return array.slice(n);
8781
+ });
8782
+
8783
+ env.define('zip', (...arrays) => {
8784
+ const length = Math.min(...arrays.map(a => a.length));
8785
+ return Array.from({ length }, (_, i) => arrays.map(a => a[i]));
8786
+ });
8787
+
8788
+ env.define('partition', (array, predicate) => {
8789
+ const truthy = [];
8790
+ const falsy = [];
8791
+ array.forEach(item => {
8792
+ if (predicate(item)) truthy.push(item);
8793
+ else falsy.push(item);
8794
+ });
8795
+ return [truthy, falsy];
8796
+ });
8797
+
8798
+ env.define('filter', (array, predicate) => {
8799
+ return array.filter(predicate);
8800
+ });
8801
+
8802
+ env.define('map', (array, fn) => {
8803
+ return array.map(fn);
8804
+ });
8805
+
8806
+ env.define('find', (array, predicate) => {
8807
+ return array.find(predicate);
8808
+ });
8809
+
8810
+ env.define('find_index', (array, predicate) => {
8811
+ return array.findIndex(predicate);
8812
+ });
8813
+
8814
+ env.define('every', (array, predicate) => {
8815
+ return array.every(predicate);
8816
+ });
8817
+
8818
+ env.define('some', (array, predicate) => {
8819
+ return array.some(predicate);
8820
+ });
8821
+
8822
+ env.define('count', (array, predicate) => {
8823
+ if (!predicate) {
8824
+ return array.length;
8825
+ }
8826
+ return array.filter(predicate).length;
8827
+ });
8828
+
8829
+ // Wang Standard Library - Object Operations
8830
+ env.define('keys', (obj) => {
8831
+ return Object.keys(obj);
8832
+ });
8833
+
8834
+ env.define('values', (obj) => {
8835
+ return Object.values(obj);
8836
+ });
8837
+
8838
+ env.define('entries', (obj) => {
8839
+ return Object.entries(obj);
8840
+ });
8841
+
8842
+ env.define('pick', (obj, keys) => {
8843
+ const result = {};
8844
+ keys.forEach(key => {
8845
+ if (key in obj) result[key] = obj[key];
8846
+ });
8847
+ return result;
8848
+ });
8849
+
8850
+ env.define('omit', (obj, keys) => {
8851
+ const result = { ...obj };
8852
+ keys.forEach(key => delete result[key]);
8853
+ return result;
8854
+ });
8855
+
8856
+ env.define('merge', (...objects) => {
8857
+ return Object.assign({}, ...objects);
8858
+ });
8859
+
8860
+ env.define('get', (obj, path, defaultValue) => {
8861
+ const keys = path.split('.');
8862
+ let current = obj;
8863
+ for (const key of keys) {
8864
+ if (current == null) return defaultValue;
8865
+ current = current[key];
8866
+ }
8867
+ return current !== undefined ? current : defaultValue;
8868
+ });
8869
+
8870
+ env.define('set', (obj, path, value) => {
8871
+ const keys = path.split('.');
8872
+ const result = JSON.parse(JSON.stringify(obj)); // Deep clone
8873
+ let current = result;
8874
+ for (let i = 0; i < keys.length - 1; i++) {
8875
+ const key = keys[i];
8876
+ if (!(key in current)) current[key] = {};
8877
+ current = current[key];
8878
+ }
8879
+ current[keys[keys.length - 1]] = value;
8880
+ return result;
8881
+ });
8882
+
8883
+ env.define('clone', (obj) => {
8884
+ return JSON.parse(JSON.stringify(obj));
8885
+ });
8886
+
8887
+ // Wang Standard Library - String Operations
8888
+ env.define('split', (str, separator) => {
8889
+ return str.split(separator);
8890
+ });
8891
+
8892
+ env.define('join', (array, separator) => {
8893
+ return array.join(separator);
8894
+ });
8895
+
8896
+ env.define('trim', (str) => {
8897
+ return str.trim();
8898
+ });
8899
+
8900
+ env.define('trim_start', (str) => {
8901
+ return str.trimStart();
8902
+ });
8903
+
8904
+ env.define('trim_end', (str) => {
8905
+ return str.trimEnd();
8906
+ });
8907
+
8908
+ env.define('upper', (str) => {
8909
+ return str.toUpperCase();
8910
+ });
8911
+
8912
+ env.define('toUpperCase', (str) => {
8913
+ return str.toUpperCase();
8914
+ });
8915
+
8916
+ env.define('lower', (str) => {
8917
+ return str.toLowerCase();
8918
+ });
8919
+
8920
+ env.define('toLowerCase', (str) => {
8921
+ return str.toLowerCase();
8922
+ });
8923
+
8924
+ env.define('capitalize', (str) => {
8925
+ if (!str) return str;
8926
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
8927
+ });
8928
+
8929
+ env.define('starts_with', (str, prefix) => {
8930
+ return str.startsWith(prefix);
8931
+ });
8932
+
8933
+ env.define('ends_with', (str, suffix) => {
8934
+ return str.endsWith(suffix);
8935
+ });
8936
+
8937
+ env.define('includes', (str, substring) => {
8938
+ return str.includes(substring);
8939
+ });
8940
+
8941
+ env.define('pad_start', (str, length, char = ' ') => {
8942
+ return str.padStart(length, char);
8943
+ });
8944
+
8945
+ env.define('pad_end', (str, length, char = ' ') => {
8946
+ return str.padEnd(length, char);
8947
+ });
8948
+
8949
+ env.define('truncate', (str, length) => {
8950
+ if (str.length <= length) return str;
8951
+ return str.slice(0, length - 3) + '...';
8952
+ });
8953
+
8954
+ env.define('replace_all', (str, search, replace) => {
8955
+ return str.replaceAll(search, replace);
8956
+ });
8957
+
8958
+ // Wang Standard Library - Type Checking
8959
+ env.define('is_string', (value) => {
8960
+ return typeof value === 'string';
8961
+ });
8962
+
8963
+ env.define('is_number', (value) => {
8964
+ return typeof value === 'number';
8965
+ });
8966
+
8967
+ env.define('is_boolean', (value) => {
8968
+ return typeof value === 'boolean';
8969
+ });
8970
+
8971
+ env.define('is_array', (value) => {
8972
+ return Array.isArray(value);
8973
+ });
8974
+
8975
+ env.define('is_object', (value) => {
8976
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
8977
+ });
8978
+
8979
+ env.define('is_function', (value) => {
8980
+ return typeof value === 'function';
8981
+ });
8982
+
8983
+ env.define('is_null', (value) => {
8984
+ return value === null;
8985
+ });
8986
+
8987
+ env.define('is_undefined', (value) => {
8988
+ return value === undefined;
8989
+ });
8990
+
8991
+ env.define('is_empty', (value) => {
8992
+ if (value == null) return true;
8993
+ if (typeof value === 'string' || Array.isArray(value)) return value.length === 0;
8994
+ if (typeof value === 'object') return Object.keys(value).length === 0;
8995
+ return false;
8996
+ });
8997
+
8998
+ // Wang Standard Library - Math Operations
8999
+ env.define('min', (array) => {
9000
+ return Math.min(...array);
9001
+ });
9002
+
9003
+ env.define('max', (array) => {
9004
+ return Math.max(...array);
9005
+ });
9006
+
9007
+ env.define('sum', (array) => {
9008
+ return array.reduce((a, b) => a + b, 0);
9009
+ });
9010
+
9011
+ env.define('avg', (array) => {
9012
+ return array.reduce((a, b) => a + b, 0) / array.length;
9013
+ });
9014
+
9015
+ env.define('median', (array) => {
9016
+ const sorted = [...array].sort((a, b) => a - b);
9017
+ const mid = Math.floor(sorted.length / 2);
9018
+ return sorted.length % 2 === 0
9019
+ ? (sorted[mid - 1] + sorted[mid]) / 2
9020
+ : sorted[mid];
9021
+ });
9022
+
9023
+ env.define('round', (num, decimals = 0) => {
9024
+ const factor = Math.pow(10, decimals);
9025
+ return Math.round(num * factor) / factor;
9026
+ });
9027
+
9028
+ env.define('floor', (num) => {
9029
+ return Math.floor(num);
9030
+ });
9031
+
9032
+ env.define('ceil', (num) => {
9033
+ return Math.ceil(num);
9034
+ });
9035
+
9036
+ env.define('abs', (num) => {
9037
+ return Math.abs(num);
9038
+ });
9039
+
9040
+ env.define('clamp', (num, min, max) => {
9041
+ return Math.min(Math.max(num, min), max);
9042
+ });
9043
+
9044
+ env.define('range', (start, end, step) => {
9045
+ // Support range(n) -> [0, 1, ..., n-1]
9046
+ if (end === undefined) {
9047
+ end = start;
9048
+ start = 0;
9049
+ step = 1;
9050
+ }
9051
+ if (step === undefined) {
9052
+ step = start < end ? 1 : -1;
9053
+ }
9054
+
9055
+ const result = [];
9056
+ if (step > 0) {
9057
+ for (let i = start; i < end; i += step) {
9058
+ result.push(i);
9059
+ }
9060
+ } else {
9061
+ for (let i = start; i > end; i += step) {
9062
+ result.push(i);
9063
+ }
9064
+ }
9065
+ return result;
9066
+ });
9067
+
9068
+ // Wang Standard Library - Utility Functions
9069
+ env.define('uuid', () => {
9070
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
9071
+ const r = Math.random() * 16 | 0;
9072
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
9073
+ return v.toString(16);
9074
+ });
9075
+ });
9076
+
9077
+ env.define('to_json', (value) => {
9078
+ return JSON.stringify(value);
9079
+ });
9080
+
9081
+ env.define('from_json', (str) => {
9082
+ return JSON.parse(str);
9083
+ });
9084
+
9085
+ env.define('sleep', async (ms) => {
9086
+ return new Promise(resolve => setTimeout(resolve, ms));
9087
+ });
9088
+
9089
+ env.define('wait', async (ms) => {
9090
+ return new Promise(resolve => setTimeout(resolve, ms));
9091
+ });
9092
+
9093
+ return env;
9094
+ }
9095
+
9096
+ /**
9097
+ * WangInterpreter compatibility adapter for JSLike
9098
+ * Maps Wang's interpreter API to JSLike's API
9099
+ */
9100
+
9101
+
9102
+ class WangInterpreter {
9103
+ constructor(options = {}) {
9104
+ this.options = options;
9105
+ this.moduleResolver = options.moduleResolver;
9106
+ this.functions = options.functions || {};
9107
+ // Create a persistent environment for setVariable support
9108
+ this.persistentEnv = null;
9109
+ }
9110
+
9111
+ setVariable(name, value) {
9112
+ // If persistent environment doesn't exist, create it
9113
+ if (!this.persistentEnv) {
9114
+ this.persistentEnv = createEnvironment();
9115
+
9116
+ // Add custom functions
9117
+ for (const [funcName, func] of Object.entries(this.functions)) {
9118
+ if (this.persistentEnv.has(funcName)) {
9119
+ this.persistentEnv.set(funcName, func);
9120
+ } else {
9121
+ this.persistentEnv.define(funcName, func);
9122
+ }
9123
+ }
9124
+ }
9125
+
9126
+ // Set the variable in persistent environment
9127
+ if (this.persistentEnv.has(name)) {
9128
+ this.persistentEnv.set(name, value);
9129
+ } else {
9130
+ this.persistentEnv.define(name, value);
9131
+ }
9132
+ }
9133
+
9134
+ // Alias for setVariable - specifically for binding functions
9135
+ bindFunction(name, func) {
9136
+ return this.setVariable(name, func);
9137
+ }
9138
+
9139
+ // Expose global context for accessing variables after execution
9140
+ get globalContext() {
9141
+ return {
9142
+ variables: this.persistentEnv?.vars || new Map()
9143
+ };
9144
+ }
9145
+
9146
+ createExecutionEnvironment() {
9147
+ // Create fresh environment for each execution
9148
+ const env = createEnvironment();
9149
+
9150
+ // Add custom functions to environment, overriding built-ins if needed
9151
+ for (const [name, func] of Object.entries(this.functions)) {
9152
+ // Use set() to override existing variables instead of define()
9153
+ if (env.has(name)) {
9154
+ env.set(name, func);
9155
+ } else {
9156
+ env.define(name, func);
9157
+ }
9158
+ }
9159
+
9160
+ return env;
9161
+ }
9162
+
9163
+ async execute(code, initialEnv = undefined, userOptions = {}) {
9164
+ // Use provided environment, persistent environment, or create fresh one
9165
+ const env = initialEnv || this.persistentEnv || this.createExecutionEnvironment();
9166
+
9167
+ // Setup console capture if withMetadata option is enabled
9168
+ const withMetadata = userOptions.withMetadata || false;
9169
+ const capturedLogs = [];
9170
+
9171
+ if (withMetadata) {
9172
+ // Override log/warn/error functions to capture calls
9173
+ const createCapture = (type) => {
9174
+ return (...args) => {
9175
+ capturedLogs.push({
9176
+ type,
9177
+ args,
9178
+ timestamp: Date.now()
9179
+ });
9180
+ // Still output to console
9181
+ console[type](...args);
9182
+ return undefined;
9183
+ };
9184
+ };
9185
+
9186
+ env.set('log', createCapture('log'));
9187
+ env.set('warn', createCapture('warn'));
9188
+ env.set('error', createCapture('error'));
9189
+ }
9190
+
9191
+ // Check if code contains top-level return statements
9192
+ // Need to detect `return` at start of line, but NOT inside function bodies
9193
+ // Simple heuristic: check if braces are balanced before the return statement
9194
+ const hasTopLevelReturn = this.hasTopLevelReturn(code);
9195
+
9196
+ // Prepare execution options
9197
+ const options = {
9198
+ moduleResolver: this.moduleResolver
9199
+ // sourceType will be auto-detected from code
9200
+ };
9201
+
9202
+ let result;
9203
+ if (hasTopLevelReturn) {
9204
+ // Wrap code in async IIFE to support top-level return statements
9205
+ const wrappedCode = `(async function() { ${code} })()`;
9206
+ try {
9207
+ result = await execute(wrappedCode, env, options);
9208
+ } catch (error) {
9209
+ throw error;
9210
+ }
9211
+ } else {
9212
+ // Execute directly - JSLike returns last evaluated expression
9213
+ try {
9214
+ result = await execute(code, env, options);
9215
+ } catch (error) {
9216
+ throw error;
9217
+ }
9218
+ }
9219
+
9220
+ // Return result with metadata if requested
9221
+ if (withMetadata) {
9222
+ return {
9223
+ result,
9224
+ metadata: {
9225
+ logs: capturedLogs
9226
+ }
9227
+ };
9228
+ }
9229
+
9230
+ return result;
9231
+ }
9232
+
9233
+ hasTopLevelReturn(code) {
9234
+ const lines = code.split('\n');
9235
+ let braceDepth = 0;
9236
+
9237
+ for (const line of lines) {
9238
+ // Check if this line has a return statement at the start (ignoring whitespace)
9239
+ const trimmed = line.trim();
9240
+ if (trimmed.startsWith('return ') || trimmed === 'return') {
9241
+ // If we're at brace depth 0, it's a top-level return
9242
+ if (braceDepth === 0) {
9243
+ return true;
9244
+ }
9245
+ }
9246
+
9247
+ // Count braces on this line (after checking for return)
9248
+ for (const char of line) {
9249
+ if (char === '{') braceDepth++;
9250
+ if (char === '}') braceDepth--;
9251
+ }
9252
+ }
9253
+
9254
+ return false;
9255
+ }
9256
+
9257
+ async executeModule(code) {
9258
+ // Same as execute for now - modules are handled by execute()
9259
+ return await this.execute(code);
9260
+ }
9261
+ }
9262
+
9263
+ class InMemoryModuleResolver {
9264
+ constructor() {
9265
+ this.modules = new Map();
9266
+ }
9267
+
9268
+ addModule(name, code, metadata) {
9269
+ this.modules.set(name, { code, metadata });
9270
+ }
9271
+
9272
+ async resolve(modulePath, fromPath) {
9273
+ const module = this.modules.get(modulePath);
9274
+ if (!module) {
9275
+ return null;
9276
+ }
9277
+ return {
9278
+ code: typeof module === 'string' ? module : module.code,
9279
+ path: modulePath,
9280
+ metadata: module.metadata
9281
+ };
9282
+ }
9283
+
9284
+ async exists(modulePath, fromPath) {
9285
+ return this.modules.has(modulePath);
9286
+ }
9287
+
9288
+ async list(prefix) {
9289
+ const paths = Array.from(this.modules.keys());
9290
+ if (prefix) {
9291
+ return paths.filter(p => p.startsWith(prefix));
9292
+ }
9293
+ return paths;
9294
+ }
9295
+ }
9296
+
9297
+ // Use bundled Acorn parser for zero runtime dependencies
9298
+
9299
+ // Helper to detect if code contains module syntax or top-level await
9300
+ function containsModuleSyntax(code) {
9301
+ // Trigger module mode for:
9302
+ // 1. import/export statements
9303
+ // 2. Top-level await (await not inside a function)
9304
+ if (/^\s*(import|export)\s+/m.test(code)) {
9305
+ return true;
9306
+ }
9307
+
9308
+ // Check for top-level await (simple heuristic: await at start of line or after statement)
9309
+ // This isn't perfect but handles common cases, including await in template literals
9310
+ // Also matches await after operators like || or && or = or inside parentheses
9311
+ if (/^await\s+/m.test(code) || /[;\n{(|&=]\s*await\s+/.test(code)) {
9312
+ return true;
9313
+ }
9314
+
9315
+ return false;
9316
+ }
9317
+
9318
+
9319
+ function parse(code, options = {}) {
9320
+ // Determine sourceType: use 'module' ONLY if explicitly requested or if code has imports/exports
9321
+ // Default to 'script' for better compatibility with labeled statements
9322
+ let sourceType = options.sourceType || 'script';
9323
+ if (!options.sourceType && containsModuleSyntax(code)) {
9324
+ sourceType = 'module';
9325
+ }
9326
+
9327
+ // Parse with Acorn
9328
+ try {
9329
+ return parse$1(code, {
9330
+ ecmaVersion: 2022, // Support ES2022 features (including top-level await)
9331
+ sourceType: sourceType,
9332
+ locations: true, // Track source locations for better error messages
9333
+ allowReturnOutsideFunction: true // Allow top-level return statements
9334
+ });
9335
+ } catch (error) {
9336
+ // Reformat error message for consistency
9337
+ throw new SyntaxError(
9338
+ `Parse error at line ${error.loc?.line || '?'}: ${error.message}`
9339
+ );
9340
+ }
9341
+ }
9342
+
9343
+ // Helper to detect if AST contains import/export declarations
9344
+ function containsModuleDeclarations(node) {
9345
+ if (!node || typeof node !== 'object') return false;
9346
+
9347
+ if (node.type === 'ImportDeclaration' ||
9348
+ node.type === 'ExportNamedDeclaration' ||
9349
+ node.type === 'ExportDefaultDeclaration' ||
9350
+ node.type === 'ExportAllDeclaration') {
9351
+ return true;
9352
+ }
9353
+
9354
+ // Check Program body for module declarations
9355
+ if (node.type === 'Program' && node.body) {
9356
+ for (const statement of node.body) {
9357
+ if (containsModuleDeclarations(statement)) return true;
9358
+ }
9359
+ }
9360
+
9361
+ return false;
9362
+ }
9363
+
9364
+ // Helper to detect if AST contains top-level await expressions
9365
+ function containsTopLevelAwait(node) {
9366
+ if (!node || typeof node !== 'object') return false;
9367
+
9368
+ if (node.type === 'AwaitExpression') return true;
9369
+
9370
+ // Don't recurse into function bodies (they handle their own await)
9371
+ if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
9372
+ return false;
9373
+ }
9374
+
9375
+ // Check all properties
9376
+ for (const key in node) {
9377
+ if (key === 'loc' || key === 'range') continue;
9378
+ const value = node[key];
9379
+ if (Array.isArray(value)) {
9380
+ for (const item of value) {
9381
+ if (containsTopLevelAwait(item)) return true;
9382
+ }
9383
+ } else if (typeof value === 'object') {
9384
+ if (containsTopLevelAwait(value)) return true;
9385
+ }
9386
+ }
9387
+
9388
+ return false;
9389
+ }
9390
+
9391
+ async function execute(code, env = null, options = {}) {
9392
+ // Parse the code
9393
+ const ast = parse(code, options);
9394
+
9395
+ // Create global environment if not provided
9396
+ if (!env) {
9397
+ env = createGlobalEnvironment(new Environment());
9398
+ }
9399
+
9400
+ // Create a child environment for user code to allow shadowing of built-ins
9401
+ // This prevents conflicts when user code declares variables with same names as stdlib functions
9402
+ const userEnv = env.extend();
9403
+
9404
+ // Create interpreter with module resolver and abort signal if provided
9405
+ const interpreter = new Interpreter(env, {
9406
+ moduleResolver: options.moduleResolver,
9407
+ abortSignal: options.abortSignal
9408
+ });
9409
+
9410
+ // Use async evaluation if:
9411
+ // 1. Explicitly requested module mode
9412
+ // 2. AST contains import/export declarations
9413
+ // 3. Code contains top-level await
9414
+ const needsAsync = options.sourceType === 'module' ||
9415
+ containsModuleDeclarations(ast) ||
9416
+ containsTopLevelAwait(ast);
9417
+
9418
+ if (needsAsync) {
9419
+ const result = await interpreter.evaluateAsync(ast, userEnv);
9420
+ return result instanceof ReturnValue ? result.value : result;
9421
+ } else {
9422
+ const result = interpreter.evaluate(ast, userEnv);
9423
+ return result instanceof ReturnValue ? result.value : result;
9424
+ }
9425
+ }
9426
+
9427
+ function createEnvironment() {
9428
+ return createGlobalEnvironment(new Environment());
6231
9429
  }
6232
9430
 
6233
- // Acorn is organized as a tokenizer and a recursive-descent parser.
6234
- // The `tokenizer` export provides an interface to the tokenizer.
9431
+ // Export utility functions for CLI tools
9432
+ const isTopLevelAwait = containsModuleSyntax;
6235
9433
 
6236
- function tokenizer(input, options) {
6237
- return Parser.tokenizer(input, options)
9434
+ /**
9435
+ * Abstract base class for module resolution
9436
+ * Extend this class to implement custom module loading strategies
9437
+ */
9438
+ class ModuleResolver {
9439
+ /**
9440
+ * Resolve a module and return its code
9441
+ * @param {string} modulePath - The module path to resolve
9442
+ * @param {string} [fromPath] - The path of the importing module
9443
+ * @returns {Promise<ModuleResolution>} The resolved module
9444
+ */
9445
+ async resolve(modulePath, fromPath) {
9446
+ throw new Error('ModuleResolver.resolve() must be implemented by subclass');
9447
+ }
9448
+
9449
+ /**
9450
+ * Check if a module exists
9451
+ * @param {string} modulePath - The module path to check
9452
+ * @param {string} [fromPath] - The path of the importing module
9453
+ * @returns {Promise<boolean>} Whether the module exists
9454
+ */
9455
+ async exists(modulePath, fromPath) {
9456
+ throw new Error('ModuleResolver.exists() must be implemented by subclass');
9457
+ }
9458
+
9459
+ /**
9460
+ * List available modules
9461
+ * @param {string} [prefix] - Optional prefix to filter modules
9462
+ * @returns {Promise<string[]>} List of module paths
9463
+ */
9464
+ async list(prefix) {
9465
+ throw new Error('ModuleResolver.list() must be implemented by subclass');
9466
+ }
6238
9467
  }
6239
9468
 
6240
- export { Node, Parser, Position, SourceLocation, TokContext, Token, TokenType, defaultOptions, getLineInfo, isIdentifierChar, isIdentifierStart, isNewLine, keywords as keywordTypes, lineBreak, lineBreakG, nonASCIIwhitespace, parse, parseExpressionAt, types as tokContexts, types$1 as tokTypes, tokenizer, version };
9469
+ /**
9470
+ * @typedef {Object} ModuleResolution
9471
+ * @property {string} code - The module source code
9472
+ * @property {string} path - The resolved module path
9473
+ * @property {any} [metadata] - Optional metadata about the module
9474
+ */
6241
9475
 
9476
+ export { Environment, InMemoryModuleResolver, Interpreter, ModuleResolver, WangInterpreter, createEnvironment, execute, isTopLevelAwait, parse };