starlight-cli 1.0.22 → 1.0.24
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 +114 -29
- package/package.json +1 -1
- package/src/evaluator.js +53 -19
- package/src/lexer.js +13 -1
- package/src/parser.js +47 -8
- package/src/starlight.js +1 -1
package/dist/index.js
CHANGED
|
@@ -1448,6 +1448,9 @@ this.global.define('str', arg => {
|
|
|
1448
1448
|
case 'ImportStatement': return this.evalImport(node, env);
|
|
1449
1449
|
case 'FunctionDeclaration': return this.evalFunctionDeclaration(node, env);
|
|
1450
1450
|
case 'CallExpression': return this.evalCall(node, env);
|
|
1451
|
+
case 'ArrowFunctionExpression':
|
|
1452
|
+
return this.evalArrowFunction(node, env);
|
|
1453
|
+
|
|
1451
1454
|
case 'ReturnStatement': {
|
|
1452
1455
|
const val = node.argument ? this.evaluate(node.argument, env) : null;
|
|
1453
1456
|
throw new ReturnValue(val);
|
|
@@ -1538,6 +1541,14 @@ evalImport(node, env) {
|
|
|
1538
1541
|
const val = this.evaluate(node.expr, env);
|
|
1539
1542
|
return env.define(node.id, val);
|
|
1540
1543
|
}
|
|
1544
|
+
evalArrowFunction(node, env) {
|
|
1545
|
+
return {
|
|
1546
|
+
params: node.params,
|
|
1547
|
+
body: node.body,
|
|
1548
|
+
env: env,
|
|
1549
|
+
arrow: true
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1541
1552
|
|
|
1542
1553
|
evalAssignment(node, env) {
|
|
1543
1554
|
const rightVal = this.evaluate(node.right, env);
|
|
@@ -1606,21 +1617,27 @@ evalImport(node, env) {
|
|
|
1606
1617
|
evalBinary(node, env) {
|
|
1607
1618
|
const l = this.evaluate(node.left, env);
|
|
1608
1619
|
const r = this.evaluate(node.right, env);
|
|
1620
|
+
|
|
1621
|
+
if (node.operator === 'SLASH' && r === 0) {
|
|
1622
|
+
throw new Error('Division by zero');
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1609
1625
|
switch (node.operator) {
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1626
|
+
case 'PLUS': return l + r;
|
|
1627
|
+
case 'MINUS': return l - r;
|
|
1628
|
+
case 'STAR': return l * r;
|
|
1629
|
+
case 'SLASH': return l / r;
|
|
1630
|
+
case 'MOD': return l % r;
|
|
1631
|
+
case 'EQEQ': return l === r;
|
|
1632
|
+
case 'NOTEQ': return l !== r;
|
|
1633
|
+
case 'LT': return l < r;
|
|
1634
|
+
case 'LTE': return l <= r;
|
|
1635
|
+
case 'GT': return l > r;
|
|
1636
|
+
case 'GTE': return l >= r;
|
|
1637
|
+
default: throw new Error(`Unknown binary operator ${node.operator}`);
|
|
1622
1638
|
}
|
|
1623
|
-
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1624
1641
|
|
|
1625
1642
|
evalLogical(node, env) {
|
|
1626
1643
|
const l = this.evaluate(node.left, env);
|
|
@@ -1694,16 +1711,31 @@ evalImport(node, env) {
|
|
|
1694
1711
|
const argVal = node.arguments[i] ? this.evaluate(node.arguments[i], env) : null;
|
|
1695
1712
|
callEnv.define(p, argVal);
|
|
1696
1713
|
});
|
|
1697
|
-
try {
|
|
1698
|
-
|
|
1714
|
+
try {
|
|
1715
|
+
const result = this.evaluate(fn.body, callEnv);
|
|
1716
|
+
return fn.arrow ? result : result;
|
|
1717
|
+
} catch (e) {
|
|
1718
|
+
if (e instanceof ReturnValue) return e.value;
|
|
1719
|
+
throw e;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1699
1722
|
}
|
|
1700
1723
|
|
|
1701
1724
|
evalIndex(node, env) {
|
|
1702
1725
|
const obj = this.evaluate(node.object, env);
|
|
1703
1726
|
const idx = this.evaluate(node.indexer, env);
|
|
1704
|
-
|
|
1727
|
+
|
|
1728
|
+
if (obj == null) throw new Error('Indexing null or undefined');
|
|
1729
|
+
if (Array.isArray(obj) && (idx < 0 || idx >= obj.length)) {
|
|
1730
|
+
throw new Error('Array index out of bounds');
|
|
1731
|
+
}
|
|
1732
|
+
if (typeof obj === 'object' && !(idx in obj)) {
|
|
1733
|
+
throw new Error(`Property '${idx}' does not exist`);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1705
1736
|
return obj[idx];
|
|
1706
|
-
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1707
1739
|
|
|
1708
1740
|
evalObject(node, env) {
|
|
1709
1741
|
const out = {};
|
|
@@ -1713,9 +1745,11 @@ evalImport(node, env) {
|
|
|
1713
1745
|
|
|
1714
1746
|
evalMember(node, env) {
|
|
1715
1747
|
const obj = this.evaluate(node.object, env);
|
|
1716
|
-
if (obj == null) throw new Error('Member access of null
|
|
1748
|
+
if (obj == null) throw new Error('Member access of null or undefined');
|
|
1749
|
+
if (!(node.property in obj)) throw new Error(`Property '${node.property}' does not exist`);
|
|
1717
1750
|
return obj[node.property];
|
|
1718
|
-
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1719
1753
|
|
|
1720
1754
|
evalUpdate(node, env) {
|
|
1721
1755
|
const arg = node.argument;
|
|
@@ -1892,7 +1926,19 @@ class Lexer {
|
|
|
1892
1926
|
const startCol = this.column;
|
|
1893
1927
|
|
|
1894
1928
|
if (char === '=' && next === '=') { tokens.push({ type: 'EQEQ', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
|
1895
|
-
|
|
1929
|
+
|
|
1930
|
+
if (char === '=' && next === '>') {
|
|
1931
|
+
tokens.push({ type: 'ARROW', line: startLine, column: startCol });
|
|
1932
|
+
this.advance(); this.advance();
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
if (char === '-' && next === '>') {
|
|
1937
|
+
tokens.push({ type: 'ARROW', line: startLine, column: startCol });
|
|
1938
|
+
this.advance(); this.advance();
|
|
1939
|
+
continue;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1896
1942
|
if (char === '!' && next === '=') { tokens.push({ type: 'NOTEQ', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
|
1897
1943
|
if (char === '<' && next === '=') { tokens.push({ type: 'LTE', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
|
1898
1944
|
if (char === '>' && next === '=') { tokens.push({ type: 'GTE', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
|
@@ -2300,6 +2346,15 @@ class Parser {
|
|
|
2300
2346
|
}
|
|
2301
2347
|
return node;
|
|
2302
2348
|
}
|
|
2349
|
+
arrowFunction(params) {
|
|
2350
|
+
this.eat('ARROW');
|
|
2351
|
+
const body = this.expression();
|
|
2352
|
+
return {
|
|
2353
|
+
type: 'ArrowFunctionExpression',
|
|
2354
|
+
params,
|
|
2355
|
+
body
|
|
2356
|
+
};
|
|
2357
|
+
}
|
|
2303
2358
|
|
|
2304
2359
|
primary() {
|
|
2305
2360
|
const t = this.current;
|
|
@@ -2326,17 +2381,47 @@ class Parser {
|
|
|
2326
2381
|
}
|
|
2327
2382
|
|
|
2328
2383
|
if (t.type === 'IDENTIFIER') {
|
|
2329
|
-
|
|
2384
|
+
const name = t.value;
|
|
2385
|
+
this.eat('IDENTIFIER');
|
|
2386
|
+
|
|
2387
|
+
if (this.current.type === 'ARROW') {
|
|
2388
|
+
return this.arrowFunction([name]);
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
return { type: 'Identifier', name };
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
|
|
2395
|
+
if (t.type === 'LPAREN') {
|
|
2396
|
+
this.eat('LPAREN');
|
|
2397
|
+
|
|
2398
|
+
const params = [];
|
|
2399
|
+
|
|
2400
|
+
if (this.current.type !== 'RPAREN') {
|
|
2401
|
+
params.push(this.current.value);
|
|
2402
|
+
this.eat('IDENTIFIER');
|
|
2403
|
+
while (this.current.type === 'COMMA') {
|
|
2404
|
+
this.eat('COMMA');
|
|
2405
|
+
params.push(this.current.value);
|
|
2330
2406
|
this.eat('IDENTIFIER');
|
|
2331
|
-
return { type: 'Identifier', name };
|
|
2332
2407
|
}
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
this.eat('RPAREN');
|
|
2411
|
+
|
|
2412
|
+
if (this.current.type === 'ARROW') {
|
|
2413
|
+
return this.arrowFunction(params);
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
if (params.length === 1) {
|
|
2417
|
+
return { type: 'Identifier', name: params[0] };
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
throw new Error(
|
|
2421
|
+
`Invalid grouped expression at line ${this.current.line}, column ${this.current.column}`
|
|
2422
|
+
);
|
|
2423
|
+
}
|
|
2333
2424
|
|
|
2334
|
-
if (t.type === 'LPAREN') {
|
|
2335
|
-
this.eat('LPAREN');
|
|
2336
|
-
const expr = this.expression();
|
|
2337
|
-
this.eat('RPAREN');
|
|
2338
|
-
return expr;
|
|
2339
|
-
}
|
|
2340
2425
|
|
|
2341
2426
|
if (t.type === 'LBRACKET') {
|
|
2342
2427
|
this.eat('LBRACKET');
|
|
@@ -2475,7 +2560,7 @@ const Lexer = __nccwpck_require__(211);
|
|
|
2475
2560
|
const Parser = __nccwpck_require__(222);
|
|
2476
2561
|
const Evaluator = __nccwpck_require__(112);
|
|
2477
2562
|
|
|
2478
|
-
const VERSION = '1.0.
|
|
2563
|
+
const VERSION = '1.0.24';
|
|
2479
2564
|
|
|
2480
2565
|
const COLOR = {
|
|
2481
2566
|
reset: '\x1b[0m',
|
package/package.json
CHANGED
package/src/evaluator.js
CHANGED
|
@@ -105,6 +105,9 @@ this.global.define('str', arg => {
|
|
|
105
105
|
case 'ImportStatement': return this.evalImport(node, env);
|
|
106
106
|
case 'FunctionDeclaration': return this.evalFunctionDeclaration(node, env);
|
|
107
107
|
case 'CallExpression': return this.evalCall(node, env);
|
|
108
|
+
case 'ArrowFunctionExpression':
|
|
109
|
+
return this.evalArrowFunction(node, env);
|
|
110
|
+
|
|
108
111
|
case 'ReturnStatement': {
|
|
109
112
|
const val = node.argument ? this.evaluate(node.argument, env) : null;
|
|
110
113
|
throw new ReturnValue(val);
|
|
@@ -195,6 +198,14 @@ evalImport(node, env) {
|
|
|
195
198
|
const val = this.evaluate(node.expr, env);
|
|
196
199
|
return env.define(node.id, val);
|
|
197
200
|
}
|
|
201
|
+
evalArrowFunction(node, env) {
|
|
202
|
+
return {
|
|
203
|
+
params: node.params,
|
|
204
|
+
body: node.body,
|
|
205
|
+
env: env,
|
|
206
|
+
arrow: true
|
|
207
|
+
};
|
|
208
|
+
}
|
|
198
209
|
|
|
199
210
|
evalAssignment(node, env) {
|
|
200
211
|
const rightVal = this.evaluate(node.right, env);
|
|
@@ -263,21 +274,27 @@ evalImport(node, env) {
|
|
|
263
274
|
evalBinary(node, env) {
|
|
264
275
|
const l = this.evaluate(node.left, env);
|
|
265
276
|
const r = this.evaluate(node.right, env);
|
|
277
|
+
|
|
278
|
+
if (node.operator === 'SLASH' && r === 0) {
|
|
279
|
+
throw new Error('Division by zero');
|
|
280
|
+
}
|
|
281
|
+
|
|
266
282
|
switch (node.operator) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
283
|
+
case 'PLUS': return l + r;
|
|
284
|
+
case 'MINUS': return l - r;
|
|
285
|
+
case 'STAR': return l * r;
|
|
286
|
+
case 'SLASH': return l / r;
|
|
287
|
+
case 'MOD': return l % r;
|
|
288
|
+
case 'EQEQ': return l === r;
|
|
289
|
+
case 'NOTEQ': return l !== r;
|
|
290
|
+
case 'LT': return l < r;
|
|
291
|
+
case 'LTE': return l <= r;
|
|
292
|
+
case 'GT': return l > r;
|
|
293
|
+
case 'GTE': return l >= r;
|
|
294
|
+
default: throw new Error(`Unknown binary operator ${node.operator}`);
|
|
279
295
|
}
|
|
280
|
-
|
|
296
|
+
}
|
|
297
|
+
|
|
281
298
|
|
|
282
299
|
evalLogical(node, env) {
|
|
283
300
|
const l = this.evaluate(node.left, env);
|
|
@@ -351,16 +368,31 @@ evalImport(node, env) {
|
|
|
351
368
|
const argVal = node.arguments[i] ? this.evaluate(node.arguments[i], env) : null;
|
|
352
369
|
callEnv.define(p, argVal);
|
|
353
370
|
});
|
|
354
|
-
try {
|
|
355
|
-
|
|
371
|
+
try {
|
|
372
|
+
const result = this.evaluate(fn.body, callEnv);
|
|
373
|
+
return fn.arrow ? result : result;
|
|
374
|
+
} catch (e) {
|
|
375
|
+
if (e instanceof ReturnValue) return e.value;
|
|
376
|
+
throw e;
|
|
377
|
+
}
|
|
378
|
+
|
|
356
379
|
}
|
|
357
380
|
|
|
358
381
|
evalIndex(node, env) {
|
|
359
382
|
const obj = this.evaluate(node.object, env);
|
|
360
383
|
const idx = this.evaluate(node.indexer, env);
|
|
361
|
-
|
|
384
|
+
|
|
385
|
+
if (obj == null) throw new Error('Indexing null or undefined');
|
|
386
|
+
if (Array.isArray(obj) && (idx < 0 || idx >= obj.length)) {
|
|
387
|
+
throw new Error('Array index out of bounds');
|
|
388
|
+
}
|
|
389
|
+
if (typeof obj === 'object' && !(idx in obj)) {
|
|
390
|
+
throw new Error(`Property '${idx}' does not exist`);
|
|
391
|
+
}
|
|
392
|
+
|
|
362
393
|
return obj[idx];
|
|
363
|
-
|
|
394
|
+
}
|
|
395
|
+
|
|
364
396
|
|
|
365
397
|
evalObject(node, env) {
|
|
366
398
|
const out = {};
|
|
@@ -370,9 +402,11 @@ evalImport(node, env) {
|
|
|
370
402
|
|
|
371
403
|
evalMember(node, env) {
|
|
372
404
|
const obj = this.evaluate(node.object, env);
|
|
373
|
-
if (obj == null) throw new Error('Member access of null
|
|
405
|
+
if (obj == null) throw new Error('Member access of null or undefined');
|
|
406
|
+
if (!(node.property in obj)) throw new Error(`Property '${node.property}' does not exist`);
|
|
374
407
|
return obj[node.property];
|
|
375
|
-
|
|
408
|
+
}
|
|
409
|
+
|
|
376
410
|
|
|
377
411
|
evalUpdate(node, env) {
|
|
378
412
|
const arg = node.argument;
|
package/src/lexer.js
CHANGED
|
@@ -139,7 +139,19 @@ class Lexer {
|
|
|
139
139
|
const startCol = this.column;
|
|
140
140
|
|
|
141
141
|
if (char === '=' && next === '=') { tokens.push({ type: 'EQEQ', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
|
142
|
-
|
|
142
|
+
|
|
143
|
+
if (char === '=' && next === '>') {
|
|
144
|
+
tokens.push({ type: 'ARROW', line: startLine, column: startCol });
|
|
145
|
+
this.advance(); this.advance();
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (char === '-' && next === '>') {
|
|
150
|
+
tokens.push({ type: 'ARROW', line: startLine, column: startCol });
|
|
151
|
+
this.advance(); this.advance();
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
143
155
|
if (char === '!' && next === '=') { tokens.push({ type: 'NOTEQ', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
|
144
156
|
if (char === '<' && next === '=') { tokens.push({ type: 'LTE', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
|
145
157
|
if (char === '>' && next === '=') { tokens.push({ type: 'GTE', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
|
package/src/parser.js
CHANGED
|
@@ -368,6 +368,15 @@ class Parser {
|
|
|
368
368
|
}
|
|
369
369
|
return node;
|
|
370
370
|
}
|
|
371
|
+
arrowFunction(params) {
|
|
372
|
+
this.eat('ARROW');
|
|
373
|
+
const body = this.expression();
|
|
374
|
+
return {
|
|
375
|
+
type: 'ArrowFunctionExpression',
|
|
376
|
+
params,
|
|
377
|
+
body
|
|
378
|
+
};
|
|
379
|
+
}
|
|
371
380
|
|
|
372
381
|
primary() {
|
|
373
382
|
const t = this.current;
|
|
@@ -394,17 +403,47 @@ class Parser {
|
|
|
394
403
|
}
|
|
395
404
|
|
|
396
405
|
if (t.type === 'IDENTIFIER') {
|
|
397
|
-
|
|
406
|
+
const name = t.value;
|
|
407
|
+
this.eat('IDENTIFIER');
|
|
408
|
+
|
|
409
|
+
if (this.current.type === 'ARROW') {
|
|
410
|
+
return this.arrowFunction([name]);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return { type: 'Identifier', name };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
if (t.type === 'LPAREN') {
|
|
418
|
+
this.eat('LPAREN');
|
|
419
|
+
|
|
420
|
+
const params = [];
|
|
421
|
+
|
|
422
|
+
if (this.current.type !== 'RPAREN') {
|
|
423
|
+
params.push(this.current.value);
|
|
424
|
+
this.eat('IDENTIFIER');
|
|
425
|
+
while (this.current.type === 'COMMA') {
|
|
426
|
+
this.eat('COMMA');
|
|
427
|
+
params.push(this.current.value);
|
|
398
428
|
this.eat('IDENTIFIER');
|
|
399
|
-
return { type: 'Identifier', name };
|
|
400
429
|
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
this.eat('RPAREN');
|
|
433
|
+
|
|
434
|
+
if (this.current.type === 'ARROW') {
|
|
435
|
+
return this.arrowFunction(params);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (params.length === 1) {
|
|
439
|
+
return { type: 'Identifier', name: params[0] };
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
throw new Error(
|
|
443
|
+
`Invalid grouped expression at line ${this.current.line}, column ${this.current.column}`
|
|
444
|
+
);
|
|
445
|
+
}
|
|
401
446
|
|
|
402
|
-
if (t.type === 'LPAREN') {
|
|
403
|
-
this.eat('LPAREN');
|
|
404
|
-
const expr = this.expression();
|
|
405
|
-
this.eat('RPAREN');
|
|
406
|
-
return expr;
|
|
407
|
-
}
|
|
408
447
|
|
|
409
448
|
if (t.type === 'LBRACKET') {
|
|
410
449
|
this.eat('LBRACKET');
|