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/README.md +46 -0
- package/dist/index.js +265 -112
- package/package.json +3 -2
- package/src/evaluator.js +131 -79
- package/src/lexer.js +1 -1
- package/src/parser.js +57 -31
- package/src/starlight.js +1 -1
- package/src/program.sl +0 -2
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) {
|
|
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
|
-
|
|
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
|
-
|
|
1466
|
-
if (value ===
|
|
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
|
-
|
|
1472
|
-
if (t === 'string') return value;
|
|
1467
|
+
if (t === 'string') return color.cyan(value);
|
|
1473
1468
|
|
|
1474
|
-
|
|
1475
|
-
if (t === 'number') return String(value);
|
|
1469
|
+
if (t === 'number') return color.green(String(value));
|
|
1476
1470
|
|
|
1477
|
-
|
|
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
|
-
|
|
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}:
|
|
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
|
-
|
|
1508
|
-
|
|
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;
|
|
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);
|
|
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
|
-
|
|
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')
|
|
1882
|
-
|
|
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; //
|
|
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('
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
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'
|
|
2142
|
-
|
|
2191
|
+
if (typeof obj === 'object') {
|
|
2192
|
+
return obj[idx]; // undefined if missing
|
|
2143
2193
|
}
|
|
2144
2194
|
|
|
2145
|
-
return
|
|
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
|
-
|
|
2165
|
-
if (
|
|
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;
|
|
2563
|
+
const t = this.current;
|
|
2511
2564
|
this.eat('LET');
|
|
2512
|
-
const idToken = this.current;
|
|
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;
|
|
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;
|
|
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;
|
|
2661
|
+
const t = this.current;
|
|
2570
2662
|
this.eat('DEFINE');
|
|
2571
|
-
const idToken = this.current;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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');
|
|
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();
|
|
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');
|
|
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.
|
|
3515
|
+
const VERSION = '1.1.3';
|
|
3363
3516
|
|
|
3364
3517
|
const COLOR = {
|
|
3365
3518
|
reset: '\x1b[0m',
|