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 +27 -12
- package/package.json +1 -1
- package/src/evaluator.js +5 -4
- package/src/parser.js +23 -9
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
2405
|
-
|
|
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 (
|
|
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
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 =
|
|
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 =
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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 (
|
|
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');
|