starlight-cli 1.0.25 → 1.0.27
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 +456 -341
- package/package.json +1 -1
- package/src/evaluator.js +434 -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,487 @@ 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
|
+
|
|
1641
|
+
if (typeof val === 'object' && val !== null) {
|
|
1642
|
+
console.log(JSON.stringify(val, null, 2));
|
|
1643
|
+
} else {
|
|
1644
|
+
console.log(val);
|
|
1645
|
+
}
|
|
1643
1646
|
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
const idx = await this.evaluate(node.indexer, env);
|
|
1647
|
+
return val;
|
|
1648
|
+
}
|
|
1647
1649
|
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1650
|
+
async evalAsk(node, env) {
|
|
1651
|
+
const prompt = await this.evaluate(node.prompt, env);
|
|
1652
|
+
const input = readlineSync.question(prompt + ' ');
|
|
1653
|
+
return input;
|
|
1654
|
+
}
|
|
1653
1655
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
}
|
|
1656
|
+
async evalDefine(node, env) {
|
|
1657
|
+
const val = node.expr ? await this.evaluate(node.expr, env) : null;
|
|
1658
|
+
return this.global.define(node.id, val);
|
|
1659
|
+
}
|
|
1659
1660
|
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
if (!(node.property in obj)) throw new Error(`Property '${node.property}' does not exist`);
|
|
1664
|
-
return obj[node.property];
|
|
1665
|
-
}
|
|
1661
|
+
async evalBinary(node, env) {
|
|
1662
|
+
const l = await this.evaluate(node.left, env);
|
|
1663
|
+
const r = await this.evaluate(node.right, env);
|
|
1666
1664
|
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1665
|
+
if (node.operator === 'SLASH' && r === 0) {
|
|
1666
|
+
throw new Error('Division by zero');
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
switch (node.operator) {
|
|
1670
|
+
case 'PLUS': return l + r;
|
|
1671
|
+
case 'MINUS': return l - r;
|
|
1672
|
+
case 'STAR': return l * r;
|
|
1673
|
+
case 'SLASH': return l / r;
|
|
1674
|
+
case 'MOD': return l % r;
|
|
1675
|
+
case 'EQEQ': return l === r;
|
|
1676
|
+
case 'NOTEQ': return l !== r;
|
|
1677
|
+
case 'LT': return l < r;
|
|
1678
|
+
case 'LTE': return l <= r;
|
|
1679
|
+
case 'GT': return l > r;
|
|
1680
|
+
case 'GTE': return l >= r;
|
|
1681
|
+
default: throw new Error(`Unknown binary operator ${node.operator}`);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
async evalLogical(node, env) {
|
|
1686
|
+
const l = await this.evaluate(node.left, env);
|
|
1687
|
+
if (node.operator === 'AND') return l && await this.evaluate(node.right, env);
|
|
1688
|
+
if (node.operator === 'OR') return l || await this.evaluate(node.right, env);
|
|
1689
|
+
throw new Error(`Unknown logical operator ${node.operator}`);
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
async evalUnary(node, env) {
|
|
1693
|
+
const val = await this.evaluate(node.argument, env);
|
|
1694
|
+
switch (node.operator) {
|
|
1695
|
+
case 'NOT': return !val;
|
|
1696
|
+
case 'MINUS': return -val;
|
|
1697
|
+
case 'PLUS': return +val;
|
|
1698
|
+
default: throw new Error(`Unknown unary operator ${node.operator}`);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
async evalIf(node, env) {
|
|
1703
|
+
const test = await this.evaluate(node.test, env);
|
|
1704
|
+
if (test) return await this.evaluate(node.consequent, env);
|
|
1705
|
+
if (node.alternate) return await this.evaluate(node.alternate, env);
|
|
1706
|
+
return null;
|
|
1707
|
+
}
|
|
1672
1708
|
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1709
|
+
async evalWhile(node, env) {
|
|
1710
|
+
while (await this.evaluate(node.test, env)) {
|
|
1711
|
+
try { await this.evaluate(node.body, env); }
|
|
1712
|
+
catch (e) {
|
|
1713
|
+
if (e instanceof BreakSignal) break;
|
|
1714
|
+
if (e instanceof ContinueSignal) continue;
|
|
1715
|
+
throw e;
|
|
1677
1716
|
}
|
|
1717
|
+
}
|
|
1718
|
+
return null;
|
|
1719
|
+
}
|
|
1678
1720
|
|
|
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; }
|
|
1721
|
+
async evalFor(node, env) {
|
|
1722
|
+
const local = new Environment(env);
|
|
1723
|
+
if (node.init) await this.evaluate(node.init, local);
|
|
1724
|
+
while (!node.test || await this.evaluate(node.test, local)) {
|
|
1725
|
+
try { await this.evaluate(node.body, local); }
|
|
1726
|
+
catch (e) {
|
|
1727
|
+
if (e instanceof BreakSignal) break;
|
|
1728
|
+
if (e instanceof ContinueSignal) {
|
|
1729
|
+
if (node.update) await this.evaluate(node.update, local);
|
|
1730
|
+
continue;
|
|
1731
|
+
}
|
|
1732
|
+
throw e;
|
|
1698
1733
|
}
|
|
1734
|
+
if (node.update) await this.evaluate(node.update, local);
|
|
1735
|
+
}
|
|
1736
|
+
return null;
|
|
1737
|
+
}
|
|
1699
1738
|
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1739
|
+
evalFunctionDeclaration(node, env) {
|
|
1740
|
+
const fn = { params: node.params, body: node.body, env, async: node.async || false };
|
|
1741
|
+
env.define(node.name, fn);
|
|
1742
|
+
return null;
|
|
1743
|
+
}
|
|
1703
1744
|
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1745
|
+
async evalCall(node, env) {
|
|
1746
|
+
const calleeEvaluated = await this.evaluate(node.callee, env);
|
|
1747
|
+
if (typeof calleeEvaluated === 'function') {
|
|
1748
|
+
const args = [];
|
|
1749
|
+
for (const a of node.arguments) args.push(await this.evaluate(a, env));
|
|
1750
|
+
return calleeEvaluated(...args);
|
|
1751
|
+
}
|
|
1752
|
+
if (!calleeEvaluated || typeof calleeEvaluated !== 'object' || !calleeEvaluated.body) {
|
|
1753
|
+
throw new Error('Call to non-function');
|
|
1754
|
+
}
|
|
1710
1755
|
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
const ast = new Parser(tokens).parse();
|
|
1756
|
+
const fn = calleeEvaluated;
|
|
1757
|
+
const callEnv = new Environment(fn.env);
|
|
1714
1758
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1759
|
+
for (let i = 0; i < fn.params.length; i++) {
|
|
1760
|
+
const argVal = node.arguments[i] ? await this.evaluate(node.arguments[i], env) : null;
|
|
1761
|
+
callEnv.define(fn.params[i], argVal);
|
|
1762
|
+
}
|
|
1717
1763
|
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1764
|
+
try {
|
|
1765
|
+
const result = await this.evaluate(fn.body, callEnv);
|
|
1766
|
+
return fn.arrow ? result : result;
|
|
1767
|
+
} catch (e) {
|
|
1768
|
+
if (e instanceof ReturnValue) return e.value;
|
|
1769
|
+
throw e;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1722
1772
|
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
if (imp.type === 'NamedImport') {
|
|
1727
|
-
if (!(imp.imported in lib)) throw new Error(`Module '${spec}' has no export '${imp.imported}'`);
|
|
1728
|
-
env.define(imp.local, lib[imp.imported]);
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1773
|
+
async evalIndex(node, env) {
|
|
1774
|
+
const obj = await this.evaluate(node.object, env);
|
|
1775
|
+
const idx = await this.evaluate(node.indexer, env);
|
|
1731
1776
|
|
|
1732
|
-
|
|
1777
|
+
if (obj == null) throw new Error('Indexing null or undefined');
|
|
1778
|
+
if (Array.isArray(obj) && (idx < 0 || idx >= obj.length)) {
|
|
1779
|
+
throw new Error('Array index out of bounds');
|
|
1780
|
+
}
|
|
1781
|
+
if (typeof obj === 'object' && !(idx in obj)) {
|
|
1782
|
+
throw new Error(`Property '${idx}' does not exist`);
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
return obj[idx];
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
async evalObject(node, env) {
|
|
1789
|
+
const out = {};
|
|
1790
|
+
for (const p of node.props) out[p.key] = await this.evaluate(p.value, env);
|
|
1791
|
+
return out;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
async evalMember(node, env) {
|
|
1795
|
+
const obj = await this.evaluate(node.object, env);
|
|
1796
|
+
if (obj == null) throw new Error('Member access of null or undefined');
|
|
1797
|
+
if (!(node.property in obj)) throw new Error(`Property '${node.property}' does not exist`);
|
|
1798
|
+
return obj[node.property];
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
async evalUpdate(node, env) {
|
|
1802
|
+
const arg = node.argument;
|
|
1803
|
+
const getCurrent = async () => {
|
|
1804
|
+
if (arg.type === 'Identifier') return env.get(arg.name);
|
|
1805
|
+
if (arg.type === 'MemberExpression') return await this.evalMember(arg, env);
|
|
1806
|
+
if (arg.type === 'IndexExpression') return await this.evalIndex(arg, env);
|
|
1807
|
+
throw new Error('Invalid update target');
|
|
1808
|
+
};
|
|
1809
|
+
const setValue = async (v) => {
|
|
1810
|
+
if (arg.type === 'Identifier') env.set(arg.name, v);
|
|
1811
|
+
else if (arg.type === 'MemberExpression') {
|
|
1812
|
+
const obj = await this.evaluate(arg.object, env);
|
|
1813
|
+
obj[arg.property] = v;
|
|
1814
|
+
} else if (arg.type === 'IndexExpression') {
|
|
1815
|
+
const obj = await this.evaluate(arg.object, env);
|
|
1816
|
+
const idx = await this.evaluate(arg.indexer, env);
|
|
1817
|
+
obj[idx] = v;
|
|
1733
1818
|
}
|
|
1819
|
+
};
|
|
1820
|
+
|
|
1821
|
+
const current = await getCurrent();
|
|
1822
|
+
const newVal = (node.operator === 'PLUSPLUS') ? current + 1 : current - 1;
|
|
1823
|
+
|
|
1824
|
+
if (node.prefix) { await setValue(newVal); return newVal; }
|
|
1825
|
+
else { await setValue(newVal); return current; }
|
|
1734
1826
|
}
|
|
1735
1827
|
|
|
1736
|
-
|
|
1737
|
-
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
module.exports = Evaluator;
|
|
1738
1831
|
|
|
1739
1832
|
/***/ }),
|
|
1740
1833
|
|
|
@@ -1822,10 +1915,13 @@ class Lexer {
|
|
|
1822
1915
|
}
|
|
1823
1916
|
|
|
1824
1917
|
const keywords = [
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1918
|
+
'let', 'sldeploy', 'if', 'else', 'while', 'for',
|
|
1919
|
+
'break', 'continue', 'func', 'return',
|
|
1920
|
+
'true', 'false', 'null',
|
|
1921
|
+
'ask', 'define', 'import', 'from', 'as',
|
|
1922
|
+
'async', 'await'
|
|
1923
|
+
];
|
|
1924
|
+
|
|
1829
1925
|
|
|
1830
1926
|
if (keywords.includes(result)) {
|
|
1831
1927
|
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
@@ -1965,6 +2061,11 @@ class Parser {
|
|
|
1965
2061
|
}
|
|
1966
2062
|
|
|
1967
2063
|
statement() {
|
|
2064
|
+
if (this.current.type === 'ASYNC' && this.peekType() === 'FUNC') {
|
|
2065
|
+
this.eat('ASYNC');
|
|
2066
|
+
this.eat('FUNC');
|
|
2067
|
+
return this.asyncFuncDeclaration();
|
|
2068
|
+
}
|
|
1968
2069
|
switch (this.current.type) {
|
|
1969
2070
|
case 'LET': return this.varDeclaration();
|
|
1970
2071
|
case 'SLDEPLOY': return this.sldeployStatement();
|
|
@@ -2012,6 +2113,24 @@ class Parser {
|
|
|
2012
2113
|
if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
|
|
2013
2114
|
return { type: 'DefineStatement', id, expr };
|
|
2014
2115
|
}
|
|
2116
|
+
asyncFuncDeclaration() {
|
|
2117
|
+
const name = this.current.value;
|
|
2118
|
+
this.eat('IDENTIFIER');
|
|
2119
|
+
this.eat('LPAREN');
|
|
2120
|
+
const params = [];
|
|
2121
|
+
if (this.current.type !== 'RPAREN') {
|
|
2122
|
+
params.push(this.current.value);
|
|
2123
|
+
this.eat('IDENTIFIER');
|
|
2124
|
+
while (this.current.type === 'COMMA') {
|
|
2125
|
+
this.eat('COMMA');
|
|
2126
|
+
params.push(this.current.value);
|
|
2127
|
+
this.eat('IDENTIFIER');
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
this.eat('RPAREN');
|
|
2131
|
+
const body = this.block();
|
|
2132
|
+
return { type: 'FunctionDeclaration', name, params, body, async: true };
|
|
2133
|
+
}
|
|
2015
2134
|
|
|
2016
2135
|
ifStatement() {
|
|
2017
2136
|
this.eat('IF');
|
|
@@ -2320,7 +2439,11 @@ arrowFunction(params) {
|
|
|
2320
2439
|
if (t.type === 'TRUE') { this.eat('TRUE'); return { type: 'Literal', value: true }; }
|
|
2321
2440
|
if (t.type === 'FALSE') { this.eat('FALSE'); return { type: 'Literal', value: false }; }
|
|
2322
2441
|
if (t.type === 'NULL') { this.eat('NULL'); return { type: 'Literal', value: null }; }
|
|
2323
|
-
|
|
2442
|
+
if (t.type === 'AWAIT') {
|
|
2443
|
+
this.eat('AWAIT');
|
|
2444
|
+
const argument = this.expression();
|
|
2445
|
+
return { type: 'AwaitExpression', argument };
|
|
2446
|
+
}
|
|
2324
2447
|
if (t.type === 'ASK') {
|
|
2325
2448
|
this.eat('ASK');
|
|
2326
2449
|
this.eat('LPAREN');
|
|
@@ -2416,14 +2539,6 @@ arrowFunction(params) {
|
|
|
2416
2539
|
|
|
2417
2540
|
module.exports = Parser;
|
|
2418
2541
|
|
|
2419
|
-
/***/ }),
|
|
2420
|
-
|
|
2421
|
-
/***/ 266:
|
|
2422
|
-
/***/ ((module) => {
|
|
2423
|
-
|
|
2424
|
-
module.exports = eval("require")("node-fetch");
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
2542
|
/***/ }),
|
|
2428
2543
|
|
|
2429
2544
|
/***/ 317:
|
|
@@ -2524,7 +2639,7 @@ const Lexer = __nccwpck_require__(211);
|
|
|
2524
2639
|
const Parser = __nccwpck_require__(222);
|
|
2525
2640
|
const Evaluator = __nccwpck_require__(112);
|
|
2526
2641
|
|
|
2527
|
-
const VERSION = '1.0.
|
|
2642
|
+
const VERSION = '1.0.27';
|
|
2528
2643
|
|
|
2529
2644
|
const COLOR = {
|
|
2530
2645
|
reset: '\x1b[0m',
|