naider 1.17.4 → 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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Node AI Development Environment** — A programming language simpler than Python, designed for AI-speed code generation, that transpiles to **15 languages**.
4
4
 
5
- NAIDE is built on four principles: simpler than Python (built-in functions, syntax sugar, zero boilerplate), one way to write everything (zero ambiguity), keyword-driven intent (the first token decides meaning), and minimal token count (fewer tokens = faster AI generation). Write once, compile to any target. 35+ built-in functions, syntax sugar (`unless`, `until`, `repeat`, `swap`, `is`/`isnt`, one-line functions), and 47 built-in features including servers, databases, authentication, bots, GraphQL, gRPC, WebRTC, blockchain, and more.
5
+ NAIDE is built on four principles: simpler than Python (built-in functions, syntax sugar, zero boilerplate), one way to write everything (zero ambiguity), keyword-driven intent (the first token decides meaning), and minimal token count (fewer tokens = faster AI generation). Write once, compile to any target. 40+ built-in functions, syntax sugar (`unless`, `until`, `repeat`, `swap`, `is`/`isnt`, one-line functions, `auto` type inference, destructuring, pipe operator), and 55+ built-in features including servers, databases, authentication, bots, GraphQL, gRPC, WebRTC, blockchain, and more.
6
6
 
7
7
  ### Compilation Targets
8
8
 
@@ -136,9 +136,29 @@ any data = null
136
136
 
137
137
  mut int counter = 0 # mutable (let)
138
138
  mut str label = "init"
139
+
140
+ auto x = 42 # type inferred (const)
141
+ auto msg = "hello" # compiler infers str
142
+ mut auto counter2 = 0 # type inferred (let)
139
143
  ```
140
144
 
141
- Types: `str`, `int`, `num`, `bool`, `list`, `map`, `any`, `json`, `void`
145
+ Types: `str`, `int`, `num`, `bool`, `list`, `map`, `any`, `json`, `void`, `auto` (inferred)
146
+
147
+ ### Destructuring
148
+
149
+ ```python
150
+ # Object destructuring
151
+ auto {name, age} = user
152
+ auto {name, age = 0} = user # with defaults
153
+ auto {name, ...rest} = user # with rest
154
+ mut {score, level} = gameState # mutable
155
+
156
+ # Array destructuring
157
+ auto [first, second] = items
158
+ auto [head, ...tail] = items # with rest
159
+ auto [x, y = 0] = coords # with defaults
160
+ mut [a, b] = pair # mutable
161
+ ```
142
162
 
143
163
  ### String Interpolation
144
164
 
@@ -257,6 +277,28 @@ model Admin extends User:
257
277
  ret ["read", "write", "delete"]
258
278
  ```
259
279
 
280
+ Schema inheritance with constructors and methods:
281
+
282
+ ```python
283
+ schema Animal:
284
+ id auto
285
+ name str required
286
+ species str required
287
+
288
+ schema Dog extends Animal:
289
+ breed str optional
290
+ trained bool default(false)
291
+
292
+ init(str name, str breed):
293
+ self.name = name
294
+ self.breed = breed
295
+
296
+ fn bark() -> str:
297
+ ret "Woof! I'm {self.name}"
298
+ ```
299
+
300
+ `init(params):` defines a constructor. `fn method():` defines methods. `extends` inherits all fields and methods from the parent.
301
+
260
302
  ### Pipe Operator
261
303
 
262
304
  ```python
@@ -264,8 +306,37 @@ list result = data
264
306
  |> filter((x) => x.active)
265
307
  |> map((x) => x.name)
266
308
  |> sort()
309
+
310
+ int total = items
311
+ |> filter((x) => x > 0)
312
+ |> map((x) => x * 2)
313
+ |> reduce((a, b) => a + b, 0)
267
314
  ```
268
315
 
316
+ Chain operations left to right for readable data transformations.
317
+
318
+ ### Optional Chaining & Null Coalescing
319
+
320
+ ```python
321
+ str name = user?.name # safe property access
322
+ any val = data?.nested?.value # deep safe access
323
+ str display = user?.name ?? "Anonymous" # fallback on null/undefined
324
+ int port = config?.port ?? 3000
325
+ ```
326
+
327
+ `?.` safely accesses properties (returns `undefined` if the left side is `null`/`undefined`). `??` provides a fallback value when the left side is `null` or `undefined`.
328
+
329
+ ### Spread Operator
330
+
331
+ ```python
332
+ list combined = [...listA, ...listB]
333
+ map merged = {...defaults, ...overrides}
334
+ list withExtra = [...items, 4, 5, 6]
335
+ map withDebug = {...config, debug: true}
336
+ ```
337
+
338
+ Spread arrays and objects with `...`. Works in list literals, map literals, and function arguments.
339
+
269
340
  ### Imports / Exports
270
341
 
271
342
  ```python
@@ -888,6 +959,15 @@ Variables become constants. Missing `required` vars exit with an error.
888
959
  ## Syntax Sugar (Simpler than Python)
889
960
 
890
961
  ```python
962
+ # auto — type inference
963
+ auto x = 42
964
+ auto msg = "hello"
965
+ mut auto counter = 0
966
+
967
+ # destructuring
968
+ auto {name, age} = user
969
+ auto [first, ...rest] = items
970
+
891
971
  # unless — negated if
892
972
  unless x > 10:
893
973
  log "small"
@@ -918,6 +998,16 @@ if y isnt null: log "exists"
918
998
  # one-line functions
919
999
  fn double(int x) -> int = x * 2
920
1000
 
1001
+ # pipe operator
1002
+ list result = items |> filter((x) => x > 0) |> map((x) => x * 2)
1003
+
1004
+ # optional chaining + null coalescing
1005
+ str name = user?.name ?? "Anonymous"
1006
+
1007
+ # spread
1008
+ list all = [...a, ...b]
1009
+ map merged = {...defaults, ...overrides}
1010
+
921
1011
  # print alias
922
1012
  print "hello world"
923
1013
  ```
@@ -955,6 +1045,15 @@ list flat_list = flat(nested)
955
1045
  list zipped = zip(a, b)
956
1046
  list chunks = chunk(items, 3)
957
1047
 
1048
+ # Functional ops (map/filter/reduce)
1049
+ list doubled = map(items, (x) => x * 2)
1050
+ list big = filter(items, (x) => x > 5)
1051
+ int total = reduce(items, (a, b) => a + b, 0)
1052
+ any found = find(items, (x) => x > 3)
1053
+ bool allPos = every(items, (x) => x > 0)
1054
+ bool hasNeg = some(items, (x) => x < 0)
1055
+ foreach(items, (x) => log x)
1056
+
958
1057
  # Math
959
1058
  num a = abs(-5)
960
1059
  num r = round(3.7)
package/SPEC.naide CHANGED
@@ -27,6 +27,26 @@ any data = null
27
27
  mut int counter = 0
28
28
  mut str label = "initial"
29
29
 
30
+ # auto 型推論 (コンパイラが型を推論)
31
+ auto x = 42 # const x = 42
32
+ auto msg = "hello" # const msg = "hello"
33
+ auto items = [1, 2, 3] # const items = [1, 2, 3]
34
+ mut auto counter2 = 0 # let counter2 = 0
35
+
36
+
37
+ # ---- 分割代入 (Destructuring) ----
38
+ # オブジェクト分割代入
39
+ auto {name2, age} = user
40
+ auto {name3, age2 = 0} = user # デフォルト値
41
+ auto {name4, ...rest} = user # レスト
42
+ mut {score, level} = gameState # 可変
43
+
44
+ # 配列分割代入
45
+ auto [first, second] = items
46
+ auto [head, ...tail] = items # レスト
47
+ auto [x2, y = 0] = coords # デフォルト値
48
+ mut [a3, b3] = pair # 可変
49
+
30
50
 
31
51
  # ---- 文字列補間 ----
32
52
  # ダブルクォートで {式} が自動展開
@@ -132,12 +152,29 @@ if err instanceof TypeError:
132
152
  log "type error occurred"
133
153
 
134
154
 
155
+ # ---- map/filter/reduce ビルトイン ----
156
+ # コレクション操作の組み込み関数
157
+ list doubled = map(items, (x) => x * 2)
158
+ list big = filter(items, (x) => x > 5)
159
+ int total2 = reduce(items, (a, b) => a + b, 0)
160
+ any found = find(items, (x) => x > 3)
161
+ bool allBig = every(items, (x) => x > 0)
162
+ bool hasBig = some(items, (x) => x > 10)
163
+ foreach(items, (x) => log x)
164
+
165
+
135
166
  # ---- パイプ演算子 ----
136
167
  # データ変換チェーンが読みやすい
137
168
  list result = [1, 2, 3, 4, 5]
138
169
  |> filter((x) => x > 2)
139
170
  |> map((x) => x * 10)
140
171
 
172
+ # パイプ + map/filter/reduce の組み合わせ
173
+ list names = users
174
+ |> filter((u) => u.active)
175
+ |> map((u) => u.name)
176
+ |> sort()
177
+
141
178
 
142
179
  # ---- クラス (model) ----
143
180
  model User:
@@ -159,6 +196,25 @@ model Admin extends User:
159
196
  ret ["read", "write", "delete"]
160
197
 
161
198
 
199
+ # ---- スキーマ継承 (schema extends) ----
200
+ # schema も extends で継承可能
201
+ schema Animal:
202
+ id auto
203
+ name str required
204
+ species str required
205
+
206
+ schema Dog extends Animal:
207
+ breed str optional
208
+ trained bool default(false)
209
+
210
+ init(str name, str breed):
211
+ self.name = name
212
+ self.breed = breed
213
+
214
+ fn bark() -> str:
215
+ ret "Woof! I'm {self.name}"
216
+
217
+
162
218
  # ---- データベース永続化 ----
163
219
  # db ディレクトリパス → スキーマストアがJSONファイルに自動保存
164
220
  db "data/"
@@ -436,7 +492,15 @@ pub str VERSION = "1.0.0"
436
492
 
437
493
 
438
494
  # ---- null安全 ----
495
+ # オプショナルチェーニング (?.)
439
496
  any val = data?.nested?.value ?? "default"
497
+ str userName = user?.name
498
+ any first = items?.[0]
499
+ any result2 = obj?.method?.()
500
+
501
+ # Null合体演算子 (??)
502
+ str displayName = user?.name ?? "Anonymous"
503
+ int port = config?.port ?? 3000
440
504
 
441
505
 
442
506
  # ---- await.all (Promise.all) ----
@@ -446,6 +510,8 @@ any val = data?.nested?.value ?? "default"
446
510
  # ---- スプレッド ----
447
511
  list combined = [...items, 4, 5, 6]
448
512
  map merged = {...config, debug: true}
513
+ list all = [...listA, ...listB]
514
+ map full = {...defaults, ...overrides}
449
515
 
450
516
 
451
517
  # ---- ページ生成 (HTML) ----
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.4",
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
  }