starlight-cli 1.1.1 → 1.1.3

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.
package/dist/index.js CHANGED
@@ -1392,7 +1392,6 @@ class Environment {
1392
1392
  if (name in this.store) return this.store[name];
1393
1393
  if (this.parent) return this.parent.get(name, node, source);
1394
1394
 
1395
- // Only suggest for top-level variable/function names
1396
1395
  let suggestion = null;
1397
1396
  if (node && source) {
1398
1397
  suggestion = this.suggest?.(name, this) || null;
@@ -1427,7 +1426,6 @@ class Evaluator {
1427
1426
  this.setupBuiltins();
1428
1427
  }
1429
1428
  suggest(name, env) {
1430
- // Collect all variable/function names from the environment chain
1431
1429
  const names = new Set();
1432
1430
  let current = env;
1433
1431
  while (current) {
@@ -1441,11 +1439,10 @@ suggest(name, env) {
1441
1439
  let bestScore = Infinity;
1442
1440
 
1443
1441
  for (const item of names) {
1444
- // simple edit distance approximation
1445
1442
  const dist = Math.abs(item.length - name.length) +
1446
1443
  [...name].filter((c, i) => c !== item[i]).length;
1447
1444
 
1448
- if (dist < bestScore && dist <= 2) { // max distance 2
1445
+ if (dist < bestScore && dist <= 2) {
1449
1446
  bestScore = dist;
1450
1447
  best = item;
1451
1448
  }
@@ -1454,58 +1451,50 @@ suggest(name, env) {
1454
1451
  return best;
1455
1452
  }
1456
1453
 
1457
-
1458
1454
  formatValue(value, seen = new Set()) {
1459
- // Circular reference handling
1455
+ const color = __nccwpck_require__(55);
1456
+
1460
1457
  if (typeof value === 'object' && value !== null) {
1461
- if (seen.has(value)) return '[Circular]';
1458
+ if (seen.has(value)) return color.red('[Circular]');
1462
1459
  seen.add(value);
1463
1460
  }
1464
1461
 
1465
- // Python-style null / undefined
1466
- if (value === null) return 'None';
1467
- if (value === undefined) return 'undefined';
1462
+ if (value === null) return color.yellow('None');
1463
+ if (value === undefined) return color.yellow('undefined');
1468
1464
 
1469
1465
  const t = typeof value;
1470
1466
 
1471
- // Strings (no quotes)
1472
- if (t === 'string') return value;
1467
+ if (t === 'string') return color.cyan(value);
1473
1468
 
1474
- // Numbers
1475
- if (t === 'number') return String(value);
1469
+ if (t === 'number') return color.green(String(value));
1476
1470
 
1477
- // Booleans (Python-style)
1478
- if (t === 'boolean') return value ? 'True' : 'False';
1471
+ if (t === 'boolean') return color.yellow(value ? 'true' : 'false');
1479
1472
 
1480
- // Native JS functions
1481
1473
  if (t === 'function') {
1482
- return value.name
1483
- ? `<function ${value.name}>`
1484
- : '<function>';
1474
+ return color.magenta(value.name ? `<function ${value.name}>` : '<function>');
1485
1475
  }
1486
1476
 
1487
- // Arrays
1488
1477
  if (Array.isArray(value)) {
1489
- return '[' + value.map(v => this.formatValue(v, seen)).join(', ') + ']';
1478
+ const items = value.map(v => this.formatValue(v, seen));
1479
+ return color.white('[ ' + items.join(', ') + ' ]');
1490
1480
  }
1491
1481
 
1492
- // Objects (including user-defined functions)
1493
1482
  if (t === 'object') {
1494
- // Detect user-defined functions (AST-based)
1495
1483
  if (value.params && value.body) {
1496
- return value.name
1497
- ? `<function ${value.name}>`
1498
- : '<function>';
1484
+ return color.magenta(value.name ? `<function ${value.name}>` : '<function>');
1499
1485
  }
1500
1486
 
1501
1487
  const entries = Object.entries(value).map(
1502
- ([k, v]) => `${k}: ${this.formatValue(v, seen)}`
1488
+ ([k, v]) => color.magenta(`${k}: `) + this.formatValue(v, seen)
1503
1489
  );
1504
- return '{ ' + entries.join(', ') + ' }';
1490
+ return color.magenta('{ ') + entries.join(color.magenta(', ')) + color.magenta(' }');
1505
1491
  }
1506
1492
 
1507
- // Fallback
1508
- return String(value);
1493
+ try {
1494
+ return String(value);
1495
+ } catch {
1496
+ return color.red('[Unprintable]');
1497
+ }
1509
1498
  }
1510
1499
 
1511
1500
 
@@ -1580,7 +1569,6 @@ this.global.define('fetch', async (url, options = {}) => {
1580
1569
  };
1581
1570
  });
1582
1571
 
1583
- // GET request
1584
1572
  this.global.define('get', async (url) => {
1585
1573
  const res = await fetch(url);
1586
1574
  return await res.json();
@@ -1627,6 +1615,11 @@ case 'ForInStatement':
1627
1615
  return await this.evalFor(node, env);
1628
1616
  case 'DoTrackStatement':
1629
1617
  return await this.evalDoTrack(node, env);
1618
+ case 'StartStatement':
1619
+ return await this.evalStartStatement(node, env);
1620
+
1621
+ case 'RaceClause':
1622
+ return await this.evalRaceClause(node, env);
1630
1623
 
1631
1624
  case 'BreakStatement': throw new BreakSignal();
1632
1625
  case 'ContinueStatement': throw new ContinueSignal();
@@ -1655,14 +1648,14 @@ case 'DoTrackStatement':
1655
1648
  const callee = await this.evaluate(node.callee, env);
1656
1649
 
1657
1650
  if (typeof callee === 'object' && callee.body) {
1658
- const evaluator = this; // <- capture the current evaluator
1651
+ const evaluator = this;
1659
1652
  const Constructor = function(...args) {
1660
1653
  const newEnv = new Environment(callee.env);
1661
1654
  newEnv.define('this', this);
1662
1655
  for (let i = 0; i < callee.params.length; i++) {
1663
1656
  newEnv.define(callee.params[i], args[i]);
1664
1657
  }
1665
- return evaluator.evaluate(callee.body, newEnv); // use captured evaluator
1658
+ return evaluator.evaluate(callee.body, newEnv);
1666
1659
  };
1667
1660
 
1668
1661
  const args = [];
@@ -1700,13 +1693,78 @@ async evalProgram(node, env) {
1700
1693
  return result;
1701
1694
  }
1702
1695
 
1696
+ async evalStartStatement(node, env) {
1697
+ try {
1698
+ const value = await this.evaluate(node.discriminant, env);
1699
+ let executing = false;
1700
+ for (const c of node.cases) {
1701
+ try {
1702
+ if (!executing) {
1703
+ const testValue = await this.evaluate(c.test, env);
1704
+ if (testValue === value) executing = true;
1705
+ }
1706
+
1707
+ if (executing) {
1708
+ await this.evaluate(c.consequent, new Environment(env));
1709
+ }
1710
+ } catch (caseErr) {
1711
+ if (caseErr instanceof BreakSignal) break;
1712
+ if (caseErr instanceof RuntimeError ||
1713
+ caseErr instanceof ReturnValue ||
1714
+ caseErr instanceof ContinueSignal) {
1715
+ throw caseErr; // propagate signals
1716
+ }
1717
+
1718
+ throw new RuntimeError(
1719
+ caseErr.message || 'Error evaluating case in start statement',
1720
+ c,
1721
+ this.source
1722
+ );
1723
+ }
1724
+ }
1725
+
1726
+ return null;
1727
+ } catch (err) {
1728
+ if (err instanceof RuntimeError ||
1729
+ err instanceof ReturnValue ||
1730
+ err instanceof BreakSignal ||
1731
+ err instanceof ContinueSignal) {
1732
+ throw err;
1733
+ }
1734
+ throw new RuntimeError(
1735
+ err.message || 'Error evaluating start statement',
1736
+ node,
1737
+ this.source
1738
+ );
1739
+ }
1740
+ }
1741
+
1742
+
1743
+ async evalRaceClause(node, env) {
1744
+ try {
1745
+ const testValue = await this.evaluate(node.test, env);
1746
+ const result = await this.evaluate(node.consequent, new Environment(env));
1747
+ return { testValue, result };
1748
+ } catch (err) {
1749
+ if (err instanceof RuntimeError ||
1750
+ err instanceof ReturnValue ||
1751
+ err instanceof BreakSignal ||
1752
+ err instanceof ContinueSignal) {
1753
+ throw err;
1754
+ }
1755
+ throw new RuntimeError(
1756
+ err.message || 'Error evaluating race clause',
1757
+ node,
1758
+ this.source
1759
+ );
1760
+ }
1761
+ }
1703
1762
 
1704
1763
  async evalDoTrack(node, env) {
1705
1764
  try {
1706
1765
  return await this.evaluate(node.body, env);
1707
1766
  } catch (err) {
1708
1767
  if (!node.handler) {
1709
- // Wrap any raw error into RuntimeError with line info
1710
1768
  if (err instanceof RuntimeError) throw err;
1711
1769
  throw new RuntimeError(err.message || 'Error in doTrack body', node.body, this.source);
1712
1770
  }
@@ -1717,7 +1775,6 @@ async evalDoTrack(node, env) {
1717
1775
  try {
1718
1776
  return await this.evaluate(node.handler, trackEnv);
1719
1777
  } catch (handlerErr) {
1720
- // Wrap handler errors as well
1721
1778
  if (handlerErr instanceof RuntimeError) throw handlerErr;
1722
1779
  throw new RuntimeError(handlerErr.message || 'Error in doTrack handler', node.handler, this.source);
1723
1780
  }
@@ -1836,23 +1893,23 @@ async evalAssignment(node, env) {
1836
1893
  const left = node.left;
1837
1894
 
1838
1895
  if (left.type === 'Identifier') return env.set(left.name, rightVal);
1839
- if (left.type === 'MemberExpression') {
1840
- const obj = await this.evaluate(left.object, env);
1841
- if (obj == null) throw new RuntimeError('Cannot assign to null or undefined', node, this.source);
1842
- obj[left.property] = rightVal;
1843
- return rightVal;
1844
- }
1845
- if (left.type === 'IndexExpression') {
1846
- const obj = await this.evaluate(left.object, env);
1847
- const idx = await this.evaluate(left.indexer, env);
1848
- if (obj == null) throw new RuntimeError('Cannot assign to null or undefined', node, this.source);
1849
- obj[idx] = rightVal;
1850
- return rightVal;
1851
- }
1852
1896
 
1897
+ if (left.type === 'MemberExpression') {
1898
+ const obj = await this.evaluate(left.object, env);
1899
+ if (obj == null) throw new RuntimeError('Cannot assign to null or undefined', node, this.source);
1900
+ obj[left.property] = rightVal; // dynamic creation of new properties allowed
1901
+ return rightVal;
1902
+ }
1853
1903
 
1854
- throw new RuntimeError('Invalid assignment target', node, this.source);
1904
+ if (left.type === 'IndexExpression') {
1905
+ const obj = await this.evaluate(left.object, env);
1906
+ const idx = await this.evaluate(left.indexer, env);
1907
+ if (obj == null) throw new RuntimeError('Cannot assign to null or undefined', node, this.source);
1908
+ obj[idx] = rightVal; // dynamic creation allowed
1909
+ return rightVal;
1910
+ }
1855
1911
 
1912
+ throw new RuntimeError('Invalid assignment target', node, this.source);
1856
1913
  }
1857
1914
 
1858
1915
  async evalCompoundAssignment(node, env) {
@@ -1860,13 +1917,13 @@ async evalCompoundAssignment(node, env) {
1860
1917
  let current;
1861
1918
 
1862
1919
  if (left.type === 'Identifier') current = env.get(left.name, left, this.source);
1863
- else if (left.type === 'MemberExpression') current = await this.evalMember(left, env);
1864
- else if (left.type === 'IndexExpression') current = await this.evalIndex(left, env);
1920
+ else if (left.type === 'MemberExpression') current = await this.evalMember(left, env) ?? 0;
1921
+ else if (left.type === 'IndexExpression') current = await this.evalIndex(left, env) ?? 0;
1865
1922
  else throw new RuntimeError('Invalid compound assignment target', node, this.source);
1866
1923
 
1867
-
1868
1924
  const rhs = await this.evaluate(node.right, env);
1869
1925
  let computed;
1926
+
1870
1927
  switch (node.operator) {
1871
1928
  case 'PLUSEQ': computed = current + rhs; break;
1872
1929
  case 'MINUSEQ': computed = current - rhs; break;
@@ -1874,16 +1931,18 @@ async evalCompoundAssignment(node, env) {
1874
1931
  case 'SLASHEQ': computed = current / rhs; break;
1875
1932
  case 'MODEQ': computed = current % rhs; break;
1876
1933
  default: throw new RuntimeError(`Unknown compound operator: ${node.operator}`, node, this.source);
1877
-
1878
1934
  }
1879
1935
 
1880
1936
  if (left.type === 'Identifier') env.set(left.name, computed);
1881
- else if (left.type === 'MemberExpression') await this.evalAssignment({ left, right: { type: 'Literal', value: computed }, type: 'AssignmentExpression' }, env);
1882
- else await this.evalAssignment({ left, right: { type: 'Literal', value: computed }, type: 'AssignmentExpression' }, env);
1937
+ else if (left.type === 'MemberExpression')
1938
+ await this.evalAssignment({ left, right: { type: 'Literal', value: computed }, type: 'AssignmentExpression' }, env);
1939
+ else
1940
+ await this.evalAssignment({ left, right: { type: 'Literal', value: computed }, type: 'AssignmentExpression' }, env);
1883
1941
 
1884
1942
  return computed;
1885
1943
  }
1886
1944
 
1945
+
1887
1946
  async evalSldeploy(node, env) {
1888
1947
  const val = await this.evaluate(node.expr, env);
1889
1948
  console.log(this.formatValue(val));
@@ -1891,6 +1950,7 @@ async evalSldeploy(node, env) {
1891
1950
  }
1892
1951
 
1893
1952
 
1953
+
1894
1954
  async evalAsk(node, env) {
1895
1955
  const prompt = await this.evaluate(node.prompt, env);
1896
1956
 
@@ -1997,11 +2057,7 @@ async evalWhile(node, env) {
1997
2057
  }
1998
2058
  return null;
1999
2059
  }
2000
-
2001
2060
  async evalFor(node, env) {
2002
- // -------------------------------
2003
- // Python-style: for x in iterable (with optional 'let')
2004
- // -------------------------------
2005
2061
  if (node.type === 'ForInStatement') {
2006
2062
  const iterable = await this.evaluate(node.iterable, env);
2007
2063
 
@@ -2009,11 +2065,8 @@ async evalFor(node, env) {
2009
2065
  throw new RuntimeError('Cannot iterate over non-iterable', node, this.source);
2010
2066
  }
2011
2067
 
2012
- const loopVar = node.variable; // STRING from parser
2013
-
2068
+ const loopVar = node.variable; // string name of the loop variable
2014
2069
  const createLoopEnv = () => node.letKeyword ? new Environment(env) : env;
2015
-
2016
- // Arrays
2017
2070
  if (Array.isArray(iterable)) {
2018
2071
  for (const value of iterable) {
2019
2072
  const loopEnv = createLoopEnv();
@@ -2028,7 +2081,6 @@ async evalFor(node, env) {
2028
2081
  }
2029
2082
  }
2030
2083
  }
2031
- // Objects (keys)
2032
2084
  else {
2033
2085
  for (const key of Object.keys(iterable)) {
2034
2086
  const loopEnv = createLoopEnv();
@@ -2047,9 +2099,6 @@ async evalFor(node, env) {
2047
2099
  return null;
2048
2100
  }
2049
2101
 
2050
- // -------------------------------
2051
- // C-style for loop
2052
- // -------------------------------
2053
2102
  const local = new Environment(env);
2054
2103
 
2055
2104
  if (node.init) await this.evaluate(node.init, local);
@@ -2071,6 +2120,7 @@ async evalFor(node, env) {
2071
2120
 
2072
2121
  return null;
2073
2122
  }
2123
+
2074
2124
  evalFunctionDeclaration(node, env) {
2075
2125
  if (!node.name || typeof node.name !== 'string') {
2076
2126
  throw new RuntimeError('Function declaration requires a valid name', node, this.source);
@@ -2133,18 +2183,17 @@ async evalIndex(node, env) {
2133
2183
  const obj = await this.evaluate(node.object, env);
2134
2184
  const idx = await this.evaluate(node.indexer, env);
2135
2185
 
2136
- if (obj == null) throw new RuntimeError('Indexing null or undefined', node, this.source);
2137
-
2138
- if (Array.isArray(obj) && (idx < 0 || idx >= obj.length)) {
2139
- throw new RuntimeError('Array index out of bounds', node, this.source);
2186
+ if (obj == null) throw new RuntimeError('Cannot index null or undefined', node, this.source);
2187
+ if (Array.isArray(obj)) {
2188
+ if (idx < 0 || idx >= obj.length) return undefined;
2189
+ return obj[idx];
2140
2190
  }
2141
- if (typeof obj === 'object' && !(idx in obj)) {
2142
- throw new RuntimeError(`Property '${idx}' does not exist`, node, this.source);
2191
+ if (typeof obj === 'object') {
2192
+ return obj[idx]; // undefined if missing
2143
2193
  }
2144
2194
 
2145
- return obj[idx];
2195
+ return undefined;
2146
2196
  }
2147
-
2148
2197
  async evalObject(node, env) {
2149
2198
  const out = {};
2150
2199
  for (const p of node.props) {
@@ -2153,19 +2202,22 @@ async evalObject(node, env) {
2153
2202
  }
2154
2203
  const key = await this.evaluate(p.key, env);
2155
2204
  const value = await this.evaluate(p.value, env);
2156
- out[key] = value;
2205
+ out[key] = value; // dynamic property assignment
2157
2206
  }
2158
2207
  return out;
2159
2208
  }
2160
2209
 
2161
2210
 
2211
+
2162
2212
  async evalMember(node, env) {
2163
2213
  const obj = await this.evaluate(node.object, env);
2164
- if (obj == null) throw new RuntimeError('Member access of null or undefined', node, this.source);
2165
- if (!(node.property in obj)) throw new RuntimeError(`Property '${node.property}' does not exist`, node, this.source);
2214
+
2215
+ if (obj == null) throw new RuntimeError('Member access of null or undefined', node, this.source);
2216
+
2166
2217
  return obj[node.property];
2167
2218
  }
2168
2219
 
2220
+
2169
2221
  async evalUpdate(node, env) {
2170
2222
  const arg = node.argument;
2171
2223
  const getCurrent = async () => {
@@ -2233,7 +2285,7 @@ class Lexer {
2233
2285
  'break', 'continue', 'func', 'return',
2234
2286
  'true', 'false', 'null',
2235
2287
  'ask', 'define', 'import', 'from', 'as',
2236
- 'async', 'await', 'new', 'in', 'do', 'track'
2288
+ 'async', 'await', 'new', 'in', 'do', 'track', 'start', 'race'
2237
2289
  ];
2238
2290
  }
2239
2291
 
@@ -2496,6 +2548,7 @@ class Parser {
2496
2548
  case 'WHILE': return this.whileStatement();
2497
2549
  case 'FOR': return this.forStatement();
2498
2550
  case 'DO': return this.doTrackStatement();
2551
+ case 'START': return this.startStatement();
2499
2552
  case 'BREAK': return this.breakStatement();
2500
2553
  case 'CONTINUE': return this.continueStatement();
2501
2554
  case 'FUNC': return this.funcDeclaration();
@@ -2507,9 +2560,9 @@ class Parser {
2507
2560
  }
2508
2561
  }
2509
2562
  varDeclaration() {
2510
- const t = this.current; // LET token
2563
+ const t = this.current;
2511
2564
  this.eat('LET');
2512
- const idToken = this.current; // identifier token
2565
+ const idToken = this.current;
2513
2566
  const id = idToken.value;
2514
2567
  this.eat('IDENTIFIER');
2515
2568
 
@@ -2519,7 +2572,6 @@ varDeclaration() {
2519
2572
  expr = this.expression();
2520
2573
  }
2521
2574
 
2522
- // semicolon optional
2523
2575
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
2524
2576
 
2525
2577
  return {
@@ -2530,9 +2582,49 @@ varDeclaration() {
2530
2582
  column: t.column
2531
2583
  };
2532
2584
  }
2585
+ startStatement() {
2586
+ const t = this.current;
2587
+ this.eat('START');
2588
+
2589
+ const discriminant = this.expression();
2590
+
2591
+ this.eat('LBRACE');
2592
+
2593
+ const cases = [];
2594
+
2595
+ while (this.current.type === 'RACE') {
2596
+ cases.push(this.raceClause());
2597
+ }
2598
+
2599
+ this.eat('RBRACE');
2600
+
2601
+ return {
2602
+ type: 'StartStatement',
2603
+ discriminant,
2604
+ cases,
2605
+ line: t.line,
2606
+ column: t.column
2607
+ };
2608
+ }
2609
+ raceClause() {
2610
+ const t = this.current;
2611
+ this.eat('RACE');
2612
+
2613
+ const test = this.expression();
2614
+
2615
+ const consequent = this.block();
2616
+
2617
+ return {
2618
+ type: 'RaceClause',
2619
+ test,
2620
+ consequent,
2621
+ line: t.line,
2622
+ column: t.column
2623
+ };
2624
+ }
2533
2625
 
2534
2626
  sldeployStatement() {
2535
- const t = this.current; // SLDEPLOY token
2627
+ const t = this.current;
2536
2628
  this.eat('SLDEPLOY');
2537
2629
  const expr = this.expression();
2538
2630
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
@@ -2545,7 +2637,7 @@ sldeployStatement() {
2545
2637
  }
2546
2638
 
2547
2639
  doTrackStatement() {
2548
- const t = this.current; // DO token
2640
+ const t = this.current;
2549
2641
  this.eat('DO');
2550
2642
 
2551
2643
  const body = this.block();
@@ -2566,9 +2658,9 @@ doTrackStatement() {
2566
2658
  }
2567
2659
 
2568
2660
  defineStatement() {
2569
- const t = this.current; // DEFINE token
2661
+ const t = this.current;
2570
2662
  this.eat('DEFINE');
2571
- const idToken = this.current; // identifier token
2663
+ const idToken = this.current;
2572
2664
  const id = idToken.value;
2573
2665
  this.eat('IDENTIFIER');
2574
2666
 
@@ -2590,7 +2682,7 @@ defineStatement() {
2590
2682
  }
2591
2683
 
2592
2684
  asyncFuncDeclaration() {
2593
- const t = this.current; // first token of function (identifier)
2685
+ const t = this.current;
2594
2686
  const name = this.current.value;
2595
2687
  this.eat('IDENTIFIER');
2596
2688
 
@@ -2608,7 +2700,6 @@ asyncFuncDeclaration() {
2608
2700
  }
2609
2701
  this.eat('RPAREN');
2610
2702
  } else {
2611
- // no parentheses: single param as Python style
2612
2703
  if (this.current.type === 'IDENTIFIER') {
2613
2704
  params.push(this.current.value);
2614
2705
  this.eat('IDENTIFIER');
@@ -2628,7 +2719,7 @@ asyncFuncDeclaration() {
2628
2719
  }
2629
2720
 
2630
2721
  ifStatement() {
2631
- const t = this.current; // IF token
2722
+ const t = this.current;
2632
2723
  this.eat('IF');
2633
2724
 
2634
2725
  let test;
@@ -2637,7 +2728,6 @@ ifStatement() {
2637
2728
  test = this.expression();
2638
2729
  this.eat('RPAREN');
2639
2730
  } else {
2640
- // Python style: no parentheses
2641
2731
  test = this.expression();
2642
2732
  }
2643
2733
 
@@ -2661,7 +2751,7 @@ ifStatement() {
2661
2751
  }
2662
2752
 
2663
2753
  whileStatement() {
2664
- const t = this.current; // WHILE token
2754
+ const t = this.current;
2665
2755
  this.eat('WHILE');
2666
2756
 
2667
2757
  let test;
@@ -2684,7 +2774,7 @@ whileStatement() {
2684
2774
  }
2685
2775
 
2686
2776
  importStatement() {
2687
- const t = this.current; // IMPORT token
2777
+ const t = this.current;
2688
2778
  this.eat('IMPORT');
2689
2779
 
2690
2780
  let specifiers = [];
@@ -2743,7 +2833,6 @@ forStatement() {
2743
2833
  const t = this.current; // FOR token
2744
2834
  this.eat('FOR');
2745
2835
 
2746
- // --- Python-style: for variable in iterable (supports optional 'let') ---
2747
2836
  if ((this.current.type === 'LET' && this.peekType() === 'IDENTIFIER' && this.peekType(2) === 'IN') ||
2748
2837
  (this.current.type === 'IDENTIFIER' && this.peekType() === 'IN')) {
2749
2838
 
@@ -2784,7 +2873,6 @@ forStatement() {
2784
2873
  };
2785
2874
  }
2786
2875
 
2787
- // --- C-style: for(init; test; update) ---
2788
2876
  let init = null;
2789
2877
  let test = null;
2790
2878
  let update = null;
@@ -2792,22 +2880,18 @@ forStatement() {
2792
2880
  if (this.current.type === 'LPAREN') {
2793
2881
  this.eat('LPAREN');
2794
2882
 
2795
- // init
2796
2883
  if (this.current.type !== 'SEMICOLON') {
2797
2884
  init = this.current.type === 'LET' ? this.varDeclaration() : this.expressionStatement();
2798
2885
  } else {
2799
2886
  this.eat('SEMICOLON');
2800
2887
  }
2801
2888
 
2802
- // test
2803
2889
  if (this.current.type !== 'SEMICOLON') test = this.expression();
2804
2890
  this.eat('SEMICOLON');
2805
2891
 
2806
- // update
2807
2892
  if (this.current.type !== 'RPAREN') update = this.expression();
2808
2893
  this.eat('RPAREN');
2809
2894
  } else {
2810
- // fallback: single expression (rare, mostly handled above)
2811
2895
  init = this.expression();
2812
2896
  if (this.current.type === 'IN') {
2813
2897
  this.eat('IN');
@@ -2830,21 +2914,19 @@ forStatement() {
2830
2914
  breakStatement() {
2831
2915
  const t = this.current; // BREAK token
2832
2916
  this.eat('BREAK');
2833
- // Python-style: no semicolon needed, ignore if present
2834
2917
  if (this.current.type === 'SEMICOLON') this.advance();
2835
2918
  return { type: 'BreakStatement', line: t.line, column: t.column };
2836
2919
  }
2837
2920
 
2838
2921
  continueStatement() {
2839
- const t = this.current; // CONTINUE token
2922
+ const t = this.current;
2840
2923
  this.eat('CONTINUE');
2841
- // Python-style: no semicolon needed, ignore if present
2842
2924
  if (this.current.type === 'SEMICOLON') this.advance();
2843
2925
  return { type: 'ContinueStatement', line: t.line, column: t.column };
2844
2926
  }
2845
2927
 
2846
2928
  funcDeclaration() {
2847
- const t = this.current; // FUNC token
2929
+ const t = this.current;
2848
2930
  this.eat('FUNC');
2849
2931
  const nameToken = this.current;
2850
2932
  const name = nameToken.value;
@@ -2866,7 +2948,6 @@ funcDeclaration() {
2866
2948
  }
2867
2949
  this.eat('RPAREN');
2868
2950
  } else {
2869
- // Python-style: single param without parentheses
2870
2951
  if (this.current.type === 'IDENTIFIER') {
2871
2952
  const paramToken = this.current;
2872
2953
  params.push({ name: paramToken.value, line: paramToken.line, column: paramToken.column });
@@ -2887,7 +2968,6 @@ returnStatement() {
2887
2968
  argument = this.expression();
2888
2969
  }
2889
2970
 
2890
- // semicolon optional
2891
2971
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
2892
2972
 
2893
2973
  return { type: 'ReturnStatement', argument, line: t.line, column: t.column };
@@ -2905,9 +2985,8 @@ block() {
2905
2985
  }
2906
2986
 
2907
2987
  expressionStatement() {
2908
- const exprToken = this.current; // first token of the expression
2988
+ const exprToken = this.current;
2909
2989
  const expr = this.expression();
2910
- // semicolon optional
2911
2990
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
2912
2991
  return { type: 'ExpressionStatement', expression: expr, line: exprToken.line, column: exprToken.column };
2913
2992
  }
@@ -3020,7 +3099,6 @@ unary() {
3020
3099
  };
3021
3100
  }
3022
3101
 
3023
- // Python-like: ignore ++ and -- if not used
3024
3102
  if (t.type === 'PLUSPLUS' || t.type === 'MINUSMINUS') {
3025
3103
  const op = t.type;
3026
3104
  this.eat(op);
@@ -3060,7 +3138,7 @@ postfix() {
3060
3138
  const args = [];
3061
3139
  while (this.current.type !== 'RPAREN' && this.current.type !== 'EOF') {
3062
3140
  args.push(this.expression());
3063
- if (this.current.type === 'COMMA') this.eat('COMMA'); // optional comma
3141
+ if (this.current.type === 'COMMA') this.eat('COMMA');
3064
3142
  }
3065
3143
  if (this.current.type === 'RPAREN') this.eat('RPAREN');
3066
3144
  node = { type: 'CallExpression', callee: node, arguments: args, line: startLine, column: startCol };
@@ -3237,11 +3315,11 @@ arrowFunction(params) {
3237
3315
  this.eat('LBRACE');
3238
3316
  const props = [];
3239
3317
  while (this.current.type !== 'RBRACE') {
3240
- const key = this.expression(); // Flexible key: can be any expression
3318
+ const key = this.expression();
3241
3319
  this.eat('COLON');
3242
3320
  const value = this.expression();
3243
3321
  props.push({ key, value });
3244
- if (this.current.type === 'COMMA') this.eat('COMMA'); // optional trailing comma
3322
+ if (this.current.type === 'COMMA') this.eat('COMMA');
3245
3323
  }
3246
3324
  this.eat('RBRACE');
3247
3325
  return { type: 'ObjectExpression', props, line: startLine, column: startCol };
@@ -3307,6 +3385,53 @@ module.exports = require("path");
3307
3385
  "use strict";
3308
3386
  module.exports = require("readline");
3309
3387
 
3388
+ /***/ }),
3389
+
3390
+ /***/ 55:
3391
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => {
3392
+
3393
+ "use strict";
3394
+ __nccwpck_require__.r(__webpack_exports__);
3395
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
3396
+ /* harmony export */ blue: () => (/* binding */ blue),
3397
+ /* harmony export */ brightBlue: () => (/* binding */ brightBlue),
3398
+ /* harmony export */ brightCyan: () => (/* binding */ brightCyan),
3399
+ /* harmony export */ brightGreen: () => (/* binding */ brightGreen),
3400
+ /* harmony export */ brightMagenta: () => (/* binding */ brightMagenta),
3401
+ /* harmony export */ brightRed: () => (/* binding */ brightRed),
3402
+ /* harmony export */ brightWhite: () => (/* binding */ brightWhite),
3403
+ /* harmony export */ brightYellow: () => (/* binding */ brightYellow),
3404
+ /* harmony export */ cyan: () => (/* binding */ cyan),
3405
+ /* harmony export */ gray: () => (/* binding */ gray),
3406
+ /* harmony export */ green: () => (/* binding */ green),
3407
+ /* harmony export */ magenta: () => (/* binding */ magenta),
3408
+ /* harmony export */ red: () => (/* binding */ red),
3409
+ /* harmony export */ white: () => (/* binding */ white),
3410
+ /* harmony export */ yellow: () => (/* binding */ yellow)
3411
+ /* harmony export */ });
3412
+ const RESET = "\x1b[0m";
3413
+
3414
+ function wrap(code, text) {
3415
+ return code + String(text) + RESET;
3416
+ }
3417
+
3418
+ const red = text => wrap("\x1b[31m", text);
3419
+ const green = text => wrap("\x1b[32m", text);
3420
+ const yellow = text => wrap("\x1b[33m", text);
3421
+ const blue = text => wrap("\x1b[34m", text);
3422
+ const magenta = text => wrap("\x1b[35m", text);
3423
+ const cyan = text => wrap("\x1b[36m", text);
3424
+ const white = text => wrap("\x1b[37m", text);
3425
+ const gray = text => wrap("\x1b[90m", text);
3426
+ const brightRed = text => wrap("\x1b[91m", text);
3427
+ const brightGreen = text => wrap("\x1b[92m", text);
3428
+ const brightYellow = text => wrap("\x1b[93m", text);
3429
+ const brightBlue = text => wrap("\x1b[94m", text);
3430
+ const brightMagenta = text => wrap("\x1b[95m", text);
3431
+ const brightCyan = text => wrap("\x1b[96m", text);
3432
+ const brightWhite = text => wrap("\x1b[97m", text);
3433
+
3434
+
3310
3435
  /***/ })
3311
3436
 
3312
3437
  /******/ });
@@ -3342,6 +3467,34 @@ module.exports = require("readline");
3342
3467
  /******/ }
3343
3468
  /******/
3344
3469
  /************************************************************************/
3470
+ /******/ /* webpack/runtime/define property getters */
3471
+ /******/ (() => {
3472
+ /******/ // define getter functions for harmony exports
3473
+ /******/ __nccwpck_require__.d = (exports, definition) => {
3474
+ /******/ for(var key in definition) {
3475
+ /******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) {
3476
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
3477
+ /******/ }
3478
+ /******/ }
3479
+ /******/ };
3480
+ /******/ })();
3481
+ /******/
3482
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
3483
+ /******/ (() => {
3484
+ /******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
3485
+ /******/ })();
3486
+ /******/
3487
+ /******/ /* webpack/runtime/make namespace object */
3488
+ /******/ (() => {
3489
+ /******/ // define __esModule on exports
3490
+ /******/ __nccwpck_require__.r = (exports) => {
3491
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
3492
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3493
+ /******/ }
3494
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
3495
+ /******/ };
3496
+ /******/ })();
3497
+ /******/
3345
3498
  /******/ /* webpack/runtime/compat */
3346
3499
  /******/
3347
3500
  /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
@@ -3359,7 +3512,7 @@ const Lexer = __nccwpck_require__(211);
3359
3512
  const Parser = __nccwpck_require__(222);
3360
3513
  const Evaluator = __nccwpck_require__(112);
3361
3514
 
3362
- const VERSION = '1.1.1';
3515
+ const VERSION = '1.1.3';
3363
3516
 
3364
3517
  const COLOR = {
3365
3518
  reset: '\x1b[0m',