starlight-cli 1.0.41 → 1.0.42

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
@@ -1801,9 +1801,8 @@ async evalWhile(node, env) {
1801
1801
  return null;
1802
1802
  }
1803
1803
  async evalFor(node, env) {
1804
-
1805
1804
  // -------------------------------
1806
- // Python-style: for x in iterable
1805
+ // Python-style: for x in iterable (with optional 'let')
1807
1806
  // -------------------------------
1808
1807
  if (node.type === 'ForInStatement') {
1809
1808
  const iterable = await this.evaluate(node.iterable, env);
@@ -1814,10 +1813,12 @@ async evalFor(node, env) {
1814
1813
 
1815
1814
  const loopVar = node.variable; // STRING from parser
1816
1815
 
1816
+ const createLoopEnv = () => node.letKeyword ? new Environment(env) : env;
1817
+
1817
1818
  // Arrays
1818
1819
  if (Array.isArray(iterable)) {
1819
1820
  for (const value of iterable) {
1820
- const loopEnv = new Environment(env);
1821
+ const loopEnv = createLoopEnv();
1821
1822
  loopEnv.define(loopVar, value);
1822
1823
 
1823
1824
  try {
@@ -1832,7 +1833,7 @@ async evalFor(node, env) {
1832
1833
  // Objects (keys)
1833
1834
  else {
1834
1835
  for (const key of Object.keys(iterable)) {
1835
- const loopEnv = new Environment(env);
1836
+ const loopEnv = createLoopEnv();
1836
1837
  loopEnv.define(loopVar, key);
1837
1838
 
1838
1839
  try {
@@ -2396,16 +2397,30 @@ importStatement() {
2396
2397
  forStatement() {
2397
2398
  this.eat('FOR');
2398
2399
 
2399
- // --- Python-style: for variable in iterable ---
2400
- if (this.current.type === 'IDENTIFIER' && this.peekType() === 'IN') {
2401
- const variable = this.current.value; // loop variable
2402
- this.eat('IDENTIFIER');
2400
+ // --- Python-style: for variable in iterable (supports optional 'let') ---
2401
+ if ((this.current.type === 'LET' && this.peekType() === 'IDENTIFIER' && this.peekType(2) === 'IN') ||
2402
+ (this.current.type === 'IDENTIFIER' && this.peekType() === 'IN')) {
2403
2403
 
2404
- this.eat('IN');
2405
- const iterable = this.expression(); // the array/object to loop over
2404
+ let variable;
2405
+ let iterable;
2406
+ let letKeyword = false;
2407
+
2408
+ if (this.current.type === 'LET') {
2409
+ letKeyword = true;
2410
+ this.eat('LET');
2411
+ variable = this.current.value;
2412
+ this.eat('IDENTIFIER');
2413
+ this.eat('IN');
2414
+ iterable = this.expression();
2415
+ } else {
2416
+ variable = this.current.value;
2417
+ this.eat('IDENTIFIER');
2418
+ this.eat('IN');
2419
+ iterable = this.expression();
2420
+ }
2406
2421
 
2407
2422
  const body = this.block();
2408
- return { type: 'ForInStatement', variable, iterable, body };
2423
+ return { type: 'ForInStatement', variable, iterable, letKeyword, body };
2409
2424
  }
2410
2425
 
2411
2426
  // --- C-style: for(init; test; update) ---
@@ -2431,7 +2446,7 @@ forStatement() {
2431
2446
  if (this.current.type !== 'RPAREN') update = this.expression();
2432
2447
  this.eat('RPAREN');
2433
2448
  } else {
2434
- // fallback: single expression (could be used for Python-style with "in", already handled above)
2449
+ // fallback: single expression (rare, mostly handled above)
2435
2450
  init = this.expression();
2436
2451
  if (this.current.type === 'IN') {
2437
2452
  this.eat('IN');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starlight-cli",
3
- "version": "1.0.41",
3
+ "version": "1.0.42",
4
4
  "description": "Starlight Programming Language CLI",
5
5
  "bin": {
6
6
  "starlight": "index.js"
package/src/evaluator.js CHANGED
@@ -458,9 +458,8 @@ async evalWhile(node, env) {
458
458
  return null;
459
459
  }
460
460
  async evalFor(node, env) {
461
-
462
461
  // -------------------------------
463
- // Python-style: for x in iterable
462
+ // Python-style: for x in iterable (with optional 'let')
464
463
  // -------------------------------
465
464
  if (node.type === 'ForInStatement') {
466
465
  const iterable = await this.evaluate(node.iterable, env);
@@ -471,10 +470,12 @@ async evalFor(node, env) {
471
470
 
472
471
  const loopVar = node.variable; // STRING from parser
473
472
 
473
+ const createLoopEnv = () => node.letKeyword ? new Environment(env) : env;
474
+
474
475
  // Arrays
475
476
  if (Array.isArray(iterable)) {
476
477
  for (const value of iterable) {
477
- const loopEnv = new Environment(env);
478
+ const loopEnv = createLoopEnv();
478
479
  loopEnv.define(loopVar, value);
479
480
 
480
481
  try {
@@ -489,7 +490,7 @@ async evalFor(node, env) {
489
490
  // Objects (keys)
490
491
  else {
491
492
  for (const key of Object.keys(iterable)) {
492
- const loopEnv = new Environment(env);
493
+ const loopEnv = createLoopEnv();
493
494
  loopEnv.define(loopVar, key);
494
495
 
495
496
  try {
package/src/parser.js CHANGED
@@ -229,16 +229,30 @@ importStatement() {
229
229
  forStatement() {
230
230
  this.eat('FOR');
231
231
 
232
- // --- Python-style: for variable in iterable ---
233
- if (this.current.type === 'IDENTIFIER' && this.peekType() === 'IN') {
234
- const variable = this.current.value; // loop variable
235
- this.eat('IDENTIFIER');
236
-
237
- this.eat('IN');
238
- const iterable = this.expression(); // the array/object to loop over
232
+ // --- Python-style: for variable in iterable (supports optional 'let') ---
233
+ if ((this.current.type === 'LET' && this.peekType() === 'IDENTIFIER' && this.peekType(2) === 'IN') ||
234
+ (this.current.type === 'IDENTIFIER' && this.peekType() === 'IN')) {
235
+
236
+ let variable;
237
+ let iterable;
238
+ let letKeyword = false;
239
+
240
+ if (this.current.type === 'LET') {
241
+ letKeyword = true;
242
+ this.eat('LET');
243
+ variable = this.current.value;
244
+ this.eat('IDENTIFIER');
245
+ this.eat('IN');
246
+ iterable = this.expression();
247
+ } else {
248
+ variable = this.current.value;
249
+ this.eat('IDENTIFIER');
250
+ this.eat('IN');
251
+ iterable = this.expression();
252
+ }
239
253
 
240
254
  const body = this.block();
241
- return { type: 'ForInStatement', variable, iterable, body };
255
+ return { type: 'ForInStatement', variable, iterable, letKeyword, body };
242
256
  }
243
257
 
244
258
  // --- C-style: for(init; test; update) ---
@@ -264,7 +278,7 @@ forStatement() {
264
278
  if (this.current.type !== 'RPAREN') update = this.expression();
265
279
  this.eat('RPAREN');
266
280
  } else {
267
- // fallback: single expression (could be used for Python-style with "in", already handled above)
281
+ // fallback: single expression (rare, mostly handled above)
268
282
  init = this.expression();
269
283
  if (this.current.type === 'IN') {
270
284
  this.eat('IN');