naider 1.17.2 → 1.18.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/lsp/server.js CHANGED
@@ -107,7 +107,7 @@ function validateDocument(uri) {
107
107
  const line = lines[i].trim();
108
108
  if (!line || line.startsWith('#') || line.startsWith('--')) continue;
109
109
 
110
- const typeMatch = line.match(/^(str|int|num|bool)\s+\w+\s*=\s*(.+)/);
110
+ const typeMatch = line.match(/^(str|int|num|bool|auto)\s+\w+\s*=\s*(.+)/);
111
111
  if (typeMatch) {
112
112
  const declType = typeMatch[1];
113
113
  const val = typeMatch[2].trim();
@@ -163,7 +163,7 @@ function indexSymbols(uri, text) {
163
163
  symbols.definitions.set(name, { line: i, col, kind: 'function' });
164
164
  }
165
165
 
166
- const varMatch = trimmed.match(/^(?:pub\s+)?(?:mut\s+)?(?:str|int|num|bool|list|map|any|json|void)\s+(\w+)\s*=/);
166
+ const varMatch = trimmed.match(/^(?:pub\s+)?(?:mut\s+)?(?:str|int|num|bool|list|map|any|json|void|auto)\s+(\w+)\s*=/);
167
167
  if (varMatch) {
168
168
  const name = varMatch[1];
169
169
  const col = line.indexOf(name);
@@ -282,9 +282,9 @@ function getCompletions() {
282
282
  'try', 'fail', 'ensure', 'server', 'model', 'schema', 'use', 'pub', 'mut',
283
283
  'log', 'typeof', 'instanceof', 'not', 'and', 'or', 'break', 'continue',
284
284
  'throw', 'new', 'await', 'test', 'assert', 'queue', 'job', 'db', 'env',
285
- 'get', 'post', 'put', 'del', 'patch', 'every', 'watch',
285
+ 'get', 'post', 'put', 'del', 'patch', 'every', 'watch', 'extends', 'init',
286
286
  ];
287
- const types = ['str', 'int', 'num', 'bool', 'list', 'map', 'any', 'json', 'void'];
287
+ const types = ['str', 'int', 'num', 'bool', 'list', 'map', 'any', 'json', 'void', 'auto'];
288
288
  const features = [
289
289
  'cors', 'auth', 'crud', 'limit', 'cookie', 'session', 'static', 'ws', 'sse',
290
290
  'cache', 'view', 'upload', 'group', 'validate', 'openapi', 'error', 'mid', 'prompt',
@@ -355,6 +355,18 @@ function getCompletions() {
355
355
  { label: 'write(path, data)', detail: 'Write to file', insertText: 'write(' },
356
356
  { label: 'fetch_json(url)', detail: 'Fetch JSON from URL', insertText: 'fetch_json(' },
357
357
  { label: 'random(min, max)', detail: 'Random number', insertText: 'random(' },
358
+ { label: 'map(list, fn)', detail: 'Transform each element', insertText: 'map(' },
359
+ { label: 'filter(list, fn)', detail: 'Filter elements by condition', insertText: 'filter(' },
360
+ { label: 'reduce(list, fn, init)', detail: 'Reduce list to single value', insertText: 'reduce(' },
361
+ { label: 'find(list, fn)', detail: 'Find first matching element', insertText: 'find(' },
362
+ { label: 'every(list, fn)', detail: 'Check if all match condition', insertText: 'every(' },
363
+ { label: 'some(list, fn)', detail: 'Check if any match condition', insertText: 'some(' },
364
+ { label: 'foreach(list, fn)', detail: 'Execute fn for each element', insertText: 'foreach(' },
365
+ { label: 'auto', detail: 'Type inference (compiler infers type)', insertText: 'auto ' },
366
+ { label: 'auto {a, b} = obj', detail: 'Object destructuring', insertText: 'auto {' },
367
+ { label: 'auto [a, b] = list', detail: 'Array destructuring', insertText: 'auto [' },
368
+ { label: 'extends', detail: 'Inherit from parent schema/model', insertText: 'extends ' },
369
+ { label: 'init(params):', detail: 'Constructor method', insertText: 'init(' },
358
370
  ];
359
371
 
360
372
  return [
@@ -409,6 +421,16 @@ const HOVER_DOCS = {
409
421
  'is': '**is** — Equality comparison (===)\n```naide\nif x is 5: log "five"\n```',
410
422
  'isnt': '**isnt** — Inequality comparison (!==)\n```naide\nif x isnt null: log "exists"\n```',
411
423
  'print': '**print** — Alias for log\n```naide\nprint "hello world"\n```',
424
+ 'auto': '**auto** — Type inference\n```naide\nauto x = 42 # compiler infers int\nauto msg = "hello" # compiler infers str\nmut auto counter = 0 # mutable, type inferred\n```\nThe compiler infers the type from the assigned value. Emits `const` (or `let` with `mut`).',
425
+ 'extends': '**extends** — Inherit from parent\n```naide\nschema Dog extends Animal:\n breed str optional\n\nmodel Admin extends User:\n str role = "admin"\n```\nInherits all fields and methods from the parent schema or model.',
426
+ 'init': '**init** — Constructor method\n```naide\nschema Dog extends Animal:\n init(str name, str breed):\n self.name = name\n self.breed = breed\n```\nDefines a constructor for schema/model classes.',
427
+ 'map': '**map** — Transform each element\n```naide\nlist doubled = map(items, (x) => x * 2)\n```\nApplies a function to every element and returns a new list.',
428
+ 'filter': '**filter** — Filter elements\n```naide\nlist big = filter(items, (x) => x > 5)\n```\nReturns a new list with only elements matching the condition.',
429
+ 'reduce': '**reduce** — Reduce to single value\n```naide\nint total = reduce(items, (a, b) => a + b, 0)\n```\nAccumulates elements into a single value using a function and initial value.',
430
+ 'find': '**find** — Find first match\n```naide\nany item = find(items, (x) => x > 3)\n```\nReturns the first element matching the condition, or `undefined`.',
431
+ 'every': '**every** — Check all match\n```naide\nbool allPositive = every(items, (x) => x > 0)\n```\nReturns `true` if all elements match the condition.',
432
+ 'some': '**some** — Check any match\n```naide\nbool hasNegative = some(items, (x) => x < 0)\n```\nReturns `true` if at least one element matches the condition.',
433
+ 'foreach': '**foreach** — Iterate with side effects\n```naide\nforeach(items, (x) => log x)\n```\nExecutes a function for each element (no return value).',
412
434
  };
413
435
 
414
436
  function getHover(params) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naider",
3
- "version": "1.17.2",
3
+ "version": "1.18.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": {
@@ -187,6 +187,8 @@ export class CGenerator {
187
187
  case 'BlockchainDecl': return this.visitBlockchain(node);
188
188
  case 'EnumDecl': return this.visitEnum(node);
189
189
  case 'Swap': return this.visitSwap(node);
190
+ case 'Destructure': return this.visitDestructure(node);
191
+ case 'ClassDecl': return this.visitClassDecl(node);
190
192
  default:
191
193
  this.emit(`/* unknown: ${node.type} */`);
192
194
  }
@@ -1000,6 +1002,62 @@ export class CGenerator {
1000
1002
  this.emit(`{ typeof(${a}) ${tmp} = ${a}; ${a} = ${b}; ${b} = ${tmp}; }`);
1001
1003
  }
1002
1004
 
1005
+ visitDestructure(node) {
1006
+ const val = this.expr(node.value);
1007
+ if (node.pattern === 'array') {
1008
+ node.names.forEach((n, i) => {
1009
+ if (!n.rest) {
1010
+ const varName = n.alias || n.name;
1011
+ this.emit(`auto ${varName} = ${val}[${i}];`);
1012
+ }
1013
+ });
1014
+ } else {
1015
+ for (const n of node.names) {
1016
+ if (!n.rest) {
1017
+ const varName = n.alias || n.name;
1018
+ this.emit(`auto ${varName} = ${val}["${n.name}"];`);
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+
1024
+ visitClassDecl(node) {
1025
+ this.emit(`/* C does not support classes; using struct + functions for ${node.name} */`);
1026
+ this.emit(`typedef struct {`);
1027
+ this.indent++;
1028
+ for (const field of node.fields) {
1029
+ this.emit(`void* ${field.name};`);
1030
+ }
1031
+ if (node.fields.length === 0) this.emit(`int __placeholder;`);
1032
+ this.indent--;
1033
+ this.emit(`} ${node.name};`);
1034
+ this.emitRaw('');
1035
+ if (node.init) {
1036
+ const params = node.init.params.map(p => `void* ${p.name}`).join(', ');
1037
+ this.emit(`${node.name} ${node.name}_create(${params || 'void'}) {`);
1038
+ this.indent++;
1039
+ this.emit(`${node.name} self;`);
1040
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1041
+ this.emit(`return self;`);
1042
+ this.indent--;
1043
+ this.emit(`}`);
1044
+ this.emitRaw('');
1045
+ }
1046
+ for (const method of node.methods) {
1047
+ const params = [`${node.name}* self`, ...method.params.map(p => `void* ${p.name}`)].join(', ');
1048
+ this.emit(`void* ${node.name}_${method.name}(${params}) {`);
1049
+ this.indent++;
1050
+ if (method.body.length === 0) {
1051
+ this.emit('return NULL;');
1052
+ } else {
1053
+ for (const stmt of method.body) this.visitStatement(stmt);
1054
+ }
1055
+ this.indent--;
1056
+ this.emit(`}`);
1057
+ this.emitRaw('');
1058
+ }
1059
+ }
1060
+
1003
1061
  generateBuiltin(name, args) {
1004
1062
  switch (name) {
1005
1063
  case 'len': return `(sizeof(${args[0]}) / sizeof(${args[0]}[0]))`;
@@ -1018,6 +1076,13 @@ export class CGenerator {
1018
1076
  case 'sleep': { this.includes.add('<unistd.h>'); return `usleep(${args[0]} * 1000)`; }
1019
1077
  case 'now': { this.includes.add('<time.h>'); return `(long long)time(NULL) * 1000`; }
1020
1078
  case 'random': { this.includes.add('<stdlib.h>'); return args.length >= 2 ? `(rand() % (${args[1]} - ${args[0]} + 1) + ${args[0]})` : `rand()`; }
1079
+ case 'map': return `/* C: map requires manual loop over ${args[0]} with ${args[1]} */`;
1080
+ case 'filter': return `/* C: filter requires manual loop over ${args[0]} with ${args[1]} */`;
1081
+ case 'reduce': return `/* C: reduce requires manual loop over ${args[0]} with ${args[1]} */`;
1082
+ case 'find': return `/* C: find requires manual loop over ${args[0]} with ${args[1]} */`;
1083
+ case 'every': return `/* C: every requires manual loop over ${args[0]} with ${args[1]} */`;
1084
+ case 'some': return `/* C: some requires manual loop over ${args[0]} with ${args[1]} */`;
1085
+ case 'foreach': return `for (int _i = 0; _i < sizeof(${args[0]})/sizeof(${args[0]}[0]); _i++) { ${args[1]}(${args[0]}[_i]); }`;
1021
1086
  default: return null;
1022
1087
  }
1023
1088
  }
@@ -188,6 +188,8 @@ export class CppGenerator {
188
188
  case 'BlockchainDecl': return this.visitBlockchain(node);
189
189
  case 'EnumDecl': return this.visitEnum(node);
190
190
  case 'Swap': return this.visitSwap(node);
191
+ case 'Destructure': return this.visitDestructure(node);
192
+ case 'ClassDecl': return this.visitClassDecl(node);
191
193
  default:
192
194
  this.emit(`/* unknown: ${node.type} */`);
193
195
  }
@@ -1233,6 +1235,75 @@ export class CppGenerator {
1233
1235
  this.emit(`std::swap(${a}, ${b});`);
1234
1236
  }
1235
1237
 
1238
+ visitDestructure(node) {
1239
+ const val = this.expr(node.value);
1240
+ if (node.pattern === 'array') {
1241
+ if (node.names.every(n => !n.rest && !n.defaultValue)) {
1242
+ this.includes.add('<tuple>');
1243
+ const names = node.names.map(n => n.alias || n.name).join(', ');
1244
+ this.emit(`auto [${names}] = ${val};`);
1245
+ } else {
1246
+ node.names.forEach((n, i) => {
1247
+ if (!n.rest) {
1248
+ const varName = n.alias || n.name;
1249
+ if (n.defaultValue) {
1250
+ this.emit(`auto ${varName} = (${i} < ${val}.size()) ? ${val}[${i}] : ${this.expr(n.defaultValue)};`);
1251
+ } else {
1252
+ this.emit(`auto ${varName} = ${val}[${i}];`);
1253
+ }
1254
+ }
1255
+ });
1256
+ }
1257
+ } else {
1258
+ for (const n of node.names) {
1259
+ if (!n.rest) {
1260
+ const varName = n.alias || n.name;
1261
+ if (n.defaultValue) {
1262
+ this.emit(`auto ${varName} = ${val}.count("${n.name}") ? ${val}["${n.name}"] : ${this.expr(n.defaultValue)};`);
1263
+ } else {
1264
+ this.emit(`auto ${varName} = ${val}["${n.name}"];`);
1265
+ }
1266
+ }
1267
+ }
1268
+ }
1269
+ }
1270
+
1271
+ visitClassDecl(node) {
1272
+ const ext = node.parent ? ` : public ${node.parent}` : '';
1273
+ this.emit(`class ${node.name}${ext} {`);
1274
+ this.emit(`public:`);
1275
+ this.indent++;
1276
+ for (const field of node.fields) {
1277
+ if (field.defaultValue) {
1278
+ this.emit(`auto ${field.name} = ${this.expr(field.defaultValue)};`);
1279
+ }
1280
+ }
1281
+ if (node.init) {
1282
+ const params = node.init.params.map(p => `auto ${p.name}`).join(', ');
1283
+ this.emit(`${node.name}(${params}) {`);
1284
+ this.indent++;
1285
+ if (node.parent) this.emit(`${node.parent}();`);
1286
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1287
+ this.indent--;
1288
+ this.emit('}');
1289
+ }
1290
+ for (const method of node.methods) {
1291
+ const params = method.params.map(p => `auto ${p.name}`).join(', ');
1292
+ this.emit(`auto ${method.name}(${params}) {`);
1293
+ this.indent++;
1294
+ if (method.body.length === 0) {
1295
+ this.emit('return 0;');
1296
+ } else {
1297
+ for (const stmt of method.body) this.visitStatement(stmt);
1298
+ }
1299
+ this.indent--;
1300
+ this.emit('}');
1301
+ }
1302
+ this.indent--;
1303
+ this.emit('};');
1304
+ this.emitRaw('');
1305
+ }
1306
+
1236
1307
  generateBuiltin(name, args) {
1237
1308
  switch (name) {
1238
1309
  case 'len': return `${args[0]}.size()`;
@@ -1258,6 +1329,13 @@ export class CppGenerator {
1258
1329
  case 'now': { this.includes.add('<chrono>'); return `std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()`; }
1259
1330
  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
1331
  case 'sum': return `([&](){ auto _v = ${args[0]}; return std::accumulate(_v.begin(), _v.end(), 0); }())`;
1332
+ case 'map': { this.includes.add('<algorithm>'); return `([&](){ auto _v = ${args[0]}; std::vector<decltype(${args[1]}(_v[0]))> _r; std::transform(_v.begin(), _v.end(), std::back_inserter(_r), ${args[1]}); return _r; }())`; }
1333
+ case 'filter': { this.includes.add('<algorithm>'); return `([&](){ auto _v = ${args[0]}; decltype(_v) _r; std::copy_if(_v.begin(), _v.end(), std::back_inserter(_r), ${args[1]}); return _r; }())`; }
1334
+ case 'reduce': { this.includes.add('<numeric>'); return `std::accumulate(${args[0]}.begin(), ${args[0]}.end(), ${args[2] || '0'}, ${args[1]})`; }
1335
+ case 'find': { this.includes.add('<algorithm>'); return `(*std::find_if(${args[0]}.begin(), ${args[0]}.end(), ${args[1]}))`; }
1336
+ case 'every': { this.includes.add('<algorithm>'); return `std::all_of(${args[0]}.begin(), ${args[0]}.end(), ${args[1]})`; }
1337
+ case 'some': { this.includes.add('<algorithm>'); return `std::any_of(${args[0]}.begin(), ${args[0]}.end(), ${args[1]})`; }
1338
+ case 'foreach': { this.includes.add('<algorithm>'); return `std::for_each(${args[0]}.begin(), ${args[0]}.end(), ${args[1]})`; }
1261
1339
  default: return null;
1262
1340
  }
1263
1341
  }
@@ -180,6 +180,8 @@ export class CSharpGenerator {
180
180
  case 'BlockchainDecl': return this.visitBlockchain(node);
181
181
  case 'EnumDecl': return this.visitEnum(node);
182
182
  case 'Swap': return this.visitSwap(node);
183
+ case 'Destructure': return this.visitDestructure(node);
184
+ case 'ClassDecl': return this.visitClassDecl(node);
183
185
  default:
184
186
  this.emit(`// unknown: ${node.type}`);
185
187
  }
@@ -1654,6 +1656,65 @@ export class CSharpGenerator {
1654
1656
  this.emit(`(${a}, ${b}) = (${b}, ${a});`);
1655
1657
  }
1656
1658
 
1659
+ visitDestructure(node) {
1660
+ const val = this.expr(node.value);
1661
+ if (node.pattern === 'array') {
1662
+ const names = node.names.filter(n => !n.rest).map(n => n.alias || n.name);
1663
+ const indexedVals = names.map((name, i) => `${val}[${i}]`);
1664
+ this.emit(`var (${names.join(', ')}) = (${indexedVals.join(', ')});`);
1665
+ } else {
1666
+ for (const n of node.names) {
1667
+ if (!n.rest) {
1668
+ const varName = n.alias || n.name;
1669
+ if (n.defaultValue) {
1670
+ this.emit(`var ${varName} = ${val}.ContainsKey("${n.name}") ? ${val}["${n.name}"] : ${this.expr(n.defaultValue)};`);
1671
+ } else {
1672
+ this.emit(`var ${varName} = ${val}["${n.name}"];`);
1673
+ }
1674
+ }
1675
+ }
1676
+ }
1677
+ }
1678
+
1679
+ visitClassDecl(node) {
1680
+ const ext = node.parent ? ` : ${node.parent}` : '';
1681
+ this.emit(`class ${node.name}${ext} {`);
1682
+ this.indent++;
1683
+ for (const field of node.fields) {
1684
+ if (field.defaultValue) {
1685
+ this.emit(`public dynamic ${field.name} = ${this.expr(field.defaultValue)};`);
1686
+ } else {
1687
+ this.emit(`public dynamic ${field.name};`);
1688
+ }
1689
+ }
1690
+ if (node.init) {
1691
+ const params = node.init.params.map(p => `dynamic ${p.name}`).join(', ');
1692
+ const baseCall = node.parent ? ' : base()' : '';
1693
+ this.emit(`public ${node.name}(${params})${baseCall} {`);
1694
+ this.indent++;
1695
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1696
+ this.indent--;
1697
+ this.emit('}');
1698
+ }
1699
+ for (const method of node.methods) {
1700
+ const params = method.params.map(p => `dynamic ${p.name}`).join(', ');
1701
+ const asyncKw = method.isAsync ? 'async ' : '';
1702
+ const returnType = method.isAsync ? 'async Task<dynamic>' : 'dynamic';
1703
+ this.emit(`public ${returnType} ${method.name}(${params}) {`);
1704
+ this.indent++;
1705
+ if (method.body.length === 0) {
1706
+ this.emit('return null;');
1707
+ } else {
1708
+ for (const stmt of method.body) this.visitStatement(stmt);
1709
+ }
1710
+ this.indent--;
1711
+ this.emit('}');
1712
+ }
1713
+ this.indent--;
1714
+ this.emit('}');
1715
+ this.emitRaw('');
1716
+ }
1717
+
1657
1718
  generateBuiltin(name, args) {
1658
1719
  switch (name) {
1659
1720
  case 'len': return `${args[0]}.Count`;
@@ -1694,6 +1755,13 @@ export class CSharpGenerator {
1694
1755
  case 'read': return `File.ReadAllText(${args[0]})`;
1695
1756
  case 'write': return `File.WriteAllText(${args[0]}, ${args[1]})`;
1696
1757
  case 'ask': return `(Console.Write(${args[0] || '""'}), Console.ReadLine() ?? "").Item2`;
1758
+ case 'map': return `${args[0]}.Select(x => ${args[1]}(x)).ToList()`;
1759
+ case 'filter': return `${args[0]}.Where(x => ${args[1]}(x)).ToList()`;
1760
+ case 'reduce': return `${args[0]}.Aggregate(${args[2] || '0'}, (acc, x) => ${args[1]}(acc, x))`;
1761
+ case 'find': return `${args[0]}.FirstOrDefault(x => ${args[1]}(x))`;
1762
+ case 'every': return `${args[0]}.All(x => ${args[1]}(x))`;
1763
+ case 'some': return `${args[0]}.Any(x => ${args[1]}(x))`;
1764
+ case 'foreach': return `${args[0]}.ForEach(x => ${args[1]}(x))`;
1697
1765
  default: return null;
1698
1766
  }
1699
1767
  }
@@ -164,6 +164,8 @@ export class DartGenerator {
164
164
  case 'BlockchainDecl': return this.visitBlockchain(node);
165
165
  case 'EnumDecl': return this.visitEnum(node);
166
166
  case 'Swap': return this.visitSwap(node);
167
+ case 'Destructure': return this.visitDestructure(node);
168
+ case 'ClassDecl': return this.visitClassDecl(node);
167
169
  default:
168
170
  this.emit(`// unknown: ${node.type}`);
169
171
  }
@@ -1592,6 +1594,71 @@ export class DartGenerator {
1592
1594
  this.emit(`{ final _tmp = ${a}; ${a} = ${b}; ${b} = _tmp; }`);
1593
1595
  }
1594
1596
 
1597
+ visitDestructure(node) {
1598
+ const val = this.expr(node.value);
1599
+ const keyword = node.isMut ? 'var' : 'final';
1600
+ if (node.pattern === 'array') {
1601
+ node.names.forEach((n, i) => {
1602
+ if (!n.rest) {
1603
+ const varName = n.alias || n.name;
1604
+ this.emit(`${keyword} ${varName} = ${val}[${i}];`);
1605
+ } else {
1606
+ this.emit(`${keyword} ${n.name} = ${val}.sublist(${i});`);
1607
+ }
1608
+ });
1609
+ } else {
1610
+ for (const n of node.names) {
1611
+ if (!n.rest) {
1612
+ const varName = n.alias || n.name;
1613
+ if (n.defaultValue) {
1614
+ this.emit(`${keyword} ${varName} = ${val}['${n.name}'] ?? ${this.expr(n.defaultValue)};`);
1615
+ } else {
1616
+ this.emit(`${keyword} ${varName} = ${val}['${n.name}'];`);
1617
+ }
1618
+ }
1619
+ }
1620
+ }
1621
+ }
1622
+
1623
+ visitClassDecl(node) {
1624
+ const ext = node.parent ? ` extends ${node.parent}` : '';
1625
+ this.emit(`class ${node.name}${ext} {`);
1626
+ this.indent++;
1627
+ for (const field of node.fields) {
1628
+ if (field.defaultValue) {
1629
+ this.emit(`var ${field.name} = ${this.expr(field.defaultValue)};`);
1630
+ } else {
1631
+ this.emit(`dynamic ${field.name};`);
1632
+ }
1633
+ }
1634
+ if (node.init) {
1635
+ const params = node.init.params.map(p => `dynamic ${p.name}`).join(', ');
1636
+ this.emit(`${node.name}(${params}) {`);
1637
+ this.indent++;
1638
+ if (node.parent) this.emit('super();');
1639
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1640
+ this.indent--;
1641
+ this.emit('}');
1642
+ }
1643
+ for (const method of node.methods) {
1644
+ const params = method.params.map(p => `dynamic ${p.name}`).join(', ');
1645
+ const asyncKw = method.isAsync ? 'async ' : '';
1646
+ const returnType = method.isAsync ? 'Future<dynamic>' : 'dynamic';
1647
+ this.emit(`${returnType} ${method.name}(${params}) ${asyncKw}{`);
1648
+ this.indent++;
1649
+ if (method.body.length === 0) {
1650
+ this.emit('return null;');
1651
+ } else {
1652
+ for (const stmt of method.body) this.visitStatement(stmt);
1653
+ }
1654
+ this.indent--;
1655
+ this.emit('}');
1656
+ }
1657
+ this.indent--;
1658
+ this.emit('}');
1659
+ this.emitRaw('');
1660
+ }
1661
+
1595
1662
  generateBuiltin(name, args) {
1596
1663
  switch (name) {
1597
1664
  case 'len': return `${args[0]}.length`;
@@ -1632,6 +1699,13 @@ export class DartGenerator {
1632
1699
  case 'read': { this.addImport('dart:io'); return `File(${args[0]}).readAsStringSync()`; }
1633
1700
  case 'write': { this.addImport('dart:io'); return `File(${args[0]}).writeAsStringSync(${args[1]})`; }
1634
1701
  case 'ask': { this.addImport('dart:io'); return `((){stdout.write(${args[0] || '""'}); return stdin.readLineSync() ?? "";}())`; }
1702
+ case 'map': return `${args[0]}.map((e) => ${args[1]}(e)).toList()`;
1703
+ case 'filter': return `${args[0]}.where((e) => ${args[1]}(e)).toList()`;
1704
+ case 'reduce': return `${args[0]}.fold(${args[2] || 'null'}, (acc, e) => ${args[1]}(acc, e))`;
1705
+ case 'find': return `${args[0]}.firstWhere((e) => ${args[1]}(e), orElse: () => null)`;
1706
+ case 'every': return `${args[0]}.every((e) => ${args[1]}(e))`;
1707
+ case 'some': return `${args[0]}.any((e) => ${args[1]}(e))`;
1708
+ case 'foreach': return `${args[0]}.forEach((e) => ${args[1]}(e))`;
1635
1709
  default: return null;
1636
1710
  }
1637
1711
  }
@@ -118,6 +118,8 @@ export class GoGenerator {
118
118
  case 'BlockchainDecl': return this.visitBlockchain(node);
119
119
  case 'EnumDecl': return this.visitEnum(node);
120
120
  case 'Swap': return this.visitSwap(node);
121
+ case 'Destructure': return this.visitDestructure(node);
122
+ case 'ClassDecl': return this.visitClassDecl(node);
121
123
  default:
122
124
  this.emit(`// unknown: ${node.type}`);
123
125
  }
@@ -1809,6 +1811,59 @@ export class GoGenerator {
1809
1811
  this.emit(`${a}, ${b} = ${b}, ${a}`);
1810
1812
  }
1811
1813
 
1814
+ visitDestructure(node) {
1815
+ const val = this.expr(node.value);
1816
+ if (node.pattern === 'array') {
1817
+ const names = node.names.filter(n => !n.rest).map(n => n.alias || n.name);
1818
+ const indexedVals = names.map((name, i) => `${val}[${i}]`);
1819
+ this.emit(`${names.join(', ')} := ${indexedVals.join(', ')}`);
1820
+ } else {
1821
+ for (const n of node.names) {
1822
+ if (!n.rest) {
1823
+ const varName = n.alias || n.name;
1824
+ this.emit(`${varName} := ${val}["${n.name}"]`);
1825
+ }
1826
+ }
1827
+ }
1828
+ }
1829
+
1830
+ visitClassDecl(node) {
1831
+ // Go uses struct + methods
1832
+ this.emit(`type ${node.name} struct {`);
1833
+ this.indent++;
1834
+ if (node.parent) this.emit(`${node.parent}`);
1835
+ for (const field of node.fields) {
1836
+ this.emit(`${field.name.charAt(0).toUpperCase() + field.name.slice(1)} interface{}`);
1837
+ }
1838
+ this.indent--;
1839
+ this.emit(`}`);
1840
+ this.emitRaw('');
1841
+ if (node.init) {
1842
+ const params = node.init.params.map(p => `${p.name} interface{}`).join(', ');
1843
+ this.emit(`func New${node.name}(${params}) *${node.name} {`);
1844
+ this.indent++;
1845
+ this.emit(`self := &${node.name}{}`);
1846
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1847
+ this.emit(`return self`);
1848
+ this.indent--;
1849
+ this.emit(`}`);
1850
+ this.emitRaw('');
1851
+ }
1852
+ for (const method of node.methods) {
1853
+ const params = method.params.map(p => `${p.name} interface{}`).join(', ');
1854
+ this.emit(`func (self *${node.name}) ${method.name.charAt(0).toUpperCase() + method.name.slice(1)}(${params}) interface{} {`);
1855
+ this.indent++;
1856
+ if (method.body.length === 0) {
1857
+ this.emit('return nil');
1858
+ } else {
1859
+ for (const stmt of method.body) this.visitStatement(stmt);
1860
+ }
1861
+ this.indent--;
1862
+ this.emit(`}`);
1863
+ this.emitRaw('');
1864
+ }
1865
+ }
1866
+
1812
1867
  generateBuiltin(name, args) {
1813
1868
  switch (name) {
1814
1869
  case 'len': return `len(${args[0]})`;
@@ -1837,6 +1892,13 @@ export class GoGenerator {
1837
1892
  case 'random': { this.addImport('math/rand'); return args.length >= 2 ? `rand.Intn(${args[1]}-${args[0]}+1)+${args[0]}` : `rand.Float64()`; }
1838
1893
  case 'sort': { this.addImport('sort'); return `func() []int { s := make([]int, len(${args[0]})); copy(s, ${args[0]}); sort.Ints(s); return s }()`; }
1839
1894
  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 }()`;
1895
+ case 'map': return `func() []interface{} { _r := make([]interface{}, len(${args[0]})); for _i, _v := range ${args[0]} { _r[_i] = ${args[1]}(_v) }; return _r }()`;
1896
+ case 'filter': return `func() []interface{} { var _r []interface{}; for _, _v := range ${args[0]} { if ${args[1]}(_v) { _r = append(_r, _v) } }; return _r }()`;
1897
+ case 'reduce': return `func() interface{} { _acc := ${args[2] || '0'}; for _, _v := range ${args[0]} { _acc = ${args[1]}(_acc, _v) }; return _acc }()`;
1898
+ case 'find': return `func() interface{} { for _, _v := range ${args[0]} { if ${args[1]}(_v) { return _v } }; return nil }()`;
1899
+ case 'every': return `func() bool { for _, _v := range ${args[0]} { if !${args[1]}(_v) { return false } }; return true }()`;
1900
+ case 'some': return `func() bool { for _, _v := range ${args[0]} { if ${args[1]}(_v) { return true } }; return false }()`;
1901
+ case 'foreach': return `func() { for _, _v := range ${args[0]} { ${args[1]}(_v) } }()`;
1840
1902
  default: return null;
1841
1903
  }
1842
1904
  }
@@ -228,6 +228,8 @@ export class JavaGenerator {
228
228
  case 'BlockchainDecl': return this.visitBlockchain(node);
229
229
  case 'EnumDecl': return this.visitEnum(node);
230
230
  case 'Swap': return this.visitSwap(node);
231
+ case 'Destructure': return this.visitDestructure(node);
232
+ case 'ClassDecl': return this.visitClassDecl(node);
231
233
  default:
232
234
  this.emit(`/* unknown: ${node.type} */`);
233
235
  }
@@ -1835,6 +1837,72 @@ export class JavaGenerator {
1835
1837
  this.emit(`{ var _tmp = ${a}; ${a} = ${b}; ${b} = _tmp; }`);
1836
1838
  }
1837
1839
 
1840
+ visitDestructure(node) {
1841
+ const val = this.expr(node.value);
1842
+ if (node.pattern === 'array') {
1843
+ node.names.forEach((n, i) => {
1844
+ if (n.rest) {
1845
+ this.emit(`var ${n.name} = ${val}.subList(${i}, ${val}.size());`);
1846
+ } else {
1847
+ const varName = n.alias || n.name;
1848
+ if (n.defaultValue) {
1849
+ this.emit(`var ${varName} = ${i} < ${val}.size() ? ${val}.get(${i}) : ${this.expr(n.defaultValue)};`);
1850
+ } else {
1851
+ this.emit(`var ${varName} = ${val}.get(${i});`);
1852
+ }
1853
+ }
1854
+ });
1855
+ } else {
1856
+ for (const n of node.names) {
1857
+ if (n.rest) {
1858
+ this.emit(`var ${n.name} = new java.util.HashMap<>(${val}); ${node.names.filter(x => !x.rest).forEach(x => `${n.name}.remove(${JSON.stringify(x.name)})`)};`);
1859
+ } else {
1860
+ const varName = n.alias || n.name;
1861
+ if (n.defaultValue) {
1862
+ this.emit(`var ${varName} = ${val}.getOrDefault(${JSON.stringify(n.name)}, ${this.expr(n.defaultValue)});`);
1863
+ } else {
1864
+ this.emit(`var ${varName} = ${val}.get(${JSON.stringify(n.name)});`);
1865
+ }
1866
+ }
1867
+ }
1868
+ }
1869
+ }
1870
+
1871
+ visitClassDecl(node) {
1872
+ const ext = node.parent ? ` extends ${node.parent}` : '';
1873
+ this.emit(`static class ${node.name}${ext} {`);
1874
+ this.indent++;
1875
+ for (const field of node.fields) {
1876
+ if (field.defaultValue) {
1877
+ this.emit(`Object ${field.name} = ${this.expr(field.defaultValue)};`);
1878
+ }
1879
+ }
1880
+ if (node.init) {
1881
+ const params = node.init.params.map(p => `Object ${p.name}`).join(', ');
1882
+ this.emit(`${node.name}(${params}) {`);
1883
+ this.indent++;
1884
+ if (node.parent) this.emit('super();');
1885
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1886
+ this.indent--;
1887
+ this.emit('}');
1888
+ }
1889
+ for (const method of node.methods) {
1890
+ const params = method.params.map(p => `Object ${p.name}`).join(', ');
1891
+ this.emit(`Object ${method.name}(${params}) {`);
1892
+ this.indent++;
1893
+ if (method.body.length === 0) {
1894
+ this.emit('return null;');
1895
+ } else {
1896
+ for (const stmt of method.body) this.visitStatement(stmt);
1897
+ }
1898
+ this.indent--;
1899
+ this.emit('}');
1900
+ }
1901
+ this.indent--;
1902
+ this.emit('}');
1903
+ this.emitRaw('');
1904
+ }
1905
+
1838
1906
  generateBuiltin(name, args) {
1839
1907
  switch (name) {
1840
1908
  case 'len': return `${args[0]}.size()`;
@@ -1869,6 +1937,13 @@ export class JavaGenerator {
1869
1937
  case 'json_parse': return `new com.google.gson.Gson().fromJson(${args[0]}, Object.class)`;
1870
1938
  case 'json_str': return `new com.google.gson.Gson().toJson(${args[0]})`;
1871
1939
  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())`;
1940
+ case 'map': { this.addImport('java.util.stream.Collectors'); return `${args[0]}.stream().map(${args[1]}).collect(Collectors.toList())`; }
1941
+ case 'filter': { this.addImport('java.util.stream.Collectors'); return `${args[0]}.stream().filter(${args[1]}).collect(Collectors.toList())`; }
1942
+ case 'reduce': return args[2] ? `${args[0]}.stream().reduce(${args[2]}, ${args[1]})` : `${args[0]}.stream().reduce(${args[1]}).orElse(null)`;
1943
+ case 'find': return `${args[0]}.stream().filter(${args[1]}).findFirst().orElse(null)`;
1944
+ case 'every': return `${args[0]}.stream().allMatch(${args[1]})`;
1945
+ case 'some': return `${args[0]}.stream().anyMatch(${args[1]})`;
1946
+ case 'foreach': return `${args[0]}.forEach(${args[1]})`;
1872
1947
  default: return null;
1873
1948
  }
1874
1949
  }