novac 2.0.1 → 2.2.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.
Files changed (161) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1574 -597
  3. package/bin/novac +468 -171
  4. package/bin/nvc +522 -0
  5. package/bin/nvml +78 -17
  6. package/demo.nv +0 -0
  7. package/demo_builtins.nv +0 -0
  8. package/demo_http.nv +0 -0
  9. package/examples/bf.nv +69 -0
  10. package/examples/math.nv +21 -0
  11. package/kits/birdAPI/kitdef.js +954 -0
  12. package/kits/kitRNG/kitdef.js +740 -0
  13. package/kits/kitSSH/kitdef.js +1272 -0
  14. package/kits/kitadb/kitdef.js +606 -0
  15. package/kits/kitai/kitdef.js +2185 -0
  16. package/kits/kitansi/kitdef.js +1402 -0
  17. package/kits/kitcanvas/kitdef.js +914 -0
  18. package/kits/kitclippy/kitdef.js +925 -0
  19. package/kits/kitformat/kitdef.js +1485 -0
  20. package/kits/kitgps/kitdef.js +1862 -0
  21. package/kits/kitlibproc/kitdef.js +3 -2
  22. package/kits/kitmatrix/ex.js +19 -0
  23. package/kits/kitmatrix/kitdef.js +960 -0
  24. package/kits/kitmorse/kitdef.js +229 -0
  25. package/kits/kitmpatch/kitdef.js +906 -0
  26. package/kits/kitnet/kitdef.js +1401 -0
  27. package/kits/kitnovacweb/README.md +1416 -143
  28. package/kits/kitnovacweb/kitdef.js +92 -2
  29. package/kits/kitnovacweb/nvml/executor.js +578 -176
  30. package/kits/kitnovacweb/nvml/index.js +2 -2
  31. package/kits/kitnovacweb/nvml/lexer.js +72 -69
  32. package/kits/kitnovacweb/nvml/parser.js +328 -159
  33. package/kits/kitnovacweb/nvml/renderer.js +770 -270
  34. package/kits/kitparse/kitdef.js +1688 -0
  35. package/kits/kitproto/kitdef.js +613 -0
  36. package/kits/kitqr/kitdef.js +637 -0
  37. package/kits/kitregex++/kitdef.js +1353 -0
  38. package/kits/kitrequire/kitdef.js +1599 -0
  39. package/kits/kitx11/kitdef.js +1 -0
  40. package/kits/kitx11/kitx11.js +2472 -0
  41. package/kits/kitx11/kitx11_conn.js +948 -0
  42. package/kits/kitx11/kitx11_worker.js +121 -0
  43. package/kits/libtea/kitdef.js +2691 -0
  44. package/kits/libterm/ex.js +285 -0
  45. package/kits/libterm/kitdef.js +1927 -0
  46. package/novac/LICENSE +21 -0
  47. package/novac/README.md +1823 -0
  48. package/novac/bin/novac +950 -0
  49. package/novac/bin/nvc +522 -0
  50. package/novac/bin/nvml +542 -0
  51. package/novac/demo.nv +245 -0
  52. package/novac/demo_builtins.nv +209 -0
  53. package/novac/demo_http.nv +62 -0
  54. package/novac/examples/bf.nv +69 -0
  55. package/novac/examples/math.nv +21 -0
  56. package/novac/kits/kitai/kitdef.js +2185 -0
  57. package/novac/kits/kitansi/kitdef.js +1402 -0
  58. package/novac/kits/kitformat/kitdef.js +1485 -0
  59. package/novac/kits/kitgps/kitdef.js +1862 -0
  60. package/novac/kits/kitlibfs/kitdef.js +231 -0
  61. package/{examples/example-project/nova_modules → novac/kits}/kitlibproc/kitdef.js +3 -2
  62. package/novac/kits/kitmatrix/ex.js +19 -0
  63. package/novac/kits/kitmatrix/kitdef.js +960 -0
  64. package/novac/kits/kitmpatch/kitdef.js +906 -0
  65. package/novac/kits/kitnovacweb/README.md +1572 -0
  66. package/novac/kits/kitnovacweb/demo.nv +12 -0
  67. package/novac/kits/kitnovacweb/demo.nvml +71 -0
  68. package/novac/kits/kitnovacweb/index.nova +12 -0
  69. package/novac/kits/kitnovacweb/kitdef.js +692 -0
  70. package/novac/kits/kitnovacweb/nova.kit.json +8 -0
  71. package/novac/kits/kitnovacweb/nvml/executor.js +739 -0
  72. package/novac/kits/kitnovacweb/nvml/index.js +67 -0
  73. package/novac/kits/kitnovacweb/nvml/lexer.js +263 -0
  74. package/novac/kits/kitnovacweb/nvml/parser.js +508 -0
  75. package/novac/kits/kitnovacweb/nvml/renderer.js +924 -0
  76. package/novac/kits/kitparse/kitdef.js +1688 -0
  77. package/novac/kits/kitregex++/kitdef.js +1353 -0
  78. package/novac/kits/kitrequire/kitdef.js +1599 -0
  79. package/novac/kits/kitx11/kitdef.js +1 -0
  80. package/novac/kits/kitx11/kitx11.js +2472 -0
  81. package/novac/kits/kitx11/kitx11_conn.js +948 -0
  82. package/novac/kits/kitx11/kitx11_worker.js +121 -0
  83. package/novac/kits/libtea/tf.js +2691 -0
  84. package/novac/kits/libterm/ex.js +285 -0
  85. package/novac/kits/libterm/kitdef.js +1927 -0
  86. package/novac/node_modules/chalk/license +9 -0
  87. package/novac/node_modules/chalk/package.json +83 -0
  88. package/novac/node_modules/chalk/readme.md +297 -0
  89. package/novac/node_modules/chalk/source/index.d.ts +325 -0
  90. package/novac/node_modules/chalk/source/index.js +225 -0
  91. package/novac/node_modules/chalk/source/utilities.js +33 -0
  92. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  93. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  94. package/novac/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  95. package/novac/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  96. package/novac/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  97. package/novac/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  98. package/novac/node_modules/commander/LICENSE +22 -0
  99. package/novac/node_modules/commander/Readme.md +1176 -0
  100. package/novac/node_modules/commander/esm.mjs +16 -0
  101. package/novac/node_modules/commander/index.js +24 -0
  102. package/novac/node_modules/commander/lib/argument.js +150 -0
  103. package/novac/node_modules/commander/lib/command.js +2777 -0
  104. package/novac/node_modules/commander/lib/error.js +39 -0
  105. package/novac/node_modules/commander/lib/help.js +747 -0
  106. package/novac/node_modules/commander/lib/option.js +380 -0
  107. package/novac/node_modules/commander/lib/suggestSimilar.js +101 -0
  108. package/novac/node_modules/commander/package-support.json +19 -0
  109. package/novac/node_modules/commander/package.json +82 -0
  110. package/novac/node_modules/commander/typings/esm.d.mts +3 -0
  111. package/novac/node_modules/commander/typings/index.d.ts +1113 -0
  112. package/novac/node_modules/node-addon-api/LICENSE.md +9 -0
  113. package/novac/node_modules/node-addon-api/README.md +95 -0
  114. package/novac/node_modules/node-addon-api/common.gypi +21 -0
  115. package/novac/node_modules/node-addon-api/except.gypi +25 -0
  116. package/novac/node_modules/node-addon-api/index.js +14 -0
  117. package/novac/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  118. package/novac/node_modules/node-addon-api/napi-inl.h +7165 -0
  119. package/novac/node_modules/node-addon-api/napi.h +3364 -0
  120. package/novac/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  121. package/novac/node_modules/node-addon-api/node_api.gyp +9 -0
  122. package/novac/node_modules/node-addon-api/noexcept.gypi +26 -0
  123. package/novac/node_modules/node-addon-api/package-support.json +21 -0
  124. package/novac/node_modules/node-addon-api/package.json +480 -0
  125. package/novac/node_modules/node-addon-api/tools/README.md +73 -0
  126. package/novac/node_modules/node-addon-api/tools/check-napi.js +99 -0
  127. package/novac/node_modules/node-addon-api/tools/clang-format.js +71 -0
  128. package/novac/node_modules/node-addon-api/tools/conversion.js +301 -0
  129. package/novac/node_modules/serialize-javascript/LICENSE +27 -0
  130. package/novac/node_modules/serialize-javascript/README.md +149 -0
  131. package/novac/node_modules/serialize-javascript/index.js +297 -0
  132. package/novac/node_modules/serialize-javascript/package.json +33 -0
  133. package/novac/package.json +27 -0
  134. package/novac/scripts/update-bin.js +24 -0
  135. package/novac/src/core/bstd.js +1035 -0
  136. package/novac/src/core/config.js +155 -0
  137. package/novac/src/core/describe.js +187 -0
  138. package/novac/src/core/emitter.js +499 -0
  139. package/novac/src/core/error.js +86 -0
  140. package/novac/src/core/executor.js +5606 -0
  141. package/novac/src/core/formatter.js +686 -0
  142. package/novac/src/core/lexer.js +1026 -0
  143. package/novac/src/core/nova_builtins.js +717 -0
  144. package/novac/src/core/nova_thread_worker.js +166 -0
  145. package/novac/src/core/parser.js +2181 -0
  146. package/novac/src/core/types.js +112 -0
  147. package/novac/src/index.js +28 -0
  148. package/novac/src/runtime/stdlib.js +244 -0
  149. package/package.json +6 -3
  150. package/scripts/update-bin.js +0 -0
  151. package/src/core/bstd.js +838 -362
  152. package/src/core/executor.js +2578 -170
  153. package/src/core/lexer.js +502 -54
  154. package/src/core/nova_builtins.js +21 -3
  155. package/src/core/parser.js +413 -72
  156. package/src/core/types.js +30 -2
  157. package/src/index.js +0 -0
  158. package/examples/example-project/README.md +0 -3
  159. package/examples/example-project/src/main.nova +0 -3
  160. package/src/core/environment.js +0 -0
  161. /package/{examples/example-project/bin/example-project.nv → novac/node_modules/node-addon-api/nothing.c} +0 -0
@@ -0,0 +1,686 @@
1
+ /**
2
+ * Nova Formatter
3
+ * Converts AST back to formatted source code
4
+ */
5
+
6
+ const { Parser } = require('./parser');
7
+
8
+ class Formatter {
9
+ constructor(source) {
10
+ this.source = source;
11
+ this.indentLevel = 0;
12
+ this.indentStr = ' '; // 2 spaces
13
+ }
14
+
15
+ format() {
16
+ try {
17
+ const parser = new Parser(this.source);
18
+ const ast = parser.parse();
19
+ return this.formatProgram(ast);
20
+ } catch (e) {
21
+ // If parsing fails, return original source
22
+ return this.source;
23
+ }
24
+ }
25
+
26
+ indent() {
27
+ return this.indentStr.repeat(this.indentLevel);
28
+ }
29
+
30
+ // ══════════════════════════ PROGRAM ══════════════════════════
31
+
32
+ formatProgram(node) {
33
+ if (!node || !node.nodes) return '';
34
+ return node.nodes.map(n => this.formatStatement(n)).filter(x => x).join('\n\n');
35
+ }
36
+
37
+ // ══════════════════════════ STATEMENTS ══════════════════════════
38
+
39
+ formatStatement(node) {
40
+ if (!node) return '';
41
+
42
+ const ind = this.indent();
43
+ switch (node.kind) {
44
+ // ── type declarations ──
45
+ case 'type_decl':
46
+ return ind + `type ${node.name}${this.formatTypeParams(node.params)} = ${this.formatTypeExpr(node.def)};`;
47
+
48
+ case 'struct_decl':
49
+ return ind + `struct ${node.name}${this.formatTypeParams(node.params)} {` +
50
+ (node.fields.length > 0 ? '\n' + node.fields.map((f, i) =>
51
+ this.indent() + this.indentStr + `${f.name}: ${this.formatTypeExpr(f.type)}${f.defaultValue ? ' = ' + this.formatExpr(f.defaultValue) : ''}${i < node.fields.length - 1 ? ',' : ''}`
52
+ ).join('\n') + '\n' + ind : '') + `}`;
53
+
54
+ case 'interface_decl':
55
+ return ind + `interface ${node.name}${this.formatTypeParams(node.params)}${node.extends && node.extends.length ? ' extends ' + node.extends.join(', ') : ''} {` +
56
+ (node.members.length > 0 ? '\n' + node.members.map((m, i) =>
57
+ this.indent() + this.indentStr + `${m.name}${m.isOptional ? '?' : ''}${m.isMethod ? '(' + m.params.map(p => p.name + (p.type ? ': ' + this.formatTypeExpr(p.type) : '')).join(', ') + ')' + (m.returnType ? ': ' + this.formatTypeExpr(m.returnType) : '') : m.returnType ? ': ' + this.formatTypeExpr(m.returnType) : ''}${i < node.members.length - 1 ? ',' : ''}`
58
+ ).join('\n') + '\n' + ind : '') + `}`;
59
+
60
+ case 'enum_decl':
61
+ return ind + `enum ${node.name} {` +
62
+ (node.variants.length > 0 ? '\n' + node.variants.map((v, i) =>
63
+ this.indent() + this.indentStr + `${v.name}${v.value ? (v.value.kind === 'tuple' ? '(' + v.value.types.map(t => this.formatTypeExpr(t)).join(', ') + ')' : ' = ' + this.formatExpr(v.value)) : ''}${i < node.variants.length - 1 ? ',' : ''}`
64
+ ).join('\n') + '\n' + ind : '') + `}`;
65
+
66
+ case 'trait_decl':
67
+ return ind + `trait ${node.name}${this.formatTypeParams(node.params)} {` +
68
+ (node.methods.length > 0 ? '\n' + node.methods.map(m =>
69
+ this.indent() + this.indentStr + `${m.name}(${m.args.map(a => this.formatFuncArg(a)).join(', ')}) {${m.body.length > 0 ? '\n' + this.formatBody(m.body) + '\n' + this.indent() + this.indentStr : ''}}`
70
+ ).join('\n') + '\n' + ind : '') + `}`;
71
+
72
+ case 'impl_decl':
73
+ return ind + `impl ${node.trait}${node.for ? ' for ' + node.for : ''} {` +
74
+ (node.methods.length > 0 ? '\n' + node.methods.map(m =>
75
+ this.indent() + this.indentStr + `${m.name}(${m.args.map(a => this.formatFuncArg(a)).join(', ')}) {${m.body.length > 0 ? '\n' + this.formatBody(m.body) + '\n' + this.indent() + this.indentStr : ''}}`
76
+ ).join('\n') + '\n' + ind : '') + `}`;
77
+
78
+ // ── variables ──
79
+ case 'declare': {
80
+ const prefix = node.isConst ? 'const' : 'let';
81
+ if (node.destructure) {
82
+ const destr = node.destructure.kind === 'objpattern'
83
+ ? '{' + node.destructure.props.map(p => p.key + (p.alias !== p.key ? ': ' + p.alias : '') + (p.defaultValue ? ' = ' + this.formatExpr(p.defaultValue) : '')).join(', ') + '}'
84
+ : '[' + node.destructure.elements.map(e => (e.rest ? '...' : '') + e.name + (e.defaultValue ? ' = ' + this.formatExpr(e.defaultValue) : '')).join(', ') + ']';
85
+ return ind + `${prefix} ${node.isPointer ? '*' : ''}${destr}${node.value ? ' = ' + this.formatExpr(node.value) : ''};`;
86
+ }
87
+ return ind + `${prefix} ${node.isPointer ? '*' : ''}${node.name}${node.explicitType ? ': ' + this.formatTypeExpr(node.explicitType) : ''}${node.value ? ' = ' + this.formatExpr(node.value) : ''};`;
88
+ }
89
+
90
+ // ── functions ──
91
+ case 'function':
92
+ return ind + `function ${node.name}(${node.args.map(a => this.formatFuncArg(a)).join(', ')})${node.returnType ? ': ' + this.formatTypeExpr(node.returnType) : ''} {` +
93
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
94
+
95
+ // ── classes ──
96
+ case 'class':
97
+ return ind + `class ${node.name}${node.superClass ? ' extends ' + this.formatExpr(node.superClass) : ''}${node.impls && node.impls.length ? ' implements ' + node.impls.join(', ') : ''} {` +
98
+ (node.members.length > 0 ? '\n' + node.members.map(m => {
99
+ const mind = this.indent() + this.indentStr;
100
+ if (m.kind === 'declare') return mind + `${m.name}: ${this.formatExpr(m.value)}`;
101
+ if (m.kind === 'function') {
102
+ return mind + (m.accessor ? m.accessor + ' ' : '') + `${m.name}(${m.args.map(a => this.formatFuncArg(a)).join(', ')})${m.returnType ? ': ' + this.formatTypeExpr(m.returnType) : ''} {` +
103
+ (m.body.length > 0 ? '\n' + this.formatBody(m.body, this.indentLevel + 2) + '\n' + mind : '') + `}`;
104
+ }
105
+ return mind + this.formatStatement(m);
106
+ }).join('\n') + '\n' + ind : '') + `}`;
107
+
108
+ // ── control flow ──
109
+ case 'branch':
110
+ return this.formatBranch(node, ind);
111
+
112
+ case 'for_of':
113
+ return ind + `for (${node.varName} of ${this.formatExpr(node.iterable)}) {` +
114
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
115
+
116
+ case 'for_in':
117
+ return ind + `for (${node.varName} in ${this.formatExpr(node.object)}) {` +
118
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
119
+
120
+ case 'each':
121
+ return ind + `each ${node.varName}${node.indexName ? ', ' + node.indexName : ''} of ${this.formatExpr(node.iterable)} {` +
122
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
123
+
124
+ case 'switch':
125
+ return ind + `switch (${this.formatExpr(node.subject)}) {` +
126
+ (node.cases.length > 0 ? '\n' + node.cases.map(c => {
127
+ const mind = this.indent() + this.indentStr;
128
+ if (c.kind === 'default_case') return mind + `default:` + (c.body.length > 0 ? '\n' + this.formatBody(c.body, this.indentLevel + 2) : '');
129
+ return mind + `case ${this.formatExpr(c.value)}:` + (c.body.length > 0 ? '\n' + this.formatBody(c.body, this.indentLevel + 2) : '');
130
+ }).join('\n') + '\n' + ind : '') + `}`;
131
+
132
+ case 'match':
133
+ return ind + `match (${this.formatExpr(node.subject)}) {` +
134
+ (node.cases.length > 0 ? '\n' + node.cases.map(c => {
135
+ const mind = this.indent() + this.indentStr;
136
+ if (c.kind === 'default_when') return mind + `default {` + (c.body.length > 0 ? '\n' + this.formatBody(c.body, this.indentLevel + 2) + '\n' + mind : '') + `}`;
137
+ return mind + `when ${c.patterns.map(p => this.formatExpr(p)).join(', ')}${c.guard ? ' where ' + this.formatExpr(c.guard) : ''} {` +
138
+ (c.body.length > 0 ? '\n' + this.formatBody(c.body, this.indentLevel + 2) + '\n' + mind : '') + `}`;
139
+ }).join('\n') + '\n' + ind : '') + `}`;
140
+
141
+ case 'try':
142
+ return ind + `try {` + (node.tryBody.length > 0 ? '\n' + this.formatBody(node.tryBody) + '\n' + ind : '') + `}` +
143
+ (node.catchBody ? ' catch' + (node.catchName ? `(${node.catchName})` : '') + ` {` +
144
+ (node.catchBody.length > 0 ? '\n' + this.formatBody(node.catchBody) + '\n' + ind : '') + `}` : '') +
145
+ (node.finallyBody ? ' finally {' + (node.finallyBody.length > 0 ? '\n' + this.formatBody(node.finallyBody) + '\n' + ind : '') + `}` : '');
146
+
147
+ case 'return':
148
+ return ind + `return${node.value ? ' ' + this.formatExpr(node.value) : ''};`;
149
+
150
+ case 'break':
151
+ return ind + `break;`;
152
+
153
+ case 'continue':
154
+ return ind + `continue;`;
155
+
156
+ case 'throw':
157
+ return ind + `throw ${this.formatExpr(node.value)};`;
158
+
159
+ case 'assert':
160
+ return ind + `assert ${this.formatExpr(node.condition)}${node.message ? ', ' + this.formatExpr(node.message) : ''};`;
161
+
162
+ case 'emit_event':
163
+ return ind + `emit ${this.formatExpr(node.event)}${node.value ? ', ' + this.formatExpr(node.value) : ''};`;
164
+
165
+ case 'on_event':
166
+ return ind + `on ${this.formatExpr(node.event)}${node.param ? `(${node.param})` : ''} {` +
167
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
168
+
169
+ case 'where':
170
+ return ind + `where (${node.bindings.map(b => `${b.name} = ${this.formatExpr(b.value)}`).join(', ')}) {` +
171
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
172
+
173
+ case 'exec':
174
+ return ind + `${this.formatExpr(node.expr)};`;
175
+
176
+ // ── Nova Classic statements ──
177
+ case 'foreach':
178
+ return ind + `foreach (${this.formatExpr(node.iterable)}) (${node.vars.join(', ')}) {` +
179
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
180
+
181
+ case 'temp':
182
+ return ind + `temp ${node.name} = ${this.formatExpr(node.value)} => {` +
183
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
184
+
185
+ case 'keep':
186
+ return ind + `keep ${node.name} = ${this.formatExpr(node.value)};`;
187
+
188
+ case 'echo':
189
+ return ind + `echo ${this.formatExpr(node.value)};`;
190
+
191
+ case 'gear_decl':
192
+ return ind + `gear${node.wait && node.wait.value !== 0 ? `(${this.formatExpr(node.wait)})` : ''} ${node.name} {` +
193
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
194
+
195
+ case 'engage':
196
+ return ind + `engage ${node.gears.join(' >> ')};`;
197
+
198
+ case 'sandbox':
199
+ return ind + `sandbox {${node.code ? ' ' + node.code + ' ' : ''}}`;
200
+
201
+ case 'infer':
202
+ return ind + `infer(${this.formatExpr(node.model)}) => ${node.varName}: ${this.formatExpr(node.prompt)};`;
203
+
204
+ case 'addto':
205
+ return ind + `addto ${node.name} ${this.formatExpr(node.value)}${node.key ? ': ' + this.formatExpr(node.key) : ''};`;
206
+
207
+ case 'macro_decl':
208
+ return ind + `macro ${node.name} = ${this.formatExpr(node.value)};`;
209
+
210
+ case 'block_decl':
211
+ return ind + `block ${node.name} {` +
212
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
213
+
214
+ case 'snippet_decl':
215
+ return ind + `snippet ${node.name} {` +
216
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
217
+
218
+ case 'defunc_decl':
219
+ return ind + `defunc ${node.name}(${node.args.map(a => this.formatFuncArg(a)).join(', ')}) => {` +
220
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
221
+
222
+ case 'lambda_decl':
223
+ return ind + `lambda ${node.name} = ${this.formatExpr(node.fn)};`;
224
+
225
+ case 'compose_decl':
226
+ return ind + `compose ${node.name} = ${node.fns.map(f => this.formatExpr(f)).join(' >> ')};`;
227
+
228
+ case 'partial_decl':
229
+ return ind + `partial ${node.name} = ${this.formatExpr(node.callee)};`;
230
+
231
+ case 'backup_val':
232
+ return ind + `backup ${node.name} = ${this.formatExpr(node.value)};`;
233
+
234
+ case 'retrieve_val':
235
+ return ind + `retrieve ${node.name};`;
236
+
237
+ case 'describe':
238
+ return ind + `describe ${this.formatExpr(node.text)};`;
239
+
240
+ case 'using_flag':
241
+ return ind + `using ${node.flag};`;
242
+
243
+ case 'unuse_flag':
244
+ return ind + `unuse ${node.flag};`;
245
+
246
+ case 'classify':
247
+ return ind + `classify ${this.formatExpr(node.value)}${node.targetType ? ' as ' + this.formatTypeExpr(node.targetType) : ''};`;
248
+
249
+ case 'rate_cast':
250
+ return ind + `rate(${this.formatExpr(node.value)}) ${node.cast_type};`;
251
+
252
+ // ── Nova Classic (ported) ──
253
+ case 'guard':
254
+ return ind + `guard (${this.formatExpr(node.cond)}) {` + (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}` +
255
+ (node.elseBody ? ` else {` + (node.elseBody.length > 0 ? '\n' + this.formatBody(node.elseBody, this.indentLevel + 1) + '\n' + ind : '') + `}` : '');
256
+
257
+ case 'when_stmt':
258
+ return ind + `when ${this.formatExpr(node.cond)} do {` +
259
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
260
+
261
+ case 'with_ctx':
262
+ return ind + `with (${this.formatExpr(node.target)}) {` +
263
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
264
+
265
+ case 'with_option':
266
+ return ind + `with option ${node.flag} {` +
267
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
268
+
269
+ case 'loop_in':
270
+ return ind + `loop ${node.varName} in ${this.formatExpr(node.iterable)} {` +
271
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
272
+
273
+ case 'wait_stmt':
274
+ return ind + `wait(${this.formatExpr(node.ms)});`;
275
+
276
+ case 'lend_fn':
277
+ return ind + `lend fn ${node.source} to ${node.target};`;
278
+
279
+ case 'lend_m':
280
+ return ind + `lend m ${node.mapName} with ${node.funcName};`;
281
+
282
+ case 'sstream_decl':
283
+ return ind + `sstream ${node.name} => {` +
284
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
285
+
286
+ case 'declare_stmt':
287
+ return ind + `declare (${this.formatExpr(node.value)}) ${node.mode} ${node.name}${node.flags.length > 0 ? ' ' + node.flags.join(' ') : ''};`;
288
+
289
+ case 'session_decl':
290
+ return ind + `session (${this.formatExpr(node.name)}) { ${node.body} }`;
291
+
292
+ case 'enter_stmt':
293
+ return ind + `enter ${node.key} ${node.type};`;
294
+
295
+ case 'namespace_decl':
296
+ return ind + `namespace ${this.formatExpr(node.path)};`;
297
+
298
+ case 'resu_decl':
299
+ return ind + `resu ${node.name}(${node.params.join(', ')}) => { ${node.body} },`;
300
+
301
+ case 'warn_stmt':
302
+ return ind + `warn ${this.formatExpr(node.msg)};`;
303
+
304
+ case 'info_stmt':
305
+ return ind + `info ${this.formatExpr(node.msg)};`;
306
+
307
+ case 'time_block':
308
+ return ind + `time {` +
309
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
310
+
311
+ case 'keyfunc_decl':
312
+ return ind + `keyfunc ${node.name}(${node.params.join(', ')}) { ${node.matchBody} } { ${node.logic} }`;
313
+
314
+ case 'print_stmt':
315
+ return ind + `print(${node.args.map(a => this.formatExpr(a)).join(', ')});`;
316
+
317
+ case 'log_stmt':
318
+ return ind + `log(${node.args.map(a => this.formatExpr(a)).join(', ')});`;
319
+
320
+ case 'println_stmt':
321
+ return ind + `println(${this.formatExpr(node.value)});`;
322
+
323
+ case 'logln_stmt':
324
+ return ind + `logln(${this.formatExpr(node.value)});`;
325
+
326
+ case 'banner_stmt':
327
+ return ind + `banner${node.args.length > 0 ? '(' + node.args.map(a => this.formatExpr(a)).join(', ') + ')' : ''};`;
328
+
329
+ case 'readfile_stmt':
330
+ return ind + `readFile ${node.varName} = (${this.formatExpr(node.path)});`;
331
+
332
+ case 'execfile_stmt':
333
+ return ind + `execFile(${this.formatExpr(node.path)});`;
334
+
335
+ case 'createfile_stmt':
336
+ return ind + `createFile(${this.formatExpr(node.path)}, ${this.formatExpr(node.content)});`;
337
+
338
+ case 'deletefile_stmt':
339
+ return ind + `deleteFile(${this.formatExpr(node.path)});`;
340
+
341
+ case 'listfiles_stmt':
342
+ return ind + `listFiles(${this.formatExpr(node.dir)})${node.varName ? ' => ' + node.varName : ''};`;
343
+
344
+ case 'term_stmt':
345
+ return ind + `term(${this.formatExpr(node.cmd)}) ${node.shell};`;
346
+
347
+ case 'sh_stmt':
348
+ return ind + `sh { ${node.code} }`;
349
+
350
+ case 'exec_stmt':
351
+ return ind + `exec(${this.formatExpr(node.code)});`;
352
+
353
+ case 'notify_stmt':
354
+ return ind + `notify(${this.formatExpr(node.title)}${node.content ? ', ' + this.formatExpr(node.content) : ''});`;
355
+
356
+ case 'toast_stmt':
357
+ return ind + `toast(${this.formatExpr(node.msg)});`;
358
+
359
+ case 'vibrate_stmt':
360
+ return ind + `vibrate(${this.formatExpr(node.ms)});`;
361
+
362
+ case 'clipboard_stmt':
363
+ return ind + `clipboard(${this.formatExpr(node.text)});`;
364
+
365
+ case 'camera_stmt':
366
+ return ind + `camera(${this.formatExpr(node.path)});`;
367
+
368
+ case 'share_stmt':
369
+ return ind + `share(${this.formatExpr(node.path)});`;
370
+
371
+ case 'open_stmt':
372
+ return ind + `open(${this.formatExpr(node.path)});`;
373
+
374
+ case 'sysinfo_stmt':
375
+ return ind + `${node.info}${node.varName ? ' => ' + node.varName : ''};`;
376
+
377
+ case 'path_stmt':
378
+ return ind + `path${node.sub}(${this.formatExpr(node.target)});`;
379
+
380
+ case 'crypto_stmt':
381
+ return ind + `${node.fn}(${this.formatExpr(node.arg)})${node.varName ? ' => ' + node.varName : ''};`;
382
+
383
+ case 'parseurl_stmt':
384
+ return ind + `parseURL(${this.formatExpr(node.url)})${node.varName ? ' => ' + node.varName : ''};`;
385
+
386
+ case 'exists_stmt':
387
+ return ind + `exists(${this.formatExpr(node.path)})${node.varName ? ' => ' + node.varName : ''};`;
388
+
389
+ case 'expt_stmt':
390
+ return ind + `expt ${node.expected} from {` +
391
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
392
+
393
+ case 'option_stmt':
394
+ return ind + `option ${node.name} = ${this.formatExpr(node.value)};`;
395
+
396
+ case 'env':
397
+ return ind + `env ${node.varName};`;
398
+
399
+ case 'hello':
400
+ return ind + `hello ${node.args.map(a => this.formatExpr(a)).join(', ')};`;
401
+
402
+ case 'eval':
403
+ return ind + `eval ${this.formatStatement(node.code)};`;
404
+
405
+ case 'import':
406
+ return ind + `import ${this.formatExpr(node.source)}${node.names && node.names.length ? ' as ' + node.names.join(', ') : ''};`;
407
+
408
+ case 'import_builtin':
409
+ return ind + `import_builtin ${node.names.join(', ')};`;
410
+
411
+ case 'from_import':
412
+ return ind + `from ${this.formatExpr(node.source)} import ${node.names.join(', ')};`;
413
+
414
+ case 'export':
415
+ return ind + `export ${node.value ? this.formatExpr(node.value) : ''};`;
416
+
417
+ case 'default_export':
418
+ return ind + `export default ${node.value ? this.formatExpr(node.value) : ''};`;
419
+
420
+ case 'namespace':
421
+ return ind + `namespace ${node.name} {` +
422
+ (node.body.length > 0 ? '\n' + this.formatBody(node.body) + '\n' + ind : '') + `}`;
423
+
424
+ case 'server_decl':
425
+ return ind + `server(${this.formatExpr(node.port)}) {` +
426
+ (node.routes.length > 0 ? '\n' + node.routes.map(r =>
427
+ this.indent() + this.indentStr + `${r.method} ${this.formatExpr(r.path)}${r.params.length > 0 ? '(' + r.params.join(', ') + ')' : ''} {` +
428
+ (r.body.length > 0 ? '\n' + this.formatBody(r.body, this.indentLevel + 2) + '\n' + this.indent() + this.indentStr : '') + `}`
429
+ ).join('\n') + '\n' + ind : '') + `}`;
430
+
431
+ case 'fetch_stmt':
432
+ return ind + `fetch(${this.formatExpr(node.url)}${node.options ? ', ' + this.formatExpr(node.options) : ''})${node.varName ? ' => ' + node.varName : ''};`;
433
+
434
+ case 'skip':
435
+ return ind + `skip;`;
436
+
437
+ case 'end_stmt':
438
+ return ind + `end;`;
439
+
440
+ case 'clear_env':
441
+ return ind + `clear;`;
442
+
443
+ case 'exec_comment':
444
+ return ind + `/?/${node.code}`;
445
+
446
+ default:
447
+ return ind + `/* unknown node kind: ${node.kind} */`;
448
+ }
449
+ }
450
+
451
+ formatBranch(node, ind) {
452
+ let result = '';
453
+ let current = node;
454
+ while (current) {
455
+ switch (current.type) {
456
+ case 'if': {
457
+ result += ind + `if (${this.formatExpr(current.args)}) {` +
458
+ (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `}`;
459
+ current = current.next;
460
+ if (current) result += ' ';
461
+ break;
462
+ }
463
+ case 'else': {
464
+ result += `else {` + (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `}`;
465
+ current = current.next;
466
+ break;
467
+ }
468
+ case 'while': {
469
+ const c = Array.isArray(current.args) ? current.args[0] : current.args;
470
+ result += ind + `while (${this.formatExpr(c)}) {` +
471
+ (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `}`;
472
+ current = current.next;
473
+ break;
474
+ }
475
+ case 'until': {
476
+ const c = Array.isArray(current.args) ? current.args[0] : current.args;
477
+ result += ind + `until (${this.formatExpr(c)}) {` +
478
+ (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `}`;
479
+ current = current.next;
480
+ break;
481
+ }
482
+ case 'unless': {
483
+ result += ind + `unless (${this.formatExpr(current.args)}) {` +
484
+ (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `}`;
485
+ current = current.next;
486
+ break;
487
+ }
488
+ case 'do': {
489
+ const c = Array.isArray(current.args) ? current.args[0] : current.args;
490
+ result += ind + `do {` + (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `} while (${this.formatExpr(c)})`;
491
+ current = current.next;
492
+ break;
493
+ }
494
+ case 'repeat': {
495
+ const t = Array.isArray(current.args) ? current.args[0] : current.args;
496
+ result += ind + `repeat (${this.formatExpr(t)}) {` +
497
+ (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `}`;
498
+ current = current.next;
499
+ break;
500
+ }
501
+ case 'for': {
502
+ const [init, cond, upd] = current.args;
503
+ result += ind + `for (${this.formatStatement(init)}${cond ? ' ' + this.formatExpr(cond) : ''}; ${upd ? this.formatStatement(upd) : ''}) {` +
504
+ (current.body.length > 0 ? '\n' + this.formatBody(current.body) + '\n' + ind : '') + `}`;
505
+ current = current.next;
506
+ break;
507
+ }
508
+ default:
509
+ current = null;
510
+ }
511
+ }
512
+ return result;
513
+ }
514
+
515
+ formatBody(body, indentLevel) {
516
+ const prevIndent = this.indentLevel;
517
+ this.indentLevel = indentLevel !== undefined ? indentLevel : this.indentLevel + 1;
518
+ const result = body.map(stmt => this.formatStatement(stmt)).filter(x => x).join('\n');
519
+ this.indentLevel = prevIndent;
520
+ return result;
521
+ }
522
+
523
+ // ══════════════════════════ EXPRESSIONS ══════════════════════════
524
+
525
+ formatExpr(node) {
526
+ if (!node) return '';
527
+
528
+ switch (node.kind) {
529
+ case 'EOF':
530
+ return '';
531
+
532
+ case 'value': {
533
+ const v = node.value;
534
+ if (typeof v === 'string') return JSON.stringify(v);
535
+ if (typeof v === 'number') return String(v);
536
+ if (typeof v === 'symbol') {
537
+ const s = v.toString();
538
+ if (s === 'Symbol(NOVA_TRUE)') return 'true';
539
+ if (s === 'Symbol(NOVA_FALSE)') return 'false';
540
+ if (s === 'Symbol(NOVA_NULL)') return 'null';
541
+ }
542
+ return String(v);
543
+ }
544
+
545
+ case 'ref':
546
+ return node.name;
547
+
548
+ case 'url_literal':
549
+ return node.value;
550
+
551
+ case 'array':
552
+ return '[' + node.elements.map(e => this.formatExpr(e)).join(', ') + ']';
553
+
554
+ case 'object':
555
+ return '{' + node.props.map(p => {
556
+ if (p.kind === 'spread') return '...' + this.formatExpr(p.value);
557
+ if (p.kind === 'computed') return '[' + this.formatExpr(p.key) + ']: ' + this.formatExpr(p.value);
558
+ const val = p.value;
559
+ if (val && val.kind === 'function') return `${p.accessor ? p.accessor + ' ' : ''}${p.key}(${val.args.map(a => this.formatFuncArg(a)).join(', ')}) { ... }`;
560
+ return `${p.key}: ${this.formatExpr(val)}`;
561
+ }).join(', ') + '}';
562
+
563
+ case 'call':
564
+ return `${this.formatExpr(node.name)}(${node.args.map(a => this.formatExpr(a)).join(', ')})`;
565
+
566
+ case 'prop':
567
+ return `${this.formatExpr(node.object)}.${node.name}`;
568
+
569
+ case 'subscript':
570
+ return `${this.formatExpr(node.object)}[${this.formatExpr(node.index)}]`;
571
+
572
+ case 'optional_call':
573
+ return `${this.formatExpr(node.callee)}?.(${node.args.map(a => this.formatExpr(a)).join(', ')})`;
574
+
575
+ case 'optional_prop':
576
+ return `${this.formatExpr(node.object)}?.${node.name}`;
577
+
578
+ case 'optional_subscript':
579
+ return `${this.formatExpr(node.object)}?.[${this.formatExpr(node.index)}]`;
580
+
581
+ case 'binary':
582
+ return `${this.formatExpr(node.left)} ${node.operator} ${this.formatExpr(node.right)}`;
583
+
584
+ case 'unary':
585
+ return `${node.operator}${this.formatExpr(node.operand)}`;
586
+
587
+ case 'prefix':
588
+ return `${node.operator}${this.formatExpr(node.operand)}`;
589
+
590
+ case 'postfix':
591
+ return `${this.formatExpr(node.operand)}${node.operator}`;
592
+
593
+ case 'ternary':
594
+ return `${this.formatExpr(node.condition)} ? ${this.formatExpr(node.consequent)} : ${this.formatExpr(node.alternate)}`;
595
+
596
+ case 'assign':
597
+ return `${this.formatExpr(node.name)} = ${this.formatExpr(node.value)}`;
598
+
599
+ case 'compound_assign':
600
+ return `${this.formatExpr(node.name)} ${node.operator} ${this.formatExpr(node.value)}`;
601
+
602
+ case 'fstring':
603
+ return `f"${node.parts.map(p => p.kind === 'value' ? p.value : '${' + this.formatExpr(p) + '}').join('')}"`;
604
+
605
+ case 'function': {
606
+ const fn = node;
607
+ return `function ${fn.name}(${fn.args.map(a => this.formatFuncArg(a)).join(', ')}) { ... }`;
608
+ }
609
+
610
+ case 'arrowfunc':
611
+ return `(${node.args.join(', ')}) => { ... }`;
612
+
613
+ case 'cast':
614
+ return `${this.formatExpr(node.value)} as ${this.formatTypeExpr(node.type)}`;
615
+
616
+ case 'new_expr':
617
+ return `new ${this.formatExpr(node.callee)}`;
618
+
619
+ case 'deref':
620
+ return `*${this.formatExpr(node.operand)}`;
621
+
622
+ case 'spread':
623
+ return `...${this.formatExpr(node.value)}`;
624
+
625
+ case 'await':
626
+ return `await ${this.formatExpr(node.operand)}`;
627
+
628
+ case 'http_request':
629
+ return `${node.method} ${this.formatExpr(node.url)}(${node.args.map(a => this.formatExpr(a)).join(', ')})`;
630
+
631
+ case 'fetch_expr':
632
+ return `fetch(${this.formatExpr(node.url)}${node.options ? ', ' + this.formatExpr(node.options) : ''})`;
633
+
634
+ case 'classify':
635
+ return `classify ${this.formatExpr(node.value)}${node.targetType ? ' as ' + this.formatTypeExpr(node.targetType) : ''}`;
636
+
637
+ case 'rate_cast':
638
+ return `rate(${this.formatExpr(node.value)}) ${node.cast_type}`;
639
+
640
+ default:
641
+ return `/* unknown expr kind: ${node.kind} */`;
642
+ }
643
+ }
644
+
645
+ formatFuncArg(arg) {
646
+ if (typeof arg === 'string') return arg;
647
+ return (arg.rest ? '...' : '') + arg.name + (arg.type ? ': ' + this.formatTypeExpr(arg.type) : '') +
648
+ (arg.defaultValue ? ' = ' + this.formatExpr(arg.defaultValue) : '');
649
+ }
650
+
651
+ formatTypeExpr(type) {
652
+ if (!type) return 'any';
653
+ if (typeof type === 'string') return type;
654
+
655
+ switch (type.kind) {
656
+ case 'named_type':
657
+ return type.name + (type.args && type.args.length ? '<' + type.args.map(a => this.formatTypeExpr(a)).join(', ') + '>' : '');
658
+
659
+ case 'array_type':
660
+ return this.formatTypeExpr(type.of) + '[]';
661
+
662
+ case 'union_type':
663
+ return type.variants.map(v => this.formatTypeExpr(v)).join(' | ');
664
+
665
+ case 'intersect_type':
666
+ return type.parts.map(p => this.formatTypeExpr(p)).join(' & ');
667
+
668
+ case 'shape_type':
669
+ return '{' + Object.entries(type.fields || {}).map(([k, f]) =>
670
+ k + (f.optional ? '?' : '') + ': ' + this.formatTypeExpr(f.type)
671
+ ).join(', ') + '}';
672
+
673
+ case 'tuple':
674
+ return '(' + (type.types ? type.types.map(t => this.formatTypeExpr(t)).join(', ') : '') + ')';
675
+
676
+ default:
677
+ return String(type);
678
+ }
679
+ }
680
+
681
+ formatTypeParams(params) {
682
+ return params && params.length ? '<' + params.join(', ') + '>' : '';
683
+ }
684
+ }
685
+
686
+ module.exports = { Formatter };