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.
@@ -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
  }
@@ -139,6 +139,8 @@ export class KotlinGenerator {
139
139
  case 'BlockchainDecl': return this.visitBlockchain(node);
140
140
  case 'EnumDecl': return this.visitEnum(node);
141
141
  case 'Swap': return this.visitSwap(node);
142
+ case 'Destructure': return this.visitDestructure(node);
143
+ case 'ClassDecl': return this.visitClassDecl(node);
142
144
  default:
143
145
  this.emit(`// unknown: ${node.type}`);
144
146
  }
@@ -1840,6 +1842,60 @@ export class KotlinGenerator {
1840
1842
  this.emit(`${a} = ${b}.also { ${b} = ${a} }`);
1841
1843
  }
1842
1844
 
1845
+ visitDestructure(node) {
1846
+ const val = this.expr(node.value);
1847
+ const keyword = node.isMut ? 'var' : 'val';
1848
+ if (node.pattern === 'array') {
1849
+ const names = node.names.filter(n => !n.rest).map(n => n.alias || n.name);
1850
+ this.emit(`${keyword} (${names.join(', ')}) = ${val}`);
1851
+ } else {
1852
+ for (const n of node.names) {
1853
+ if (!n.rest) {
1854
+ const varName = n.alias || n.name;
1855
+ if (n.defaultValue) {
1856
+ this.emit(`${keyword} ${varName} = ${val}["${n.name}"] ?: ${this.expr(n.defaultValue)}`);
1857
+ } else {
1858
+ this.emit(`${keyword} ${varName} = ${val}["${n.name}"]`);
1859
+ }
1860
+ }
1861
+ }
1862
+ }
1863
+ }
1864
+
1865
+ visitClassDecl(node) {
1866
+ const ext = node.parent ? ` : ${node.parent}()` : '';
1867
+ const initParams = node.init ? node.init.params.map(p => `${p.name}: Any`).join(', ') : '';
1868
+ this.emit(`open class ${node.name}(${initParams})${ext} {`);
1869
+ this.indent++;
1870
+ for (const field of node.fields) {
1871
+ if (field.defaultValue) {
1872
+ this.emit(`var ${field.name} = ${this.expr(field.defaultValue)}`);
1873
+ }
1874
+ }
1875
+ if (node.init) {
1876
+ this.emit(`init {`);
1877
+ this.indent++;
1878
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1879
+ this.indent--;
1880
+ this.emit(`}`);
1881
+ }
1882
+ for (const method of node.methods) {
1883
+ const params = method.params.map(p => `${p.name}: Any`).join(', ');
1884
+ this.emit(`fun ${method.name}(${params}): Any? {`);
1885
+ this.indent++;
1886
+ if (method.body.length === 0) {
1887
+ this.emit('return null');
1888
+ } else {
1889
+ for (const stmt of method.body) this.visitStatement(stmt);
1890
+ }
1891
+ this.indent--;
1892
+ this.emit('}');
1893
+ }
1894
+ this.indent--;
1895
+ this.emit('}');
1896
+ this.emitRaw('');
1897
+ }
1898
+
1843
1899
  generateBuiltin(name, args) {
1844
1900
  switch (name) {
1845
1901
  case 'len': return `${args[0]}.size`;
@@ -1880,6 +1936,13 @@ export class KotlinGenerator {
1880
1936
  case 'read': return `java.io.File(${args[0]}).readText()`;
1881
1937
  case 'write': return `java.io.File(${args[0]}).writeText(${args[1]})`;
1882
1938
  case 'ask': return `(print(${args[0] || '""'}); readLine() ?: "")`;
1939
+ case 'map': return `${args[0]}.map { ${args[1]}(it) }`;
1940
+ case 'filter': return `${args[0]}.filter { ${args[1]}(it) }`;
1941
+ case 'reduce': return args.length >= 3 ? `${args[0]}.fold(${args[2]}) { acc, it -> ${args[1]}(acc, it) }` : `${args[0]}.reduce { acc, it -> ${args[1]}(acc, it) }`;
1942
+ case 'find': return `${args[0]}.find { ${args[1]}(it) }`;
1943
+ case 'every': return `${args[0]}.all { ${args[1]}(it) }`;
1944
+ case 'some': return `${args[0]}.any { ${args[1]}(it) }`;
1945
+ case 'foreach': return `${args[0]}.forEach { ${args[1]}(it) }`;
1883
1946
  default: return null;
1884
1947
  }
1885
1948
  }
@@ -105,6 +105,8 @@ export class PhpGenerator {
105
105
  case 'BlockchainDecl': return this.visitBlockchain(node);
106
106
  case 'EnumDecl': return this.visitEnum(node);
107
107
  case 'Swap': return this.visitSwap(node);
108
+ case 'Destructure': return this.visitDestructure(node);
109
+ case 'ClassDecl': return this.visitClassDecl(node);
108
110
  default:
109
111
  this.emit(`/* unknown: ${node.type} */`);
110
112
  }
@@ -1599,6 +1601,58 @@ export class PhpGenerator {
1599
1601
  this.emit(`[$${a.replace('$','')}, $${b.replace('$','')}] = [$${b.replace('$','')}, $${a.replace('$','')}];`);
1600
1602
  }
1601
1603
 
1604
+ visitDestructure(node) {
1605
+ const val = this.expr(node.value);
1606
+ if (node.pattern === 'array') {
1607
+ const names = node.names.map(n => {
1608
+ if (n.rest) return `...$${n.name}`;
1609
+ return `$${n.alias || n.name}`;
1610
+ });
1611
+ this.emit(`[${names.join(', ')}] = ${val};`);
1612
+ } else {
1613
+ const parts = node.names.filter(n => !n.rest).map(n => {
1614
+ const varName = n.alias || n.name;
1615
+ return `'${n.name}' => $${varName}`;
1616
+ });
1617
+ this.emit(`[${parts.join(', ')}] = ${val};`);
1618
+ }
1619
+ }
1620
+
1621
+ visitClassDecl(node) {
1622
+ const ext = node.parent ? ` extends ${node.parent}` : '';
1623
+ this.emit(`class ${node.name}${ext} {`);
1624
+ this.indent++;
1625
+ for (const field of node.fields) {
1626
+ if (field.defaultValue) {
1627
+ this.emit(`public $${field.name} = ${this.expr(field.defaultValue)};`);
1628
+ }
1629
+ }
1630
+ if (node.init) {
1631
+ const params = node.init.params.map(p => `$${p.name}`).join(', ');
1632
+ this.emit(`public function __construct(${params}) {`);
1633
+ this.indent++;
1634
+ if (node.parent) this.emit('parent::__construct();');
1635
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1636
+ this.indent--;
1637
+ this.emit('}');
1638
+ }
1639
+ for (const method of node.methods) {
1640
+ const params = method.params.map(p => `$${p.name}`).join(', ');
1641
+ this.emit(`public function ${method.name}(${params}) {`);
1642
+ this.indent++;
1643
+ if (method.body.length === 0) {
1644
+ this.emit('// empty');
1645
+ } else {
1646
+ for (const stmt of method.body) this.visitStatement(stmt);
1647
+ }
1648
+ this.indent--;
1649
+ this.emit('}');
1650
+ }
1651
+ this.indent--;
1652
+ this.emit('}');
1653
+ this.emitRaw('');
1654
+ }
1655
+
1602
1656
  generateBuiltin(name, args) {
1603
1657
  switch (name) {
1604
1658
  case 'len': return `count(${args[0]})`;
@@ -1639,6 +1693,13 @@ export class PhpGenerator {
1639
1693
  case 'ask': return `readline(${args[0] || '""'})`;
1640
1694
  case 'chunk': return `array_chunk(${args[0]}, ${args[1]})`;
1641
1695
  case 'zip': return `array_map(null, ${args[0]}, ${args[1]})`;
1696
+ case 'map': return `array_map(${args[1]}, ${args[0]})`;
1697
+ case 'filter': return `array_values(array_filter(${args[0]}, ${args[1]}))`;
1698
+ case 'reduce': return `array_reduce(${args[0]}, ${args[1]}, ${args[2] || 'null'})`;
1699
+ case 'find': return `current(array_filter(${args[0]}, ${args[1]}))`;
1700
+ case 'every': return `count(array_filter(${args[0]}, ${args[1]})) === count(${args[0]})`;
1701
+ case 'some': return `count(array_filter(${args[0]}, ${args[1]})) > 0`;
1702
+ case 'foreach': return `array_walk(${args[0]}, ${args[1]})`;
1642
1703
  default: return null;
1643
1704
  }
1644
1705
  }
@@ -164,6 +164,8 @@ export class PythonGenerator {
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
  }
@@ -2494,6 +2496,83 @@ export class PythonGenerator {
2494
2496
  this.emit(`${a}, ${b} = ${b}, ${a}`);
2495
2497
  }
2496
2498
 
2499
+ // ===== Destructure =====
2500
+ visitDestructure(node) {
2501
+ const val = this.expr(node.value);
2502
+ if (node.pattern === 'array') {
2503
+ const names = node.names.map(n => {
2504
+ if (n.rest) return `*${n.name}`;
2505
+ return n.name;
2506
+ });
2507
+ this.emit(`${names.join(', ')} = ${val}`);
2508
+ // Handle defaults for array destructuring
2509
+ for (const n of node.names) {
2510
+ if (n.defaultValue && !n.rest) {
2511
+ this.emit(`${n.name} = ${n.name} if ${n.name} is not None else ${this.expr(n.defaultValue)}`);
2512
+ }
2513
+ }
2514
+ } else {
2515
+ // object destructuring — per-field assignment
2516
+ for (const n of node.names) {
2517
+ if (n.rest) {
2518
+ this.emit(`${n.name} = {k: v for k, v in ${val}.items() if k not in {${node.names.filter(x => !x.rest).map(x => JSON.stringify(x.name)).join(', ')}}}`);
2519
+ } else {
2520
+ const varName = n.alias || n.name;
2521
+ if (n.defaultValue) {
2522
+ this.emit(`${varName} = ${val}.get(${JSON.stringify(n.name)}, ${this.expr(n.defaultValue)})`);
2523
+ } else {
2524
+ this.emit(`${varName} = ${val}[${JSON.stringify(n.name)}]`);
2525
+ }
2526
+ }
2527
+ }
2528
+ }
2529
+ }
2530
+
2531
+ // ===== ClassDecl =====
2532
+ visitClassDecl(node) {
2533
+ const ext = node.parent ? `(${node.parent})` : '';
2534
+ this.emit(`class ${node.name}${ext}:`);
2535
+ this.indent++;
2536
+ if (node.init) {
2537
+ const params = node.init.params.map(p => p.name).join(', ');
2538
+ const selfParams = params ? `self, ${params}` : 'self';
2539
+ this.emit(`def __init__(${selfParams}):`);
2540
+ this.indent++;
2541
+ if (node.parent) this.emit('super().__init__()');
2542
+ if (node.init.body.length === 0 && !node.parent) {
2543
+ this.emit('pass');
2544
+ } else {
2545
+ for (const stmt of node.init.body) this.visitStatement(stmt);
2546
+ }
2547
+ this.indent--;
2548
+ this.emitRaw('');
2549
+ }
2550
+ for (const field of node.fields) {
2551
+ if (field.defaultValue) {
2552
+ this.emit(`${field.name} = ${this.expr(field.defaultValue)}`);
2553
+ }
2554
+ }
2555
+ for (const method of node.methods) {
2556
+ const async = method.isAsync ? 'async ' : '';
2557
+ const params = method.params.map(p => p.name).join(', ');
2558
+ const selfParams = params ? `self, ${params}` : 'self';
2559
+ this.emit(`${async}def ${method.name}(${selfParams}):`);
2560
+ this.indent++;
2561
+ if (method.body.length === 0) {
2562
+ this.emit('pass');
2563
+ } else {
2564
+ for (const stmt of method.body) this.visitStatement(stmt);
2565
+ }
2566
+ this.indent--;
2567
+ this.emitRaw('');
2568
+ }
2569
+ if (!node.init && node.fields.length === 0 && node.methods.length === 0) {
2570
+ this.emit('pass');
2571
+ }
2572
+ this.indent--;
2573
+ this.emitRaw('');
2574
+ }
2575
+
2497
2576
  // ===== Builtins =====
2498
2577
  generateBuiltin(name, args) {
2499
2578
  switch (name) {
@@ -2536,6 +2615,13 @@ export class PythonGenerator {
2536
2615
  case 'now': { this.addImport('time'); return `int(time.time() * 1000)`; }
2537
2616
  case 'time': { this.addFromImport('datetime', 'datetime'); return `datetime.now().isoformat()`; }
2538
2617
  case 'chunk': return `[${args[0]}[i:i+${args[1]}] for i in range(0, len(${args[0]}), ${args[1]})]`;
2618
+ case 'map': return `list(map(${args[1]}, ${args[0]}))`;
2619
+ case 'filter': return `list(filter(${args[1]}, ${args[0]}))`;
2620
+ case 'reduce': { this.addFromImport('functools', 'reduce'); return args[2] ? `reduce(${args[1]}, ${args[0]}, ${args[2]})` : `reduce(${args[1]}, ${args[0]})`; }
2621
+ case 'find': return `next((x for x in ${args[0]} if ${args[1]}(x)), None)`;
2622
+ case 'every': return `all(${args[1]}(x) for x in ${args[0]})`;
2623
+ case 'some': return `any(${args[1]}(x) for x in ${args[0]})`;
2624
+ case 'foreach': return `[${args[1]}(x) for x in ${args[0]}]`;
2539
2625
  default: return null;
2540
2626
  }
2541
2627
  }
@@ -113,6 +113,8 @@ export class RubyGenerator {
113
113
  case 'BlockchainDecl': return this.visitBlockchain(node);
114
114
  case 'EnumDecl': return this.visitEnum(node);
115
115
  case 'Swap': return this.visitSwap(node);
116
+ case 'Destructure': return this.visitDestructure(node);
117
+ case 'ClassDecl': return this.visitClassDecl(node);
116
118
  default:
117
119
  this.emit(`# unknown: ${node.type}`);
118
120
  }
@@ -1553,6 +1555,51 @@ export class RubyGenerator {
1553
1555
  this.emit(`${a}, ${b} = ${b}, ${a}`);
1554
1556
  }
1555
1557
 
1558
+ visitDestructure(node) {
1559
+ const val = this.expr(node.value);
1560
+ if (node.pattern === 'array') {
1561
+ const names = node.names.map(n => {
1562
+ if (n.rest) return `*${n.name}`;
1563
+ return n.alias || n.name;
1564
+ });
1565
+ this.emit(`${names.join(', ')} = ${val}`);
1566
+ } else {
1567
+ const keys = node.names.filter(n => !n.rest).map(n => `:${n.name}`);
1568
+ const vars = node.names.filter(n => !n.rest).map(n => n.alias || n.name);
1569
+ this.emit(`${vars.join(', ')} = ${val}.values_at(${keys.join(', ')})`);
1570
+ }
1571
+ }
1572
+
1573
+ visitClassDecl(node) {
1574
+ const ext = node.parent ? ` < ${node.parent}` : '';
1575
+ this.emit(`class ${node.name}${ext}`);
1576
+ this.indent++;
1577
+ if (node.init) {
1578
+ const params = node.init.params.map(p => p.name).join(', ');
1579
+ this.emit(`def initialize(${params})`);
1580
+ this.indent++;
1581
+ if (node.parent) this.emit('super()');
1582
+ for (const stmt of node.init.body) this.visitStatement(stmt);
1583
+ this.indent--;
1584
+ this.emit('end');
1585
+ }
1586
+ for (const method of node.methods) {
1587
+ const params = method.params.map(p => p.name).join(', ');
1588
+ this.emit(`def ${method.name}(${params})`);
1589
+ this.indent++;
1590
+ if (method.body.length === 0) {
1591
+ this.emit('nil');
1592
+ } else {
1593
+ for (const stmt of method.body) this.visitStatement(stmt);
1594
+ }
1595
+ this.indent--;
1596
+ this.emit('end');
1597
+ }
1598
+ this.indent--;
1599
+ this.emit('end');
1600
+ this.emitRaw('');
1601
+ }
1602
+
1556
1603
  generateBuiltin(name, args) {
1557
1604
  switch (name) {
1558
1605
  case 'len': return `${args[0]}.length`;
@@ -1593,6 +1640,13 @@ export class RubyGenerator {
1593
1640
  case 'read': return `File.read(${args[0]})`;
1594
1641
  case 'write': return `File.write(${args[0]}, ${args[1]})`;
1595
1642
  case 'ask': return `(print(${args[0] || '""'}); gets.chomp)`;
1643
+ case 'map': return `${args[0]}.map { |_x| ${args[1]}.call(_x) }`;
1644
+ case 'filter': return `${args[0]}.select { |_x| ${args[1]}.call(_x) }`;
1645
+ case 'reduce': return args.length >= 3 ? `${args[0]}.reduce(${args[2]}) { |_acc, _x| ${args[1]}.call(_acc, _x) }` : `${args[0]}.reduce { |_acc, _x| ${args[1]}.call(_acc, _x) }`;
1646
+ case 'find': return `${args[0]}.find { |_x| ${args[1]}.call(_x) }`;
1647
+ case 'every': return `${args[0]}.all? { |_x| ${args[1]}.call(_x) }`;
1648
+ case 'some': return `${args[0]}.any? { |_x| ${args[1]}.call(_x) }`;
1649
+ case 'foreach': return `${args[0]}.each { |_x| ${args[1]}.call(_x) }`;
1596
1650
  default: return null;
1597
1651
  }
1598
1652
  }