naider 1.16.0 → 1.17.0

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/README.md CHANGED
@@ -1405,6 +1405,76 @@ naide pkg list # list installed NAIDE packages
1405
1405
 
1406
1406
  The `naide.pkg.json` manifest tracks NAIDE-specific metadata (main entry, exports, dependencies) while using npm as the underlying registry.
1407
1407
 
1408
+ ## NAIDE vs Python — Side by Side
1409
+
1410
+ **Read a file, process lines, write result:**
1411
+
1412
+ ```python
1413
+ # Python (8 lines)
1414
+ with open("input.txt") as f:
1415
+ lines = f.read().strip().split("\n")
1416
+ upper_lines = [line.upper() for line in lines]
1417
+ result = "\n".join(upper_lines)
1418
+ with open("output.txt", "w") as f:
1419
+ f.write(result)
1420
+ print(f"Processed {len(upper_lines)} lines")
1421
+ ```
1422
+
1423
+ ```python
1424
+ # NAIDE (4 lines)
1425
+ list lines = split(trim(read("input.txt")), "\n")
1426
+ list upper_lines = [upper(line) for line in lines]
1427
+ write("output.txt", join(upper_lines, "\n"))
1428
+ print "Processed {len(upper_lines)} lines"
1429
+ ```
1430
+
1431
+ **Sort, deduplicate, and swap:**
1432
+
1433
+ ```python
1434
+ # Python (5 lines)
1435
+ items = [3, 1, 4, 1, 5]
1436
+ items = sorted(set(items))
1437
+ a, b = 1, 2
1438
+ a, b = b, a
1439
+ print(f"a={a}, b={b}")
1440
+ ```
1441
+
1442
+ ```python
1443
+ # NAIDE (5 lines)
1444
+ list items = unique(sort([3, 1, 4, 1, 5]))
1445
+ mut int a = 1
1446
+ mut int b = 2
1447
+ swap a, b
1448
+ print "a={a}, b={b}"
1449
+ ```
1450
+
1451
+ **Simple API server:**
1452
+
1453
+ ```python
1454
+ # Python + Flask (12 lines)
1455
+ from flask import Flask, jsonify
1456
+ app = Flask(__name__)
1457
+
1458
+ @app.route("/")
1459
+ def index():
1460
+ return jsonify({"message": "Hello"})
1461
+
1462
+ @app.route("/health")
1463
+ def health():
1464
+ return jsonify({"status": "ok"})
1465
+
1466
+ app.run(port=3000)
1467
+ ```
1468
+
1469
+ ```python
1470
+ # NAIDE (5 lines)
1471
+ server app port 3000:
1472
+ get "/":
1473
+ ret {message: "Hello"}
1474
+ get "/health":
1475
+ ret {status: "ok"}
1476
+ ```
1477
+
1408
1478
  ## Why NAIDE?
1409
1479
 
1410
1480
  AI code generation speed depends on:
@@ -1412,6 +1482,7 @@ AI code generation speed depends on:
1412
1482
  1. **Token count** — fewer output tokens = faster generation
1413
1483
  2. **Predictability** — one way to write everything = better next-token prediction
1414
1484
  3. **Context window** — shorter code = more room for complex projects
1485
+ 4. **Simplicity** — built-in functions mean zero imports and less boilerplate
1415
1486
 
1416
1487
  NAIDE-X is designed as an **AI-internal representation** — the AI thinks in NAIDE-X, users receive standard JavaScript.
1417
1488
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naider",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "NAIDE - Simpler than Python, compiles to 15 targets. AI-specialized language with 35+ built-in functions, syntax sugar (unless/until/repeat/swap/is/isnt), and 47 features. Targets: Node.js, Python, TypeScript, C, C++, Java, Go, Rust, PHP, Ruby, Kotlin, Swift, Dart, C#, Bun.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -185,6 +185,8 @@ export class CGenerator {
185
185
  case 'GrpcDecl': return this.visitGrpc(node);
186
186
  case 'WebrtcDecl': return this.visitWebrtc(node);
187
187
  case 'BlockchainDecl': return this.visitBlockchain(node);
188
+ case 'EnumDecl': return this.visitEnum(node);
189
+ case 'Swap': return this.visitSwap(node);
188
190
  default:
189
191
  this.emit(`/* unknown: ${node.type} */`);
190
192
  }
@@ -873,6 +875,12 @@ export class CGenerator {
873
875
  generateCall(node) {
874
876
  const args = node.args.map(a => this.expr(a)).join(', ');
875
877
 
878
+ if (node.callee.type === 'Identifier') {
879
+ const argList = node.args.map(a => this.expr(a));
880
+ const b = this.generateBuiltin(node.callee.name, argList);
881
+ if (b) return b;
882
+ }
883
+
876
884
  if (node.callee.type === 'Identifier') {
877
885
  const name = node.callee.name;
878
886
  if (name === 'parseInt') return `atoi(${args})`;
@@ -974,6 +982,46 @@ export class CGenerator {
974
982
  return result;
975
983
  }
976
984
 
985
+ visitEnum(node) {
986
+ this.emit(`typedef enum {`);
987
+ this.indent++;
988
+ node.values.forEach((v, i) => {
989
+ this.emit(`${node.name}_${v} = ${i},`);
990
+ });
991
+ this.indent--;
992
+ this.emit(`} ${node.name};`);
993
+ this.emitRaw('');
994
+ }
995
+
996
+ visitSwap(node) {
997
+ const a = this.expr(node.a);
998
+ const b = this.expr(node.b);
999
+ const tmp = `_tmp_${a.replace(/[^a-zA-Z0-9]/g, '')}`;
1000
+ this.emit(`{ typeof(${a}) ${tmp} = ${a}; ${a} = ${b}; ${b} = ${tmp}; }`);
1001
+ }
1002
+
1003
+ generateBuiltin(name, args) {
1004
+ switch (name) {
1005
+ case 'len': return `(sizeof(${args[0]}) / sizeof(${args[0]}[0]))`;
1006
+ case 'abs': return `abs(${args[0]})`;
1007
+ case 'sqrt': { this.includes.add('<math.h>'); return `sqrt(${args[0]})`; }
1008
+ case 'pow': { this.includes.add('<math.h>'); return `pow(${args[0]}, ${args[1]})`; }
1009
+ case 'ceil': { this.includes.add('<math.h>'); return `ceil(${args[0]})`; }
1010
+ case 'floor': { this.includes.add('<math.h>'); return `floor(${args[0]})`; }
1011
+ case 'round': { this.includes.add('<math.h>'); return `round(${args[0]})`; }
1012
+ case 'exit': { this.includes.add('<stdlib.h>'); return `exit(${args[0] || '0'})`; }
1013
+ case 'str': return `snprintf(_buf, sizeof(_buf), "%d", ${args[0]})`;
1014
+ case 'int': { this.includes.add('<stdlib.h>'); return `atoi(${args[0]})`; }
1015
+ case 'float': { this.includes.add('<stdlib.h>'); return `atof(${args[0]})`; }
1016
+ case 'upper': { this.includes.add('<ctype.h>'); return `toupper(${args[0]})`; }
1017
+ case 'lower': { this.includes.add('<ctype.h>'); return `tolower(${args[0]})`; }
1018
+ case 'sleep': { this.includes.add('<unistd.h>'); return `usleep(${args[0]} * 1000)`; }
1019
+ case 'now': { this.includes.add('<time.h>'); return `(long long)time(NULL) * 1000`; }
1020
+ case 'random': { this.includes.add('<stdlib.h>'); return args.length >= 2 ? `(rand() % (${args[1]} - ${args[0]} + 1) + ${args[0]})` : `rand()`; }
1021
+ default: return null;
1022
+ }
1023
+ }
1024
+
977
1025
  rawString(strData) {
978
1026
  if (!strData) return '';
979
1027
  if (strData.raw !== null && strData.raw !== undefined) return strData.raw;
@@ -186,6 +186,8 @@ export class CppGenerator {
186
186
  case 'GrpcDecl': return this.visitGrpc(node);
187
187
  case 'WebrtcDecl': return this.visitWebrtc(node);
188
188
  case 'BlockchainDecl': return this.visitBlockchain(node);
189
+ case 'EnumDecl': return this.visitEnum(node);
190
+ case 'Swap': return this.visitSwap(node);
189
191
  default:
190
192
  this.emit(`/* unknown: ${node.type} */`);
191
193
  }
@@ -983,6 +985,10 @@ export class CppGenerator {
983
985
  const args = node.args.map(a => this.expr(a)).join(', ');
984
986
 
985
987
  if (node.callee.type === 'Identifier') {
988
+ const argList = node.args.map(a => this.expr(a));
989
+ const b = this.generateBuiltin(node.callee.name, argList);
990
+ if (b) return b;
991
+
986
992
  const name = node.callee.name;
987
993
  if (name === 'parseInt') return `stoi(${args})`;
988
994
  if (name === 'parseFloat') return `stod(${args})`;
@@ -1208,4 +1214,51 @@ export class CppGenerator {
1208
1214
  this.inFunction = saved;
1209
1215
  return result;
1210
1216
  }
1217
+
1218
+ visitEnum(node) {
1219
+ this.emit(`enum class ${node.name} {`);
1220
+ this.indent++;
1221
+ node.values.forEach((v, i) => {
1222
+ this.emit(`${v} = ${i},`);
1223
+ });
1224
+ this.indent--;
1225
+ this.emit(`};`);
1226
+ this.emitRaw('');
1227
+ }
1228
+
1229
+ visitSwap(node) {
1230
+ this.includes.add('<utility>');
1231
+ const a = this.expr(node.a);
1232
+ const b = this.expr(node.b);
1233
+ this.emit(`std::swap(${a}, ${b});`);
1234
+ }
1235
+
1236
+ generateBuiltin(name, args) {
1237
+ switch (name) {
1238
+ case 'len': return `${args[0]}.size()`;
1239
+ case 'sort': { this.includes.add('<algorithm>'); return `([&](){ auto _v = ${args[0]}; std::sort(_v.begin(), _v.end()); return _v; }())`; }
1240
+ case 'reverse': { this.includes.add('<algorithm>'); return `([&](){ auto _v = ${args[0]}; std::reverse(_v.begin(), _v.end()); return _v; }())`; }
1241
+ case 'contains': return `(std::find(${args[0]}.begin(), ${args[0]}.end(), ${args[1]}) != ${args[0]}.end())`;
1242
+ case 'abs': { this.includes.add('<cmath>'); return `std::abs(${args[0]})`; }
1243
+ case 'sqrt': { this.includes.add('<cmath>'); return `std::sqrt(${args[0]})`; }
1244
+ case 'pow': { this.includes.add('<cmath>'); return `std::pow(${args[0]}, ${args[1]})`; }
1245
+ case 'ceil': { this.includes.add('<cmath>'); return `std::ceil(${args[0]})`; }
1246
+ case 'floor': { this.includes.add('<cmath>'); return `std::floor(${args[0]})`; }
1247
+ case 'round': { this.includes.add('<cmath>'); return `std::round(${args[0]})`; }
1248
+ case 'str': return `std::to_string(${args[0]})`;
1249
+ case 'int': return `std::stoi(${args[0]})`;
1250
+ case 'float': return `std::stof(${args[0]})`;
1251
+ case 'upper': { this.includes.add('<algorithm>'); this.includes.add('<cctype>'); return `([&](){ auto _s = ${args[0]}; std::transform(_s.begin(), _s.end(), _s.begin(), ::toupper); return _s; }())`; }
1252
+ case 'lower': { this.includes.add('<algorithm>'); this.includes.add('<cctype>'); return `([&](){ auto _s = ${args[0]}; std::transform(_s.begin(), _s.end(), _s.begin(), ::tolower); return _s; }())`; }
1253
+ case 'trim': return `([&](){ auto _s = ${args[0]}; _s.erase(0, _s.find_first_not_of(" \\t\\n\\r")); _s.erase(_s.find_last_not_of(" \\t\\n\\r") + 1); return _s; }())`;
1254
+ case 'keys': return `([&](){ std::vector<std::string> _k; for (auto& [k,v] : ${args[0]}) _k.push_back(k); return _k; }())`;
1255
+ case 'values': return `([&](){ std::vector<auto> _v; for (auto& [k,v] : ${args[0]}) _v.push_back(v); return _v; }())`;
1256
+ case 'exit': return `exit(${args[0] || '0'})`;
1257
+ case 'sleep': { this.includes.add('<thread>'); this.includes.add('<chrono>'); return `std::this_thread::sleep_for(std::chrono::milliseconds(${args[0]}))`; }
1258
+ case 'now': { this.includes.add('<chrono>'); return `std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()`; }
1259
+ case 'random': { this.includes.add('<random>'); return args.length >= 2 ? `([](int a, int b){ std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<> dis(a,b); return dis(gen); })(${args[0]}, ${args[1]})` : `([]{ std::random_device rd; return rd(); }())`; }
1260
+ case 'sum': return `([&](){ auto _v = ${args[0]}; return std::accumulate(_v.begin(), _v.end(), 0); }())`;
1261
+ default: return null;
1262
+ }
1263
+ }
1211
1264
  }
@@ -178,6 +178,8 @@ export class CSharpGenerator {
178
178
  case 'GrpcDecl': return this.visitGrpc(node);
179
179
  case 'WebrtcDecl': return this.visitWebrtc(node);
180
180
  case 'BlockchainDecl': return this.visitBlockchain(node);
181
+ case 'EnumDecl': return this.visitEnum(node);
182
+ case 'Swap': return this.visitSwap(node);
181
183
  default:
182
184
  this.emit(`// unknown: ${node.type}`);
183
185
  }
@@ -1431,6 +1433,12 @@ export class CSharpGenerator {
1431
1433
  generateCall(node) {
1432
1434
  const args = node.args.map(a => this.expr(a)).join(', ');
1433
1435
 
1436
+ if (node.callee.type === 'Identifier') {
1437
+ const argList = node.args.map(a => this.expr(a));
1438
+ const b = this.generateBuiltin(node.callee.name, argList);
1439
+ if (b) return b;
1440
+ }
1441
+
1434
1442
  if (node.callee.type === 'Identifier') {
1435
1443
  const name = node.callee.name;
1436
1444
  if (name === 'parseInt') return `int.Parse(${args})`;
@@ -1630,4 +1638,63 @@ export class CSharpGenerator {
1630
1638
  this.indent = savedIndent;
1631
1639
  return result;
1632
1640
  }
1641
+
1642
+ visitEnum(node) {
1643
+ this.emit(`enum ${node.name} {`);
1644
+ this.indent++;
1645
+ this.emit(node.values.join(', '));
1646
+ this.indent--;
1647
+ this.emit(`}`);
1648
+ this.emitRaw('');
1649
+ }
1650
+
1651
+ visitSwap(node) {
1652
+ const a = this.expr(node.a);
1653
+ const b = this.expr(node.b);
1654
+ this.emit(`(${a}, ${b}) = (${b}, ${a});`);
1655
+ }
1656
+
1657
+ generateBuiltin(name, args) {
1658
+ switch (name) {
1659
+ case 'len': return `${args[0]}.Count`;
1660
+ case 'sort': return `${args[0]}.OrderBy(x => x).ToList()`;
1661
+ case 'reverse': return `${args[0]}.AsEnumerable().Reverse().ToList()`;
1662
+ case 'unique': return `${args[0]}.Distinct().ToList()`;
1663
+ case 'upper': return `${args[0]}.ToUpper()`;
1664
+ case 'lower': return `${args[0]}.ToLower()`;
1665
+ case 'trim': return `${args[0]}.Trim()`;
1666
+ case 'split': return `${args[0]}.Split(${args[1] || '","'}).ToList()`;
1667
+ case 'join': return `string.Join(${args[1] || '","'}, ${args[0]})`;
1668
+ case 'contains': return `${args[0]}.Contains(${args[1]})`;
1669
+ case 'replace': return `${args[0]}.Replace(${args[1]}, ${args[2]})`;
1670
+ case 'keys': return `${args[0]}.Keys.ToList()`;
1671
+ case 'values': return `${args[0]}.Values.ToList()`;
1672
+ case 'entries': return `${args[0]}.ToList()`;
1673
+ case 'range': return args.length >= 2 ? `Enumerable.Range(${args[0]}, ${args[1]} - ${args[0]}).ToList()` : `Enumerable.Range(0, ${args[0]}).ToList()`;
1674
+ case 'abs': return `Math.Abs(${args[0]})`;
1675
+ case 'sqrt': return `Math.Sqrt(${args[0]})`;
1676
+ case 'pow': return `Math.Pow(${args[0]}, ${args[1]})`;
1677
+ case 'ceil': return `Math.Ceiling((double)${args[0]})`;
1678
+ case 'floor': return `Math.Floor((double)${args[0]})`;
1679
+ case 'round': return `Math.Round((double)${args[0]})`;
1680
+ case 'sum': return `${args[0]}.Sum()`;
1681
+ case 'flat': return `${args[0]}.SelectMany(x => x).ToList()`;
1682
+ case 'zip': return `${args[0]}.Zip(${args[1]}).ToList()`;
1683
+ case 'chunk': return `${args[0]}.Chunk(${args[1]}).Select(c => c.ToList()).ToList()`;
1684
+ case 'str': return `${args[0]}.ToString()`;
1685
+ case 'int': return `int.Parse(${args[0]})`;
1686
+ case 'float': return `double.Parse(${args[0]})`;
1687
+ case 'json_parse': return `System.Text.Json.JsonSerializer.Deserialize<object>(${args[0]})`;
1688
+ case 'json_str': return `System.Text.Json.JsonSerializer.Serialize(${args[0]})`;
1689
+ case 'now': return `DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()`;
1690
+ case 'time': return `DateTime.Now.ToString("o")`;
1691
+ case 'exit': return `Environment.Exit(${args[0] || '0'})`;
1692
+ case 'sleep': return `Thread.Sleep(${args[0]})`;
1693
+ case 'random': return args.length >= 2 ? `new Random().Next(${args[0]}, ${args[1]} + 1)` : `new Random().NextDouble()`;
1694
+ case 'read': return `File.ReadAllText(${args[0]})`;
1695
+ case 'write': return `File.WriteAllText(${args[0]}, ${args[1]})`;
1696
+ case 'ask': return `(Console.Write(${args[0] || '""'}), Console.ReadLine() ?? "").Item2`;
1697
+ default: return null;
1698
+ }
1699
+ }
1633
1700
  }
@@ -162,6 +162,8 @@ export class DartGenerator {
162
162
  case 'GrpcDecl': return this.visitGrpc(node);
163
163
  case 'WebrtcDecl': return this.visitWebrtc(node);
164
164
  case 'BlockchainDecl': return this.visitBlockchain(node);
165
+ case 'EnumDecl': return this.visitEnum(node);
166
+ case 'Swap': return this.visitSwap(node);
165
167
  default:
166
168
  this.emit(`// unknown: ${node.type}`);
167
169
  }
@@ -1364,6 +1366,12 @@ export class DartGenerator {
1364
1366
  generateCall(node) {
1365
1367
  const args = node.args.map(a => this.expr(a)).join(', ');
1366
1368
 
1369
+ if (node.callee.type === 'Identifier') {
1370
+ const argList = node.args.map(a => this.expr(a));
1371
+ const b = this.generateBuiltin(node.callee.name, argList);
1372
+ if (b) return b;
1373
+ }
1374
+
1367
1375
  if (node.callee.type === 'Identifier') {
1368
1376
  const name = node.callee.name;
1369
1377
  if (name === 'parseInt') return `int.parse(${args})`;
@@ -1566,4 +1574,65 @@ export class DartGenerator {
1566
1574
  this.inFunction = wasInFunction;
1567
1575
  return result;
1568
1576
  }
1577
+
1578
+ visitEnum(node) {
1579
+ this.emit(`enum ${node.name} {`);
1580
+ this.indent++;
1581
+ node.values.forEach(v => {
1582
+ this.emit(`${v.toLowerCase()},`);
1583
+ });
1584
+ this.indent--;
1585
+ this.emit(`}`);
1586
+ this.emitRaw('');
1587
+ }
1588
+
1589
+ visitSwap(node) {
1590
+ const a = this.expr(node.a);
1591
+ const b = this.expr(node.b);
1592
+ this.emit(`{ final _tmp = ${a}; ${a} = ${b}; ${b} = _tmp; }`);
1593
+ }
1594
+
1595
+ generateBuiltin(name, args) {
1596
+ switch (name) {
1597
+ case 'len': return `${args[0]}.length`;
1598
+ case 'sort': return `(List.from(${args[0]})..sort())`;
1599
+ case 'reverse': return `${args[0]}.reversed.toList()`;
1600
+ case 'unique': return `${args[0]}.toSet().toList()`;
1601
+ case 'upper': return `${args[0]}.toUpperCase()`;
1602
+ case 'lower': return `${args[0]}.toLowerCase()`;
1603
+ case 'trim': return `${args[0]}.trim()`;
1604
+ case 'split': return `${args[0]}.split(${args[1] || '","'})`;
1605
+ case 'join': return `${args[0]}.join(${args[1] || '","'})`;
1606
+ case 'contains': return `${args[0]}.contains(${args[1]})`;
1607
+ case 'replace': return `${args[0]}.replaceAll(${args[1]}, ${args[2]})`;
1608
+ case 'keys': return `${args[0]}.keys.toList()`;
1609
+ case 'values': return `${args[0]}.values.toList()`;
1610
+ case 'entries': return `${args[0]}.entries.toList()`;
1611
+ case 'range': return args.length >= 2 ? `List.generate(${args[1]} - ${args[0]}, (i) => i + ${args[0]})` : `List.generate(${args[0]}, (i) => i)`;
1612
+ case 'abs': return `${args[0]}.abs()`;
1613
+ case 'sqrt': { this.addImport('dart:math'); return `sqrt(${args[0]}.toDouble())`; }
1614
+ case 'pow': { this.addImport('dart:math'); return `pow(${args[0]}, ${args[1]})`; }
1615
+ case 'ceil': return `${args[0]}.ceil()`;
1616
+ case 'floor': return `${args[0]}.floor()`;
1617
+ case 'round': return `${args[0]}.round()`;
1618
+ case 'sum': return `${args[0]}.reduce((a, b) => a + b)`;
1619
+ case 'flat': return `${args[0]}.expand((x) => x).toList()`;
1620
+ case 'zip': return `List.generate(${args[0]}.length, (i) => [${args[0]}[i], ${args[1]}[i]])`;
1621
+ case 'chunk': return `[for (var i = 0; i < ${args[0]}.length; i += ${args[1]}) ${args[0]}.sublist(i, i + ${args[1]} > ${args[0]}.length ? ${args[0]}.length : i + ${args[1]})]`;
1622
+ case 'str': return `${args[0]}.toString()`;
1623
+ case 'int': return `int.parse(${args[0]})`;
1624
+ case 'float': return `double.parse(${args[0]})`;
1625
+ case 'json_parse': { this.addImport('dart:convert'); return `jsonDecode(${args[0]})`; }
1626
+ case 'json_str': { this.addImport('dart:convert'); return `jsonEncode(${args[0]})`; }
1627
+ case 'now': return `DateTime.now().millisecondsSinceEpoch`;
1628
+ case 'time': return `DateTime.now().toIso8601String()`;
1629
+ case 'exit': return `exit(${args[0] || '0'})`;
1630
+ case 'sleep': return `await Future.delayed(Duration(milliseconds: ${args[0]}))`;
1631
+ case 'random': { this.addImport('dart:math'); return args.length >= 2 ? `(Random().nextInt(${args[1]} - ${args[0]} + 1) + ${args[0]})` : `Random().nextDouble()`; }
1632
+ case 'read': { this.addImport('dart:io'); return `File(${args[0]}).readAsStringSync()`; }
1633
+ case 'write': { this.addImport('dart:io'); return `File(${args[0]}).writeAsStringSync(${args[1]})`; }
1634
+ case 'ask': { this.addImport('dart:io'); return `((){stdout.write(${args[0] || '""'}); return stdin.readLineSync() ?? "";}())`; }
1635
+ default: return null;
1636
+ }
1637
+ }
1569
1638
  }
@@ -116,6 +116,8 @@ export class GoGenerator {
116
116
  case 'GrpcDecl': return this.visitGrpc(node);
117
117
  case 'WebrtcDecl': return this.visitWebrtc(node);
118
118
  case 'BlockchainDecl': return this.visitBlockchain(node);
119
+ case 'EnumDecl': return this.visitEnum(node);
120
+ case 'Swap': return this.visitSwap(node);
119
121
  default:
120
122
  this.emit(`// unknown: ${node.type}`);
121
123
  }
@@ -1614,6 +1616,12 @@ export class GoGenerator {
1614
1616
  }
1615
1617
 
1616
1618
  generateCall(node) {
1619
+ if (node.callee.type === 'Identifier') {
1620
+ const argList = node.args.map(a => this.expr(a));
1621
+ const b = this.generateBuiltin(node.callee.name, argList);
1622
+ if (b) return b;
1623
+ }
1624
+
1617
1625
  const args = node.args.map(a => this.expr(a)).join(', ');
1618
1626
 
1619
1627
  // Map common JS global functions to Go
@@ -1778,4 +1786,58 @@ export class GoGenerator {
1778
1786
  this.indent = savedIndent;
1779
1787
  return result;
1780
1788
  }
1789
+
1790
+ visitEnum(node) {
1791
+ this.emit(`type ${node.name} int`);
1792
+ this.emit(`const (`);
1793
+ this.indent++;
1794
+ node.values.forEach((v, i) => {
1795
+ if (i === 0) {
1796
+ this.emit(`${v} ${node.name} = iota`);
1797
+ } else {
1798
+ this.emit(`${v}`);
1799
+ }
1800
+ });
1801
+ this.indent--;
1802
+ this.emit(`)`);
1803
+ this.emitRaw('');
1804
+ }
1805
+
1806
+ visitSwap(node) {
1807
+ const a = this.expr(node.a);
1808
+ const b = this.expr(node.b);
1809
+ this.emit(`${a}, ${b} = ${b}, ${a}`);
1810
+ }
1811
+
1812
+ generateBuiltin(name, args) {
1813
+ switch (name) {
1814
+ case 'len': return `len(${args[0]})`;
1815
+ case 'str': { this.addImport('strconv'); return `strconv.Itoa(${args[0]})`; }
1816
+ case 'int': { this.addImport('strconv'); return `func() int { v, _ := strconv.Atoi(${args[0]}); return v }()`; }
1817
+ case 'float': { this.addImport('strconv'); return `func() float64 { v, _ := strconv.ParseFloat(${args[0]}, 64); return v }()`; }
1818
+ case 'upper': { this.addImport('strings'); return `strings.ToUpper(${args[0]})`; }
1819
+ case 'lower': { this.addImport('strings'); return `strings.ToLower(${args[0]})`; }
1820
+ case 'trim': { this.addImport('strings'); return `strings.TrimSpace(${args[0]})`; }
1821
+ case 'split': { this.addImport('strings'); return `strings.Split(${args[0]}, ${args[1] || '","'})`; }
1822
+ case 'join': { this.addImport('strings'); return `strings.Join(${args[0]}, ${args[1] || '","'})`; }
1823
+ case 'contains': { this.addImport('strings'); return `strings.Contains(${args[0]}, ${args[1]})`; }
1824
+ case 'replace': { this.addImport('strings'); return `strings.ReplaceAll(${args[0]}, ${args[1]}, ${args[2]})`; }
1825
+ case 'abs': { this.addImport('math'); return `math.Abs(${args[0]})`; }
1826
+ case 'sqrt': { this.addImport('math'); return `math.Sqrt(${args[0]})`; }
1827
+ case 'pow': { this.addImport('math'); return `math.Pow(${args[0]}, ${args[1]})`; }
1828
+ case 'ceil': { this.addImport('math'); return `math.Ceil(${args[0]})`; }
1829
+ case 'floor': { this.addImport('math'); return `math.Floor(${args[0]})`; }
1830
+ case 'round': { this.addImport('math'); return `math.Round(${args[0]})`; }
1831
+ case 'exit': { this.addImport('os'); return `os.Exit(${args[0] || '0'})`; }
1832
+ case 'sleep': { this.addImport('time'); return `time.Sleep(time.Duration(${args[0]}) * time.Millisecond)`; }
1833
+ case 'now': { this.addImport('time'); return `time.Now().UnixMilli()`; }
1834
+ case 'time': { this.addImport('time'); return `time.Now().Format(time.RFC3339)`; }
1835
+ case 'json_parse': { this.addImport('encoding/json'); return `func() interface{} { var v interface{}; json.Unmarshal([]byte(${args[0]}), &v); return v }()`; }
1836
+ case 'json_str': { this.addImport('encoding/json'); return `func() string { b, _ := json.Marshal(${args[0]}); return string(b) }()`; }
1837
+ case 'random': { this.addImport('math/rand'); return args.length >= 2 ? `rand.Intn(${args[1]}-${args[0]}+1)+${args[0]}` : `rand.Float64()`; }
1838
+ case 'sort': { this.addImport('sort'); return `func() []int { s := make([]int, len(${args[0]})); copy(s, ${args[0]}); sort.Ints(s); return s }()`; }
1839
+ case 'reverse': return `func() []interface{} { s := make([]interface{}, len(${args[0]})); copy(s, ${args[0]}); for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { s[i], s[j] = s[j], s[i] }; return s }()`;
1840
+ default: return null;
1841
+ }
1842
+ }
1781
1843
  }
@@ -226,6 +226,8 @@ export class JavaGenerator {
226
226
  case 'GrpcDecl': return this.visitGrpc(node);
227
227
  case 'WebrtcDecl': return this.visitWebrtc(node);
228
228
  case 'BlockchainDecl': return this.visitBlockchain(node);
229
+ case 'EnumDecl': return this.visitEnum(node);
230
+ case 'Swap': return this.visitSwap(node);
229
231
  default:
230
232
  this.emit(`/* unknown: ${node.type} */`);
231
233
  }
@@ -1598,6 +1600,12 @@ export class JavaGenerator {
1598
1600
  }
1599
1601
 
1600
1602
  generateCall(node) {
1603
+ if (node.callee.type === 'Identifier') {
1604
+ const argList = node.args.map(a => this.expr(a));
1605
+ const b = this.generateBuiltin(node.callee.name, argList);
1606
+ if (b) return b;
1607
+ }
1608
+
1601
1609
  const args = node.args.map(a => this.expr(a)).join(', ');
1602
1610
 
1603
1611
  if (node.callee.type === 'Identifier') {
@@ -1811,4 +1819,57 @@ export class JavaGenerator {
1811
1819
  this.indent = savedIndent;
1812
1820
  return result;
1813
1821
  }
1822
+
1823
+ visitEnum(node) {
1824
+ this.emit(`enum ${node.name} {`);
1825
+ this.indent++;
1826
+ this.emit(node.values.join(', ') + ';');
1827
+ this.indent--;
1828
+ this.emit(`}`);
1829
+ this.emitRaw('');
1830
+ }
1831
+
1832
+ visitSwap(node) {
1833
+ const a = this.expr(node.a);
1834
+ const b = this.expr(node.b);
1835
+ this.emit(`{ var _tmp = ${a}; ${a} = ${b}; ${b} = _tmp; }`);
1836
+ }
1837
+
1838
+ generateBuiltin(name, args) {
1839
+ switch (name) {
1840
+ case 'len': return `${args[0]}.size()`;
1841
+ case 'sort': return `${args[0]}.stream().sorted().collect(java.util.stream.Collectors.toList())`;
1842
+ case 'reverse': return `{ var _l = new java.util.ArrayList<>(${args[0]}); java.util.Collections.reverse(_l); return _l; }`;
1843
+ case 'contains': return `${args[0]}.contains(${args[1]})`;
1844
+ case 'keys': return `new java.util.ArrayList<>(${args[0]}.keySet())`;
1845
+ case 'values': return `new java.util.ArrayList<>(${args[0]}.values())`;
1846
+ case 'entries': return `new java.util.ArrayList<>(${args[0]}.entrySet())`;
1847
+ case 'abs': return `Math.abs(${args[0]})`;
1848
+ case 'sqrt': return `Math.sqrt(${args[0]})`;
1849
+ case 'pow': return `Math.pow(${args[0]}, ${args[1]})`;
1850
+ case 'ceil': return `Math.ceil(${args[0]})`;
1851
+ case 'floor': return `Math.floor(${args[0]})`;
1852
+ case 'round': return `Math.round(${args[0]})`;
1853
+ case 'random': return args.length >= 2 ? `new java.util.Random().nextInt(${args[1]} - ${args[0]} + 1) + ${args[0]}` : `Math.random()`;
1854
+ case 'str': return `String.valueOf(${args[0]})`;
1855
+ case 'int': return `Integer.parseInt(${args[0]})`;
1856
+ case 'float': return `Double.parseDouble(${args[0]})`;
1857
+ case 'upper': return `${args[0]}.toUpperCase()`;
1858
+ case 'lower': return `${args[0]}.toLowerCase()`;
1859
+ case 'trim': return `${args[0]}.trim()`;
1860
+ case 'split': return `java.util.Arrays.asList(${args[0]}.split(${args[1] || '","'}))`;
1861
+ case 'join': return `String.join(${args[1] || '","'}, ${args[0]})`;
1862
+ case 'replace': return `${args[0]}.replace(${args[1]}, ${args[2]})`;
1863
+ case 'sum': return `${args[0]}.stream().mapToInt(Integer::intValue).sum()`;
1864
+ case 'unique': return `new java.util.ArrayList<>(new java.util.LinkedHashSet<>(${args[0]}))`;
1865
+ case 'exit': return `System.exit(${args[0] || '0'})`;
1866
+ case 'sleep': return `Thread.sleep(${args[0]})`;
1867
+ case 'now': return `System.currentTimeMillis()`;
1868
+ case 'time': return `java.time.LocalDateTime.now().toString()`;
1869
+ case 'json_parse': return `new com.google.gson.Gson().fromJson(${args[0]}, Object.class)`;
1870
+ case 'json_str': return `new com.google.gson.Gson().toJson(${args[0]})`;
1871
+ case 'range': return args.length >= 2 ? `java.util.stream.IntStream.range(${args[0]}, ${args[1]}).boxed().collect(java.util.stream.Collectors.toList())` : `java.util.stream.IntStream.range(0, ${args[0]}).boxed().collect(java.util.stream.Collectors.toList())`;
1872
+ default: return null;
1873
+ }
1874
+ }
1814
1875
  }
@@ -137,6 +137,8 @@ export class KotlinGenerator {
137
137
  case 'GrpcDecl': return this.visitGrpc(node);
138
138
  case 'WebrtcDecl': return this.visitWebrtc(node);
139
139
  case 'BlockchainDecl': return this.visitBlockchain(node);
140
+ case 'EnumDecl': return this.visitEnum(node);
141
+ case 'Swap': return this.visitSwap(node);
140
142
  default:
141
143
  this.emit(`// unknown: ${node.type}`);
142
144
  }
@@ -1641,6 +1643,12 @@ export class KotlinGenerator {
1641
1643
  generateCall(node) {
1642
1644
  const args = node.args.map(a => this.expr(a)).join(', ');
1643
1645
 
1646
+ if (node.callee.type === 'Identifier') {
1647
+ const argList = node.args.map(a => this.expr(a));
1648
+ const b = this.generateBuiltin(node.callee.name, argList);
1649
+ if (b) return b;
1650
+ }
1651
+
1644
1652
  if (node.callee.type === 'Identifier') {
1645
1653
  const name = node.callee.name;
1646
1654
  if (name === 'parseInt') return `(${args}).toInt()`;
@@ -1816,4 +1824,63 @@ export class KotlinGenerator {
1816
1824
  this.indent = savedIndent;
1817
1825
  return result;
1818
1826
  }
1827
+
1828
+ visitEnum(node) {
1829
+ this.emit(`enum class ${node.name} {`);
1830
+ this.indent++;
1831
+ this.emit(node.values.join(', '));
1832
+ this.indent--;
1833
+ this.emit(`}`);
1834
+ this.emitRaw('');
1835
+ }
1836
+
1837
+ visitSwap(node) {
1838
+ const a = this.expr(node.a);
1839
+ const b = this.expr(node.b);
1840
+ this.emit(`${a} = ${b}.also { ${b} = ${a} }`);
1841
+ }
1842
+
1843
+ generateBuiltin(name, args) {
1844
+ switch (name) {
1845
+ case 'len': return `${args[0]}.size`;
1846
+ case 'sort': return `${args[0]}.sorted()`;
1847
+ case 'reverse': return `${args[0]}.reversed()`;
1848
+ case 'unique': return `${args[0]}.distinct()`;
1849
+ case 'upper': return `${args[0]}.uppercase()`;
1850
+ case 'lower': return `${args[0]}.lowercase()`;
1851
+ case 'trim': return `${args[0]}.trim()`;
1852
+ case 'split': return `${args[0]}.split(${args[1] || '","'})`;
1853
+ case 'join': return `${args[0]}.joinToString(${args[1] || '","'})`;
1854
+ case 'contains': return `${args[0]}.contains(${args[1]})`;
1855
+ case 'replace': return `${args[0]}.replace(${args[1]}, ${args[2]})`;
1856
+ case 'keys': return `${args[0]}.keys.toList()`;
1857
+ case 'values': return `${args[0]}.values.toList()`;
1858
+ case 'entries': return `${args[0]}.entries.toList()`;
1859
+ case 'range': return args.length >= 2 ? `(${args[0]} until ${args[1]}).toList()` : `(0 until ${args[0]}).toList()`;
1860
+ case 'abs': return `kotlin.math.abs(${args[0]})`;
1861
+ case 'sqrt': return `kotlin.math.sqrt(${args[0]}.toDouble())`;
1862
+ case 'pow': return `kotlin.math.pow(${args[0]}.toDouble(), ${args[1]}.toDouble())`;
1863
+ case 'ceil': return `kotlin.math.ceil(${args[0]}.toDouble())`;
1864
+ case 'floor': return `kotlin.math.floor(${args[0]}.toDouble())`;
1865
+ case 'round': return `kotlin.math.round(${args[0]}.toDouble())`;
1866
+ case 'sum': return `${args[0]}.sum()`;
1867
+ case 'flat': return `${args[0]}.flatten()`;
1868
+ case 'zip': return `${args[0]}.zip(${args[1]})`;
1869
+ case 'chunk': return `${args[0]}.chunked(${args[1]})`;
1870
+ case 'str': return `${args[0]}.toString()`;
1871
+ case 'int': return `${args[0]}.toInt()`;
1872
+ case 'float': return `${args[0]}.toDouble()`;
1873
+ case 'json_parse': return `com.google.gson.Gson().fromJson(${args[0]}, Any::class.java)`;
1874
+ case 'json_str': return `com.google.gson.Gson().toJson(${args[0]})`;
1875
+ case 'now': return `System.currentTimeMillis()`;
1876
+ case 'time': return `java.time.LocalDateTime.now().toString()`;
1877
+ case 'exit': return `kotlin.system.exitProcess(${args[0] || '0'})`;
1878
+ case 'sleep': return `Thread.sleep(${args[0]}.toLong())`;
1879
+ case 'random': return args.length >= 2 ? `(${args[0]}..${args[1]}).random()` : `kotlin.random.Random.nextDouble()`;
1880
+ case 'read': return `java.io.File(${args[0]}).readText()`;
1881
+ case 'write': return `java.io.File(${args[0]}).writeText(${args[1]})`;
1882
+ case 'ask': return `(print(${args[0] || '""'}); readLine() ?: "")`;
1883
+ default: return null;
1884
+ }
1885
+ }
1819
1886
  }
@@ -103,6 +103,8 @@ export class PhpGenerator {
103
103
  case 'GrpcDecl': return this.visitGrpc(node);
104
104
  case 'WebrtcDecl': return this.visitWebrtc(node);
105
105
  case 'BlockchainDecl': return this.visitBlockchain(node);
106
+ case 'EnumDecl': return this.visitEnum(node);
107
+ case 'Swap': return this.visitSwap(node);
106
108
  default:
107
109
  this.emit(`/* unknown: ${node.type} */`);
108
110
  }
@@ -1366,6 +1368,12 @@ export class PhpGenerator {
1366
1368
  }
1367
1369
 
1368
1370
  generateCall(node) {
1371
+ if (node.callee.type === 'Identifier') {
1372
+ const argList = node.args.map(a => this.expr(a));
1373
+ const b = this.generateBuiltin(node.callee.name, argList);
1374
+ if (b) return b;
1375
+ }
1376
+
1369
1377
  const args = node.args.map(a => this.expr(a)).join(', ');
1370
1378
 
1371
1379
  // Map global function calls
@@ -1573,4 +1581,65 @@ export class PhpGenerator {
1573
1581
  this.indent = savedIndent;
1574
1582
  return result;
1575
1583
  }
1584
+
1585
+ visitEnum(node) {
1586
+ this.emit(`class ${node.name} {`);
1587
+ this.indent++;
1588
+ node.values.forEach((v, i) => {
1589
+ this.emit(`const ${v} = ${i};`);
1590
+ });
1591
+ this.indent--;
1592
+ this.emit(`}`);
1593
+ this.emitRaw('');
1594
+ }
1595
+
1596
+ visitSwap(node) {
1597
+ const a = this.expr(node.a);
1598
+ const b = this.expr(node.b);
1599
+ this.emit(`[$${a.replace('$','')}, $${b.replace('$','')}] = [$${b.replace('$','')}, $${a.replace('$','')}];`);
1600
+ }
1601
+
1602
+ generateBuiltin(name, args) {
1603
+ switch (name) {
1604
+ case 'len': return `count(${args[0]})`;
1605
+ case 'sort': return `(function($a) { sort($a); return $a; })(${args[0]})`;
1606
+ case 'reverse': return `array_reverse(${args[0]})`;
1607
+ case 'unique': return `array_values(array_unique(${args[0]}))`;
1608
+ case 'upper': return `strtoupper(${args[0]})`;
1609
+ case 'lower': return `strtolower(${args[0]})`;
1610
+ case 'trim': return `trim(${args[0]})`;
1611
+ case 'split': return `explode(${args[1] || '","'}, ${args[0]})`;
1612
+ case 'join': return `implode(${args[1] || '","'}, ${args[0]})`;
1613
+ case 'contains': return `in_array(${args[1]}, ${args[0]})`;
1614
+ case 'replace': return `str_replace(${args[1]}, ${args[2]}, ${args[0]})`;
1615
+ case 'keys': return `array_keys(${args[0]})`;
1616
+ case 'values': return `array_values(${args[0]})`;
1617
+ case 'entries': return `array_map(null, array_keys(${args[0]}), array_values(${args[0]}))`;
1618
+ case 'range': return args.length >= 2 ? `range(${args[0]}, ${args[1]} - 1)` : `range(0, ${args[0]} - 1)`;
1619
+ case 'abs': return `abs(${args[0]})`;
1620
+ case 'round': return `round(${args[0]})`;
1621
+ case 'ceil': return `ceil(${args[0]})`;
1622
+ case 'floor': return `floor(${args[0]})`;
1623
+ case 'sqrt': return `sqrt(${args[0]})`;
1624
+ case 'pow': return `pow(${args[0]}, ${args[1]})`;
1625
+ case 'sum': return `array_sum(${args[0]})`;
1626
+ case 'flat': return `array_merge(...${args[0]})`;
1627
+ case 'str': return `strval(${args[0]})`;
1628
+ case 'int': return `intval(${args[0]})`;
1629
+ case 'float': return `floatval(${args[0]})`;
1630
+ case 'json_parse': return `json_decode(${args[0]}, true)`;
1631
+ case 'json_str': return `json_encode(${args[0]})`;
1632
+ case 'now': return `(int)(microtime(true) * 1000)`;
1633
+ case 'time': return `date('c')`;
1634
+ case 'exit': return `exit(${args[0] || '0'})`;
1635
+ case 'sleep': return `usleep(${args[0]} * 1000)`;
1636
+ case 'random': return args.length >= 2 ? `random_int(${args[0]}, ${args[1]})` : `(mt_rand() / mt_getrandmax())`;
1637
+ case 'read': return `file_get_contents(${args[0]})`;
1638
+ case 'write': return `file_put_contents(${args[0]}, ${args[1]})`;
1639
+ case 'ask': return `readline(${args[0] || '""'})`;
1640
+ case 'chunk': return `array_chunk(${args[0]}, ${args[1]})`;
1641
+ case 'zip': return `array_map(null, ${args[0]}, ${args[1]})`;
1642
+ default: return null;
1643
+ }
1644
+ }
1576
1645
  }
@@ -111,6 +111,8 @@ export class RubyGenerator {
111
111
  case 'GrpcDecl': return this.visitGrpc(node);
112
112
  case 'WebrtcDecl': return this.visitWebrtc(node);
113
113
  case 'BlockchainDecl': return this.visitBlockchain(node);
114
+ case 'EnumDecl': return this.visitEnum(node);
115
+ case 'Swap': return this.visitSwap(node);
114
116
  default:
115
117
  this.emit(`# unknown: ${node.type}`);
116
118
  }
@@ -1330,6 +1332,12 @@ export class RubyGenerator {
1330
1332
  }
1331
1333
 
1332
1334
  generateCall(node) {
1335
+ if (node.callee.type === 'Identifier') {
1336
+ const argList = node.args.map(a => this.expr(a));
1337
+ const b = this.generateBuiltin(node.callee.name, argList);
1338
+ if (b) return b;
1339
+ }
1340
+
1333
1341
  const args = node.args.map(a => this.expr(a)).join(', ');
1334
1342
 
1335
1343
  // Map global function calls
@@ -1527,4 +1535,65 @@ export class RubyGenerator {
1527
1535
  this.indent = savedIndent;
1528
1536
  return result;
1529
1537
  }
1538
+
1539
+ visitEnum(node) {
1540
+ this.emit(`module ${node.name}`);
1541
+ this.indent++;
1542
+ node.values.forEach((v, i) => {
1543
+ this.emit(`${v} = ${i}`);
1544
+ });
1545
+ this.indent--;
1546
+ this.emit(`end`);
1547
+ this.emitRaw('');
1548
+ }
1549
+
1550
+ visitSwap(node) {
1551
+ const a = this.expr(node.a);
1552
+ const b = this.expr(node.b);
1553
+ this.emit(`${a}, ${b} = ${b}, ${a}`);
1554
+ }
1555
+
1556
+ generateBuiltin(name, args) {
1557
+ switch (name) {
1558
+ case 'len': return `${args[0]}.length`;
1559
+ case 'sort': return `${args[0]}.sort`;
1560
+ case 'reverse': return `${args[0]}.reverse`;
1561
+ case 'unique': return `${args[0]}.uniq`;
1562
+ case 'upper': return `${args[0]}.upcase`;
1563
+ case 'lower': return `${args[0]}.downcase`;
1564
+ case 'trim': return `${args[0]}.strip`;
1565
+ case 'split': return `${args[0]}.split(${args[1] || '","'})`;
1566
+ case 'join': return `${args[0]}.join(${args[1] || '","'})`;
1567
+ case 'contains': return `${args[0]}.include?(${args[1]})`;
1568
+ case 'replace': return `${args[0]}.gsub(${args[1]}, ${args[2]})`;
1569
+ case 'keys': return `${args[0]}.keys`;
1570
+ case 'values': return `${args[0]}.values`;
1571
+ case 'entries': return `${args[0]}.to_a`;
1572
+ case 'range': return args.length >= 2 ? `(${args[0]}...${args[1]}).to_a` : `(0...${args[0]}).to_a`;
1573
+ case 'abs': return `${args[0]}.abs`;
1574
+ case 'round': return `${args[0]}.round`;
1575
+ case 'ceil': return `${args[0]}.ceil`;
1576
+ case 'floor': return `${args[0]}.floor`;
1577
+ case 'sqrt': return `Math.sqrt(${args[0]})`;
1578
+ case 'pow': return `${args[0]} ** ${args[1]}`;
1579
+ case 'sum': return `${args[0]}.sum`;
1580
+ case 'flat': return `${args[0]}.flatten`;
1581
+ case 'zip': return `${args[0]}.zip(${args[1]})`;
1582
+ case 'chunk': return `${args[0]}.each_slice(${args[1]}).to_a`;
1583
+ case 'str': return `${args[0]}.to_s`;
1584
+ case 'int': return `${args[0]}.to_i`;
1585
+ case 'float': return `${args[0]}.to_f`;
1586
+ case 'json_parse': return `JSON.parse(${args[0]})`;
1587
+ case 'json_str': return `JSON.generate(${args[0]})`;
1588
+ case 'now': return `(Time.now.to_f * 1000).to_i`;
1589
+ case 'time': return `Time.now.iso8601`;
1590
+ case 'exit': return `exit(${args[0] || '0'})`;
1591
+ case 'sleep': return `sleep(${args[0]} / 1000.0)`;
1592
+ case 'random': return args.length >= 2 ? `rand(${args[0]}..${args[1]})` : `rand`;
1593
+ case 'read': return `File.read(${args[0]})`;
1594
+ case 'write': return `File.write(${args[0]}, ${args[1]})`;
1595
+ case 'ask': return `(print(${args[0] || '""'}); gets.chomp)`;
1596
+ default: return null;
1597
+ }
1598
+ }
1530
1599
  }
@@ -207,6 +207,8 @@ export class RustGenerator {
207
207
  case 'GrpcDecl': return this.visitGrpc(node);
208
208
  case 'WebrtcDecl': return this.visitWebrtc(node);
209
209
  case 'BlockchainDecl': return this.visitBlockchain(node);
210
+ case 'EnumDecl': return this.visitEnum(node);
211
+ case 'Swap': return this.visitSwap(node);
210
212
  default:
211
213
  this.emit(`/* unknown: ${node.type} */`);
212
214
  }
@@ -1707,6 +1709,12 @@ export class RustGenerator {
1707
1709
  }
1708
1710
 
1709
1711
  generateCall(node) {
1712
+ if (node.callee.type === 'Identifier') {
1713
+ const argList = node.args.map(a => this.expr(a));
1714
+ const b = this.generateBuiltin(node.callee.name, argList);
1715
+ if (b) return b;
1716
+ }
1717
+
1710
1718
  const args = node.args.map(a => this.expr(a)).join(', ');
1711
1719
 
1712
1720
  // Map common JS global functions to Rust
@@ -1884,4 +1892,57 @@ export class RustGenerator {
1884
1892
  this.indent = savedIndent;
1885
1893
  return result;
1886
1894
  }
1895
+
1896
+ visitEnum(node) {
1897
+ this.emit(`#[derive(Debug, Clone, Copy, PartialEq)]`);
1898
+ this.emit(`enum ${node.name} {`);
1899
+ this.indent++;
1900
+ node.values.forEach(v => {
1901
+ this.emit(`${v},`);
1902
+ });
1903
+ this.indent--;
1904
+ this.emit(`}`);
1905
+ this.emitRaw('');
1906
+ }
1907
+
1908
+ visitSwap(node) {
1909
+ const a = this.expr(node.a);
1910
+ const b = this.expr(node.b);
1911
+ this.emit(`std::mem::swap(&mut ${a}, &mut ${b});`);
1912
+ }
1913
+
1914
+ generateBuiltin(name, args) {
1915
+ switch (name) {
1916
+ case 'len': return `${args[0]}.len()`;
1917
+ case 'str': return `${args[0]}.to_string()`;
1918
+ case 'int': return `${args[0]}.parse::<i64>().unwrap_or(0)`;
1919
+ case 'float': return `${args[0]}.parse::<f64>().unwrap_or(0.0)`;
1920
+ case 'upper': return `${args[0]}.to_uppercase()`;
1921
+ case 'lower': return `${args[0]}.to_lowercase()`;
1922
+ case 'trim': return `${args[0]}.trim().to_string()`;
1923
+ case 'split': return `${args[0]}.split(${args[1] || '","'}).collect::<Vec<&str>>()`;
1924
+ case 'join': return `${args[0]}.join(${args[1] || '","'})`;
1925
+ case 'contains': return `${args[0]}.contains(${args[1]})`;
1926
+ case 'replace': return `${args[0]}.replace(${args[1]}, ${args[2]})`;
1927
+ case 'sort': return `{ let mut v = ${args[0]}.clone(); v.sort(); v }`;
1928
+ case 'reverse': return `{ let mut v = ${args[0]}.clone(); v.reverse(); v }`;
1929
+ case 'abs': return `${args[0]}.abs()`;
1930
+ case 'sqrt': return `(${args[0]} as f64).sqrt()`;
1931
+ case 'pow': return `(${args[0]} as f64).powi(${args[1]} as i32)`;
1932
+ case 'ceil': return `(${args[0]} as f64).ceil()`;
1933
+ case 'floor': return `(${args[0]} as f64).floor()`;
1934
+ case 'round': return `(${args[0]} as f64).round()`;
1935
+ case 'sum': return `${args[0]}.iter().sum::<i64>()`;
1936
+ case 'unique': return `{ let mut v = ${args[0]}.clone(); v.sort(); v.dedup(); v }`;
1937
+ case 'exit': return `std::process::exit(${args[0] || '0'})`;
1938
+ case 'sleep': return `std::thread::sleep(std::time::Duration::from_millis(${args[0]} as u64))`;
1939
+ case 'now': return `std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64`;
1940
+ case 'random': return args.length >= 2 ? `rand::thread_rng().gen_range(${args[0]}..=${args[1]})` : `rand::random::<f64>()`;
1941
+ case 'keys': return `${args[0]}.keys().cloned().collect::<Vec<_>>()`;
1942
+ case 'values': return `${args[0]}.values().cloned().collect::<Vec<_>>()`;
1943
+ case 'range': return args.length >= 2 ? `(${args[0]}..${args[1]}).collect::<Vec<_>>()` : `(0..${args[0]}).collect::<Vec<_>>()`;
1944
+ case 'flat': return `${args[0]}.into_iter().flatten().collect::<Vec<_>>()`;
1945
+ default: return null;
1946
+ }
1947
+ }
1887
1948
  }
@@ -139,6 +139,8 @@ export class SwiftGenerator {
139
139
  case 'GrpcDecl': return this.visitGrpc(node);
140
140
  case 'WebrtcDecl': return this.visitWebrtc(node);
141
141
  case 'BlockchainDecl': return this.visitBlockchain(node);
142
+ case 'EnumDecl': return this.visitEnum(node);
143
+ case 'Swap': return this.visitSwap(node);
142
144
  default:
143
145
  this.emit(`// unknown: ${node.type}`);
144
146
  }
@@ -1555,6 +1557,12 @@ export class SwiftGenerator {
1555
1557
  }
1556
1558
 
1557
1559
  generateCall(node) {
1560
+ if (node.callee.type === 'Identifier') {
1561
+ const argList = node.args.map(a => this.expr(a));
1562
+ const b = this.generateBuiltin(node.callee.name, argList);
1563
+ if (b) return b;
1564
+ }
1565
+
1558
1566
  const args = node.args.map(a => this.expr(a)).join(', ');
1559
1567
 
1560
1568
  if (node.callee.type === 'Identifier') {
@@ -1732,4 +1740,63 @@ export class SwiftGenerator {
1732
1740
  this.indent = savedIndent;
1733
1741
  return result;
1734
1742
  }
1743
+
1744
+ visitEnum(node) {
1745
+ this.emit(`enum ${node.name}: Int, CaseIterable {`);
1746
+ this.indent++;
1747
+ node.values.forEach((v, i) => {
1748
+ this.emit(`case ${v.toLowerCase()} = ${i}`);
1749
+ });
1750
+ this.indent--;
1751
+ this.emit(`}`);
1752
+ this.emitRaw('');
1753
+ }
1754
+
1755
+ visitSwap(node) {
1756
+ const a = this.expr(node.a);
1757
+ const b = this.expr(node.b);
1758
+ this.emit(`swap(&${a}, &${b})`);
1759
+ }
1760
+
1761
+ generateBuiltin(name, args) {
1762
+ switch (name) {
1763
+ case 'len': return `${args[0]}.count`;
1764
+ case 'sort': return `${args[0]}.sorted()`;
1765
+ case 'reverse': return `${args[0]}.reversed()`;
1766
+ case 'unique': return `Array(Set(${args[0]}))`;
1767
+ case 'upper': return `${args[0]}.uppercased()`;
1768
+ case 'lower': return `${args[0]}.lowercased()`;
1769
+ case 'trim': return `${args[0]}.trimmingCharacters(in: .whitespacesAndNewlines)`;
1770
+ case 'split': return `${args[0]}.components(separatedBy: ${args[1] || '","'})`;
1771
+ case 'join': return `${args[0]}.joined(separator: ${args[1] || '","'})`;
1772
+ case 'contains': return `${args[0]}.contains(${args[1]})`;
1773
+ case 'replace': return `${args[0]}.replacingOccurrences(of: ${args[1]}, with: ${args[2]})`;
1774
+ case 'keys': return `Array(${args[0]}.keys)`;
1775
+ case 'values': return `Array(${args[0]}.values)`;
1776
+ case 'range': return args.length >= 2 ? `Array(${args[0]}..<${args[1]})` : `Array(0..<${args[0]})`;
1777
+ case 'abs': return `abs(${args[0]})`;
1778
+ case 'sqrt': { this.addImport('Foundation'); return `sqrt(Double(${args[0]}))`; }
1779
+ case 'pow': { this.addImport('Foundation'); return `pow(Double(${args[0]}), Double(${args[1]}))`; }
1780
+ case 'ceil': { this.addImport('Foundation'); return `ceil(Double(${args[0]}))`; }
1781
+ case 'floor': { this.addImport('Foundation'); return `floor(Double(${args[0]}))`; }
1782
+ case 'round': { this.addImport('Foundation'); return `round(Double(${args[0]}))`; }
1783
+ case 'sum': return `${args[0]}.reduce(0, +)`;
1784
+ case 'flat': return `${args[0]}.flatMap { $0 }`;
1785
+ case 'zip': return `Array(zip(${args[0]}, ${args[1]}))`;
1786
+ case 'chunk': return `stride(from: 0, to: ${args[0]}.count, by: ${args[1]}).map { Array(${args[0]}[$0..<min($0+${args[1]}, ${args[0]}.count)]) }`;
1787
+ case 'str': return `String(${args[0]})`;
1788
+ case 'int': return `Int(${args[0]}) ?? 0`;
1789
+ case 'float': return `Double(${args[0]}) ?? 0.0`;
1790
+ case 'json_parse': { this.addImport('Foundation'); return `try? JSONSerialization.jsonObject(with: ${args[0]}.data(using: .utf8)!, options: [])`; }
1791
+ case 'json_str': { this.addImport('Foundation'); return `String(data: try! JSONSerialization.data(withJSONObject: ${args[0]}), encoding: .utf8)!`; }
1792
+ case 'now': { this.addImport('Foundation'); return `Int(Date().timeIntervalSince1970 * 1000)`; }
1793
+ case 'time': { this.addImport('Foundation'); return `ISO8601DateFormatter().string(from: Date())`; }
1794
+ case 'exit': { this.addImport('Foundation'); return `exit(${args[0] || '0'})`; }
1795
+ case 'sleep': { this.addImport('Foundation'); return `Thread.sleep(forTimeInterval: Double(${args[0]}) / 1000.0)`; }
1796
+ case 'random': return args.length >= 2 ? `Int.random(in: ${args[0]}...${args[1]})` : `Double.random(in: 0...1)`;
1797
+ case 'read': return `try! String(contentsOfFile: ${args[0]})`;
1798
+ case 'write': return `try! ${args[1]}.write(toFile: ${args[0]}, atomically: true, encoding: .utf8)`;
1799
+ default: return null;
1800
+ }
1801
+ }
1735
1802
  }
package/src/parser.js CHANGED
@@ -135,7 +135,18 @@ export class Parser {
135
135
 
136
136
  error(msg, tok) {
137
137
  const t = tok || this.peek();
138
- return new Error(`[NAIDE Parse Error] ${msg} at line ${t.line}:${t.col}`);
138
+ let hint = '';
139
+ const v = t.value;
140
+ if (v === 'unless') hint = '\n Hint: unless <condition>:';
141
+ else if (v === 'until') hint = '\n Hint: until <condition>:';
142
+ else if (v === 'repeat') hint = '\n Hint: repeat <count>: or repeat <count> as <var>:';
143
+ else if (v === 'swap') hint = '\n Hint: swap <a>, <b>';
144
+ else if (v === 'enum') hint = '\n Hint: enum <Name>: then indent values';
145
+ else if (v === 'fn') hint = '\n Hint: fn <name>(<params>) -> <type>: or fn <name>(<params>) -> <type> = <expr>';
146
+ else if (v === 'if') hint = '\n Hint: if <condition>:';
147
+ else if (v === 'for') hint = '\n Hint: for <var> in <iterable>:';
148
+ else if (v === 'while') hint = '\n Hint: while <condition>:';
149
+ return new Error(`[NAIDE Parse Error] ${msg} at line ${t.line}:${t.col}${hint}`);
139
150
  }
140
151
 
141
152
  skipNewlines() {