bonescript-compiler 0.5.2 → 0.5.4

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 (187) hide show
  1. package/LICENSE +21 -21
  2. package/dist/algorithm_catalog.js +166 -166
  3. package/dist/cli.d.ts +1 -2
  4. package/dist/cli.js +543 -75
  5. package/dist/cli.js.map +1 -1
  6. package/dist/emit_capability.d.ts +0 -13
  7. package/dist/emit_capability.js +128 -292
  8. package/dist/emit_capability.js.map +1 -1
  9. package/dist/emit_composition.js +3 -37
  10. package/dist/emit_composition.js.map +1 -1
  11. package/dist/emit_deploy.js +162 -162
  12. package/dist/emit_events.d.ts +0 -1
  13. package/dist/emit_events.js +275 -342
  14. package/dist/emit_events.js.map +1 -1
  15. package/dist/emit_full.js +106 -268
  16. package/dist/emit_full.js.map +1 -1
  17. package/dist/emit_maintenance.js +249 -249
  18. package/dist/emit_runtime.d.ts +11 -17
  19. package/dist/emit_runtime.js +688 -29
  20. package/dist/emit_runtime.js.map +1 -1
  21. package/dist/emit_sourcemap.js +66 -66
  22. package/dist/emit_tests.js +0 -37
  23. package/dist/emit_tests.js.map +1 -1
  24. package/dist/emitter.js +16 -82
  25. package/dist/emitter.js.map +1 -1
  26. package/dist/extension_manager.d.ts +2 -2
  27. package/dist/extension_manager.js +3 -6
  28. package/dist/extension_manager.js.map +1 -1
  29. package/dist/ir.d.ts +0 -4
  30. package/dist/lowering.d.ts +14 -5
  31. package/dist/lowering.js +417 -66
  32. package/dist/lowering.js.map +1 -1
  33. package/dist/module_loader.d.ts +2 -2
  34. package/dist/module_loader.js +23 -20
  35. package/dist/module_loader.js.map +1 -1
  36. package/dist/optimizer.js +1 -1
  37. package/dist/optimizer.js.map +1 -1
  38. package/dist/scaffold.d.ts +2 -2
  39. package/dist/scaffold.js +319 -315
  40. package/dist/scaffold.js.map +1 -1
  41. package/dist/source_map.js.map +1 -0
  42. package/dist/test.js.map +1 -0
  43. package/dist/test_typechecker.d.ts +5 -0
  44. package/dist/test_typechecker.js +126 -0
  45. package/dist/test_typechecker.js.map +1 -0
  46. package/dist/typechecker.d.ts +0 -5
  47. package/dist/typechecker.js +13 -68
  48. package/dist/typechecker.js.map +1 -1
  49. package/dist/verifier.d.ts +1 -5
  50. package/dist/verifier.js +35 -140
  51. package/dist/verifier.js.map +1 -1
  52. package/package.json +52 -62
  53. package/src/algorithm_catalog.ts +345 -345
  54. package/src/ast.d.ts +244 -0
  55. package/src/ast.ts +334 -334
  56. package/src/cli.ts +624 -98
  57. package/src/emit_batch.ts +140 -140
  58. package/src/emit_capability.ts +436 -617
  59. package/src/emit_composition.ts +196 -229
  60. package/src/emit_deploy.ts +190 -190
  61. package/src/emit_events.ts +307 -377
  62. package/src/emit_extras.ts +240 -240
  63. package/src/emit_full.ts +309 -475
  64. package/src/emit_maintenance.ts +459 -459
  65. package/src/emit_runtime.ts +730 -17
  66. package/src/emit_sourcemap.ts +140 -140
  67. package/src/emit_tests.ts +205 -246
  68. package/src/emit_websocket.ts +229 -229
  69. package/src/emitter.ts +578 -642
  70. package/src/extension_manager.ts +187 -189
  71. package/src/formatter.ts +297 -297
  72. package/src/index.ts +88 -88
  73. package/src/ir.ts +215 -216
  74. package/src/lexer.d.ts +195 -0
  75. package/src/lexer.ts +630 -630
  76. package/src/lowering.ts +556 -168
  77. package/src/module_loader.ts +114 -112
  78. package/src/optimizer.ts +196 -196
  79. package/src/parse_decls.d.ts +13 -0
  80. package/src/parse_decls.ts +409 -409
  81. package/src/parse_decls2.d.ts +13 -0
  82. package/src/parse_decls2.ts +244 -244
  83. package/src/parse_expr.d.ts +7 -0
  84. package/src/parse_expr.ts +197 -197
  85. package/src/parse_types.d.ts +6 -0
  86. package/src/parse_types.ts +54 -54
  87. package/src/parser.d.ts +10 -0
  88. package/src/parser.ts +1 -1
  89. package/src/parser_base.d.ts +19 -0
  90. package/src/parser_base.ts +57 -57
  91. package/src/parser_recovery.ts +153 -153
  92. package/src/scaffold.ts +375 -371
  93. package/src/solver.ts +330 -330
  94. package/src/typechecker.d.ts +52 -0
  95. package/src/typechecker.ts +591 -657
  96. package/src/types.d.ts +38 -0
  97. package/src/types.ts +122 -122
  98. package/src/verifier.ts +46 -152
  99. package/README.md +0 -382
  100. package/dist/commands/check.d.ts +0 -5
  101. package/dist/commands/check.js +0 -34
  102. package/dist/commands/check.js.map +0 -1
  103. package/dist/commands/compile.d.ts +0 -5
  104. package/dist/commands/compile.js +0 -215
  105. package/dist/commands/compile.js.map +0 -1
  106. package/dist/commands/debug.d.ts +0 -5
  107. package/dist/commands/debug.js +0 -59
  108. package/dist/commands/debug.js.map +0 -1
  109. package/dist/commands/diff.d.ts +0 -5
  110. package/dist/commands/diff.js +0 -125
  111. package/dist/commands/diff.js.map +0 -1
  112. package/dist/commands/fmt.d.ts +0 -5
  113. package/dist/commands/fmt.js +0 -49
  114. package/dist/commands/fmt.js.map +0 -1
  115. package/dist/commands/init.d.ts +0 -5
  116. package/dist/commands/init.js +0 -96
  117. package/dist/commands/init.js.map +0 -1
  118. package/dist/commands/ir.d.ts +0 -5
  119. package/dist/commands/ir.js +0 -27
  120. package/dist/commands/ir.js.map +0 -1
  121. package/dist/commands/lex.d.ts +0 -5
  122. package/dist/commands/lex.js +0 -21
  123. package/dist/commands/lex.js.map +0 -1
  124. package/dist/commands/parse.d.ts +0 -5
  125. package/dist/commands/parse.js +0 -30
  126. package/dist/commands/parse.js.map +0 -1
  127. package/dist/commands/test.d.ts +0 -5
  128. package/dist/commands/test.js +0 -61
  129. package/dist/commands/test.js.map +0 -1
  130. package/dist/commands/verify_determinism.d.ts +0 -5
  131. package/dist/commands/verify_determinism.js +0 -64
  132. package/dist/commands/verify_determinism.js.map +0 -1
  133. package/dist/commands/watch.d.ts +0 -5
  134. package/dist/commands/watch.js +0 -50
  135. package/dist/commands/watch.js.map +0 -1
  136. package/dist/emit_auth.d.ts +0 -18
  137. package/dist/emit_auth.js +0 -507
  138. package/dist/emit_auth.js.map +0 -1
  139. package/dist/emit_database.d.ts +0 -7
  140. package/dist/emit_database.js +0 -74
  141. package/dist/emit_database.js.map +0 -1
  142. package/dist/emit_index.d.ts +0 -6
  143. package/dist/emit_index.js +0 -202
  144. package/dist/emit_index.js.map +0 -1
  145. package/dist/emit_models.d.ts +0 -12
  146. package/dist/emit_models.js +0 -171
  147. package/dist/emit_models.js.map +0 -1
  148. package/dist/emit_openapi.d.ts +0 -9
  149. package/dist/emit_openapi.js +0 -308
  150. package/dist/emit_openapi.js.map +0 -1
  151. package/dist/emit_package.d.ts +0 -7
  152. package/dist/emit_package.js +0 -70
  153. package/dist/emit_package.js.map +0 -1
  154. package/dist/emit_router.d.ts +0 -12
  155. package/dist/emit_router.js +0 -390
  156. package/dist/emit_router.js.map +0 -1
  157. package/dist/lowering_channels.d.ts +0 -11
  158. package/dist/lowering_channels.js +0 -103
  159. package/dist/lowering_channels.js.map +0 -1
  160. package/dist/lowering_entities.d.ts +0 -11
  161. package/dist/lowering_entities.js +0 -232
  162. package/dist/lowering_entities.js.map +0 -1
  163. package/dist/lowering_helpers.d.ts +0 -13
  164. package/dist/lowering_helpers.js +0 -76
  165. package/dist/lowering_helpers.js.map +0 -1
  166. package/src/commands/check.ts +0 -33
  167. package/src/commands/compile.ts +0 -191
  168. package/src/commands/debug.ts +0 -33
  169. package/src/commands/diff.ts +0 -108
  170. package/src/commands/fmt.ts +0 -22
  171. package/src/commands/init.ts +0 -72
  172. package/src/commands/ir.ts +0 -23
  173. package/src/commands/lex.ts +0 -17
  174. package/src/commands/parse.ts +0 -24
  175. package/src/commands/test.ts +0 -36
  176. package/src/commands/verify_determinism.ts +0 -66
  177. package/src/commands/watch.ts +0 -25
  178. package/src/emit_auth.ts +0 -513
  179. package/src/emit_database.ts +0 -75
  180. package/src/emit_index.ts +0 -210
  181. package/src/emit_models.ts +0 -176
  182. package/src/emit_openapi.ts +0 -318
  183. package/src/emit_package.ts +0 -69
  184. package/src/emit_router.ts +0 -409
  185. package/src/lowering_channels.ts +0 -108
  186. package/src/lowering_entities.ts +0 -258
  187. package/src/lowering_helpers.ts +0 -75
package/dist/cli.js CHANGED
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * BoneScript compiler CLI — dispatcher
4
- * Each command lives in its own file under commands/.
3
+ * BoneScript compiler CLI
5
4
  */
6
5
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
6
  if (k2 === undefined) k2 = k;
@@ -29,109 +28,578 @@ var __importStar = (this && this.__importStar) || function (mod) {
29
28
  Object.defineProperty(exports, "__esModule", { value: true });
30
29
  const fs = __importStar(require("fs"));
31
30
  const path = __importStar(require("path"));
32
- const compile_1 = require("./commands/compile");
33
- const check_1 = require("./commands/check");
34
- const lex_1 = require("./commands/lex");
35
- const parse_1 = require("./commands/parse");
36
- const ir_1 = require("./commands/ir");
37
- const fmt_1 = require("./commands/fmt");
38
- const watch_1 = require("./commands/watch");
39
- const init_1 = require("./commands/init");
40
- const diff_1 = require("./commands/diff");
41
- const debug_1 = require("./commands/debug");
42
- const test_1 = require("./commands/test");
43
- const verify_determinism_1 = require("./commands/verify_determinism");
44
- // ─── Helpers ──────────────────────────────────────────────────────────────────
45
- /** Read a file and pass its contents to an async action. */
46
- async function requireFile(filePath, action) {
47
- if (!filePath) {
48
- console.error("Error: No input file specified.");
49
- process.exit(1);
50
- }
51
- const resolved = path.resolve(filePath);
52
- try {
53
- await fs.promises.access(resolved);
54
- }
55
- catch {
56
- console.error(`Error: File not found: ${resolved}`);
57
- process.exit(1);
58
- }
59
- const source = await fs.promises.readFile(resolved, "utf-8");
60
- await action(source, resolved);
61
- }
62
- function showHelp() {
63
- console.log("BoneScript compiler v0.3.0");
64
- console.log("");
65
- console.log("Usage:");
66
- console.log(" bonec compile <file> Compile to runnable project");
67
- console.log(" bonec check <file> Lex + parse + type check (no codegen)");
68
- console.log(" bonec lex <file> Show token stream");
69
- console.log(" bonec parse <file> Show AST");
70
- console.log(" bonec ir <file> Show IR (JSON)");
71
- console.log(" bonec fmt <file> Format file in place");
72
- console.log(" bonec watch <file> Recompile on change");
73
- console.log(" bonec diff <old.bone> <new.bone> Show schema migration diff");
74
- console.log(" bonec init <name> --domain <domain> Scaffold from a domain template");
75
- console.log(" bonec test [output-dir] Run generated regression tests");
76
- console.log(" bonec debug <file> Generate source maps");
77
- console.log(" bonec verify-determinism <file> Confirm two compilations are identical");
78
- console.log("");
79
- console.log("Domain options: multiplayer_game, saas_platform, iot_system,");
80
- console.log(" social_network, marketplace, realtime_collaboration");
81
- console.log(" --out <dir> Output directory for init (default: ./<name>)");
82
- }
83
- // ─── Dispatch ─────────────────────────────────────────────────────────────────
84
- async function main() {
31
+ const crypto_1 = require("crypto");
32
+ const lexer_1 = require("./lexer");
33
+ const parser_1 = require("./parser");
34
+ const parser_recovery_1 = require("./parser_recovery");
35
+ const typechecker_1 = require("./typechecker");
36
+ const lowering_1 = require("./lowering");
37
+ const solver_1 = require("./solver");
38
+ const emit_full_1 = require("./emit_full");
39
+ const verifier_1 = require("./verifier");
40
+ const module_loader_1 = require("./module_loader");
41
+ const formatter_1 = require("./formatter");
42
+ const scaffold_1 = require("./scaffold");
43
+ const extension_manager_1 = require("./extension_manager");
44
+ const optimizer_1 = require("./optimizer");
45
+ function main() {
85
46
  const args = process.argv.slice(2);
86
47
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
87
48
  showHelp();
88
49
  return;
89
50
  }
90
- switch (args[0]) {
51
+ const command = args[0];
52
+ switch (command) {
91
53
  case "compile":
92
- await requireFile(args[1], compile_1.runCompile);
93
- break;
94
- case "check":
95
- await requireFile(args[1], (src) => (0, check_1.runCheck)(src));
54
+ requireFile(args[1], runCompile);
96
55
  break;
97
56
  case "lex":
98
- await requireFile(args[1], (src) => (0, lex_1.runLex)(src));
57
+ requireFile(args[1], runLex);
99
58
  break;
100
59
  case "parse":
101
- await requireFile(args[1], (src) => (0, parse_1.runParse)(src));
60
+ requireFile(args[1], runParse);
102
61
  break;
103
62
  case "ir":
104
- await requireFile(args[1], (src) => (0, ir_1.runIR)(src));
63
+ requireFile(args[1], runIR);
64
+ break;
65
+ case "check":
66
+ requireFile(args[1], runCheck);
105
67
  break;
106
68
  case "fmt":
107
- await requireFile(args[1], fmt_1.runFormat);
69
+ requireFile(args[1], runFormat);
108
70
  break;
109
71
  case "watch":
110
- await requireFile(args[1], watch_1.runWatch);
72
+ requireFile(args[1], runWatch);
111
73
  break;
112
74
  case "init":
113
- await (0, init_1.runInit)(args.slice(1));
75
+ runInit(args.slice(1));
114
76
  break;
115
77
  case "diff":
116
- await (0, diff_1.runDiff)(args.slice(1));
78
+ runDiff(args.slice(1));
117
79
  break;
118
80
  case "debug":
119
- await requireFile(args[1], debug_1.runDebug);
81
+ requireFile(args[1], runDebug);
120
82
  break;
121
83
  case "test":
122
- await (0, test_1.runTest)(args.slice(1));
84
+ runTest(args.slice(1));
123
85
  break;
124
86
  case "verify-determinism":
125
- await requireFile(args[1], (src) => (0, verify_determinism_1.runVerifyDeterminism)(src));
87
+ requireFile(args[1], runVerifyDeterminism);
126
88
  break;
127
89
  default:
128
- console.error(`Unknown command: ${args[0]}`);
90
+ console.error(`Unknown command: ${command}`);
129
91
  showHelp();
130
92
  process.exit(1);
131
93
  }
132
94
  }
133
- main().catch(e => {
134
- console.error(`x Fatal: ${e.message}`);
135
- process.exit(1);
136
- });
95
+ function showHelp() {
96
+ console.log("BoneScript compiler v0.2.0");
97
+ console.log("");
98
+ console.log("Usage:");
99
+ console.log(" bonec compile <file> Compile to runnable project");
100
+ console.log(" bonec check <file> Lex + parse + type check (no codegen)");
101
+ console.log(" bonec lex <file> Show token stream");
102
+ console.log(" bonec parse <file> Show AST");
103
+ console.log(" bonec ir <file> Show IR (JSON)");
104
+ console.log(" bonec fmt <file> Format file in place");
105
+ console.log(" bonec watch <file> Recompile on change");
106
+ console.log(" bonec diff <old.bone> <new.bone> Show schema migration diff");
107
+ console.log("");
108
+ console.log("init options:");
109
+ console.log(" bonec init <name> --domain <name> Scaffold from a domain template");
110
+ console.log(" --domain <name> Domain template (default: saas_platform)");
111
+ console.log(" Options: multiplayer_game, saas_platform, iot_system,");
112
+ console.log(" social_network, marketplace, realtime_collaboration");
113
+ console.log(" --out <dir> Output directory (default: current dir)");
114
+ }
115
+ function requireFile(filePath, action) {
116
+ if (!filePath) {
117
+ console.error("Error: No input file specified.");
118
+ process.exit(1);
119
+ }
120
+ const resolved = path.resolve(filePath);
121
+ if (!fs.existsSync(resolved)) {
122
+ console.error(`Error: File not found: ${resolved}`);
123
+ process.exit(1);
124
+ }
125
+ const source = fs.readFileSync(resolved, "utf-8");
126
+ action(source, resolved);
127
+ }
128
+ // ─── Lex ─────────────────────────────────────────────────────────────────────
129
+ function runLex(source) {
130
+ try {
131
+ const tokens = new lexer_1.Lexer(source).tokenize();
132
+ console.log(JSON.stringify(tokens, null, 2));
133
+ console.log(`\nv ${tokens.length} tokens produced.`);
134
+ }
135
+ catch (e) {
136
+ console.error(`x ${e.message}`);
137
+ process.exit(1);
138
+ }
139
+ }
140
+ // ─── Parse ───────────────────────────────────────────────────────────────────
141
+ function runParse(source) {
142
+ try {
143
+ const tokens = new lexer_1.Lexer(source).tokenize();
144
+ const result = new parser_recovery_1.RecoveringParser(tokens).parse();
145
+ if (result.errors.length > 0) {
146
+ console.error(`x ${result.errors.length} parse error(s):`);
147
+ for (const e of result.errors)
148
+ console.error(` ${e.message}`);
149
+ if (!result.ast)
150
+ process.exit(1);
151
+ }
152
+ console.log(JSON.stringify(result.ast, null, 2));
153
+ console.log(`\nv Parsed ${result.ast?.systems.length || 0} system(s).`);
154
+ }
155
+ catch (e) {
156
+ console.error(`x ${e.message}`);
157
+ process.exit(1);
158
+ }
159
+ }
160
+ // ─── IR ──────────────────────────────────────────────────────────────────────
161
+ function runIR(source) {
162
+ try {
163
+ const tokens = new lexer_1.Lexer(source).tokenize();
164
+ const ast = new parser_1.Parser(tokens).parse();
165
+ const sourceHash = (0, crypto_1.createHash)("sha256").update(source).digest("hex").slice(0, 16);
166
+ const irSystems = new lowering_1.Lowering().lower(ast, sourceHash);
167
+ console.log(JSON.stringify(irSystems, null, 2));
168
+ console.log(`\nv Lowered to ${irSystems.length} IR system(s).`);
169
+ }
170
+ catch (e) {
171
+ console.error(`x ${e.message}`);
172
+ process.exit(1);
173
+ }
174
+ }
175
+ // ─── Check ───────────────────────────────────────────────────────────────────
176
+ function runCheck(source) {
177
+ const tokens = new lexer_1.Lexer(source).tokenize();
178
+ const result = new parser_recovery_1.RecoveringParser(tokens).parse();
179
+ let totalErrors = 0;
180
+ if (result.errors.length > 0) {
181
+ for (const e of result.errors) {
182
+ console.error(` parse: ${e.message}`);
183
+ totalErrors++;
184
+ }
185
+ }
186
+ if (result.ast) {
187
+ const typeErrors = new typechecker_1.TypeChecker().check(result.ast);
188
+ for (const err of typeErrors) {
189
+ console.error(` type: ${err.code} at ${err.loc.line}:${err.loc.column}: ${err.message}`);
190
+ totalErrors++;
191
+ }
192
+ }
193
+ if (totalErrors === 0) {
194
+ console.log("v Check passed (0 errors)");
195
+ }
196
+ else {
197
+ console.log(`x ${totalErrors} error(s) found.`);
198
+ process.exit(1);
199
+ }
200
+ }
201
+ // ─── Format ──────────────────────────────────────────────────────────────────
202
+ function runFormat(source, resolved) {
203
+ try {
204
+ const tokens = new lexer_1.Lexer(source).tokenize();
205
+ const ast = new parser_1.Parser(tokens).parse();
206
+ const formatted = new formatter_1.Formatter().format(ast);
207
+ fs.writeFileSync(resolved, formatted, "utf-8");
208
+ console.log(`v Formatted ${resolved}`);
209
+ }
210
+ catch (e) {
211
+ console.error(`x ${e.message}`);
212
+ process.exit(1);
213
+ }
214
+ }
215
+ // ─── Watch ───────────────────────────────────────────────────────────────────
216
+ function runWatch(_source, resolved) {
217
+ console.log(`Watching ${resolved}...`);
218
+ const compile = () => {
219
+ try {
220
+ const fresh = fs.readFileSync(resolved, "utf-8");
221
+ console.log(`\n[${new Date().toLocaleTimeString()}] Compiling...`);
222
+ runCompile(fresh, resolved);
223
+ }
224
+ catch (e) {
225
+ console.error(`x ${e.message}`);
226
+ }
227
+ };
228
+ compile();
229
+ fs.watchFile(resolved, { interval: 500 }, (curr, prev) => {
230
+ if (curr.mtimeMs !== prev.mtimeMs)
231
+ compile();
232
+ });
233
+ }
234
+ // ─── Init ────────────────────────────────────────────────────────────────────
235
+ function runInit(args) {
236
+ if (args.length === 0) {
237
+ console.error("Error: bone init requires a project name.");
238
+ console.error("Example: bone init my-project --domain saas_platform");
239
+ process.exit(1);
240
+ }
241
+ const name = args[0];
242
+ let domain = "saas_platform";
243
+ let outDir = path.resolve(name);
244
+ for (let i = 1; i < args.length; i++) {
245
+ if (args[i] === "--domain" && args[i + 1]) {
246
+ domain = args[i + 1];
247
+ i++;
248
+ }
249
+ else if (args[i] === "--out" && args[i + 1]) {
250
+ outDir = path.resolve(args[i + 1]);
251
+ i++;
252
+ }
253
+ }
254
+ const validDomains = [
255
+ "multiplayer_game", "saas_platform", "iot_system",
256
+ "social_network", "marketplace", "realtime_collaboration",
257
+ ];
258
+ if (!validDomains.includes(domain)) {
259
+ console.error(`Error: Invalid domain '${domain}'. Valid: ${validDomains.join(", ")}`);
260
+ process.exit(1);
261
+ }
262
+ const result = (0, scaffold_1.scaffold)({ name, domain, outDir });
263
+ console.log(`v Created ${result.created.length} file(s):`);
264
+ for (const f of result.created)
265
+ console.log(` ${f}`);
266
+ console.log(`\nNext steps:`);
267
+ console.log(` cd ${outDir}`);
268
+ console.log(` bone compile ${name}.bone`);
269
+ }
270
+ // ─── Compile (full pipeline) ─────────────────────────────────────────────────
271
+ function runCompile(source, resolved) {
272
+ try {
273
+ const tokens = new lexer_1.Lexer(source).tokenize();
274
+ console.log(` [1/7] Lexed: ${tokens.length} tokens`);
275
+ // Use module loader to handle imports
276
+ const loader = new module_loader_1.ModuleLoader();
277
+ const loadResult = loader.load(resolved);
278
+ if (loadResult.errors.length > 0) {
279
+ console.log(` [2/7] Parse: ${loadResult.errors.length} error(s)`);
280
+ for (const e of loadResult.errors.slice(0, 10)) {
281
+ console.log(` ${path.basename(e.file)}: ${e.error.message}`);
282
+ }
283
+ if (!loadResult.ast)
284
+ process.exit(1);
285
+ }
286
+ else {
287
+ const sysCount = loadResult.ast?.systems.length || 0;
288
+ console.log(` [2/7] Parsed: ${sysCount} system(s) from ${loadResult.loadedFiles.length} file(s)`);
289
+ }
290
+ const ast = loadResult.ast;
291
+ for (const sys of ast.systems) {
292
+ console.log(` System '${sys.name}':`);
293
+ const counts = {};
294
+ for (const d of sys.declarations)
295
+ counts[d.kind] = (counts[d.kind] || 0) + 1;
296
+ for (const [kind, count] of Object.entries(counts)) {
297
+ console.log(` ${kind}: ${count}`);
298
+ }
299
+ }
300
+ // Stage 3: Type Check
301
+ const checker = new typechecker_1.TypeChecker();
302
+ const typeErrors = checker.check(ast);
303
+ if (typeErrors.length > 0) {
304
+ console.log(` [3/7] Type check: ${typeErrors.length} error(s)`);
305
+ for (const err of typeErrors) {
306
+ console.log(` ${err.code} at ${err.loc.line}:${err.loc.column}: ${err.message}`);
307
+ }
308
+ }
309
+ else {
310
+ console.log(` [3/7] Type check: v (0 errors)`);
311
+ }
312
+ // Stage 4: Lower to IR
313
+ const sourceHash = (0, crypto_1.createHash)("sha256").update(source).digest("hex").slice(0, 16);
314
+ const lowering = new lowering_1.Lowering();
315
+ const irSystems = lowering.lower(ast, sourceHash);
316
+ const totalModules = irSystems.reduce((sum, s) => sum + s.modules.length, 0);
317
+ const totalEvents = irSystems.reduce((sum, s) => sum + s.events.length, 0);
318
+ const totalFlows = irSystems.reduce((sum, s) => sum + s.flows.length, 0);
319
+ console.log(` [4/7] Lower to IR: ${totalModules} modules, ${totalEvents} events, ${totalFlows} flows`);
320
+ for (const sys of irSystems) {
321
+ for (const mod of sys.modules) {
322
+ const methodCount = mod.interfaces.reduce((s, i) => s + i.methods.length, 0);
323
+ console.log(` ${mod.kind.padEnd(16)} ${mod.name.padEnd(24)} (${methodCount} methods, ${mod.models.length} models)`);
324
+ }
325
+ }
326
+ // Stage 4.5: IR Optimization
327
+ for (let i = 0; i < irSystems.length; i++) {
328
+ const result = (0, optimizer_1.optimize)(irSystems[i]);
329
+ irSystems[i] = result.system;
330
+ if (result.log.length > 0) {
331
+ console.log(` [4.5] IR optimize: ${result.modulesRemoved} modules removed, ${result.eventsDeduped} events deduped, ${result.depsRemoved} deps minimized`);
332
+ }
333
+ }
334
+ // Stage 5: Constraint Solve
335
+ const solver = new solver_1.ConstraintSolver();
336
+ let totalResolved = 0;
337
+ for (const sys of irSystems) {
338
+ const result = solver.solve(sys);
339
+ sys.resolution = result.resolution;
340
+ totalResolved += Object.keys(result.resolution).length;
341
+ if (result.errors.length > 0) {
342
+ console.log(` [5/7] Constraint solve: ${result.errors.length} error(s)`);
343
+ for (const err of result.errors)
344
+ console.log(` x ${err}`);
345
+ }
346
+ else {
347
+ console.log(` [5/7] Constraint solve: v (${totalResolved} resolved, ${result.assumptions.length} assumptions)`);
348
+ for (const a of result.assumptions.slice(0, 5))
349
+ console.log(` ${a}`);
350
+ if (result.assumptions.length > 5)
351
+ console.log(` ... and ${result.assumptions.length - 5} more`);
352
+ }
353
+ }
354
+ // Stage 6: Code Emit
355
+ const emitter = new emit_full_1.FullEmitter();
356
+ const allFiles = [];
357
+ for (const sys of irSystems) {
358
+ const files = emitter.emit(sys);
359
+ allFiles.push(...files);
360
+ }
361
+ console.log(` [6/7] Code emit: ${allFiles.length} files generated`);
362
+ const byLang = {};
363
+ for (const f of allFiles)
364
+ byLang[f.language] = (byLang[f.language] || 0) + 1;
365
+ for (const [lang, count] of Object.entries(byLang)) {
366
+ console.log(` ${lang}: ${count} file(s)`);
367
+ }
368
+ // Stage 7: Verify
369
+ const verifier = new verifier_1.Verifier();
370
+ const verifyResult = verifier.verify(irSystems[0], allFiles);
371
+ const errCount = verifyResult.issues.filter(i => i.severity === "error").length;
372
+ const warnCount = verifyResult.issues.filter(i => i.severity === "warning").length;
373
+ if (verifyResult.passed) {
374
+ console.log(` [7/7] Verify: v (${allFiles.length} files, ${warnCount} warnings)`);
375
+ }
376
+ else {
377
+ console.log(` [7/7] Verify: FAILED (${errCount} errors, ${warnCount} warnings)`);
378
+ }
379
+ for (const issue of verifyResult.issues.slice(0, 10)) {
380
+ const icon = issue.severity === "error" ? "x" : "!";
381
+ console.log(` ${icon} ${issue.code}: ${issue.message}`);
382
+ }
383
+ // Write output — merge extension point implementations from existing files
384
+ const outputDir = path.resolve(path.dirname(resolved), "output");
385
+ const allExtensions = irSystems.flatMap(s => s.extension_points || []);
386
+ let extensionErrors = [];
387
+ for (const f of allFiles) {
388
+ const outPath = path.join(outputDir, f.path);
389
+ const dir = path.dirname(outPath);
390
+ if (!fs.existsSync(dir))
391
+ fs.mkdirSync(dir, { recursive: true });
392
+ // For extensions.ts: merge preserved implementations
393
+ if (f.path === "src/extensions.ts" && allExtensions.length > 0) {
394
+ const astExtensions = ast.systems.flatMap(s => s.declarations.filter((d) => d.kind === "ExtensionPointDecl"));
395
+ const { content, validationErrors } = (0, extension_manager_1.mergeWithExisting)(f.content, outPath, astExtensions);
396
+ for (const e of validationErrors)
397
+ extensionErrors.push(e.message);
398
+ fs.writeFileSync(outPath, content, "utf-8");
399
+ }
400
+ else {
401
+ fs.writeFileSync(outPath, f.content, "utf-8");
402
+ }
403
+ }
404
+ if (extensionErrors.length > 0) {
405
+ console.log(`\n Extension point errors:`);
406
+ for (const e of extensionErrors)
407
+ console.log(` x ${e}`);
408
+ process.exit(1);
409
+ }
410
+ console.log(`\nv Compilation complete. ${allFiles.length} files written to output/`);
411
+ }
412
+ catch (e) {
413
+ console.error(`x ${e.message}`);
414
+ process.exit(1);
415
+ }
416
+ }
417
+ main();
418
+ // ─── Diff ─────────────────────────────────────────────────────────────────────
419
+ function runDiff(args) {
420
+ if (args.length < 2) {
421
+ console.error("Usage: bone diff <old.bone> <new.bone>");
422
+ process.exit(1);
423
+ }
424
+ const [oldFile, newFile] = args;
425
+ const compileToIR = (filePath) => {
426
+ const resolved = path.resolve(filePath);
427
+ if (!fs.existsSync(resolved)) {
428
+ console.error(`File not found: ${resolved}`);
429
+ process.exit(1);
430
+ }
431
+ const source = fs.readFileSync(resolved, "utf-8");
432
+ const tokens = new lexer_1.Lexer(source).tokenize();
433
+ const ast = new parser_1.Parser(tokens).parse();
434
+ const hash = (0, crypto_1.createHash)("sha256").update(source).digest("hex").slice(0, 16);
435
+ return new lowering_1.Lowering().lower(ast, hash);
436
+ };
437
+ const oldIR = compileToIR(oldFile);
438
+ const newIR = compileToIR(newFile);
439
+ const oldModels = [];
440
+ const newModels = [];
441
+ for (const sys of oldIR)
442
+ for (const mod of sys.modules)
443
+ for (const m of mod.models)
444
+ oldModels.push(m);
445
+ for (const sys of newIR)
446
+ for (const mod of sys.modules)
447
+ for (const m of mod.models)
448
+ newModels.push(m);
449
+ const oldByName = new Map(oldModels.map(m => [m.name, m]));
450
+ const newByName = new Map(newModels.map(m => [m.name, m]));
451
+ const statements = [];
452
+ // New tables
453
+ for (const [name, model] of newByName) {
454
+ if (!oldByName.has(name)) {
455
+ statements.push(`-- NEW TABLE: ${name}`);
456
+ statements.push(`-- Run: bone compile ${newFile} (generates full migration)`);
457
+ }
458
+ }
459
+ // Removed tables
460
+ for (const [name] of oldByName) {
461
+ if (!newByName.has(name)) {
462
+ const table = name.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase() + "s";
463
+ statements.push(`-- WARNING: Table '${table}' removed from schema`);
464
+ statements.push(`-- Manual: ALTER TABLE ${table} ... (or DROP TABLE ${table})`);
465
+ }
466
+ }
467
+ // Modified tables
468
+ for (const [name, newModel] of newByName) {
469
+ const oldModel = oldByName.get(name);
470
+ if (!oldModel)
471
+ continue;
472
+ const table = name.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase() + "s";
473
+ const oldFields = new Map(oldModel.fields.map((f) => [f.name, f]));
474
+ const newFields = new Map(newModel.fields.map((f) => [f.name, f]));
475
+ const sqlTypeMap = {
476
+ string: "VARCHAR", uint: "BIGINT", int: "BIGINT", float: "DOUBLE PRECISION",
477
+ bool: "BOOLEAN", timestamp: "TIMESTAMPTZ", uuid: "UUID", bytes: "BYTEA", json: "JSONB",
478
+ };
479
+ for (const [fname, field] of newFields) {
480
+ if (!oldFields.has(fname)) {
481
+ const sqlType = sqlTypeMap[field.type] || "JSONB";
482
+ statements.push(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${fname} ${sqlType};`);
483
+ }
484
+ }
485
+ for (const [fname] of oldFields) {
486
+ if (!newFields.has(fname)) {
487
+ statements.push(`-- WARNING: Column '${table}.${fname}' removed`);
488
+ statements.push(`-- Manual: ALTER TABLE ${table} DROP COLUMN ${fname};`);
489
+ }
490
+ }
491
+ }
492
+ if (statements.length === 0) {
493
+ console.log("No schema changes detected.");
494
+ }
495
+ else {
496
+ console.log(`-- BoneScript schema diff: ${path.basename(oldFile)} → ${path.basename(newFile)}`);
497
+ console.log(`-- Generated: ${new Date().toISOString()}`);
498
+ console.log(``);
499
+ console.log(statements.join("\n"));
500
+ }
501
+ }
502
+ // ─── Debug ────────────────────────────────────────────────────────────────────
503
+ function runDebug(source, resolved) {
504
+ try {
505
+ const tokens = new lexer_1.Lexer(source).tokenize();
506
+ const ast = new parser_1.Parser(tokens).parse();
507
+ const sourceHash = (0, crypto_1.createHash)("sha256").update(source).digest("hex").slice(0, 16);
508
+ const irSystems = new lowering_1.Lowering().lower(ast, sourceHash);
509
+ const { emitSourceMapFile } = require("./emit_sourcemap");
510
+ for (const sys of irSystems) {
511
+ const mapContent = emitSourceMapFile(sys, path.basename(resolved));
512
+ const mapPath = path.join(path.dirname(resolved), `${sys.name}.bone.map`);
513
+ fs.writeFileSync(mapPath, mapContent, "utf-8");
514
+ console.log(`v Source map written: ${mapPath}`);
515
+ console.log(` ${sys.modules.length} modules mapped`);
516
+ console.log(` Use output/src/debug.ts to get annotated runtime errors`);
517
+ }
518
+ }
519
+ catch (e) {
520
+ console.error(`x ${e.message}`);
521
+ process.exit(1);
522
+ }
523
+ }
524
+ // ─── Test ─────────────────────────────────────────────────────────────────────
525
+ function runTest(args) {
526
+ const outputDir = args[0] ? path.resolve(args[0]) : path.resolve("output");
527
+ const testFile = path.join(outputDir, "src", "tests.ts");
528
+ if (!fs.existsSync(testFile)) {
529
+ console.error(`No test file found at ${testFile}`);
530
+ console.error("Run 'bone compile <file>' first to generate tests.");
531
+ process.exit(1);
532
+ }
533
+ console.log(`Running BoneScript regression tests...`);
534
+ console.log(`Test file: ${testFile}`);
535
+ console.log(`Target: ${process.env.TEST_BASE_URL || "http://localhost:3000"}`);
536
+ console.log(``);
537
+ // Run the generated test file using ts-node
538
+ const { execSync } = require("child_process");
539
+ try {
540
+ execSync(`npx ts-node ${testFile}`, {
541
+ cwd: outputDir,
542
+ stdio: "inherit",
543
+ env: { ...process.env },
544
+ });
545
+ }
546
+ catch {
547
+ process.exit(1);
548
+ }
549
+ }
550
+ // ─── Verify Determinism ───────────────────────────────────────────────────────
551
+ function runVerifyDeterminism(source, resolved) {
552
+ console.log("Verifying compilation determinism...");
553
+ const compile = () => {
554
+ const tokens = new lexer_1.Lexer(source).tokenize();
555
+ const ast = new parser_1.Parser(tokens).parse();
556
+ const hash = (0, crypto_1.createHash)("sha256").update(source).digest("hex").slice(0, 16);
557
+ const ir = new lowering_1.Lowering().lower(ast, hash);
558
+ const emitter = new emit_full_1.FullEmitter();
559
+ const files = [];
560
+ for (const sys of ir) {
561
+ for (const f of emitter.emit(sys)) {
562
+ files.push({ path: f.path, content: f.content });
563
+ }
564
+ }
565
+ // Sort for canonical comparison
566
+ files.sort((a, b) => a.path.localeCompare(b.path));
567
+ return JSON.stringify(files);
568
+ };
569
+ const run1 = compile();
570
+ const run2 = compile();
571
+ if (run1 === run2) {
572
+ const hash = (0, crypto_1.createHash)("sha256").update(run1).digest("hex").slice(0, 16);
573
+ console.log(`v Deterministic. Both runs produced identical output.`);
574
+ console.log(` Output hash: ${hash}`);
575
+ }
576
+ else {
577
+ // Find first divergence
578
+ const files1 = JSON.parse(run1);
579
+ const files2 = JSON.parse(run2);
580
+ for (let i = 0; i < Math.max(files1.length, files2.length); i++) {
581
+ const f1 = files1[i];
582
+ const f2 = files2[i];
583
+ if (!f1 || !f2 || f1.path !== f2.path || f1.content !== f2.content) {
584
+ console.error(`x NON-DETERMINISTIC: First divergence at file ${i}`);
585
+ console.error(` Run 1: ${f1?.path || "(missing)"}`);
586
+ console.error(` Run 2: ${f2?.path || "(missing)"}`);
587
+ if (f1 && f2 && f1.path === f2.path) {
588
+ // Find first differing line
589
+ const lines1 = f1.content.split("\n");
590
+ const lines2 = f2.content.split("\n");
591
+ for (let j = 0; j < Math.max(lines1.length, lines2.length); j++) {
592
+ if (lines1[j] !== lines2[j]) {
593
+ console.error(` First differing line ${j + 1}:`);
594
+ console.error(` Run 1: ${lines1[j]}`);
595
+ console.error(` Run 2: ${lines2[j]}`);
596
+ break;
597
+ }
598
+ }
599
+ }
600
+ process.exit(1);
601
+ }
602
+ }
603
+ }
604
+ }
137
605
  //# sourceMappingURL=cli.js.map