starlight-cli 1.0.30 → 1.0.32
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 +46 -1
- package/package.json +1 -1
- package/src/evaluator.js +29 -0
- package/src/lexer.js +1 -1
- package/src/parser.js +16 -0
package/dist/index.js
CHANGED
|
@@ -1496,6 +1496,35 @@ async evaluate(node, env = this.global) {
|
|
|
1496
1496
|
const val = await this.evaluate(node.argument, env);
|
|
1497
1497
|
return val;
|
|
1498
1498
|
}
|
|
1499
|
+
case 'NewExpression': {
|
|
1500
|
+
const callee = await this.evaluate(node.callee, env);
|
|
1501
|
+
|
|
1502
|
+
if (typeof callee === 'object' && callee.body) {
|
|
1503
|
+
// This is a Starlight "func" object — wrap it in JS function
|
|
1504
|
+
const Constructor = function(...args) {
|
|
1505
|
+
const newEnv = new Environment(callee.env);
|
|
1506
|
+
newEnv.define('this', this); // bind 'this' for the constructor
|
|
1507
|
+
for (let i = 0; i < callee.params.length; i++) {
|
|
1508
|
+
newEnv.define(callee.params[i], args[i]);
|
|
1509
|
+
}
|
|
1510
|
+
return this.evaluate(callee.body, newEnv);
|
|
1511
|
+
}.bind(this);
|
|
1512
|
+
|
|
1513
|
+
const args = [];
|
|
1514
|
+
for (const a of node.arguments) args.push(await this.evaluate(a, env));
|
|
1515
|
+
|
|
1516
|
+
return new Constructor(...args);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
if (typeof callee !== 'function') {
|
|
1520
|
+
throw new Error('NewExpression callee is not a function');
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
const args = [];
|
|
1524
|
+
for (const a of node.arguments) args.push(await this.evaluate(a, env));
|
|
1525
|
+
return new callee(...args);
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1499
1528
|
default:
|
|
1500
1529
|
throw new Error(`Unknown node type in evaluator: ${node.type}`);
|
|
1501
1530
|
}
|
|
@@ -1919,7 +1948,7 @@ class Lexer {
|
|
|
1919
1948
|
'break', 'continue', 'func', 'return',
|
|
1920
1949
|
'true', 'false', 'null',
|
|
1921
1950
|
'ask', 'define', 'import', 'from', 'as',
|
|
1922
|
-
'async', 'await'
|
|
1951
|
+
'async', 'await', 'new'
|
|
1923
1952
|
];
|
|
1924
1953
|
|
|
1925
1954
|
|
|
@@ -2444,6 +2473,22 @@ if (t.type === 'AWAIT') {
|
|
|
2444
2473
|
const argument = this.expression();
|
|
2445
2474
|
return { type: 'AwaitExpression', argument };
|
|
2446
2475
|
}
|
|
2476
|
+
if (t.type === 'NEW') {
|
|
2477
|
+
this.eat('NEW');
|
|
2478
|
+
const callee = this.primary(); // the class or function being called
|
|
2479
|
+
this.eat('LPAREN');
|
|
2480
|
+
const args = [];
|
|
2481
|
+
if (this.current.type !== 'RPAREN') {
|
|
2482
|
+
args.push(this.expression());
|
|
2483
|
+
while (this.current.type === 'COMMA') {
|
|
2484
|
+
this.eat('COMMA');
|
|
2485
|
+
args.push(this.expression());
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
this.eat('RPAREN');
|
|
2489
|
+
return { type: 'NewExpression', callee, arguments: args };
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2447
2492
|
if (t.type === 'ASK') {
|
|
2448
2493
|
this.eat('ASK');
|
|
2449
2494
|
this.eat('LPAREN');
|
package/package.json
CHANGED
package/src/evaluator.js
CHANGED
|
@@ -153,6 +153,35 @@ async evaluate(node, env = this.global) {
|
|
|
153
153
|
const val = await this.evaluate(node.argument, env);
|
|
154
154
|
return val;
|
|
155
155
|
}
|
|
156
|
+
case 'NewExpression': {
|
|
157
|
+
const callee = await this.evaluate(node.callee, env);
|
|
158
|
+
|
|
159
|
+
if (typeof callee === 'object' && callee.body) {
|
|
160
|
+
// This is a Starlight "func" object — wrap it in JS function
|
|
161
|
+
const Constructor = function(...args) {
|
|
162
|
+
const newEnv = new Environment(callee.env);
|
|
163
|
+
newEnv.define('this', this); // bind 'this' for the constructor
|
|
164
|
+
for (let i = 0; i < callee.params.length; i++) {
|
|
165
|
+
newEnv.define(callee.params[i], args[i]);
|
|
166
|
+
}
|
|
167
|
+
return this.evaluate(callee.body, newEnv);
|
|
168
|
+
}.bind(this);
|
|
169
|
+
|
|
170
|
+
const args = [];
|
|
171
|
+
for (const a of node.arguments) args.push(await this.evaluate(a, env));
|
|
172
|
+
|
|
173
|
+
return new Constructor(...args);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (typeof callee !== 'function') {
|
|
177
|
+
throw new Error('NewExpression callee is not a function');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const args = [];
|
|
181
|
+
for (const a of node.arguments) args.push(await this.evaluate(a, env));
|
|
182
|
+
return new callee(...args);
|
|
183
|
+
}
|
|
184
|
+
|
|
156
185
|
default:
|
|
157
186
|
throw new Error(`Unknown node type in evaluator: ${node.type}`);
|
|
158
187
|
}
|
package/src/lexer.js
CHANGED
package/src/parser.js
CHANGED
|
@@ -414,6 +414,22 @@ if (t.type === 'AWAIT') {
|
|
|
414
414
|
const argument = this.expression();
|
|
415
415
|
return { type: 'AwaitExpression', argument };
|
|
416
416
|
}
|
|
417
|
+
if (t.type === 'NEW') {
|
|
418
|
+
this.eat('NEW');
|
|
419
|
+
const callee = this.primary(); // the class or function being called
|
|
420
|
+
this.eat('LPAREN');
|
|
421
|
+
const args = [];
|
|
422
|
+
if (this.current.type !== 'RPAREN') {
|
|
423
|
+
args.push(this.expression());
|
|
424
|
+
while (this.current.type === 'COMMA') {
|
|
425
|
+
this.eat('COMMA');
|
|
426
|
+
args.push(this.expression());
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
this.eat('RPAREN');
|
|
430
|
+
return { type: 'NewExpression', callee, arguments: args };
|
|
431
|
+
}
|
|
432
|
+
|
|
417
433
|
if (t.type === 'ASK') {
|
|
418
434
|
this.eat('ASK');
|
|
419
435
|
this.eat('LPAREN');
|