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 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 { constructor(value) { this.value = value; } }
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
- constructor(parent = null) {
1356
- this.store = Object.create(null);
1357
- this.parent = parent;
1358
- }
1357
+ constructor(parent = null) {
1358
+ this.store = Object.create(null);
1359
+ this.parent = parent;
1360
+ }
1359
1361
 
1360
- has(name) {
1361
- if (name in this.store) return true;
1362
- if (this.parent) return this.parent.has(name);
1363
- return false;
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
- get(name) {
1367
- if (name in this.store) return this.store[name];
1368
- if (this.parent) return this.parent.get(name);
1369
- throw new Error(`Undefined variable: ${name}`);
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
- set(name, value) {
1373
- if (name in this.store) { this.store[name] = value; return value; }
1374
- if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
1375
- this.store[name] = value;
1376
- return value;
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
- define(name, value) {
1380
- this.store[name] = value;
1381
- return value;
1382
- }
1381
+ define(name, value) {
1382
+ this.store[name] = value;
1383
+ return value;
1384
+ }
1383
1385
  }
1384
1386
 
1385
1387
  class Evaluator {
1386
- constructor() {
1387
- this.global = new Environment();
1388
- this.setupBuiltins();
1389
- }
1388
+ constructor() {
1389
+ this.global = new Environment();
1390
+ this.setupBuiltins();
1391
+ }
1390
1392
 
1391
- setupBuiltins() {
1392
- this.global.define('len', arg => {
1393
- if (Array.isArray(arg) || typeof arg === 'string') return arg.length;
1394
- if (arg && typeof arg === 'object') return Object.keys(arg).length;
1395
- return 0;
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
- async evaluate(node, env = this.global) {
1420
- switch (node.type) {
1421
- case 'Program': return await this.evalProgram(node, env);
1422
- case 'BlockStatement': return await this.evalBlock(node, new Environment(env));
1423
- case 'VarDeclaration': return await this.evalVarDeclaration(node, env);
1424
- case 'AssignmentExpression': return await this.evalAssignment(node, env);
1425
- case 'CompoundAssignment': return await this.evalCompoundAssignment(node, env);
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
- async evalProgram(node, env) {
1459
- let result = null;
1460
- for (const stmt of node.body) result = await this.evaluate(stmt, env);
1461
- return result;
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
- async evalBlock(node, env) {
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
- async evalVarDeclaration(node, env) {
1477
- const val = await this.evaluate(node.expr, env);
1478
- return env.define(node.id, val);
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
- async evalArrowFunction(node, env) {
1482
- return { params: node.params, body: node.body, env, arrow: true };
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
- async evalAssignment(node, env) {
1486
- const rightVal = await this.evaluate(node.right, env);
1487
- const left = node.left;
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
- if (left.type === 'Identifier') return env.set(left.name, rightVal);
1490
- if (left.type === 'MemberExpression') {
1491
- const obj = await this.evalMemberObj(left, env);
1492
- obj[left.property] = rightVal;
1493
- return rightVal;
1494
- }
1495
- if (left.type === 'IndexExpression') {
1496
- const obj = await this.evalIndexObj(left, env);
1497
- const idx = await this.evaluate(left.indexer, env);
1498
- obj[idx] = rightVal;
1499
- return rightVal;
1500
- }
1501
- throw new Error('Invalid assignment target');
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
- async evalCompoundAssignment(node, env) {
1505
- const left = node.left;
1506
- let current;
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
- if (left.type === 'Identifier') env.set(left.name, computed);
1524
- else await this.evalAssignment({ left, right: { type: 'Literal', value: computed }, type: 'AssignmentExpression' }, env);
1534
+ const moduleEnv = new Environment(env);
1535
+ await this.evaluate(ast, moduleEnv);
1525
1536
 
1526
- return computed;
1537
+ lib = {};
1538
+ for (const key of Object.keys(moduleEnv.store)) {
1539
+ lib[key] = moduleEnv.store[key];
1527
1540
  }
1528
1541
 
1529
- async evalSldeploy(node, env) {
1530
- const val = await this.evaluate(node.expr, env);
1531
- console.log(val);
1532
- return val;
1533
- }
1542
+ lib.default = lib;
1543
+ }
1534
1544
 
1535
- async evalAsk(node, env) {
1536
- const prompt = await this.evaluate(node.prompt, env);
1537
- return readlineSync.question(prompt + ' ');
1545
+ for (const imp of node.specifiers) {
1546
+ if (imp.type === 'DefaultImport') {
1547
+ env.define(imp.local, lib.default ?? lib);
1538
1548
  }
1539
-
1540
- async evalDefine(node, env) {
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
- async evalBinary(node, env) {
1546
- const l = await this.evaluate(node.left, env);
1547
- const r = await this.evaluate(node.right, env);
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
- async evalLogical(node, env) {
1568
- const l = await this.evaluate(node.left, env);
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
- async evalUnary(node, env) {
1575
- const val = await this.evaluate(node.argument, env);
1576
- switch (node.operator) {
1577
- case 'NOT': return !val;
1578
- case 'MINUS': return -val;
1579
- case 'PLUS': return +val;
1580
- default: throw new Error(`Unknown unary operator ${node.operator}`);
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
- async evalIf(node, env) {
1585
- const test = await this.evaluate(node.test, env);
1586
- if (test) return await this.evaluate(node.consequent, env);
1587
- if (node.alternate) return await this.evaluate(node.alternate, env);
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
- async evalWhile(node, env) {
1592
- while (await this.evaluate(node.test, env)) {
1593
- try { await this.evaluate(node.body, env); }
1594
- catch (e) { if (e instanceof BreakSignal) break; if (e instanceof ContinueSignal) continue; throw e; }
1595
- }
1596
- return null;
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
- async evalFor(node, env) {
1600
- const local = new Environment(env);
1601
- if (node.init) await this.evaluate(node.init, local);
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
- async evalFunctionDeclaration(node, env) {
1615
- const fn = { params: node.params, body: node.body, env };
1616
- env.define(node.name, fn);
1617
- return null;
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
- async evalCall(node, env) {
1621
- const calleeEvaluated = await this.evaluate(node.callee, env);
1608
+ throw new Error('Invalid assignment target');
1609
+ }
1622
1610
 
1623
- if (typeof calleeEvaluated === 'function') {
1624
- const args = [];
1625
- for (const a of node.arguments) args.push(await this.evaluate(a, env));
1626
- return await calleeEvaluated(...args);
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
- if (!calleeEvaluated || typeof calleeEvaluated !== 'object' || !calleeEvaluated.body) throw new Error('Call to non-function');
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
- const fn = calleeEvaluated;
1632
- const callEnv = new Environment(fn.env);
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
- try {
1639
- const result = await this.evaluate(fn.body, callEnv);
1640
- return fn.arrow ? result : result;
1641
- } catch (e) { if (e instanceof ReturnValue) return e.value; throw e; }
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
- async evalIndex(node, env) {
1645
- const obj = await this.evaluate(node.object, env);
1646
- const idx = await this.evaluate(node.indexer, env);
1647
+ return val;
1648
+ }
1647
1649
 
1648
- if (obj == null) throw new Error('Indexing null or undefined');
1649
- if (Array.isArray(obj) && (idx < 0 || idx >= obj.length)) throw new Error('Array index out of bounds');
1650
- if (typeof obj === 'object' && !(idx in obj)) throw new Error(`Property '${idx}' does not exist`);
1651
- return obj[idx];
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
- async evalObject(node, env) {
1655
- const out = {};
1656
- for (const p of node.props) out[p.key] = await this.evaluate(p.value, env);
1657
- return out;
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
- async evalMember(node, env) {
1661
- const obj = await this.evaluate(node.object, env);
1662
- if (obj == null) throw new Error('Member access of null or undefined');
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
- async evalMemberObj(node, env) {
1668
- const obj = await this.evaluate(node.object, env);
1669
- if (obj == null) throw new Error('Member access of null or undefined');
1670
- return obj;
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
- async evalIndexObj(node, env) {
1674
- const obj = await this.evaluate(node.object, env);
1675
- if (obj == null) throw new Error('Indexing null or undefined');
1676
- return obj;
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
- async evalUpdate(node, env) {
1680
- const arg = node.argument;
1681
- const getCurrent = async () => {
1682
- if (arg.type === 'Identifier') return env.get(arg.name);
1683
- if (arg.type === 'MemberExpression') return await this.evalMember(arg, env);
1684
- if (arg.type === 'IndexExpression') return await this.evalIndex(arg, env);
1685
- throw new Error('Invalid update target');
1686
- };
1687
- const setValue = async (v) => {
1688
- if (arg.type === 'Identifier') env.set(arg.name, v);
1689
- else if (arg.type === 'MemberExpression') { const obj = await this.evalMemberObj(arg, env); obj[arg.property] = v; }
1690
- else if (arg.type === 'IndexExpression') { const obj = await this.evalIndexObj(arg, env); const idx = await this.evaluate(arg.indexer, env); obj[idx] = v; }
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
- async evalImport(node, env) {
1701
- const spec = node.path;
1702
- let lib;
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
- try {
1705
- const resolved = require.resolve(spec, { paths: [process.cwd()] });
1706
- lib = require(resolved);
1707
- } catch (e) {
1708
- const fullPath = path.isAbsolute(spec) ? spec : path.join(process.cwd(), spec.endsWith('.sl') ? spec : spec + '.sl');
1709
- if (!fs.existsSync(fullPath)) throw new Error(`Import not found: ${spec}`);
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
- const code = fs.readFileSync(fullPath, 'utf-8');
1712
- const tokens = new Lexer(code).getTokens();
1713
- const ast = new Parser(tokens).parse();
1756
+ const fn = calleeEvaluated;
1757
+ const callEnv = new Environment(fn.env);
1714
1758
 
1715
- const moduleEnv = new Environment(env);
1716
- await this.evaluate(ast, moduleEnv);
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
- lib = {};
1719
- for (const key of Object.keys(moduleEnv.store)) lib[key] = moduleEnv.store[key];
1720
- lib.default = lib;
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
- for (const imp of node.specifiers) {
1724
- if (imp.type === 'DefaultImport') env.define(imp.local, lib.default ?? lib);
1725
- if (imp.type === 'NamespaceImport') env.define(imp.local, lib);
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
- return null;
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
- module.exports = Evaluator;
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
- 'let', 'sldeploy', 'if', 'else', 'while', 'for',
1826
- 'break', 'continue', 'func', 'return', 'true', 'false', 'null',
1827
- 'ask', 'define', 'import', 'from', 'as'
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.25';
2642
+ const VERSION = '1.0.27';
2528
2643
 
2529
2644
  const COLOR = {
2530
2645
  reset: '\x1b[0m',