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 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 { 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
+ console.log(val);
1641
+ return val;
1642
+ }
1643
1643
 
1644
- async evalIndex(node, env) {
1645
- const obj = await this.evaluate(node.object, env);
1646
- const idx = await this.evaluate(node.indexer, env);
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
- 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 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
- 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
- }
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
- 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
- }
1659
+ if (node.operator === 'SLASH' && r === 0) {
1660
+ throw new Error('Division by zero');
1661
+ }
1666
1662
 
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
- }
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
- 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;
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
- 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; }
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
- async evalImport(node, env) {
1701
- const spec = node.path;
1702
- let lib;
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
- 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}`);
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
- const code = fs.readFileSync(fullPath, 'utf-8');
1712
- const tokens = new Lexer(code).getTokens();
1713
- const ast = new Parser(tokens).parse();
1750
+ const fn = calleeEvaluated;
1751
+ const callEnv = new Environment(fn.env);
1714
1752
 
1715
- const moduleEnv = new Environment(env);
1716
- await this.evaluate(ast, moduleEnv);
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
- lib = {};
1719
- for (const key of Object.keys(moduleEnv.store)) lib[key] = moduleEnv.store[key];
1720
- lib.default = lib;
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
- 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
- }
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
- return null;
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
- module.exports = Evaluator;
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
- 'let', 'sldeploy', 'if', 'else', 'while', 'for',
1826
- 'break', 'continue', 'func', 'return', 'true', 'false', 'null',
1827
- 'ask', 'define', 'import', 'from', 'as'
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.25';
2636
+ const VERSION = '1.0.26';
2528
2637
 
2529
2638
  const COLOR = {
2530
2639
  reset: '\x1b[0m',