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 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
- case 'PLUS': return l + r;
1611
- case 'MINUS': return l - r;
1612
- case 'STAR': return l * r;
1613
- case 'SLASH': return l / r;
1614
- case 'MOD': return l % r;
1615
- case 'EQEQ': return l === r;
1616
- case 'NOTEQ': return l !== r;
1617
- case 'LT': return l < r;
1618
- case 'LTE': return l <= r;
1619
- case 'GT': return l > r;
1620
- case 'GTE': return l >= r;
1621
- default: throw new Error(`Unknown binary operator ${node.operator}`);
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 { return this.evaluate(fn.body, callEnv); }
1698
- catch (e) { if (e instanceof ReturnValue) return e.value; throw e; }
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
- if (obj == null) throw new Error('Indexing null/undefined');
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/undefined');
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
- if (char === '=' && next === '>') { tokens.push({ type: 'ARROW', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
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
- const name = t.value;
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.22';
2563
+ const VERSION = '1.0.24';
2479
2564
 
2480
2565
  const COLOR = {
2481
2566
  reset: '\x1b[0m',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starlight-cli",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "Starlight Programming Language CLI",
5
5
  "bin": {
6
6
  "starlight": "index.js"
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
- case 'PLUS': return l + r;
268
- case 'MINUS': return l - r;
269
- case 'STAR': return l * r;
270
- case 'SLASH': return l / r;
271
- case 'MOD': return l % r;
272
- case 'EQEQ': return l === r;
273
- case 'NOTEQ': return l !== r;
274
- case 'LT': return l < r;
275
- case 'LTE': return l <= r;
276
- case 'GT': return l > r;
277
- case 'GTE': return l >= r;
278
- default: throw new Error(`Unknown binary operator ${node.operator}`);
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 { return this.evaluate(fn.body, callEnv); }
355
- catch (e) { if (e instanceof ReturnValue) return e.value; throw e; }
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
- if (obj == null) throw new Error('Indexing null/undefined');
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/undefined');
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
- if (char === '=' && next === '>') { tokens.push({ type: 'ARROW', line: startLine, column: startCol }); this.advance(); this.advance(); continue; }
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
- const name = t.value;
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');
package/src/starlight.js CHANGED
@@ -9,7 +9,7 @@ const Lexer = require('./lexer');
9
9
  const Parser = require('./parser');
10
10
  const Evaluator = require('./evaluator');
11
11
 
12
- const VERSION = '1.0.22';
12
+ const VERSION = '1.0.24';
13
13
 
14
14
  const COLOR = {
15
15
  reset: '\x1b[0m',