redscript-mc 1.2.30 → 2.0.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 (269) hide show
  1. package/.claude/commands/build-test.md +10 -0
  2. package/.claude/commands/deploy-demo.md +12 -0
  3. package/.claude/commands/stage-status.md +13 -0
  4. package/.claude/settings.json +12 -0
  5. package/.github/workflows/ci.yml +1 -0
  6. package/CLAUDE.md +231 -0
  7. package/demo.gif +0 -0
  8. package/dist/cli.js +2 -554
  9. package/dist/compile.js +2 -266
  10. package/dist/index.js +2 -159
  11. package/dist/lowering/index.js +5 -3
  12. package/dist/src/__tests__/cli.test.d.ts +1 -0
  13. package/dist/src/__tests__/cli.test.js +104 -0
  14. package/dist/src/__tests__/codegen.test.d.ts +1 -0
  15. package/dist/src/__tests__/codegen.test.js +152 -0
  16. package/dist/src/__tests__/compile-all.test.d.ts +10 -0
  17. package/dist/src/__tests__/compile-all.test.js +108 -0
  18. package/dist/src/__tests__/dce.test.d.ts +1 -0
  19. package/dist/src/__tests__/dce.test.js +102 -0
  20. package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
  21. package/dist/src/__tests__/diagnostics.test.js +177 -0
  22. package/dist/src/__tests__/e2e.test.d.ts +6 -0
  23. package/dist/src/__tests__/e2e.test.js +1789 -0
  24. package/dist/src/__tests__/entity-types.test.d.ts +1 -0
  25. package/dist/src/__tests__/entity-types.test.js +203 -0
  26. package/dist/src/__tests__/formatter.test.d.ts +1 -0
  27. package/dist/src/__tests__/formatter.test.js +40 -0
  28. package/dist/src/__tests__/lexer.test.d.ts +1 -0
  29. package/dist/src/__tests__/lexer.test.js +343 -0
  30. package/dist/src/__tests__/lowering.test.d.ts +1 -0
  31. package/dist/src/__tests__/lowering.test.js +1015 -0
  32. package/dist/src/__tests__/macro.test.d.ts +8 -0
  33. package/dist/src/__tests__/macro.test.js +306 -0
  34. package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
  35. package/dist/src/__tests__/mc-integration.test.js +817 -0
  36. package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
  37. package/dist/src/__tests__/mc-syntax.test.js +124 -0
  38. package/dist/src/__tests__/nbt.test.d.ts +1 -0
  39. package/dist/src/__tests__/nbt.test.js +82 -0
  40. package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
  41. package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
  42. package/dist/src/__tests__/optimizer.test.d.ts +1 -0
  43. package/dist/src/__tests__/optimizer.test.js +149 -0
  44. package/dist/src/__tests__/parser.test.d.ts +1 -0
  45. package/dist/src/__tests__/parser.test.js +807 -0
  46. package/dist/src/__tests__/repl.test.d.ts +1 -0
  47. package/dist/src/__tests__/repl.test.js +27 -0
  48. package/dist/src/__tests__/runtime.test.d.ts +1 -0
  49. package/dist/src/__tests__/runtime.test.js +289 -0
  50. package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
  51. package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
  52. package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
  53. package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
  54. package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
  55. package/dist/src/__tests__/stdlib-math.test.js +351 -0
  56. package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
  57. package/dist/src/__tests__/stdlib-vec.test.js +263 -0
  58. package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
  59. package/dist/src/__tests__/structure-optimizer.test.js +33 -0
  60. package/dist/src/__tests__/typechecker.test.d.ts +1 -0
  61. package/dist/src/__tests__/typechecker.test.js +552 -0
  62. package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
  63. package/dist/src/__tests__/var-allocator.test.js +69 -0
  64. package/dist/src/ast/types.d.ts +515 -0
  65. package/dist/src/ast/types.js +9 -0
  66. package/dist/src/builtins/metadata.d.ts +36 -0
  67. package/dist/src/builtins/metadata.js +1014 -0
  68. package/dist/src/cli.d.ts +11 -0
  69. package/dist/src/cli.js +443 -0
  70. package/dist/src/codegen/cmdblock/index.d.ts +26 -0
  71. package/dist/src/codegen/cmdblock/index.js +45 -0
  72. package/dist/src/codegen/mcfunction/index.d.ts +40 -0
  73. package/dist/src/codegen/mcfunction/index.js +606 -0
  74. package/dist/src/codegen/structure/index.d.ts +24 -0
  75. package/dist/src/codegen/structure/index.js +279 -0
  76. package/dist/src/codegen/var-allocator.d.ts +45 -0
  77. package/dist/src/codegen/var-allocator.js +104 -0
  78. package/dist/src/compile.d.ts +37 -0
  79. package/dist/src/compile.js +165 -0
  80. package/dist/src/diagnostics/index.d.ts +44 -0
  81. package/dist/src/diagnostics/index.js +140 -0
  82. package/dist/src/events/types.d.ts +35 -0
  83. package/dist/src/events/types.js +59 -0
  84. package/dist/src/formatter/index.d.ts +1 -0
  85. package/dist/src/formatter/index.js +26 -0
  86. package/dist/src/index.d.ts +22 -0
  87. package/dist/src/index.js +45 -0
  88. package/dist/src/ir/builder.d.ts +33 -0
  89. package/dist/src/ir/builder.js +99 -0
  90. package/dist/src/ir/types.d.ts +132 -0
  91. package/dist/src/ir/types.js +15 -0
  92. package/dist/src/lexer/index.d.ts +37 -0
  93. package/dist/src/lexer/index.js +569 -0
  94. package/dist/src/lowering/index.d.ts +188 -0
  95. package/dist/src/lowering/index.js +3405 -0
  96. package/dist/src/mc-test/client.d.ts +128 -0
  97. package/dist/src/mc-test/client.js +174 -0
  98. package/dist/src/mc-test/runner.d.ts +28 -0
  99. package/dist/src/mc-test/runner.js +151 -0
  100. package/dist/src/mc-test/setup.d.ts +11 -0
  101. package/dist/src/mc-test/setup.js +98 -0
  102. package/dist/src/mc-validator/index.d.ts +17 -0
  103. package/dist/src/mc-validator/index.js +322 -0
  104. package/dist/src/nbt/index.d.ts +86 -0
  105. package/dist/src/nbt/index.js +250 -0
  106. package/dist/src/optimizer/commands.d.ts +38 -0
  107. package/dist/src/optimizer/commands.js +451 -0
  108. package/dist/src/optimizer/dce.d.ts +34 -0
  109. package/dist/src/optimizer/dce.js +639 -0
  110. package/dist/src/optimizer/passes.d.ts +34 -0
  111. package/dist/src/optimizer/passes.js +243 -0
  112. package/dist/src/optimizer/structure.d.ts +9 -0
  113. package/dist/src/optimizer/structure.js +356 -0
  114. package/dist/src/parser/index.d.ts +93 -0
  115. package/dist/src/parser/index.js +1687 -0
  116. package/dist/src/repl.d.ts +16 -0
  117. package/dist/src/repl.js +165 -0
  118. package/dist/src/runtime/index.d.ts +107 -0
  119. package/dist/src/runtime/index.js +1409 -0
  120. package/dist/src/typechecker/index.d.ts +61 -0
  121. package/dist/src/typechecker/index.js +1034 -0
  122. package/dist/src/types/entity-hierarchy.d.ts +29 -0
  123. package/dist/src/types/entity-hierarchy.js +107 -0
  124. package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
  125. package/dist/src2/__tests__/e2e/basic.test.js +140 -0
  126. package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
  127. package/dist/src2/__tests__/e2e/macros.test.js +182 -0
  128. package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
  129. package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
  130. package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
  131. package/dist/src2/__tests__/hir/desugar.test.js +234 -0
  132. package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
  133. package/dist/src2/__tests__/lir/lower.test.js +559 -0
  134. package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
  135. package/dist/src2/__tests__/lir/types.test.js +185 -0
  136. package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
  137. package/dist/src2/__tests__/lir/verify.test.js +221 -0
  138. package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
  139. package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
  140. package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
  141. package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
  142. package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
  143. package/dist/src2/__tests__/mir/verify.test.js +223 -0
  144. package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
  145. package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
  146. package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
  147. package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
  148. package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
  149. package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
  150. package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
  151. package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
  152. package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
  153. package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
  154. package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
  155. package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
  156. package/dist/src2/emit/compile.d.ts +19 -0
  157. package/dist/src2/emit/compile.js +80 -0
  158. package/dist/src2/emit/index.d.ts +17 -0
  159. package/dist/src2/emit/index.js +172 -0
  160. package/dist/src2/hir/lower.d.ts +15 -0
  161. package/dist/src2/hir/lower.js +378 -0
  162. package/dist/src2/hir/types.d.ts +373 -0
  163. package/dist/src2/hir/types.js +16 -0
  164. package/dist/src2/lir/lower.d.ts +15 -0
  165. package/dist/src2/lir/lower.js +453 -0
  166. package/dist/src2/lir/types.d.ts +136 -0
  167. package/dist/src2/lir/types.js +11 -0
  168. package/dist/src2/lir/verify.d.ts +14 -0
  169. package/dist/src2/lir/verify.js +113 -0
  170. package/dist/src2/mir/lower.d.ts +9 -0
  171. package/dist/src2/mir/lower.js +1030 -0
  172. package/dist/src2/mir/macro.d.ts +22 -0
  173. package/dist/src2/mir/macro.js +168 -0
  174. package/dist/src2/mir/types.d.ts +183 -0
  175. package/dist/src2/mir/types.js +11 -0
  176. package/dist/src2/mir/verify.d.ts +16 -0
  177. package/dist/src2/mir/verify.js +216 -0
  178. package/dist/src2/optimizer/block_merge.d.ts +12 -0
  179. package/dist/src2/optimizer/block_merge.js +84 -0
  180. package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
  181. package/dist/src2/optimizer/branch_simplify.js +28 -0
  182. package/dist/src2/optimizer/constant_fold.d.ts +10 -0
  183. package/dist/src2/optimizer/constant_fold.js +85 -0
  184. package/dist/src2/optimizer/copy_prop.d.ts +9 -0
  185. package/dist/src2/optimizer/copy_prop.js +113 -0
  186. package/dist/src2/optimizer/dce.d.ts +8 -0
  187. package/dist/src2/optimizer/dce.js +155 -0
  188. package/dist/src2/optimizer/pipeline.d.ts +10 -0
  189. package/dist/src2/optimizer/pipeline.js +42 -0
  190. package/dist/tsconfig.tsbuildinfo +1 -0
  191. package/docs/compiler-pipeline-redesign.md +2243 -0
  192. package/docs/optimization-ideas.md +1076 -0
  193. package/editors/vscode/package-lock.json +3 -3
  194. package/editors/vscode/package.json +1 -1
  195. package/jest.config.js +1 -1
  196. package/package.json +6 -5
  197. package/scripts/postbuild.js +15 -0
  198. package/src/__tests__/cli.test.ts +8 -220
  199. package/src/__tests__/dce.test.ts +11 -56
  200. package/src/__tests__/diagnostics.test.ts +59 -38
  201. package/src/__tests__/mc-integration.test.ts +1 -2
  202. package/src/ast/types.ts +6 -1
  203. package/src/cli.ts +29 -156
  204. package/src/compile.ts +6 -162
  205. package/src/index.ts +14 -178
  206. package/src/mc-test/runner.ts +4 -3
  207. package/src/parser/index.ts +1 -1
  208. package/src/repl.ts +1 -1
  209. package/src/runtime/index.ts +1 -1
  210. package/src2/__tests__/e2e/basic.test.ts +154 -0
  211. package/src2/__tests__/e2e/macros.test.ts +199 -0
  212. package/src2/__tests__/e2e/migrate.test.ts +3008 -0
  213. package/src2/__tests__/hir/desugar.test.ts +263 -0
  214. package/src2/__tests__/lir/lower.test.ts +619 -0
  215. package/src2/__tests__/lir/types.test.ts +207 -0
  216. package/src2/__tests__/lir/verify.test.ts +249 -0
  217. package/src2/__tests__/mir/arithmetic.test.ts +156 -0
  218. package/src2/__tests__/mir/control-flow.test.ts +242 -0
  219. package/src2/__tests__/mir/verify.test.ts +254 -0
  220. package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
  221. package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
  222. package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
  223. package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
  224. package/src2/__tests__/optimizer/dce.test.ts +83 -0
  225. package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
  226. package/src2/emit/compile.ts +99 -0
  227. package/src2/emit/index.ts +222 -0
  228. package/src2/hir/lower.ts +428 -0
  229. package/src2/hir/types.ts +216 -0
  230. package/src2/lir/lower.ts +556 -0
  231. package/src2/lir/types.ts +109 -0
  232. package/src2/lir/verify.ts +129 -0
  233. package/src2/mir/lower.ts +1160 -0
  234. package/src2/mir/macro.ts +167 -0
  235. package/src2/mir/types.ts +106 -0
  236. package/src2/mir/verify.ts +218 -0
  237. package/src2/optimizer/block_merge.ts +93 -0
  238. package/src2/optimizer/branch_simplify.ts +27 -0
  239. package/src2/optimizer/constant_fold.ts +88 -0
  240. package/src2/optimizer/copy_prop.ts +106 -0
  241. package/src2/optimizer/dce.ts +133 -0
  242. package/src2/optimizer/pipeline.ts +44 -0
  243. package/tsconfig.json +2 -2
  244. package/src/__tests__/codegen.test.ts +0 -161
  245. package/src/__tests__/e2e.test.ts +0 -2039
  246. package/src/__tests__/entity-types.test.ts +0 -236
  247. package/src/__tests__/lowering.test.ts +0 -1185
  248. package/src/__tests__/macro.test.ts +0 -343
  249. package/src/__tests__/nbt.test.ts +0 -58
  250. package/src/__tests__/optimizer-advanced.test.ts +0 -144
  251. package/src/__tests__/optimizer.test.ts +0 -162
  252. package/src/__tests__/runtime.test.ts +0 -305
  253. package/src/__tests__/stdlib-advanced.test.ts +0 -379
  254. package/src/__tests__/stdlib-bigint.test.ts +0 -427
  255. package/src/__tests__/stdlib-math.test.ts +0 -374
  256. package/src/__tests__/stdlib-vec.test.ts +0 -259
  257. package/src/__tests__/structure-optimizer.test.ts +0 -38
  258. package/src/__tests__/var-allocator.test.ts +0 -75
  259. package/src/codegen/cmdblock/index.ts +0 -63
  260. package/src/codegen/mcfunction/index.ts +0 -662
  261. package/src/codegen/structure/index.ts +0 -346
  262. package/src/codegen/var-allocator.ts +0 -104
  263. package/src/ir/builder.ts +0 -116
  264. package/src/ir/types.ts +0 -134
  265. package/src/lowering/index.ts +0 -3876
  266. package/src/optimizer/commands.ts +0 -534
  267. package/src/optimizer/dce.ts +0 -679
  268. package/src/optimizer/passes.ts +0 -250
  269. package/src/optimizer/structure.ts +0 -450
@@ -0,0 +1,639 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeadCodeEliminator = void 0;
4
+ exports.eliminateDeadCode = eliminateDeadCode;
5
+ function copySpan(target, source) {
6
+ const descriptor = Object.getOwnPropertyDescriptor(source, 'span');
7
+ if (descriptor) {
8
+ Object.defineProperty(target, 'span', descriptor);
9
+ }
10
+ return target;
11
+ }
12
+ function isConstantBoolean(expr) {
13
+ if (expr.kind === 'bool_lit') {
14
+ return expr.value;
15
+ }
16
+ return null;
17
+ }
18
+ function isPureExpr(expr) {
19
+ switch (expr.kind) {
20
+ case 'int_lit':
21
+ case 'float_lit':
22
+ case 'byte_lit':
23
+ case 'short_lit':
24
+ case 'long_lit':
25
+ case 'double_lit':
26
+ case 'rel_coord':
27
+ case 'local_coord':
28
+ case 'bool_lit':
29
+ case 'str_lit':
30
+ case 'mc_name':
31
+ case 'range_lit':
32
+ case 'selector':
33
+ case 'ident':
34
+ case 'blockpos':
35
+ return true;
36
+ case 'str_interp':
37
+ return expr.parts.every(part => typeof part === 'string' || isPureExpr(part));
38
+ case 'f_string':
39
+ return expr.parts.every(part => part.kind === 'text' || isPureExpr(part.expr));
40
+ case 'binary':
41
+ return isPureExpr(expr.left) && isPureExpr(expr.right);
42
+ case 'is_check':
43
+ return isPureExpr(expr.expr);
44
+ case 'unary':
45
+ return isPureExpr(expr.operand);
46
+ case 'member':
47
+ return isPureExpr(expr.obj);
48
+ case 'index':
49
+ return isPureExpr(expr.obj) && isPureExpr(expr.index);
50
+ case 'array_lit':
51
+ return expr.elements.every(isPureExpr);
52
+ case 'struct_lit':
53
+ return expr.fields.every(field => isPureExpr(field.value));
54
+ case 'lambda':
55
+ return true;
56
+ case 'assign':
57
+ case 'member_assign':
58
+ case 'call':
59
+ case 'invoke':
60
+ case 'static_call':
61
+ return false;
62
+ }
63
+ }
64
+ class DeadCodeEliminator {
65
+ constructor() {
66
+ this.functionMap = new Map();
67
+ this.reachableFunctions = new Set();
68
+ this.usedConstants = new Set();
69
+ this.localReads = new Set();
70
+ this.localDeclIds = new WeakMap();
71
+ this.localIdCounter = 0;
72
+ this.warnings = [];
73
+ }
74
+ eliminate(program) {
75
+ this.functionMap.clear();
76
+ this.reachableFunctions.clear();
77
+ this.usedConstants.clear();
78
+ this.localReads.clear();
79
+ this.localIdCounter = 0;
80
+ this.warnings.length = 0;
81
+ for (const fn of program.declarations) {
82
+ this.functionMap.set(fn.name, fn);
83
+ }
84
+ const entryPoints = this.findEntryPoints(program);
85
+ if (entryPoints.length === 0) {
86
+ for (const fn of program.declarations) {
87
+ this.markReachable(fn.name);
88
+ }
89
+ }
90
+ else {
91
+ for (const fnName of entryPoints) {
92
+ this.markReachable(fnName);
93
+ }
94
+ }
95
+ for (const global of program.globals) {
96
+ this.collectExprRefs(global.init, []);
97
+ }
98
+ for (const implBlock of program.implBlocks) {
99
+ for (const method of implBlock.methods) {
100
+ this.collectFunctionRefs(method);
101
+ }
102
+ }
103
+ return {
104
+ ...program,
105
+ declarations: program.declarations
106
+ .filter(fn => this.reachableFunctions.has(fn.name))
107
+ .map(fn => this.transformFunction(fn)),
108
+ consts: program.consts.filter(constDecl => this.usedConstants.has(constDecl.name)),
109
+ implBlocks: program.implBlocks.map(implBlock => ({
110
+ ...implBlock,
111
+ methods: implBlock.methods.map(method => this.transformFunction(method)),
112
+ })),
113
+ };
114
+ }
115
+ findEntryPoints(program) {
116
+ const entries = new Set();
117
+ for (const fn of program.declarations) {
118
+ // Library functions (from `module library;` or `librarySources`) are
119
+ // NOT MC entry points — they're only kept if reachable from user code.
120
+ // Exception: decorators like @tick / @load / @on / @keep always force inclusion.
121
+ if (!fn.isLibraryFn) {
122
+ // All top-level non-library functions are entry points (callable via /function)
123
+ // Exception: functions starting with _ are considered private/internal
124
+ if (!fn.name.startsWith('_')) {
125
+ entries.add(fn.name);
126
+ }
127
+ }
128
+ // Decorated functions are always entry points regardless of library mode or _ prefix
129
+ if (fn.decorators.some(decorator => [
130
+ 'tick',
131
+ 'load',
132
+ 'on',
133
+ 'on_trigger',
134
+ 'on_advancement',
135
+ 'on_craft',
136
+ 'on_death',
137
+ 'on_login',
138
+ 'on_join_team',
139
+ 'keep',
140
+ ].includes(decorator.name))) {
141
+ entries.add(fn.name);
142
+ }
143
+ }
144
+ return [...entries];
145
+ }
146
+ markReachable(fnName) {
147
+ if (this.reachableFunctions.has(fnName)) {
148
+ return;
149
+ }
150
+ const fn = this.functionMap.get(fnName);
151
+ if (!fn) {
152
+ return;
153
+ }
154
+ this.reachableFunctions.add(fnName);
155
+ this.collectFunctionRefs(fn);
156
+ // @requires("dep") — when fn is reachable, its required dependencies are
157
+ // also pulled into the reachable set so they survive DCE.
158
+ for (const decorator of fn.decorators) {
159
+ if (decorator.name === 'require_on_load') {
160
+ for (const arg of decorator.rawArgs ?? []) {
161
+ if (arg.kind === 'string') {
162
+ this.markReachable(arg.value);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ collectFunctionRefs(fn) {
169
+ const scope = [fn.params.map(param => ({ id: `param:${fn.name}:${param.name}`, name: param.name }))];
170
+ for (const param of fn.params) {
171
+ if (param.default) {
172
+ this.collectExprRefs(param.default, scope);
173
+ }
174
+ }
175
+ this.collectStmtRefs(fn.body, scope);
176
+ }
177
+ collectStmtRefs(block, scope) {
178
+ scope.push([]);
179
+ for (const stmt of block) {
180
+ this.collectStmtRef(stmt, scope);
181
+ }
182
+ scope.pop();
183
+ }
184
+ collectStmtRef(stmt, scope) {
185
+ switch (stmt.kind) {
186
+ case 'let': {
187
+ this.collectExprRefs(stmt.init, scope);
188
+ const id = `local:${stmt.name}:${this.localIdCounter++}:${(stmt.span?.line ?? 0)}:${(stmt.span?.col ?? 0)}`;
189
+ this.localDeclIds.set(stmt, id);
190
+ scope[scope.length - 1].push({ id, name: stmt.name });
191
+ break;
192
+ }
193
+ case 'expr':
194
+ this.collectExprRefs(stmt.expr, scope);
195
+ break;
196
+ case 'return':
197
+ if (stmt.value) {
198
+ this.collectExprRefs(stmt.value, scope);
199
+ }
200
+ break;
201
+ case 'if': {
202
+ this.collectExprRefs(stmt.cond, scope);
203
+ const constant = isConstantBoolean(stmt.cond);
204
+ if (constant === true) {
205
+ this.collectStmtRefs(stmt.then, scope);
206
+ }
207
+ else if (constant === false) {
208
+ if (stmt.else_) {
209
+ this.collectStmtRefs(stmt.else_, scope);
210
+ }
211
+ }
212
+ else {
213
+ this.collectStmtRefs(stmt.then, scope);
214
+ if (stmt.else_) {
215
+ this.collectStmtRefs(stmt.else_, scope);
216
+ }
217
+ }
218
+ break;
219
+ }
220
+ case 'while':
221
+ this.collectExprRefs(stmt.cond, scope);
222
+ this.collectStmtRefs(stmt.body, scope);
223
+ break;
224
+ case 'for':
225
+ scope.push([]);
226
+ if (stmt.init) {
227
+ this.collectStmtRef(stmt.init, scope);
228
+ }
229
+ this.collectExprRefs(stmt.cond, scope);
230
+ this.collectExprRefs(stmt.step, scope);
231
+ this.collectStmtRefs(stmt.body, scope);
232
+ scope.pop();
233
+ break;
234
+ case 'foreach':
235
+ this.collectExprRefs(stmt.iterable, scope);
236
+ scope.push([{ id: `foreach:${stmt.binding}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.binding }]);
237
+ this.collectStmtRefs(stmt.body, scope);
238
+ scope.pop();
239
+ break;
240
+ case 'for_range':
241
+ this.collectExprRefs(stmt.start, scope);
242
+ this.collectExprRefs(stmt.end, scope);
243
+ scope.push([{ id: `range:${stmt.varName}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.varName }]);
244
+ this.collectStmtRefs(stmt.body, scope);
245
+ scope.pop();
246
+ break;
247
+ case 'match':
248
+ this.collectExprRefs(stmt.expr, scope);
249
+ for (const arm of stmt.arms) {
250
+ if (arm.pattern) {
251
+ this.collectExprRefs(arm.pattern, scope);
252
+ }
253
+ this.collectStmtRefs(arm.body, scope);
254
+ }
255
+ break;
256
+ case 'as_block':
257
+ case 'at_block':
258
+ case 'as_at':
259
+ case 'execute':
260
+ this.collectNestedStmtRefs(stmt, scope);
261
+ break;
262
+ case 'raw':
263
+ case 'break':
264
+ case 'continue':
265
+ break;
266
+ }
267
+ }
268
+ collectNestedStmtRefs(stmt, scope) {
269
+ if (stmt.kind === 'execute') {
270
+ for (const sub of stmt.subcommands) {
271
+ if ('varName' in sub && sub.varName) {
272
+ const resolved = this.resolveLocal(sub.varName, scope);
273
+ if (resolved) {
274
+ this.localReads.add(resolved.id);
275
+ }
276
+ }
277
+ }
278
+ }
279
+ this.collectStmtRefs(stmt.body, scope);
280
+ }
281
+ collectExprRefs(expr, scope) {
282
+ switch (expr.kind) {
283
+ case 'ident': {
284
+ const resolved = this.resolveLocal(expr.name, scope);
285
+ if (resolved) {
286
+ this.localReads.add(resolved.id);
287
+ }
288
+ else {
289
+ this.usedConstants.add(expr.name);
290
+ }
291
+ break;
292
+ }
293
+ case 'call':
294
+ {
295
+ const resolved = this.resolveLocal(expr.fn, scope);
296
+ if (resolved) {
297
+ this.localReads.add(resolved.id);
298
+ }
299
+ else if (this.functionMap.has(expr.fn)) {
300
+ this.markReachable(expr.fn);
301
+ }
302
+ }
303
+ for (const arg of expr.args) {
304
+ this.collectExprRefs(arg, scope);
305
+ }
306
+ break;
307
+ case 'static_call':
308
+ for (const arg of expr.args) {
309
+ this.collectExprRefs(arg, scope);
310
+ }
311
+ break;
312
+ case 'invoke':
313
+ this.collectExprRefs(expr.callee, scope);
314
+ for (const arg of expr.args) {
315
+ this.collectExprRefs(arg, scope);
316
+ }
317
+ break;
318
+ case 'member':
319
+ this.collectExprRefs(expr.obj, scope);
320
+ break;
321
+ case 'member_assign':
322
+ this.collectExprRefs(expr.obj, scope);
323
+ this.collectExprRefs(expr.value, scope);
324
+ break;
325
+ case 'index':
326
+ this.collectExprRefs(expr.obj, scope);
327
+ this.collectExprRefs(expr.index, scope);
328
+ break;
329
+ case 'array_lit':
330
+ expr.elements.forEach(element => this.collectExprRefs(element, scope));
331
+ break;
332
+ case 'struct_lit':
333
+ expr.fields.forEach(field => this.collectExprRefs(field.value, scope));
334
+ break;
335
+ case 'binary':
336
+ this.collectExprRefs(expr.left, scope);
337
+ this.collectExprRefs(expr.right, scope);
338
+ break;
339
+ case 'is_check':
340
+ this.collectExprRefs(expr.expr, scope);
341
+ break;
342
+ case 'unary':
343
+ this.collectExprRefs(expr.operand, scope);
344
+ break;
345
+ case 'assign': {
346
+ this.collectExprRefs(expr.value, scope);
347
+ break;
348
+ }
349
+ case 'str_interp':
350
+ expr.parts.forEach(part => {
351
+ if (typeof part !== 'string') {
352
+ this.collectExprRefs(part, scope);
353
+ }
354
+ });
355
+ break;
356
+ case 'f_string':
357
+ expr.parts.forEach(part => {
358
+ if (part.kind === 'expr') {
359
+ this.collectExprRefs(part.expr, scope);
360
+ }
361
+ });
362
+ break;
363
+ case 'lambda': {
364
+ const lambdaScope = [
365
+ ...scope.map(entries => [...entries]),
366
+ expr.params.map(param => ({ id: `lambda:${param.name}:${expr.span?.line ?? 0}:${expr.span?.col ?? 0}`, name: param.name })),
367
+ ];
368
+ if (Array.isArray(expr.body)) {
369
+ this.collectStmtRefs(expr.body, lambdaScope);
370
+ }
371
+ else {
372
+ this.collectExprRefs(expr.body, lambdaScope);
373
+ }
374
+ break;
375
+ }
376
+ case 'blockpos':
377
+ case 'bool_lit':
378
+ case 'byte_lit':
379
+ case 'double_lit':
380
+ case 'float_lit':
381
+ case 'int_lit':
382
+ case 'long_lit':
383
+ case 'mc_name':
384
+ case 'range_lit':
385
+ case 'selector':
386
+ case 'short_lit':
387
+ case 'str_lit':
388
+ break;
389
+ }
390
+ }
391
+ resolveLocal(name, scope) {
392
+ for (let i = scope.length - 1; i >= 0; i--) {
393
+ for (let j = scope[i].length - 1; j >= 0; j--) {
394
+ if (scope[i][j].name === name) {
395
+ return scope[i][j];
396
+ }
397
+ }
398
+ }
399
+ return null;
400
+ }
401
+ transformFunction(fn) {
402
+ const scope = [fn.params.map(param => ({ id: `param:${fn.name}:${param.name}`, name: param.name }))];
403
+ const body = this.transformBlock(fn.body, scope);
404
+ return body === fn.body ? fn : copySpan({ ...fn, body }, fn);
405
+ }
406
+ transformBlock(block, scope) {
407
+ scope.push([]);
408
+ const transformed = [];
409
+ for (const stmt of block) {
410
+ const next = this.transformStmt(stmt, scope);
411
+ transformed.push(...next);
412
+ }
413
+ scope.pop();
414
+ return transformed;
415
+ }
416
+ transformStmt(stmt, scope) {
417
+ switch (stmt.kind) {
418
+ case 'let': {
419
+ const init = this.transformExpr(stmt.init, scope);
420
+ const id = this.localDeclIds.get(stmt) ?? `local:${stmt.name}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`;
421
+ scope[scope.length - 1].push({ id, name: stmt.name });
422
+ if (this.localReads.has(id)) {
423
+ if (init === stmt.init) {
424
+ return [stmt];
425
+ }
426
+ return [copySpan({ ...stmt, init }, stmt)];
427
+ }
428
+ // Unused variable - emit warning
429
+ this.warnings.push({
430
+ message: `Unused variable '${stmt.name}'`,
431
+ code: 'W_UNUSED_VAR',
432
+ line: stmt.span?.line,
433
+ col: stmt.span?.col,
434
+ });
435
+ if (isPureExpr(init)) {
436
+ return [];
437
+ }
438
+ return [copySpan({ kind: 'expr', expr: init }, stmt)];
439
+ }
440
+ case 'expr': {
441
+ const expr = this.transformExpr(stmt.expr, scope);
442
+ if (expr.kind === 'assign') {
443
+ const resolved = this.resolveLocal(expr.target, scope);
444
+ if (resolved && !this.localReads.has(resolved.id)) {
445
+ if (isPureExpr(expr.value)) {
446
+ return [];
447
+ }
448
+ return [copySpan({ kind: 'expr', expr: expr.value }, stmt)];
449
+ }
450
+ }
451
+ if (expr === stmt.expr) {
452
+ return [stmt];
453
+ }
454
+ return [copySpan({ ...stmt, expr }, stmt)];
455
+ }
456
+ case 'return': {
457
+ if (!stmt.value) {
458
+ return [stmt];
459
+ }
460
+ const value = this.transformExpr(stmt.value, scope);
461
+ if (value === stmt.value) {
462
+ return [stmt];
463
+ }
464
+ return [copySpan({ ...stmt, value }, stmt)];
465
+ }
466
+ case 'if': {
467
+ const cond = this.transformExpr(stmt.cond, scope);
468
+ const constant = isConstantBoolean(cond);
469
+ if (constant === true) {
470
+ return this.transformBlock(stmt.then, scope);
471
+ }
472
+ if (constant === false) {
473
+ return stmt.else_ ? this.transformBlock(stmt.else_, scope) : [];
474
+ }
475
+ const thenBlock = this.transformBlock(stmt.then, scope);
476
+ const elseBlock = stmt.else_ ? this.transformBlock(stmt.else_, scope) : undefined;
477
+ if (cond === stmt.cond && thenBlock === stmt.then && elseBlock === stmt.else_) {
478
+ return [stmt];
479
+ }
480
+ return [copySpan({ ...stmt, cond, then: thenBlock, else_: elseBlock }, stmt)];
481
+ }
482
+ case 'while': {
483
+ const cond = this.transformExpr(stmt.cond, scope);
484
+ if (isConstantBoolean(cond) === false) {
485
+ return [];
486
+ }
487
+ const body = this.transformBlock(stmt.body, scope);
488
+ return [copySpan({ ...stmt, cond, body }, stmt)];
489
+ }
490
+ case 'for': {
491
+ const forScope = [...scope, []];
492
+ const init = stmt.init ? this.transformStmt(stmt.init, forScope)[0] : undefined;
493
+ const cond = this.transformExpr(stmt.cond, forScope);
494
+ if (isConstantBoolean(cond) === false) {
495
+ return init ? [init] : [];
496
+ }
497
+ const step = this.transformExpr(stmt.step, forScope);
498
+ const body = this.transformBlock(stmt.body, forScope);
499
+ return [copySpan({ ...stmt, init, cond, step, body }, stmt)];
500
+ }
501
+ case 'foreach': {
502
+ const iterable = this.transformExpr(stmt.iterable, scope);
503
+ const foreachScope = [...scope, [{ id: `foreach:${stmt.binding}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.binding }]];
504
+ const body = this.transformBlock(stmt.body, foreachScope);
505
+ return [copySpan({ ...stmt, iterable, body }, stmt)];
506
+ }
507
+ case 'for_range': {
508
+ const start = this.transformExpr(stmt.start, scope);
509
+ const end = this.transformExpr(stmt.end, scope);
510
+ const rangeScope = [...scope, [{ id: `range:${stmt.varName}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.varName }]];
511
+ const body = this.transformBlock(stmt.body, rangeScope);
512
+ return [copySpan({ ...stmt, start, end, body }, stmt)];
513
+ }
514
+ case 'match': {
515
+ const expr = this.transformExpr(stmt.expr, scope);
516
+ const arms = stmt.arms.map(arm => ({
517
+ pattern: arm.pattern ? this.transformExpr(arm.pattern, scope) : null,
518
+ body: this.transformBlock(arm.body, scope),
519
+ }));
520
+ return [copySpan({ ...stmt, expr, arms }, stmt)];
521
+ }
522
+ case 'as_block':
523
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
524
+ case 'at_block':
525
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
526
+ case 'as_at':
527
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
528
+ case 'execute':
529
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
530
+ case 'raw':
531
+ return [stmt];
532
+ case 'break':
533
+ return [stmt];
534
+ case 'continue':
535
+ return [stmt];
536
+ }
537
+ }
538
+ transformExpr(expr, scope) {
539
+ switch (expr.kind) {
540
+ case 'call':
541
+ return copySpan({ ...expr, args: expr.args.map(arg => this.transformExpr(arg, scope)) }, expr);
542
+ case 'static_call':
543
+ return copySpan({ ...expr, args: expr.args.map(arg => this.transformExpr(arg, scope)) }, expr);
544
+ case 'invoke':
545
+ return copySpan({
546
+ ...expr,
547
+ callee: this.transformExpr(expr.callee, scope),
548
+ args: expr.args.map(arg => this.transformExpr(arg, scope)),
549
+ }, expr);
550
+ case 'binary':
551
+ return copySpan({
552
+ ...expr,
553
+ left: this.transformExpr(expr.left, scope),
554
+ right: this.transformExpr(expr.right, scope),
555
+ }, expr);
556
+ case 'is_check':
557
+ return copySpan({ ...expr, expr: this.transformExpr(expr.expr, scope) }, expr);
558
+ case 'unary':
559
+ return copySpan({ ...expr, operand: this.transformExpr(expr.operand, scope) }, expr);
560
+ case 'assign':
561
+ return copySpan({ ...expr, value: this.transformExpr(expr.value, scope) }, expr);
562
+ case 'member':
563
+ return copySpan({ ...expr, obj: this.transformExpr(expr.obj, scope) }, expr);
564
+ case 'member_assign':
565
+ return copySpan({
566
+ ...expr,
567
+ obj: this.transformExpr(expr.obj, scope),
568
+ value: this.transformExpr(expr.value, scope),
569
+ }, expr);
570
+ case 'index':
571
+ return copySpan({
572
+ ...expr,
573
+ obj: this.transformExpr(expr.obj, scope),
574
+ index: this.transformExpr(expr.index, scope),
575
+ }, expr);
576
+ case 'array_lit':
577
+ return copySpan({ ...expr, elements: expr.elements.map(element => this.transformExpr(element, scope)) }, expr);
578
+ case 'struct_lit':
579
+ return copySpan({
580
+ ...expr,
581
+ fields: expr.fields.map(field => ({ ...field, value: this.transformExpr(field.value, scope) })),
582
+ }, expr);
583
+ case 'str_interp':
584
+ return copySpan({
585
+ ...expr,
586
+ parts: expr.parts.map(part => typeof part === 'string' ? part : this.transformExpr(part, scope)),
587
+ }, expr);
588
+ case 'f_string':
589
+ return copySpan({
590
+ ...expr,
591
+ parts: expr.parts.map(part => part.kind === 'text' ? part : { kind: 'expr', expr: this.transformExpr(part.expr, scope) }),
592
+ }, expr);
593
+ case 'lambda': {
594
+ const lambdaScope = [
595
+ ...scope.map(entries => [...entries]),
596
+ expr.params.map(param => ({ id: `lambda:${param.name}:${expr.span?.line ?? 0}:${expr.span?.col ?? 0}`, name: param.name })),
597
+ ];
598
+ const body = Array.isArray(expr.body)
599
+ ? this.transformBlock(expr.body, lambdaScope)
600
+ : this.transformExpr(expr.body, lambdaScope);
601
+ return copySpan({ ...expr, body }, expr);
602
+ }
603
+ case 'blockpos':
604
+ case 'bool_lit':
605
+ case 'byte_lit':
606
+ case 'double_lit':
607
+ case 'float_lit':
608
+ case 'ident':
609
+ case 'int_lit':
610
+ case 'long_lit':
611
+ case 'mc_name':
612
+ case 'range_lit':
613
+ case 'rel_coord':
614
+ case 'local_coord':
615
+ case 'selector':
616
+ case 'short_lit':
617
+ case 'str_lit':
618
+ return expr;
619
+ }
620
+ }
621
+ }
622
+ exports.DeadCodeEliminator = DeadCodeEliminator;
623
+ function eliminateDeadCode(program, sourceRanges) {
624
+ const eliminator = new DeadCodeEliminator();
625
+ const result = eliminator.eliminate(program);
626
+ let warnings = eliminator.warnings;
627
+ // Resolve combined-source line numbers back to original file + line
628
+ if (sourceRanges && sourceRanges.length > 0) {
629
+ const { resolveSourceLine } = require('../compile');
630
+ warnings = warnings.map(w => {
631
+ if (w.line == null)
632
+ return w;
633
+ const resolved = resolveSourceLine(w.line, sourceRanges);
634
+ return { ...w, line: resolved.line, filePath: resolved.filePath ?? w.filePath };
635
+ });
636
+ }
637
+ return { program: result, warnings };
638
+ }
639
+ //# sourceMappingURL=dce.js.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Optimization passes over IR.
3
+ *
4
+ * Each pass: IRFunction → IRFunction (pure transformation)
5
+ *
6
+ * Pipeline order:
7
+ * 1. constantFolding — evaluate constant expressions at compile time
8
+ * 2. copyPropagation — eliminate redundant copies
9
+ * 3. deadCodeElimination — remove unused assignments
10
+ * 4. commandMerging — MC-specific: merge chained execute conditions
11
+ */
12
+ import type { IRFunction } from '../ir/types';
13
+ import { type OptimizationStats } from './commands';
14
+ export declare function constantFolding(fn: IRFunction): IRFunction;
15
+ export declare function constantFoldingWithStats(fn: IRFunction): {
16
+ fn: IRFunction;
17
+ stats: Partial<OptimizationStats>;
18
+ };
19
+ export declare function copyPropagation(fn: IRFunction): IRFunction;
20
+ export declare function deadCodeElimination(fn: IRFunction): IRFunction;
21
+ export declare function deadCodeEliminationWithStats(fn: IRFunction): {
22
+ fn: IRFunction;
23
+ stats: Partial<OptimizationStats>;
24
+ };
25
+ export interface OptimizationPass {
26
+ name: string;
27
+ run: (fn: IRFunction) => IRFunction;
28
+ }
29
+ export declare const defaultPipeline: OptimizationPass[];
30
+ export declare function optimize(fn: IRFunction, passes?: OptimizationPass[]): IRFunction;
31
+ export declare function optimizeWithStats(fn: IRFunction, passes?: OptimizationPass[]): {
32
+ fn: IRFunction;
33
+ stats: OptimizationStats;
34
+ };