starlight-cli 1.1.15 → 1.1.16
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 +233 -15
- package/package.json +1 -1
- package/src/evaluator.js +90 -2
- package/src/parser.js +142 -12
- package/src/starlight.js +1 -1
package/dist/index.js
CHANGED
|
@@ -10632,10 +10632,17 @@ async evaluate(node, env = this.global) {
|
|
|
10632
10632
|
case 'SldeployStatement': return await this.evalSldeploy(node, env);
|
|
10633
10633
|
case 'AskStatement': return await this.evalAsk(node, env);
|
|
10634
10634
|
case 'DefineStatement': return await this.evalDefine(node, env);
|
|
10635
|
+
case 'FunctionExpression':
|
|
10636
|
+
return this.evalFunctionExpression(node, env);
|
|
10637
|
+
case 'SliceExpression':
|
|
10638
|
+
return await this.evalSlice(node, env);
|
|
10639
|
+
|
|
10635
10640
|
case 'ExpressionStatement': return await this.evaluate(node.expression, env);
|
|
10636
10641
|
case 'BinaryExpression': return await this.evalBinary(node, env);
|
|
10637
10642
|
case 'LogicalExpression': return await this.evalLogical(node, env);
|
|
10638
10643
|
case 'UnaryExpression': return await this.evalUnary(node, env);
|
|
10644
|
+
case 'ConditionalExpression':
|
|
10645
|
+
return await this.evalConditional(node, env);
|
|
10639
10646
|
case 'Literal': return node.value;
|
|
10640
10647
|
case 'Identifier': return env.get(node.name, node, this.source);
|
|
10641
10648
|
case 'IfStatement': return await this.evalIf(node, env);
|
|
@@ -10738,6 +10745,36 @@ async evalProgram(node, env) {
|
|
|
10738
10745
|
}
|
|
10739
10746
|
return result;
|
|
10740
10747
|
}
|
|
10748
|
+
async evalSlice(node, env) {
|
|
10749
|
+
try {
|
|
10750
|
+
const arr = await this.evaluate(node.object, env);
|
|
10751
|
+
const start = node.start ? await this.evaluate(node.start, env) : 0;
|
|
10752
|
+
const end = node.end ? await this.evaluate(node.end, env) : arr.length;
|
|
10753
|
+
|
|
10754
|
+
if (!Array.isArray(arr)) {
|
|
10755
|
+
throw new RuntimeError(
|
|
10756
|
+
'Slice target must be an array',
|
|
10757
|
+
node,
|
|
10758
|
+
this.source,
|
|
10759
|
+
env
|
|
10760
|
+
);
|
|
10761
|
+
}
|
|
10762
|
+
|
|
10763
|
+
const s = start < 0 ? Math.max(arr.length + start, 0) : Math.min(start, arr.length);
|
|
10764
|
+
const e = end < 0 ? Math.max(arr.length + end, 0) : Math.min(end, arr.length);
|
|
10765
|
+
|
|
10766
|
+
return arr.slice(s, e);
|
|
10767
|
+
|
|
10768
|
+
} catch (err) {
|
|
10769
|
+
if (err instanceof RuntimeError) throw err;
|
|
10770
|
+
throw new RuntimeError(
|
|
10771
|
+
err.message || 'Error evaluating slice expression',
|
|
10772
|
+
node,
|
|
10773
|
+
this.source,
|
|
10774
|
+
env
|
|
10775
|
+
);
|
|
10776
|
+
}
|
|
10777
|
+
}
|
|
10741
10778
|
|
|
10742
10779
|
async evalStartStatement(node, env) {
|
|
10743
10780
|
try {
|
|
@@ -10786,6 +10823,24 @@ async evalStartStatement(node, env) {
|
|
|
10786
10823
|
);
|
|
10787
10824
|
}
|
|
10788
10825
|
}
|
|
10826
|
+
async evalConditional(node, env) {
|
|
10827
|
+
try {
|
|
10828
|
+
const test = await this.evaluate(node.test, env);
|
|
10829
|
+
if (test) {
|
|
10830
|
+
return await this.evaluate(node.consequent, env);
|
|
10831
|
+
} else {
|
|
10832
|
+
return await this.evaluate(node.alternate, env);
|
|
10833
|
+
}
|
|
10834
|
+
} catch (e) {
|
|
10835
|
+
if (e instanceof RuntimeError) throw e;
|
|
10836
|
+
throw new RuntimeError(
|
|
10837
|
+
e.message || 'Error evaluating conditional expression',
|
|
10838
|
+
node,
|
|
10839
|
+
this.source,
|
|
10840
|
+
env
|
|
10841
|
+
);
|
|
10842
|
+
}
|
|
10843
|
+
}
|
|
10789
10844
|
|
|
10790
10845
|
async evalRaceClause(node, env) {
|
|
10791
10846
|
try {
|
|
@@ -11396,6 +11451,41 @@ async evalFor(node, env) {
|
|
|
11396
11451
|
);
|
|
11397
11452
|
}
|
|
11398
11453
|
}
|
|
11454
|
+
evalFunctionExpression(node, env) {
|
|
11455
|
+
if (!node.body || !Array.isArray(node.params)) {
|
|
11456
|
+
throw new RuntimeError(
|
|
11457
|
+
'Invalid function expression',
|
|
11458
|
+
node,
|
|
11459
|
+
this.source,
|
|
11460
|
+
env
|
|
11461
|
+
);
|
|
11462
|
+
}
|
|
11463
|
+
|
|
11464
|
+
const evaluator = this;
|
|
11465
|
+
|
|
11466
|
+
const fn = async function (...args) {
|
|
11467
|
+
const localEnv = new Environment(env);
|
|
11468
|
+
|
|
11469
|
+
for (let i = 0; i < node.params.length; i++) {
|
|
11470
|
+
const param = node.params[i];
|
|
11471
|
+
const paramName = typeof param === 'string' ? param : param.name;
|
|
11472
|
+
localEnv.define(paramName, args[i]);
|
|
11473
|
+
}
|
|
11474
|
+
|
|
11475
|
+
try {
|
|
11476
|
+
const result = await evaluator.evaluate(node.body, localEnv);
|
|
11477
|
+
return result === undefined ? null : result;
|
|
11478
|
+
} catch (e) {
|
|
11479
|
+
if (e instanceof ReturnValue) return e.value === undefined ? null : e.value;
|
|
11480
|
+
throw e;
|
|
11481
|
+
}
|
|
11482
|
+
};
|
|
11483
|
+
fn.params = node.params;
|
|
11484
|
+
fn.body = node.body;
|
|
11485
|
+
fn.env = env;
|
|
11486
|
+
|
|
11487
|
+
return fn;
|
|
11488
|
+
}
|
|
11399
11489
|
|
|
11400
11490
|
evalFunctionDeclaration(node, env) {
|
|
11401
11491
|
try {
|
|
@@ -11483,7 +11573,6 @@ async evalCall(node, env) {
|
|
|
11483
11573
|
);
|
|
11484
11574
|
}
|
|
11485
11575
|
}
|
|
11486
|
-
|
|
11487
11576
|
async evalIndex(node, env) {
|
|
11488
11577
|
try {
|
|
11489
11578
|
const obj = await this.evaluate(node.object, env);
|
|
@@ -11516,7 +11605,6 @@ async evalIndex(node, env) {
|
|
|
11516
11605
|
);
|
|
11517
11606
|
}
|
|
11518
11607
|
}
|
|
11519
|
-
|
|
11520
11608
|
async evalObject(node, env) {
|
|
11521
11609
|
try {
|
|
11522
11610
|
const out = {};
|
|
@@ -13161,33 +13249,100 @@ postfix() {
|
|
|
13161
13249
|
while (true) {
|
|
13162
13250
|
const t = this.current;
|
|
13163
13251
|
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13252
|
+
if (t.type === 'LBRACKET') {
|
|
13253
|
+
const startLine = t.line;
|
|
13254
|
+
const startCol = t.column;
|
|
13255
|
+
this.eat('LBRACKET');
|
|
13256
|
+
|
|
13257
|
+
let start = null;
|
|
13258
|
+
let end = null;
|
|
13259
|
+
let step = null;
|
|
13260
|
+
|
|
13261
|
+
if (this.current.type === 'COLON') {
|
|
13262
|
+
this.eat('COLON');
|
|
13263
|
+
|
|
13264
|
+
if (this.current.type !== 'RBRACKET' && this.current.type !== 'COLON') {
|
|
13265
|
+
end = this.expression();
|
|
13266
|
+
}
|
|
13267
|
+
|
|
13268
|
+
if (this.current.type === 'COLON') {
|
|
13269
|
+
this.eat('COLON');
|
|
13270
|
+
if (this.current.type !== 'RBRACKET') {
|
|
13271
|
+
step = this.expression();
|
|
13272
|
+
}
|
|
13273
|
+
}
|
|
13274
|
+
|
|
13275
|
+
if (this.current.type !== 'RBRACKET') {
|
|
13276
|
+
throw new ParseError(
|
|
13277
|
+
"Expected ']' after slice",
|
|
13278
|
+
this.current,
|
|
13279
|
+
this.source
|
|
13280
|
+
);
|
|
13281
|
+
}
|
|
13282
|
+
|
|
13283
|
+
this.eat('RBRACKET');
|
|
13284
|
+
|
|
13285
|
+
node = {
|
|
13286
|
+
type: 'SliceExpression',
|
|
13287
|
+
object: node,
|
|
13288
|
+
start,
|
|
13289
|
+
end,
|
|
13290
|
+
step,
|
|
13291
|
+
line: startLine,
|
|
13292
|
+
column: startCol
|
|
13293
|
+
};
|
|
13168
13294
|
|
|
13169
|
-
|
|
13295
|
+
} else {
|
|
13296
|
+
start = this.expression();
|
|
13297
|
+
|
|
13298
|
+
if (this.current.type === 'COLON') {
|
|
13299
|
+
this.eat('COLON');
|
|
13300
|
+
|
|
13301
|
+
if (this.current.type !== 'RBRACKET' && this.current.type !== 'COLON') {
|
|
13302
|
+
end = this.expression();
|
|
13303
|
+
}
|
|
13304
|
+
|
|
13305
|
+
if (this.current.type === 'COLON') {
|
|
13306
|
+
this.eat('COLON');
|
|
13307
|
+
if (this.current.type !== 'RBRACKET') {
|
|
13308
|
+
step = this.expression();
|
|
13309
|
+
}
|
|
13310
|
+
}
|
|
13170
13311
|
|
|
13171
13312
|
if (this.current.type !== 'RBRACKET') {
|
|
13172
13313
|
throw new ParseError(
|
|
13173
|
-
"Expected ']' after
|
|
13314
|
+
"Expected ']' after slice",
|
|
13174
13315
|
this.current,
|
|
13175
|
-
this.source
|
|
13176
|
-
"Index access must be closed, e.g. arr[0]"
|
|
13316
|
+
this.source
|
|
13177
13317
|
);
|
|
13178
13318
|
}
|
|
13179
13319
|
|
|
13180
13320
|
this.eat('RBRACKET');
|
|
13181
13321
|
|
|
13322
|
+
node = {
|
|
13323
|
+
type: 'SliceExpression',
|
|
13324
|
+
object: node,
|
|
13325
|
+
start,
|
|
13326
|
+
end,
|
|
13327
|
+
step,
|
|
13328
|
+
line: startLine,
|
|
13329
|
+
column: startCol
|
|
13330
|
+
};
|
|
13331
|
+
|
|
13332
|
+
} else {
|
|
13333
|
+
this.eat('RBRACKET');
|
|
13182
13334
|
node = {
|
|
13183
13335
|
type: 'IndexExpression',
|
|
13184
13336
|
object: node,
|
|
13185
|
-
indexer:
|
|
13337
|
+
indexer: start,
|
|
13186
13338
|
line: startLine,
|
|
13187
13339
|
column: startCol
|
|
13188
13340
|
};
|
|
13189
|
-
continue;
|
|
13190
13341
|
}
|
|
13342
|
+
}
|
|
13343
|
+
}
|
|
13344
|
+
|
|
13345
|
+
|
|
13191
13346
|
|
|
13192
13347
|
if (t.type === 'LPAREN') {
|
|
13193
13348
|
const startLine = t.line;
|
|
@@ -13319,6 +13474,7 @@ arrowFunction(params) {
|
|
|
13319
13474
|
};
|
|
13320
13475
|
}
|
|
13321
13476
|
|
|
13477
|
+
|
|
13322
13478
|
primary() {
|
|
13323
13479
|
const t = this.current;
|
|
13324
13480
|
|
|
@@ -13390,7 +13546,6 @@ primary() {
|
|
|
13390
13546
|
return { type: 'NewExpression', callee, arguments: args, line: t.line, column: t.column };
|
|
13391
13547
|
}
|
|
13392
13548
|
|
|
13393
|
-
// ---- ask(...) function call ----
|
|
13394
13549
|
if (t.type === 'ASK') {
|
|
13395
13550
|
this.eat('ASK');
|
|
13396
13551
|
|
|
@@ -13431,6 +13586,69 @@ primary() {
|
|
|
13431
13586
|
column: t.column
|
|
13432
13587
|
};
|
|
13433
13588
|
}
|
|
13589
|
+
if (t.type === 'FUNC') {
|
|
13590
|
+
const funcToken = t;
|
|
13591
|
+
this.eat('FUNC');
|
|
13592
|
+
|
|
13593
|
+
let params = [];
|
|
13594
|
+
if (this.current.type === 'LPAREN') {
|
|
13595
|
+
this.eat('LPAREN');
|
|
13596
|
+
|
|
13597
|
+
if (this.current.type !== 'RPAREN') {
|
|
13598
|
+
if (this.current.type !== 'IDENTIFIER') {
|
|
13599
|
+
throw new ParseError(
|
|
13600
|
+
"Expected parameter name",
|
|
13601
|
+
this.current,
|
|
13602
|
+
this.source
|
|
13603
|
+
);
|
|
13604
|
+
}
|
|
13605
|
+
|
|
13606
|
+
params.push(this.current.value);
|
|
13607
|
+
this.eat('IDENTIFIER');
|
|
13608
|
+
|
|
13609
|
+
while (this.current.type === 'COMMA') {
|
|
13610
|
+
this.eat('COMMA');
|
|
13611
|
+
if (this.current.type !== 'IDENTIFIER') {
|
|
13612
|
+
throw new ParseError(
|
|
13613
|
+
"Expected parameter name",
|
|
13614
|
+
this.current,
|
|
13615
|
+
this.source
|
|
13616
|
+
);
|
|
13617
|
+
}
|
|
13618
|
+
params.push(this.current.value);
|
|
13619
|
+
this.eat('IDENTIFIER');
|
|
13620
|
+
}
|
|
13621
|
+
}
|
|
13622
|
+
|
|
13623
|
+
if (this.current.type !== 'RPAREN') {
|
|
13624
|
+
throw new ParseError(
|
|
13625
|
+
"Expected ')' after function parameters",
|
|
13626
|
+
this.current,
|
|
13627
|
+
this.source
|
|
13628
|
+
);
|
|
13629
|
+
}
|
|
13630
|
+
|
|
13631
|
+
this.eat('RPAREN');
|
|
13632
|
+
}
|
|
13633
|
+
|
|
13634
|
+
if (this.current.type !== 'LBRACE') {
|
|
13635
|
+
throw new ParseError(
|
|
13636
|
+
"Expected '{' to start function body",
|
|
13637
|
+
this.current,
|
|
13638
|
+
this.source
|
|
13639
|
+
);
|
|
13640
|
+
}
|
|
13641
|
+
|
|
13642
|
+
const body = this.block();
|
|
13643
|
+
|
|
13644
|
+
return {
|
|
13645
|
+
type: 'FunctionExpression',
|
|
13646
|
+
params,
|
|
13647
|
+
body,
|
|
13648
|
+
line: funcToken.line,
|
|
13649
|
+
column: funcToken.column
|
|
13650
|
+
};
|
|
13651
|
+
}
|
|
13434
13652
|
|
|
13435
13653
|
if (t.type === 'IDENTIFIER') {
|
|
13436
13654
|
const name = t.value;
|
|
@@ -13567,7 +13785,7 @@ primary() {
|
|
|
13567
13785
|
t,
|
|
13568
13786
|
this.source
|
|
13569
13787
|
);
|
|
13570
|
-
}
|
|
13788
|
+
}
|
|
13571
13789
|
|
|
13572
13790
|
}
|
|
13573
13791
|
|
|
@@ -13751,7 +13969,7 @@ const Lexer = __nccwpck_require__(211);
|
|
|
13751
13969
|
const Parser = __nccwpck_require__(222);
|
|
13752
13970
|
const Evaluator = __nccwpck_require__(112);
|
|
13753
13971
|
|
|
13754
|
-
const VERSION = '1.1.
|
|
13972
|
+
const VERSION = '1.1.16';
|
|
13755
13973
|
|
|
13756
13974
|
const COLOR = {
|
|
13757
13975
|
reset: '\x1b[0m',
|
package/package.json
CHANGED
package/src/evaluator.js
CHANGED
|
@@ -422,10 +422,17 @@ async evaluate(node, env = this.global) {
|
|
|
422
422
|
case 'SldeployStatement': return await this.evalSldeploy(node, env);
|
|
423
423
|
case 'AskStatement': return await this.evalAsk(node, env);
|
|
424
424
|
case 'DefineStatement': return await this.evalDefine(node, env);
|
|
425
|
+
case 'FunctionExpression':
|
|
426
|
+
return this.evalFunctionExpression(node, env);
|
|
427
|
+
case 'SliceExpression':
|
|
428
|
+
return await this.evalSlice(node, env);
|
|
429
|
+
|
|
425
430
|
case 'ExpressionStatement': return await this.evaluate(node.expression, env);
|
|
426
431
|
case 'BinaryExpression': return await this.evalBinary(node, env);
|
|
427
432
|
case 'LogicalExpression': return await this.evalLogical(node, env);
|
|
428
433
|
case 'UnaryExpression': return await this.evalUnary(node, env);
|
|
434
|
+
case 'ConditionalExpression':
|
|
435
|
+
return await this.evalConditional(node, env);
|
|
429
436
|
case 'Literal': return node.value;
|
|
430
437
|
case 'Identifier': return env.get(node.name, node, this.source);
|
|
431
438
|
case 'IfStatement': return await this.evalIf(node, env);
|
|
@@ -528,6 +535,36 @@ async evalProgram(node, env) {
|
|
|
528
535
|
}
|
|
529
536
|
return result;
|
|
530
537
|
}
|
|
538
|
+
async evalSlice(node, env) {
|
|
539
|
+
try {
|
|
540
|
+
const arr = await this.evaluate(node.object, env);
|
|
541
|
+
const start = node.start ? await this.evaluate(node.start, env) : 0;
|
|
542
|
+
const end = node.end ? await this.evaluate(node.end, env) : arr.length;
|
|
543
|
+
|
|
544
|
+
if (!Array.isArray(arr)) {
|
|
545
|
+
throw new RuntimeError(
|
|
546
|
+
'Slice target must be an array',
|
|
547
|
+
node,
|
|
548
|
+
this.source,
|
|
549
|
+
env
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const s = start < 0 ? Math.max(arr.length + start, 0) : Math.min(start, arr.length);
|
|
554
|
+
const e = end < 0 ? Math.max(arr.length + end, 0) : Math.min(end, arr.length);
|
|
555
|
+
|
|
556
|
+
return arr.slice(s, e);
|
|
557
|
+
|
|
558
|
+
} catch (err) {
|
|
559
|
+
if (err instanceof RuntimeError) throw err;
|
|
560
|
+
throw new RuntimeError(
|
|
561
|
+
err.message || 'Error evaluating slice expression',
|
|
562
|
+
node,
|
|
563
|
+
this.source,
|
|
564
|
+
env
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
531
568
|
|
|
532
569
|
async evalStartStatement(node, env) {
|
|
533
570
|
try {
|
|
@@ -576,6 +613,24 @@ async evalStartStatement(node, env) {
|
|
|
576
613
|
);
|
|
577
614
|
}
|
|
578
615
|
}
|
|
616
|
+
async evalConditional(node, env) {
|
|
617
|
+
try {
|
|
618
|
+
const test = await this.evaluate(node.test, env);
|
|
619
|
+
if (test) {
|
|
620
|
+
return await this.evaluate(node.consequent, env);
|
|
621
|
+
} else {
|
|
622
|
+
return await this.evaluate(node.alternate, env);
|
|
623
|
+
}
|
|
624
|
+
} catch (e) {
|
|
625
|
+
if (e instanceof RuntimeError) throw e;
|
|
626
|
+
throw new RuntimeError(
|
|
627
|
+
e.message || 'Error evaluating conditional expression',
|
|
628
|
+
node,
|
|
629
|
+
this.source,
|
|
630
|
+
env
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
579
634
|
|
|
580
635
|
async evalRaceClause(node, env) {
|
|
581
636
|
try {
|
|
@@ -1186,6 +1241,41 @@ async evalFor(node, env) {
|
|
|
1186
1241
|
);
|
|
1187
1242
|
}
|
|
1188
1243
|
}
|
|
1244
|
+
evalFunctionExpression(node, env) {
|
|
1245
|
+
if (!node.body || !Array.isArray(node.params)) {
|
|
1246
|
+
throw new RuntimeError(
|
|
1247
|
+
'Invalid function expression',
|
|
1248
|
+
node,
|
|
1249
|
+
this.source,
|
|
1250
|
+
env
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
const evaluator = this;
|
|
1255
|
+
|
|
1256
|
+
const fn = async function (...args) {
|
|
1257
|
+
const localEnv = new Environment(env);
|
|
1258
|
+
|
|
1259
|
+
for (let i = 0; i < node.params.length; i++) {
|
|
1260
|
+
const param = node.params[i];
|
|
1261
|
+
const paramName = typeof param === 'string' ? param : param.name;
|
|
1262
|
+
localEnv.define(paramName, args[i]);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
try {
|
|
1266
|
+
const result = await evaluator.evaluate(node.body, localEnv);
|
|
1267
|
+
return result === undefined ? null : result;
|
|
1268
|
+
} catch (e) {
|
|
1269
|
+
if (e instanceof ReturnValue) return e.value === undefined ? null : e.value;
|
|
1270
|
+
throw e;
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
fn.params = node.params;
|
|
1274
|
+
fn.body = node.body;
|
|
1275
|
+
fn.env = env;
|
|
1276
|
+
|
|
1277
|
+
return fn;
|
|
1278
|
+
}
|
|
1189
1279
|
|
|
1190
1280
|
evalFunctionDeclaration(node, env) {
|
|
1191
1281
|
try {
|
|
@@ -1273,7 +1363,6 @@ async evalCall(node, env) {
|
|
|
1273
1363
|
);
|
|
1274
1364
|
}
|
|
1275
1365
|
}
|
|
1276
|
-
|
|
1277
1366
|
async evalIndex(node, env) {
|
|
1278
1367
|
try {
|
|
1279
1368
|
const obj = await this.evaluate(node.object, env);
|
|
@@ -1306,7 +1395,6 @@ async evalIndex(node, env) {
|
|
|
1306
1395
|
);
|
|
1307
1396
|
}
|
|
1308
1397
|
}
|
|
1309
|
-
|
|
1310
1398
|
async evalObject(node, env) {
|
|
1311
1399
|
try {
|
|
1312
1400
|
const out = {};
|
package/src/parser.js
CHANGED
|
@@ -1292,33 +1292,100 @@ postfix() {
|
|
|
1292
1292
|
while (true) {
|
|
1293
1293
|
const t = this.current;
|
|
1294
1294
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1295
|
+
if (t.type === 'LBRACKET') {
|
|
1296
|
+
const startLine = t.line;
|
|
1297
|
+
const startCol = t.column;
|
|
1298
|
+
this.eat('LBRACKET');
|
|
1299
|
+
|
|
1300
|
+
let start = null;
|
|
1301
|
+
let end = null;
|
|
1302
|
+
let step = null;
|
|
1299
1303
|
|
|
1300
|
-
|
|
1304
|
+
if (this.current.type === 'COLON') {
|
|
1305
|
+
this.eat('COLON');
|
|
1306
|
+
|
|
1307
|
+
if (this.current.type !== 'RBRACKET' && this.current.type !== 'COLON') {
|
|
1308
|
+
end = this.expression();
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
if (this.current.type === 'COLON') {
|
|
1312
|
+
this.eat('COLON');
|
|
1313
|
+
if (this.current.type !== 'RBRACKET') {
|
|
1314
|
+
step = this.expression();
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
if (this.current.type !== 'RBRACKET') {
|
|
1319
|
+
throw new ParseError(
|
|
1320
|
+
"Expected ']' after slice",
|
|
1321
|
+
this.current,
|
|
1322
|
+
this.source
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
this.eat('RBRACKET');
|
|
1327
|
+
|
|
1328
|
+
node = {
|
|
1329
|
+
type: 'SliceExpression',
|
|
1330
|
+
object: node,
|
|
1331
|
+
start,
|
|
1332
|
+
end,
|
|
1333
|
+
step,
|
|
1334
|
+
line: startLine,
|
|
1335
|
+
column: startCol
|
|
1336
|
+
};
|
|
1337
|
+
|
|
1338
|
+
} else {
|
|
1339
|
+
start = this.expression();
|
|
1340
|
+
|
|
1341
|
+
if (this.current.type === 'COLON') {
|
|
1342
|
+
this.eat('COLON');
|
|
1343
|
+
|
|
1344
|
+
if (this.current.type !== 'RBRACKET' && this.current.type !== 'COLON') {
|
|
1345
|
+
end = this.expression();
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
if (this.current.type === 'COLON') {
|
|
1349
|
+
this.eat('COLON');
|
|
1350
|
+
if (this.current.type !== 'RBRACKET') {
|
|
1351
|
+
step = this.expression();
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1301
1354
|
|
|
1302
1355
|
if (this.current.type !== 'RBRACKET') {
|
|
1303
1356
|
throw new ParseError(
|
|
1304
|
-
"Expected ']' after
|
|
1357
|
+
"Expected ']' after slice",
|
|
1305
1358
|
this.current,
|
|
1306
|
-
this.source
|
|
1307
|
-
"Index access must be closed, e.g. arr[0]"
|
|
1359
|
+
this.source
|
|
1308
1360
|
);
|
|
1309
1361
|
}
|
|
1310
1362
|
|
|
1311
1363
|
this.eat('RBRACKET');
|
|
1312
1364
|
|
|
1365
|
+
node = {
|
|
1366
|
+
type: 'SliceExpression',
|
|
1367
|
+
object: node,
|
|
1368
|
+
start,
|
|
1369
|
+
end,
|
|
1370
|
+
step,
|
|
1371
|
+
line: startLine,
|
|
1372
|
+
column: startCol
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
} else {
|
|
1376
|
+
this.eat('RBRACKET');
|
|
1313
1377
|
node = {
|
|
1314
1378
|
type: 'IndexExpression',
|
|
1315
1379
|
object: node,
|
|
1316
|
-
indexer:
|
|
1380
|
+
indexer: start,
|
|
1317
1381
|
line: startLine,
|
|
1318
1382
|
column: startCol
|
|
1319
1383
|
};
|
|
1320
|
-
continue;
|
|
1321
1384
|
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
|
|
1322
1389
|
|
|
1323
1390
|
if (t.type === 'LPAREN') {
|
|
1324
1391
|
const startLine = t.line;
|
|
@@ -1450,6 +1517,7 @@ arrowFunction(params) {
|
|
|
1450
1517
|
};
|
|
1451
1518
|
}
|
|
1452
1519
|
|
|
1520
|
+
|
|
1453
1521
|
primary() {
|
|
1454
1522
|
const t = this.current;
|
|
1455
1523
|
|
|
@@ -1521,7 +1589,6 @@ primary() {
|
|
|
1521
1589
|
return { type: 'NewExpression', callee, arguments: args, line: t.line, column: t.column };
|
|
1522
1590
|
}
|
|
1523
1591
|
|
|
1524
|
-
// ---- ask(...) function call ----
|
|
1525
1592
|
if (t.type === 'ASK') {
|
|
1526
1593
|
this.eat('ASK');
|
|
1527
1594
|
|
|
@@ -1562,6 +1629,69 @@ primary() {
|
|
|
1562
1629
|
column: t.column
|
|
1563
1630
|
};
|
|
1564
1631
|
}
|
|
1632
|
+
if (t.type === 'FUNC') {
|
|
1633
|
+
const funcToken = t;
|
|
1634
|
+
this.eat('FUNC');
|
|
1635
|
+
|
|
1636
|
+
let params = [];
|
|
1637
|
+
if (this.current.type === 'LPAREN') {
|
|
1638
|
+
this.eat('LPAREN');
|
|
1639
|
+
|
|
1640
|
+
if (this.current.type !== 'RPAREN') {
|
|
1641
|
+
if (this.current.type !== 'IDENTIFIER') {
|
|
1642
|
+
throw new ParseError(
|
|
1643
|
+
"Expected parameter name",
|
|
1644
|
+
this.current,
|
|
1645
|
+
this.source
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
params.push(this.current.value);
|
|
1650
|
+
this.eat('IDENTIFIER');
|
|
1651
|
+
|
|
1652
|
+
while (this.current.type === 'COMMA') {
|
|
1653
|
+
this.eat('COMMA');
|
|
1654
|
+
if (this.current.type !== 'IDENTIFIER') {
|
|
1655
|
+
throw new ParseError(
|
|
1656
|
+
"Expected parameter name",
|
|
1657
|
+
this.current,
|
|
1658
|
+
this.source
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1661
|
+
params.push(this.current.value);
|
|
1662
|
+
this.eat('IDENTIFIER');
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
if (this.current.type !== 'RPAREN') {
|
|
1667
|
+
throw new ParseError(
|
|
1668
|
+
"Expected ')' after function parameters",
|
|
1669
|
+
this.current,
|
|
1670
|
+
this.source
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
this.eat('RPAREN');
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
if (this.current.type !== 'LBRACE') {
|
|
1678
|
+
throw new ParseError(
|
|
1679
|
+
"Expected '{' to start function body",
|
|
1680
|
+
this.current,
|
|
1681
|
+
this.source
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
const body = this.block();
|
|
1686
|
+
|
|
1687
|
+
return {
|
|
1688
|
+
type: 'FunctionExpression',
|
|
1689
|
+
params,
|
|
1690
|
+
body,
|
|
1691
|
+
line: funcToken.line,
|
|
1692
|
+
column: funcToken.column
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1565
1695
|
|
|
1566
1696
|
if (t.type === 'IDENTIFIER') {
|
|
1567
1697
|
const name = t.value;
|
|
@@ -1698,7 +1828,7 @@ primary() {
|
|
|
1698
1828
|
t,
|
|
1699
1829
|
this.source
|
|
1700
1830
|
);
|
|
1701
|
-
}
|
|
1831
|
+
}
|
|
1702
1832
|
|
|
1703
1833
|
}
|
|
1704
1834
|
|