starlight-cli 1.0.25 → 1.0.26
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 +450 -341
- package/package.json +1 -1
- package/src/evaluator.js +428 -340
- package/src/lexer.js +7 -4
- package/src/parser.js +28 -1
- package/src/starlight.js +1 -1
package/dist/index.js
CHANGED
|
@@ -1347,394 +1347,481 @@ const Lexer = __nccwpck_require__(211);
|
|
|
1347
1347
|
const Parser = __nccwpck_require__(222);
|
|
1348
1348
|
const path = __nccwpck_require__(928);
|
|
1349
1349
|
|
|
1350
|
-
class ReturnValue {
|
|
1350
|
+
class ReturnValue {
|
|
1351
|
+
constructor(value) { this.value = value; }
|
|
1352
|
+
}
|
|
1351
1353
|
class BreakSignal {}
|
|
1352
1354
|
class ContinueSignal {}
|
|
1353
1355
|
|
|
1354
1356
|
class Environment {
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1357
|
+
constructor(parent = null) {
|
|
1358
|
+
this.store = Object.create(null);
|
|
1359
|
+
this.parent = parent;
|
|
1360
|
+
}
|
|
1359
1361
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1362
|
+
has(name) {
|
|
1363
|
+
if (name in this.store) return true;
|
|
1364
|
+
if (this.parent) return this.parent.has(name);
|
|
1365
|
+
return false;
|
|
1366
|
+
}
|
|
1365
1367
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1368
|
+
get(name) {
|
|
1369
|
+
if (name in this.store) return this.store[name];
|
|
1370
|
+
if (this.parent) return this.parent.get(name);
|
|
1371
|
+
throw new Error(`Undefined variable: ${name}`);
|
|
1372
|
+
}
|
|
1371
1373
|
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1374
|
+
set(name, value) {
|
|
1375
|
+
if (name in this.store) { this.store[name] = value; return value; }
|
|
1376
|
+
if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
|
|
1377
|
+
this.store[name] = value;
|
|
1378
|
+
return value;
|
|
1379
|
+
}
|
|
1378
1380
|
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1381
|
+
define(name, value) {
|
|
1382
|
+
this.store[name] = value;
|
|
1383
|
+
return value;
|
|
1384
|
+
}
|
|
1383
1385
|
}
|
|
1384
1386
|
|
|
1385
1387
|
class Evaluator {
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1388
|
+
constructor() {
|
|
1389
|
+
this.global = new Environment();
|
|
1390
|
+
this.setupBuiltins();
|
|
1391
|
+
}
|
|
1390
1392
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
this.global.define('print', arg => { console.log(arg); return null; });
|
|
1399
|
-
this.global.define('type', arg => Array.isArray(arg) ? 'array' : typeof arg);
|
|
1400
|
-
this.global.define('keys', arg => arg && typeof arg === 'object' ? Object.keys(arg) : []);
|
|
1401
|
-
this.global.define('values', arg => arg && typeof arg === 'object' ? Object.values(arg) : []);
|
|
1402
|
-
|
|
1403
|
-
this.global.define('ask', prompt => readlineSync.question(prompt + ' '));
|
|
1404
|
-
this.global.define('num', arg => {
|
|
1405
|
-
const n = Number(arg);
|
|
1406
|
-
if (Number.isNaN(n)) throw new Error('Cannot convert value to number');
|
|
1407
|
-
return n;
|
|
1408
|
-
});
|
|
1409
|
-
this.global.define('str', arg => String(arg));
|
|
1410
|
-
|
|
1411
|
-
// Async fetch built-in for API requests
|
|
1412
|
-
this.global.define('fetch', async (url, options) => {
|
|
1413
|
-
const fetch = __nccwpck_require__(266); // Make sure node-fetch is installed
|
|
1414
|
-
const res = await fetch(url, options);
|
|
1415
|
-
return res;
|
|
1416
|
-
});
|
|
1417
|
-
}
|
|
1393
|
+
setupBuiltins() {
|
|
1394
|
+
this.global.define('len', arg => {
|
|
1395
|
+
if (Array.isArray(arg) || typeof arg === 'string') return arg.length;
|
|
1396
|
+
if (arg && typeof arg === 'object') return Object.keys(arg).length;
|
|
1397
|
+
return 0;
|
|
1398
|
+
});
|
|
1418
1399
|
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
case 'SldeployStatement': return await this.evalSldeploy(node, env);
|
|
1427
|
-
case 'AskStatement': return await this.evalAsk(node, env);
|
|
1428
|
-
case 'DefineStatement': return await this.evalDefine(node, env);
|
|
1429
|
-
case 'ExpressionStatement': return await this.evaluate(node.expression, env);
|
|
1430
|
-
case 'BinaryExpression': return await this.evalBinary(node, env);
|
|
1431
|
-
case 'LogicalExpression': return await this.evalLogical(node, env);
|
|
1432
|
-
case 'UnaryExpression': return await this.evalUnary(node, env);
|
|
1433
|
-
case 'Literal': return node.value;
|
|
1434
|
-
case 'Identifier': return env.get(node.name);
|
|
1435
|
-
case 'IfStatement': return await this.evalIf(node, env);
|
|
1436
|
-
case 'WhileStatement': return await this.evalWhile(node, env);
|
|
1437
|
-
case 'ForStatement': return await this.evalFor(node, env);
|
|
1438
|
-
case 'BreakStatement': throw new BreakSignal();
|
|
1439
|
-
case 'ContinueStatement': throw new ContinueSignal();
|
|
1440
|
-
case 'ImportStatement': return await this.evalImport(node, env);
|
|
1441
|
-
case 'FunctionDeclaration': return await this.evalFunctionDeclaration(node, env);
|
|
1442
|
-
case 'CallExpression': return await this.evalCall(node, env);
|
|
1443
|
-
case 'ArrowFunctionExpression': return await this.evalArrowFunction(node, env);
|
|
1444
|
-
case 'ReturnStatement': {
|
|
1445
|
-
const val = node.argument ? await this.evaluate(node.argument, env) : null;
|
|
1446
|
-
throw new ReturnValue(val);
|
|
1447
|
-
}
|
|
1448
|
-
case 'ArrayExpression': return await Promise.all(node.elements.map(el => this.evaluate(el, env)));
|
|
1449
|
-
case 'IndexExpression': return await this.evalIndex(node, env);
|
|
1450
|
-
case 'ObjectExpression': return await this.evalObject(node, env);
|
|
1451
|
-
case 'MemberExpression': return await this.evalMember(node, env);
|
|
1452
|
-
case 'UpdateExpression': return await this.evalUpdate(node, env);
|
|
1453
|
-
default:
|
|
1454
|
-
throw new Error(`Unknown node type in evaluator: ${node.type}`);
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1400
|
+
this.global.define('print', arg => { console.log(arg); return null; });
|
|
1401
|
+
this.global.define('type', arg => {
|
|
1402
|
+
if (Array.isArray(arg)) return 'array';
|
|
1403
|
+
return typeof arg;
|
|
1404
|
+
});
|
|
1405
|
+
this.global.define('keys', arg => arg && typeof arg === 'object' ? Object.keys(arg) : []);
|
|
1406
|
+
this.global.define('values', arg => arg && typeof arg === 'object' ? Object.values(arg) : []);
|
|
1457
1407
|
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1408
|
+
this.global.define('ask', prompt => {
|
|
1409
|
+
const readlineSync = __nccwpck_require__(552);
|
|
1410
|
+
return readlineSync.question(prompt + ' ');
|
|
1411
|
+
});
|
|
1412
|
+
this.global.define('num', arg => {
|
|
1413
|
+
const n = Number(arg);
|
|
1414
|
+
if (Number.isNaN(n)) {
|
|
1415
|
+
throw new Error('Cannot convert value to number');
|
|
1416
|
+
}
|
|
1417
|
+
return n;
|
|
1418
|
+
});
|
|
1419
|
+
this.global.define('fetch', async (url, options = {}) => {
|
|
1420
|
+
const res = await fetch(url, options);
|
|
1421
|
+
return {
|
|
1422
|
+
status: res.status,
|
|
1423
|
+
ok: res.ok,
|
|
1424
|
+
text: async () => await res.text(),
|
|
1425
|
+
json: async () => await res.json()
|
|
1426
|
+
};
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1429
|
+
// GET request
|
|
1430
|
+
this.global.define('get', async (url) => {
|
|
1431
|
+
const res = await fetch(url);
|
|
1432
|
+
return await res.json();
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
this.global.define('post', async (url, data) => {
|
|
1436
|
+
const res = await fetch(url, {
|
|
1437
|
+
method: 'POST',
|
|
1438
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1439
|
+
body: JSON.stringify(data)
|
|
1440
|
+
});
|
|
1441
|
+
return await res.json();
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1444
|
+
this.global.define('sleep', async (ms) => {
|
|
1445
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1446
|
+
});
|
|
1447
|
+
this.global.define('str', arg => {
|
|
1448
|
+
return String(arg);
|
|
1449
|
+
});
|
|
1463
1450
|
|
|
1464
|
-
|
|
1465
|
-
let result = null;
|
|
1466
|
-
for (const stmt of node.body) {
|
|
1467
|
-
try { result = await this.evaluate(stmt, env); }
|
|
1468
|
-
catch (e) {
|
|
1469
|
-
if (e instanceof ReturnValue || e instanceof BreakSignal || e instanceof ContinueSignal) throw e;
|
|
1470
|
-
throw e;
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
return result;
|
|
1474
|
-
}
|
|
1451
|
+
}
|
|
1475
1452
|
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1453
|
+
async evaluate(node, env = this.global) {
|
|
1454
|
+
switch (node.type) {
|
|
1455
|
+
case 'Program': return await this.evalProgram(node, env);
|
|
1456
|
+
case 'BlockStatement': return await this.evalBlock(node, new Environment(env));
|
|
1457
|
+
case 'VarDeclaration': return await this.evalVarDeclaration(node, env);
|
|
1458
|
+
case 'AssignmentExpression': return await this.evalAssignment(node, env);
|
|
1459
|
+
case 'CompoundAssignment': return await this.evalCompoundAssignment(node, env);
|
|
1460
|
+
case 'SldeployStatement': return await this.evalSldeploy(node, env);
|
|
1461
|
+
case 'AskStatement': return await this.evalAsk(node, env);
|
|
1462
|
+
case 'DefineStatement': return await this.evalDefine(node, env);
|
|
1463
|
+
case 'ExpressionStatement': return await this.evaluate(node.expression, env);
|
|
1464
|
+
case 'BinaryExpression': return await this.evalBinary(node, env);
|
|
1465
|
+
case 'LogicalExpression': return await this.evalLogical(node, env);
|
|
1466
|
+
case 'UnaryExpression': return await this.evalUnary(node, env);
|
|
1467
|
+
case 'Literal': return node.value;
|
|
1468
|
+
case 'Identifier': return env.get(node.name);
|
|
1469
|
+
case 'IfStatement': return await this.evalIf(node, env);
|
|
1470
|
+
case 'WhileStatement': return await this.evalWhile(node, env);
|
|
1471
|
+
case 'ForStatement': return await this.evalFor(node, env);
|
|
1472
|
+
case 'BreakStatement': throw new BreakSignal();
|
|
1473
|
+
case 'ContinueStatement': throw new ContinueSignal();
|
|
1474
|
+
case 'ImportStatement': return await this.evalImport(node, env);
|
|
1475
|
+
case 'FunctionDeclaration': return this.evalFunctionDeclaration(node, env);
|
|
1476
|
+
case 'CallExpression': return await this.evalCall(node, env);
|
|
1477
|
+
case 'ArrowFunctionExpression': return this.evalArrowFunction(node, env);
|
|
1478
|
+
case 'ReturnStatement': {
|
|
1479
|
+
const val = node.argument ? await this.evaluate(node.argument, env) : null;
|
|
1480
|
+
throw new ReturnValue(val);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
case 'ArrayExpression':
|
|
1484
|
+
return await Promise.all(node.elements.map(el => this.evaluate(el, env)));
|
|
1485
|
+
case 'IndexExpression': return await this.evalIndex(node, env);
|
|
1486
|
+
case 'ObjectExpression': {
|
|
1487
|
+
const out = {};
|
|
1488
|
+
for (const p of node.props) {
|
|
1489
|
+
out[p.key] = await this.evaluate(p.value, env);
|
|
1490
|
+
}
|
|
1491
|
+
return out;
|
|
1479
1492
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1493
|
+
case 'MemberExpression': return await this.evalMember(node, env);
|
|
1494
|
+
case 'UpdateExpression': return await this.evalUpdate(node, env);
|
|
1495
|
+
case 'AwaitExpression': {
|
|
1496
|
+
const val = await this.evaluate(node.argument, env);
|
|
1497
|
+
return val;
|
|
1483
1498
|
}
|
|
1499
|
+
default:
|
|
1500
|
+
throw new Error(`Unknown node type in evaluator: ${node.type}`);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1484
1503
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1504
|
+
async evalProgram(node, env) {
|
|
1505
|
+
let result = null;
|
|
1506
|
+
for (const stmt of node.body) {
|
|
1507
|
+
result = await this.evaluate(stmt, env);
|
|
1508
|
+
}
|
|
1509
|
+
return result;
|
|
1510
|
+
}
|
|
1488
1511
|
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1512
|
+
async evalImport(node, env) {
|
|
1513
|
+
const spec = node.path;
|
|
1514
|
+
let lib;
|
|
1515
|
+
|
|
1516
|
+
try {
|
|
1517
|
+
const resolved = require.resolve(spec, {
|
|
1518
|
+
paths: [process.cwd()]
|
|
1519
|
+
});
|
|
1520
|
+
lib = require(resolved);
|
|
1521
|
+
} catch (e) {
|
|
1522
|
+
const fullPath = path.isAbsolute(spec)
|
|
1523
|
+
? spec
|
|
1524
|
+
: path.join(process.cwd(), spec.endsWith('.sl') ? spec : spec + '.sl');
|
|
1525
|
+
|
|
1526
|
+
if (!fs.existsSync(fullPath)) {
|
|
1527
|
+
throw new Error(`Import not found: ${spec}`);
|
|
1502
1528
|
}
|
|
1503
1529
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
if (left.type === 'Identifier') current = env.get(left.name);
|
|
1508
|
-
else if (left.type === 'MemberExpression') current = await this.evalMember(left, env);
|
|
1509
|
-
else if (left.type === 'IndexExpression') current = await this.evalIndex(left, env);
|
|
1510
|
-
else throw new Error('Invalid compound assignment target');
|
|
1511
|
-
|
|
1512
|
-
const rhs = await this.evaluate(node.right, env);
|
|
1513
|
-
let computed;
|
|
1514
|
-
switch (node.operator) {
|
|
1515
|
-
case 'PLUSEQ': computed = current + rhs; break;
|
|
1516
|
-
case 'MINUSEQ': computed = current - rhs; break;
|
|
1517
|
-
case 'STAREQ': computed = current * rhs; break;
|
|
1518
|
-
case 'SLASHEQ': computed = current / rhs; break;
|
|
1519
|
-
case 'MODEQ': computed = current % rhs; break;
|
|
1520
|
-
default: throw new Error('Unknown compound operator');
|
|
1521
|
-
}
|
|
1530
|
+
const code = fs.readFileSync(fullPath, 'utf-8');
|
|
1531
|
+
const tokens = new Lexer(code).getTokens();
|
|
1532
|
+
const ast = new Parser(tokens).parse();
|
|
1522
1533
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1534
|
+
const moduleEnv = new Environment(env);
|
|
1535
|
+
await this.evaluate(ast, moduleEnv);
|
|
1525
1536
|
|
|
1526
|
-
|
|
1537
|
+
lib = {};
|
|
1538
|
+
for (const key of Object.keys(moduleEnv.store)) {
|
|
1539
|
+
lib[key] = moduleEnv.store[key];
|
|
1527
1540
|
}
|
|
1528
1541
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
console.log(val);
|
|
1532
|
-
return val;
|
|
1533
|
-
}
|
|
1542
|
+
lib.default = lib;
|
|
1543
|
+
}
|
|
1534
1544
|
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1545
|
+
for (const imp of node.specifiers) {
|
|
1546
|
+
if (imp.type === 'DefaultImport') {
|
|
1547
|
+
env.define(imp.local, lib.default ?? lib);
|
|
1538
1548
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
const val = node.expr ? await this.evaluate(node.expr, env) : null;
|
|
1542
|
-
return this.global.define(node.id, val);
|
|
1549
|
+
if (imp.type === 'NamespaceImport') {
|
|
1550
|
+
env.define(imp.local, lib);
|
|
1543
1551
|
}
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
if (node.operator === 'SLASH' && r === 0) throw new Error('Division by zero');
|
|
1550
|
-
|
|
1551
|
-
switch (node.operator) {
|
|
1552
|
-
case 'PLUS': return l + r;
|
|
1553
|
-
case 'MINUS': return l - r;
|
|
1554
|
-
case 'STAR': return l * r;
|
|
1555
|
-
case 'SLASH': return l / r;
|
|
1556
|
-
case 'MOD': return l % r;
|
|
1557
|
-
case 'EQEQ': return l === r;
|
|
1558
|
-
case 'NOTEQ': return l !== r;
|
|
1559
|
-
case 'LT': return l < r;
|
|
1560
|
-
case 'LTE': return l <= r;
|
|
1561
|
-
case 'GT': return l > r;
|
|
1562
|
-
case 'GTE': return l >= r;
|
|
1563
|
-
default: throw new Error(`Unknown binary operator ${node.operator}`);
|
|
1564
|
-
}
|
|
1552
|
+
if (imp.type === 'NamedImport') {
|
|
1553
|
+
if (!(imp.imported in lib)) {
|
|
1554
|
+
throw new Error(`Module '${spec}' has no export '${imp.imported}'`);
|
|
1555
|
+
}
|
|
1556
|
+
env.define(imp.local, lib[imp.imported]);
|
|
1565
1557
|
}
|
|
1558
|
+
}
|
|
1566
1559
|
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
if (node.operator === 'AND') return l && await this.evaluate(node.right, env);
|
|
1570
|
-
if (node.operator === 'OR') return l || await this.evaluate(node.right, env);
|
|
1571
|
-
throw new Error(`Unknown logical operator ${node.operator}`);
|
|
1572
|
-
}
|
|
1560
|
+
return null;
|
|
1561
|
+
}
|
|
1573
1562
|
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1563
|
+
async evalBlock(node, env) {
|
|
1564
|
+
let result = null;
|
|
1565
|
+
for (const stmt of node.body) {
|
|
1566
|
+
try {
|
|
1567
|
+
result = await this.evaluate(stmt, env);
|
|
1568
|
+
} catch (e) {
|
|
1569
|
+
if (e instanceof ReturnValue || e instanceof BreakSignal || e instanceof ContinueSignal) throw e;
|
|
1570
|
+
throw e;
|
|
1582
1571
|
}
|
|
1572
|
+
}
|
|
1573
|
+
return result;
|
|
1574
|
+
}
|
|
1583
1575
|
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
return null;
|
|
1589
|
-
}
|
|
1576
|
+
async evalVarDeclaration(node, env) {
|
|
1577
|
+
const val = await this.evaluate(node.expr, env);
|
|
1578
|
+
return env.define(node.id, val);
|
|
1579
|
+
}
|
|
1590
1580
|
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1581
|
+
evalArrowFunction(node, env) {
|
|
1582
|
+
return {
|
|
1583
|
+
params: node.params,
|
|
1584
|
+
body: node.body,
|
|
1585
|
+
env: env,
|
|
1586
|
+
arrow: true,
|
|
1587
|
+
async: node.async || false
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1598
1590
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
while (!node.test || await this.evaluate(node.test, local)) {
|
|
1603
|
-
try { await this.evaluate(node.body, local); }
|
|
1604
|
-
catch (e) {
|
|
1605
|
-
if (e instanceof BreakSignal) break;
|
|
1606
|
-
if (e instanceof ContinueSignal) { if (node.update) await this.evaluate(node.update, local); continue; }
|
|
1607
|
-
throw e;
|
|
1608
|
-
}
|
|
1609
|
-
if (node.update) await this.evaluate(node.update, local);
|
|
1610
|
-
}
|
|
1611
|
-
return null;
|
|
1612
|
-
}
|
|
1591
|
+
async evalAssignment(node, env) {
|
|
1592
|
+
const rightVal = await this.evaluate(node.right, env);
|
|
1593
|
+
const left = node.left;
|
|
1613
1594
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1595
|
+
if (left.type === 'Identifier') return env.set(left.name, rightVal);
|
|
1596
|
+
if (left.type === 'MemberExpression') {
|
|
1597
|
+
const obj = await this.evaluate(left.object, env);
|
|
1598
|
+
obj[left.property] = rightVal;
|
|
1599
|
+
return rightVal;
|
|
1600
|
+
}
|
|
1601
|
+
if (left.type === 'IndexExpression') {
|
|
1602
|
+
const obj = await this.evaluate(left.object, env);
|
|
1603
|
+
const idx = await this.evaluate(left.indexer, env);
|
|
1604
|
+
obj[idx] = rightVal;
|
|
1605
|
+
return rightVal;
|
|
1606
|
+
}
|
|
1619
1607
|
|
|
1620
|
-
|
|
1621
|
-
|
|
1608
|
+
throw new Error('Invalid assignment target');
|
|
1609
|
+
}
|
|
1622
1610
|
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1611
|
+
async evalCompoundAssignment(node, env) {
|
|
1612
|
+
const left = node.left;
|
|
1613
|
+
let current;
|
|
1614
|
+
|
|
1615
|
+
if (left.type === 'Identifier') current = env.get(left.name);
|
|
1616
|
+
else if (left.type === 'MemberExpression') current = await this.evalMember(left, env);
|
|
1617
|
+
else if (left.type === 'IndexExpression') current = await this.evalIndex(left, env);
|
|
1618
|
+
else throw new Error('Invalid compound assignment target');
|
|
1619
|
+
|
|
1620
|
+
const rhs = await this.evaluate(node.right, env);
|
|
1621
|
+
let computed;
|
|
1622
|
+
switch (node.operator) {
|
|
1623
|
+
case 'PLUSEQ': computed = current + rhs; break;
|
|
1624
|
+
case 'MINUSEQ': computed = current - rhs; break;
|
|
1625
|
+
case 'STAREQ': computed = current * rhs; break;
|
|
1626
|
+
case 'SLASHEQ': computed = current / rhs; break;
|
|
1627
|
+
case 'MODEQ': computed = current % rhs; break;
|
|
1628
|
+
default: throw new Error('Unknown compound operator');
|
|
1629
|
+
}
|
|
1628
1630
|
|
|
1629
|
-
|
|
1631
|
+
if (left.type === 'Identifier') env.set(left.name, computed);
|
|
1632
|
+
else if (left.type === 'MemberExpression') await this.evalAssignment({ left, right: { type: 'Literal', value: computed }, type: 'AssignmentExpression' }, env);
|
|
1633
|
+
else await this.evalAssignment({ left, right: { type: 'Literal', value: computed }, type: 'AssignmentExpression' }, env);
|
|
1630
1634
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
for (let i = 0; i < fn.params.length; i++) {
|
|
1634
|
-
const argVal = node.arguments[i] ? await this.evaluate(node.arguments[i], env) : null;
|
|
1635
|
-
callEnv.define(fn.params[i], argVal);
|
|
1636
|
-
}
|
|
1635
|
+
return computed;
|
|
1636
|
+
}
|
|
1637
1637
|
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1638
|
+
async evalSldeploy(node, env) {
|
|
1639
|
+
const val = await this.evaluate(node.expr, env);
|
|
1640
|
+
console.log(val);
|
|
1641
|
+
return val;
|
|
1642
|
+
}
|
|
1643
1643
|
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1644
|
+
async evalAsk(node, env) {
|
|
1645
|
+
const prompt = await this.evaluate(node.prompt, env);
|
|
1646
|
+
const input = readlineSync.question(prompt + ' ');
|
|
1647
|
+
return input;
|
|
1648
|
+
}
|
|
1647
1649
|
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
}
|
|
1650
|
+
async evalDefine(node, env) {
|
|
1651
|
+
const val = node.expr ? await this.evaluate(node.expr, env) : null;
|
|
1652
|
+
return this.global.define(node.id, val);
|
|
1653
|
+
}
|
|
1653
1654
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
return out;
|
|
1658
|
-
}
|
|
1655
|
+
async evalBinary(node, env) {
|
|
1656
|
+
const l = await this.evaluate(node.left, env);
|
|
1657
|
+
const r = await this.evaluate(node.right, env);
|
|
1659
1658
|
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
if (!(node.property in obj)) throw new Error(`Property '${node.property}' does not exist`);
|
|
1664
|
-
return obj[node.property];
|
|
1665
|
-
}
|
|
1659
|
+
if (node.operator === 'SLASH' && r === 0) {
|
|
1660
|
+
throw new Error('Division by zero');
|
|
1661
|
+
}
|
|
1666
1662
|
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1663
|
+
switch (node.operator) {
|
|
1664
|
+
case 'PLUS': return l + r;
|
|
1665
|
+
case 'MINUS': return l - r;
|
|
1666
|
+
case 'STAR': return l * r;
|
|
1667
|
+
case 'SLASH': return l / r;
|
|
1668
|
+
case 'MOD': return l % r;
|
|
1669
|
+
case 'EQEQ': return l === r;
|
|
1670
|
+
case 'NOTEQ': return l !== r;
|
|
1671
|
+
case 'LT': return l < r;
|
|
1672
|
+
case 'LTE': return l <= r;
|
|
1673
|
+
case 'GT': return l > r;
|
|
1674
|
+
case 'GTE': return l >= r;
|
|
1675
|
+
default: throw new Error(`Unknown binary operator ${node.operator}`);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1672
1678
|
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1679
|
+
async evalLogical(node, env) {
|
|
1680
|
+
const l = await this.evaluate(node.left, env);
|
|
1681
|
+
if (node.operator === 'AND') return l && await this.evaluate(node.right, env);
|
|
1682
|
+
if (node.operator === 'OR') return l || await this.evaluate(node.right, env);
|
|
1683
|
+
throw new Error(`Unknown logical operator ${node.operator}`);
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
async evalUnary(node, env) {
|
|
1687
|
+
const val = await this.evaluate(node.argument, env);
|
|
1688
|
+
switch (node.operator) {
|
|
1689
|
+
case 'NOT': return !val;
|
|
1690
|
+
case 'MINUS': return -val;
|
|
1691
|
+
case 'PLUS': return +val;
|
|
1692
|
+
default: throw new Error(`Unknown unary operator ${node.operator}`);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
async evalIf(node, env) {
|
|
1697
|
+
const test = await this.evaluate(node.test, env);
|
|
1698
|
+
if (test) return await this.evaluate(node.consequent, env);
|
|
1699
|
+
if (node.alternate) return await this.evaluate(node.alternate, env);
|
|
1700
|
+
return null;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
async evalWhile(node, env) {
|
|
1704
|
+
while (await this.evaluate(node.test, env)) {
|
|
1705
|
+
try { await this.evaluate(node.body, env); }
|
|
1706
|
+
catch (e) {
|
|
1707
|
+
if (e instanceof BreakSignal) break;
|
|
1708
|
+
if (e instanceof ContinueSignal) continue;
|
|
1709
|
+
throw e;
|
|
1677
1710
|
}
|
|
1711
|
+
}
|
|
1712
|
+
return null;
|
|
1713
|
+
}
|
|
1678
1714
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
};
|
|
1692
|
-
|
|
1693
|
-
const current = await getCurrent();
|
|
1694
|
-
const newVal = (node.operator === 'PLUSPLUS') ? current + 1 : current - 1;
|
|
1695
|
-
|
|
1696
|
-
if (node.prefix) { await setValue(newVal); return newVal; }
|
|
1697
|
-
else { await setValue(newVal); return current; }
|
|
1715
|
+
async evalFor(node, env) {
|
|
1716
|
+
const local = new Environment(env);
|
|
1717
|
+
if (node.init) await this.evaluate(node.init, local);
|
|
1718
|
+
while (!node.test || await this.evaluate(node.test, local)) {
|
|
1719
|
+
try { await this.evaluate(node.body, local); }
|
|
1720
|
+
catch (e) {
|
|
1721
|
+
if (e instanceof BreakSignal) break;
|
|
1722
|
+
if (e instanceof ContinueSignal) {
|
|
1723
|
+
if (node.update) await this.evaluate(node.update, local);
|
|
1724
|
+
continue;
|
|
1725
|
+
}
|
|
1726
|
+
throw e;
|
|
1698
1727
|
}
|
|
1728
|
+
if (node.update) await this.evaluate(node.update, local);
|
|
1729
|
+
}
|
|
1730
|
+
return null;
|
|
1731
|
+
}
|
|
1699
1732
|
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1733
|
+
evalFunctionDeclaration(node, env) {
|
|
1734
|
+
const fn = { params: node.params, body: node.body, env, async: node.async || false };
|
|
1735
|
+
env.define(node.name, fn);
|
|
1736
|
+
return null;
|
|
1737
|
+
}
|
|
1703
1738
|
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1739
|
+
async evalCall(node, env) {
|
|
1740
|
+
const calleeEvaluated = await this.evaluate(node.callee, env);
|
|
1741
|
+
if (typeof calleeEvaluated === 'function') {
|
|
1742
|
+
const args = [];
|
|
1743
|
+
for (const a of node.arguments) args.push(await this.evaluate(a, env));
|
|
1744
|
+
return calleeEvaluated(...args);
|
|
1745
|
+
}
|
|
1746
|
+
if (!calleeEvaluated || typeof calleeEvaluated !== 'object' || !calleeEvaluated.body) {
|
|
1747
|
+
throw new Error('Call to non-function');
|
|
1748
|
+
}
|
|
1710
1749
|
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
const ast = new Parser(tokens).parse();
|
|
1750
|
+
const fn = calleeEvaluated;
|
|
1751
|
+
const callEnv = new Environment(fn.env);
|
|
1714
1752
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1753
|
+
for (let i = 0; i < fn.params.length; i++) {
|
|
1754
|
+
const argVal = node.arguments[i] ? await this.evaluate(node.arguments[i], env) : null;
|
|
1755
|
+
callEnv.define(fn.params[i], argVal);
|
|
1756
|
+
}
|
|
1717
1757
|
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1758
|
+
try {
|
|
1759
|
+
const result = await this.evaluate(fn.body, callEnv);
|
|
1760
|
+
return fn.arrow ? result : result;
|
|
1761
|
+
} catch (e) {
|
|
1762
|
+
if (e instanceof ReturnValue) return e.value;
|
|
1763
|
+
throw e;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1722
1766
|
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1767
|
+
async evalIndex(node, env) {
|
|
1768
|
+
const obj = await this.evaluate(node.object, env);
|
|
1769
|
+
const idx = await this.evaluate(node.indexer, env);
|
|
1770
|
+
|
|
1771
|
+
if (obj == null) throw new Error('Indexing null or undefined');
|
|
1772
|
+
if (Array.isArray(obj) && (idx < 0 || idx >= obj.length)) {
|
|
1773
|
+
throw new Error('Array index out of bounds');
|
|
1774
|
+
}
|
|
1775
|
+
if (typeof obj === 'object' && !(idx in obj)) {
|
|
1776
|
+
throw new Error(`Property '${idx}' does not exist`);
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
return obj[idx];
|
|
1780
|
+
}
|
|
1731
1781
|
|
|
1732
|
-
|
|
1782
|
+
async evalObject(node, env) {
|
|
1783
|
+
const out = {};
|
|
1784
|
+
for (const p of node.props) out[p.key] = await this.evaluate(p.value, env);
|
|
1785
|
+
return out;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
async evalMember(node, env) {
|
|
1789
|
+
const obj = await this.evaluate(node.object, env);
|
|
1790
|
+
if (obj == null) throw new Error('Member access of null or undefined');
|
|
1791
|
+
if (!(node.property in obj)) throw new Error(`Property '${node.property}' does not exist`);
|
|
1792
|
+
return obj[node.property];
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
async evalUpdate(node, env) {
|
|
1796
|
+
const arg = node.argument;
|
|
1797
|
+
const getCurrent = async () => {
|
|
1798
|
+
if (arg.type === 'Identifier') return env.get(arg.name);
|
|
1799
|
+
if (arg.type === 'MemberExpression') return await this.evalMember(arg, env);
|
|
1800
|
+
if (arg.type === 'IndexExpression') return await this.evalIndex(arg, env);
|
|
1801
|
+
throw new Error('Invalid update target');
|
|
1802
|
+
};
|
|
1803
|
+
const setValue = async (v) => {
|
|
1804
|
+
if (arg.type === 'Identifier') env.set(arg.name, v);
|
|
1805
|
+
else if (arg.type === 'MemberExpression') {
|
|
1806
|
+
const obj = await this.evaluate(arg.object, env);
|
|
1807
|
+
obj[arg.property] = v;
|
|
1808
|
+
} else if (arg.type === 'IndexExpression') {
|
|
1809
|
+
const obj = await this.evaluate(arg.object, env);
|
|
1810
|
+
const idx = await this.evaluate(arg.indexer, env);
|
|
1811
|
+
obj[idx] = v;
|
|
1733
1812
|
}
|
|
1813
|
+
};
|
|
1814
|
+
|
|
1815
|
+
const current = await getCurrent();
|
|
1816
|
+
const newVal = (node.operator === 'PLUSPLUS') ? current + 1 : current - 1;
|
|
1817
|
+
|
|
1818
|
+
if (node.prefix) { await setValue(newVal); return newVal; }
|
|
1819
|
+
else { await setValue(newVal); return current; }
|
|
1734
1820
|
}
|
|
1735
1821
|
|
|
1736
|
-
|
|
1737
|
-
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
module.exports = Evaluator;
|
|
1738
1825
|
|
|
1739
1826
|
/***/ }),
|
|
1740
1827
|
|
|
@@ -1822,10 +1909,13 @@ class Lexer {
|
|
|
1822
1909
|
}
|
|
1823
1910
|
|
|
1824
1911
|
const keywords = [
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1912
|
+
'let', 'sldeploy', 'if', 'else', 'while', 'for',
|
|
1913
|
+
'break', 'continue', 'func', 'return',
|
|
1914
|
+
'true', 'false', 'null',
|
|
1915
|
+
'ask', 'define', 'import', 'from', 'as',
|
|
1916
|
+
'async', 'await'
|
|
1917
|
+
];
|
|
1918
|
+
|
|
1829
1919
|
|
|
1830
1920
|
if (keywords.includes(result)) {
|
|
1831
1921
|
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
@@ -1965,6 +2055,11 @@ class Parser {
|
|
|
1965
2055
|
}
|
|
1966
2056
|
|
|
1967
2057
|
statement() {
|
|
2058
|
+
if (this.current.type === 'ASYNC' && this.peekType() === 'FUNC') {
|
|
2059
|
+
this.eat('ASYNC');
|
|
2060
|
+
this.eat('FUNC');
|
|
2061
|
+
return this.asyncFuncDeclaration();
|
|
2062
|
+
}
|
|
1968
2063
|
switch (this.current.type) {
|
|
1969
2064
|
case 'LET': return this.varDeclaration();
|
|
1970
2065
|
case 'SLDEPLOY': return this.sldeployStatement();
|
|
@@ -2012,6 +2107,24 @@ class Parser {
|
|
|
2012
2107
|
if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
|
|
2013
2108
|
return { type: 'DefineStatement', id, expr };
|
|
2014
2109
|
}
|
|
2110
|
+
asyncFuncDeclaration() {
|
|
2111
|
+
const name = this.current.value;
|
|
2112
|
+
this.eat('IDENTIFIER');
|
|
2113
|
+
this.eat('LPAREN');
|
|
2114
|
+
const params = [];
|
|
2115
|
+
if (this.current.type !== 'RPAREN') {
|
|
2116
|
+
params.push(this.current.value);
|
|
2117
|
+
this.eat('IDENTIFIER');
|
|
2118
|
+
while (this.current.type === 'COMMA') {
|
|
2119
|
+
this.eat('COMMA');
|
|
2120
|
+
params.push(this.current.value);
|
|
2121
|
+
this.eat('IDENTIFIER');
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
this.eat('RPAREN');
|
|
2125
|
+
const body = this.block();
|
|
2126
|
+
return { type: 'FunctionDeclaration', name, params, body, async: true };
|
|
2127
|
+
}
|
|
2015
2128
|
|
|
2016
2129
|
ifStatement() {
|
|
2017
2130
|
this.eat('IF');
|
|
@@ -2320,7 +2433,11 @@ arrowFunction(params) {
|
|
|
2320
2433
|
if (t.type === 'TRUE') { this.eat('TRUE'); return { type: 'Literal', value: true }; }
|
|
2321
2434
|
if (t.type === 'FALSE') { this.eat('FALSE'); return { type: 'Literal', value: false }; }
|
|
2322
2435
|
if (t.type === 'NULL') { this.eat('NULL'); return { type: 'Literal', value: null }; }
|
|
2323
|
-
|
|
2436
|
+
if (t.type === 'AWAIT') {
|
|
2437
|
+
this.eat('AWAIT');
|
|
2438
|
+
const argument = this.expression();
|
|
2439
|
+
return { type: 'AwaitExpression', argument };
|
|
2440
|
+
}
|
|
2324
2441
|
if (t.type === 'ASK') {
|
|
2325
2442
|
this.eat('ASK');
|
|
2326
2443
|
this.eat('LPAREN');
|
|
@@ -2416,14 +2533,6 @@ arrowFunction(params) {
|
|
|
2416
2533
|
|
|
2417
2534
|
module.exports = Parser;
|
|
2418
2535
|
|
|
2419
|
-
/***/ }),
|
|
2420
|
-
|
|
2421
|
-
/***/ 266:
|
|
2422
|
-
/***/ ((module) => {
|
|
2423
|
-
|
|
2424
|
-
module.exports = eval("require")("node-fetch");
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
2536
|
/***/ }),
|
|
2428
2537
|
|
|
2429
2538
|
/***/ 317:
|
|
@@ -2524,7 +2633,7 @@ const Lexer = __nccwpck_require__(211);
|
|
|
2524
2633
|
const Parser = __nccwpck_require__(222);
|
|
2525
2634
|
const Evaluator = __nccwpck_require__(112);
|
|
2526
2635
|
|
|
2527
|
-
const VERSION = '1.0.
|
|
2636
|
+
const VERSION = '1.0.26';
|
|
2528
2637
|
|
|
2529
2638
|
const COLOR = {
|
|
2530
2639
|
reset: '\x1b[0m',
|