redscript-mc 1.2.29 → 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 (274) 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/README.md +29 -28
  8. package/README.zh.md +28 -28
  9. package/demo.gif +0 -0
  10. package/dist/cli.js +2 -554
  11. package/dist/compile.js +2 -266
  12. package/dist/index.js +2 -159
  13. package/dist/lexer/index.js +9 -1
  14. package/dist/lowering/index.js +22 -5
  15. package/dist/src/__tests__/cli.test.d.ts +1 -0
  16. package/dist/src/__tests__/cli.test.js +104 -0
  17. package/dist/src/__tests__/codegen.test.d.ts +1 -0
  18. package/dist/src/__tests__/codegen.test.js +152 -0
  19. package/dist/src/__tests__/compile-all.test.d.ts +10 -0
  20. package/dist/src/__tests__/compile-all.test.js +108 -0
  21. package/dist/src/__tests__/dce.test.d.ts +1 -0
  22. package/dist/src/__tests__/dce.test.js +102 -0
  23. package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
  24. package/dist/src/__tests__/diagnostics.test.js +177 -0
  25. package/dist/src/__tests__/e2e.test.d.ts +6 -0
  26. package/dist/src/__tests__/e2e.test.js +1789 -0
  27. package/dist/src/__tests__/entity-types.test.d.ts +1 -0
  28. package/dist/src/__tests__/entity-types.test.js +203 -0
  29. package/dist/src/__tests__/formatter.test.d.ts +1 -0
  30. package/dist/src/__tests__/formatter.test.js +40 -0
  31. package/dist/src/__tests__/lexer.test.d.ts +1 -0
  32. package/dist/src/__tests__/lexer.test.js +343 -0
  33. package/dist/src/__tests__/lowering.test.d.ts +1 -0
  34. package/dist/src/__tests__/lowering.test.js +1015 -0
  35. package/dist/src/__tests__/macro.test.d.ts +8 -0
  36. package/dist/src/__tests__/macro.test.js +306 -0
  37. package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
  38. package/dist/src/__tests__/mc-integration.test.js +817 -0
  39. package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
  40. package/dist/src/__tests__/mc-syntax.test.js +124 -0
  41. package/dist/src/__tests__/nbt.test.d.ts +1 -0
  42. package/dist/src/__tests__/nbt.test.js +82 -0
  43. package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
  44. package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
  45. package/dist/src/__tests__/optimizer.test.d.ts +1 -0
  46. package/dist/src/__tests__/optimizer.test.js +149 -0
  47. package/dist/src/__tests__/parser.test.d.ts +1 -0
  48. package/dist/src/__tests__/parser.test.js +807 -0
  49. package/dist/src/__tests__/repl.test.d.ts +1 -0
  50. package/dist/src/__tests__/repl.test.js +27 -0
  51. package/dist/src/__tests__/runtime.test.d.ts +1 -0
  52. package/dist/src/__tests__/runtime.test.js +289 -0
  53. package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
  54. package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
  55. package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
  56. package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
  57. package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
  58. package/dist/src/__tests__/stdlib-math.test.js +351 -0
  59. package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
  60. package/dist/src/__tests__/stdlib-vec.test.js +263 -0
  61. package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
  62. package/dist/src/__tests__/structure-optimizer.test.js +33 -0
  63. package/dist/src/__tests__/typechecker.test.d.ts +1 -0
  64. package/dist/src/__tests__/typechecker.test.js +552 -0
  65. package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
  66. package/dist/src/__tests__/var-allocator.test.js +69 -0
  67. package/dist/src/ast/types.d.ts +515 -0
  68. package/dist/src/ast/types.js +9 -0
  69. package/dist/src/builtins/metadata.d.ts +36 -0
  70. package/dist/src/builtins/metadata.js +1014 -0
  71. package/dist/src/cli.d.ts +11 -0
  72. package/dist/src/cli.js +443 -0
  73. package/dist/src/codegen/cmdblock/index.d.ts +26 -0
  74. package/dist/src/codegen/cmdblock/index.js +45 -0
  75. package/dist/src/codegen/mcfunction/index.d.ts +40 -0
  76. package/dist/src/codegen/mcfunction/index.js +606 -0
  77. package/dist/src/codegen/structure/index.d.ts +24 -0
  78. package/dist/src/codegen/structure/index.js +279 -0
  79. package/dist/src/codegen/var-allocator.d.ts +45 -0
  80. package/dist/src/codegen/var-allocator.js +104 -0
  81. package/dist/src/compile.d.ts +37 -0
  82. package/dist/src/compile.js +165 -0
  83. package/dist/src/diagnostics/index.d.ts +44 -0
  84. package/dist/src/diagnostics/index.js +140 -0
  85. package/dist/src/events/types.d.ts +35 -0
  86. package/dist/src/events/types.js +59 -0
  87. package/dist/src/formatter/index.d.ts +1 -0
  88. package/dist/src/formatter/index.js +26 -0
  89. package/dist/src/index.d.ts +22 -0
  90. package/dist/src/index.js +45 -0
  91. package/dist/src/ir/builder.d.ts +33 -0
  92. package/dist/src/ir/builder.js +99 -0
  93. package/dist/src/ir/types.d.ts +132 -0
  94. package/dist/src/ir/types.js +15 -0
  95. package/dist/src/lexer/index.d.ts +37 -0
  96. package/dist/src/lexer/index.js +569 -0
  97. package/dist/src/lowering/index.d.ts +188 -0
  98. package/dist/src/lowering/index.js +3405 -0
  99. package/dist/src/mc-test/client.d.ts +128 -0
  100. package/dist/src/mc-test/client.js +174 -0
  101. package/dist/src/mc-test/runner.d.ts +28 -0
  102. package/dist/src/mc-test/runner.js +151 -0
  103. package/dist/src/mc-test/setup.d.ts +11 -0
  104. package/dist/src/mc-test/setup.js +98 -0
  105. package/dist/src/mc-validator/index.d.ts +17 -0
  106. package/dist/src/mc-validator/index.js +322 -0
  107. package/dist/src/nbt/index.d.ts +86 -0
  108. package/dist/src/nbt/index.js +250 -0
  109. package/dist/src/optimizer/commands.d.ts +38 -0
  110. package/dist/src/optimizer/commands.js +451 -0
  111. package/dist/src/optimizer/dce.d.ts +34 -0
  112. package/dist/src/optimizer/dce.js +639 -0
  113. package/dist/src/optimizer/passes.d.ts +34 -0
  114. package/dist/src/optimizer/passes.js +243 -0
  115. package/dist/src/optimizer/structure.d.ts +9 -0
  116. package/dist/src/optimizer/structure.js +356 -0
  117. package/dist/src/parser/index.d.ts +93 -0
  118. package/dist/src/parser/index.js +1687 -0
  119. package/dist/src/repl.d.ts +16 -0
  120. package/dist/src/repl.js +165 -0
  121. package/dist/src/runtime/index.d.ts +107 -0
  122. package/dist/src/runtime/index.js +1409 -0
  123. package/dist/src/typechecker/index.d.ts +61 -0
  124. package/dist/src/typechecker/index.js +1034 -0
  125. package/dist/src/types/entity-hierarchy.d.ts +29 -0
  126. package/dist/src/types/entity-hierarchy.js +107 -0
  127. package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
  128. package/dist/src2/__tests__/e2e/basic.test.js +140 -0
  129. package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
  130. package/dist/src2/__tests__/e2e/macros.test.js +182 -0
  131. package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
  132. package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
  133. package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
  134. package/dist/src2/__tests__/hir/desugar.test.js +234 -0
  135. package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
  136. package/dist/src2/__tests__/lir/lower.test.js +559 -0
  137. package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
  138. package/dist/src2/__tests__/lir/types.test.js +185 -0
  139. package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
  140. package/dist/src2/__tests__/lir/verify.test.js +221 -0
  141. package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
  142. package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
  143. package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
  144. package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
  145. package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
  146. package/dist/src2/__tests__/mir/verify.test.js +223 -0
  147. package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
  148. package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
  149. package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
  150. package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
  151. package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
  152. package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
  153. package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
  154. package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
  155. package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
  156. package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
  157. package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
  158. package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
  159. package/dist/src2/emit/compile.d.ts +19 -0
  160. package/dist/src2/emit/compile.js +80 -0
  161. package/dist/src2/emit/index.d.ts +17 -0
  162. package/dist/src2/emit/index.js +172 -0
  163. package/dist/src2/hir/lower.d.ts +15 -0
  164. package/dist/src2/hir/lower.js +378 -0
  165. package/dist/src2/hir/types.d.ts +373 -0
  166. package/dist/src2/hir/types.js +16 -0
  167. package/dist/src2/lir/lower.d.ts +15 -0
  168. package/dist/src2/lir/lower.js +453 -0
  169. package/dist/src2/lir/types.d.ts +136 -0
  170. package/dist/src2/lir/types.js +11 -0
  171. package/dist/src2/lir/verify.d.ts +14 -0
  172. package/dist/src2/lir/verify.js +113 -0
  173. package/dist/src2/mir/lower.d.ts +9 -0
  174. package/dist/src2/mir/lower.js +1030 -0
  175. package/dist/src2/mir/macro.d.ts +22 -0
  176. package/dist/src2/mir/macro.js +168 -0
  177. package/dist/src2/mir/types.d.ts +183 -0
  178. package/dist/src2/mir/types.js +11 -0
  179. package/dist/src2/mir/verify.d.ts +16 -0
  180. package/dist/src2/mir/verify.js +216 -0
  181. package/dist/src2/optimizer/block_merge.d.ts +12 -0
  182. package/dist/src2/optimizer/block_merge.js +84 -0
  183. package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
  184. package/dist/src2/optimizer/branch_simplify.js +28 -0
  185. package/dist/src2/optimizer/constant_fold.d.ts +10 -0
  186. package/dist/src2/optimizer/constant_fold.js +85 -0
  187. package/dist/src2/optimizer/copy_prop.d.ts +9 -0
  188. package/dist/src2/optimizer/copy_prop.js +113 -0
  189. package/dist/src2/optimizer/dce.d.ts +8 -0
  190. package/dist/src2/optimizer/dce.js +155 -0
  191. package/dist/src2/optimizer/pipeline.d.ts +10 -0
  192. package/dist/src2/optimizer/pipeline.js +42 -0
  193. package/dist/tsconfig.tsbuildinfo +1 -0
  194. package/docs/compiler-pipeline-redesign.md +2243 -0
  195. package/docs/optimization-ideas.md +1076 -0
  196. package/editors/vscode/package-lock.json +3 -3
  197. package/editors/vscode/package.json +1 -1
  198. package/examples/readme-demo.mcrs +44 -66
  199. package/jest.config.js +1 -1
  200. package/package.json +6 -5
  201. package/scripts/postbuild.js +15 -0
  202. package/src/__tests__/cli.test.ts +8 -220
  203. package/src/__tests__/dce.test.ts +11 -56
  204. package/src/__tests__/diagnostics.test.ts +59 -38
  205. package/src/__tests__/mc-integration.test.ts +1 -2
  206. package/src/ast/types.ts +6 -1
  207. package/src/cli.ts +29 -156
  208. package/src/compile.ts +6 -162
  209. package/src/index.ts +14 -178
  210. package/src/lexer/index.ts +9 -1
  211. package/src/mc-test/runner.ts +4 -3
  212. package/src/parser/index.ts +1 -1
  213. package/src/repl.ts +1 -1
  214. package/src/runtime/index.ts +1 -1
  215. package/src2/__tests__/e2e/basic.test.ts +154 -0
  216. package/src2/__tests__/e2e/macros.test.ts +199 -0
  217. package/src2/__tests__/e2e/migrate.test.ts +3008 -0
  218. package/src2/__tests__/hir/desugar.test.ts +263 -0
  219. package/src2/__tests__/lir/lower.test.ts +619 -0
  220. package/src2/__tests__/lir/types.test.ts +207 -0
  221. package/src2/__tests__/lir/verify.test.ts +249 -0
  222. package/src2/__tests__/mir/arithmetic.test.ts +156 -0
  223. package/src2/__tests__/mir/control-flow.test.ts +242 -0
  224. package/src2/__tests__/mir/verify.test.ts +254 -0
  225. package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
  226. package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
  227. package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
  228. package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
  229. package/src2/__tests__/optimizer/dce.test.ts +83 -0
  230. package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
  231. package/src2/emit/compile.ts +99 -0
  232. package/src2/emit/index.ts +222 -0
  233. package/src2/hir/lower.ts +428 -0
  234. package/src2/hir/types.ts +216 -0
  235. package/src2/lir/lower.ts +556 -0
  236. package/src2/lir/types.ts +109 -0
  237. package/src2/lir/verify.ts +129 -0
  238. package/src2/mir/lower.ts +1160 -0
  239. package/src2/mir/macro.ts +167 -0
  240. package/src2/mir/types.ts +106 -0
  241. package/src2/mir/verify.ts +218 -0
  242. package/src2/optimizer/block_merge.ts +93 -0
  243. package/src2/optimizer/branch_simplify.ts +27 -0
  244. package/src2/optimizer/constant_fold.ts +88 -0
  245. package/src2/optimizer/copy_prop.ts +106 -0
  246. package/src2/optimizer/dce.ts +133 -0
  247. package/src2/optimizer/pipeline.ts +44 -0
  248. package/tsconfig.json +2 -2
  249. package/src/__tests__/codegen.test.ts +0 -161
  250. package/src/__tests__/e2e.test.ts +0 -2039
  251. package/src/__tests__/entity-types.test.ts +0 -236
  252. package/src/__tests__/lowering.test.ts +0 -1185
  253. package/src/__tests__/macro.test.ts +0 -343
  254. package/src/__tests__/nbt.test.ts +0 -58
  255. package/src/__tests__/optimizer-advanced.test.ts +0 -144
  256. package/src/__tests__/optimizer.test.ts +0 -162
  257. package/src/__tests__/runtime.test.ts +0 -305
  258. package/src/__tests__/stdlib-advanced.test.ts +0 -379
  259. package/src/__tests__/stdlib-bigint.test.ts +0 -427
  260. package/src/__tests__/stdlib-math.test.ts +0 -374
  261. package/src/__tests__/stdlib-vec.test.ts +0 -259
  262. package/src/__tests__/structure-optimizer.test.ts +0 -38
  263. package/src/__tests__/var-allocator.test.ts +0 -75
  264. package/src/codegen/cmdblock/index.ts +0 -63
  265. package/src/codegen/mcfunction/index.ts +0 -662
  266. package/src/codegen/structure/index.ts +0 -346
  267. package/src/codegen/var-allocator.ts +0 -104
  268. package/src/ir/builder.ts +0 -116
  269. package/src/ir/types.ts +0 -134
  270. package/src/lowering/index.ts +0 -3860
  271. package/src/optimizer/commands.ts +0 -534
  272. package/src/optimizer/dce.ts +0 -679
  273. package/src/optimizer/passes.ts +0 -250
  274. package/src/optimizer/structure.ts +0 -450
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ describe('LIR types — Slot', () => {
4
+ test('Slot has player and obj fields', () => {
5
+ const slot = { player: '$t0', obj: '__test' };
6
+ expect(slot.player).toBe('$t0');
7
+ expect(slot.obj).toBe('__test');
8
+ });
9
+ });
10
+ describe('LIR types — instructions', () => {
11
+ test('score_set instruction', () => {
12
+ const instr = { kind: 'score_set', dst: { player: '$x', obj: '__ns' }, value: 42 };
13
+ expect(instr.kind).toBe('score_set');
14
+ });
15
+ test('score_copy instruction', () => {
16
+ const dst = { player: '$x', obj: '__ns' };
17
+ const src = { player: '$y', obj: '__ns' };
18
+ const instr = { kind: 'score_copy', dst, src };
19
+ expect(instr.kind).toBe('score_copy');
20
+ });
21
+ test('score arithmetic instructions', () => {
22
+ const dst = { player: '$x', obj: '__ns' };
23
+ const src = { player: '$y', obj: '__ns' };
24
+ const ops = ['score_add', 'score_sub', 'score_mul', 'score_div', 'score_mod'];
25
+ for (const kind of ops) {
26
+ const instr = { kind, dst, src };
27
+ expect(instr.kind).toBe(kind);
28
+ }
29
+ });
30
+ test('score_min, score_max instructions', () => {
31
+ const dst = { player: '$x', obj: '__ns' };
32
+ const src = { player: '$y', obj: '__ns' };
33
+ const min = { kind: 'score_min', dst, src };
34
+ const max = { kind: 'score_max', dst, src };
35
+ expect(min.kind).toBe('score_min');
36
+ expect(max.kind).toBe('score_max');
37
+ });
38
+ test('score_swap instruction', () => {
39
+ const a = { player: '$x', obj: '__ns' };
40
+ const b = { player: '$y', obj: '__ns' };
41
+ const instr = { kind: 'score_swap', a, b };
42
+ expect(instr.kind).toBe('score_swap');
43
+ });
44
+ test('store_cmd_to_score instruction', () => {
45
+ const dst = { player: '$x', obj: '__ns' };
46
+ const cmd = { kind: 'call', fn: 'test:foo' };
47
+ const instr = { kind: 'store_cmd_to_score', dst, cmd };
48
+ expect(instr.kind).toBe('store_cmd_to_score');
49
+ });
50
+ test('store_score_to_nbt instruction', () => {
51
+ const instr = {
52
+ kind: 'store_score_to_nbt',
53
+ ns: 'rs:data', path: 'value', type: 'int', scale: 1,
54
+ src: { player: '$x', obj: '__ns' },
55
+ };
56
+ expect(instr.kind).toBe('store_score_to_nbt');
57
+ });
58
+ test('store_nbt_to_score instruction', () => {
59
+ const instr = {
60
+ kind: 'store_nbt_to_score',
61
+ dst: { player: '$x', obj: '__ns' },
62
+ ns: 'rs:data', path: 'value', scale: 1,
63
+ };
64
+ expect(instr.kind).toBe('store_nbt_to_score');
65
+ });
66
+ test('nbt_set_literal instruction', () => {
67
+ const instr = { kind: 'nbt_set_literal', ns: 'rs:data', path: 'x', value: '42' };
68
+ expect(instr.kind).toBe('nbt_set_literal');
69
+ });
70
+ test('nbt_copy instruction', () => {
71
+ const instr = {
72
+ kind: 'nbt_copy',
73
+ srcNs: 'rs:a', srcPath: 'x',
74
+ dstNs: 'rs:b', dstPath: 'y',
75
+ };
76
+ expect(instr.kind).toBe('nbt_copy');
77
+ });
78
+ test('call instruction', () => {
79
+ const instr = { kind: 'call', fn: 'test:foo' };
80
+ expect(instr.kind).toBe('call');
81
+ });
82
+ test('call_macro instruction', () => {
83
+ const instr = { kind: 'call_macro', fn: 'test:draw', storage: 'rs:macro_args' };
84
+ expect(instr.kind).toBe('call_macro');
85
+ });
86
+ test('call_if_matches instruction', () => {
87
+ const instr = {
88
+ kind: 'call_if_matches',
89
+ fn: 'test:branch',
90
+ slot: { player: '$cond', obj: '__ns' },
91
+ range: '1',
92
+ };
93
+ expect(instr.kind).toBe('call_if_matches');
94
+ });
95
+ test('call_unless_matches instruction', () => {
96
+ const instr = {
97
+ kind: 'call_unless_matches',
98
+ fn: 'test:branch',
99
+ slot: { player: '$cond', obj: '__ns' },
100
+ range: '1',
101
+ };
102
+ expect(instr.kind).toBe('call_unless_matches');
103
+ });
104
+ test('call_if_score instruction', () => {
105
+ const instr = {
106
+ kind: 'call_if_score',
107
+ fn: 'test:check',
108
+ a: { player: '$x', obj: '__ns' },
109
+ op: 'lt',
110
+ b: { player: '$y', obj: '__ns' },
111
+ };
112
+ expect(instr.kind).toBe('call_if_score');
113
+ });
114
+ test('call_unless_score instruction', () => {
115
+ const instr = {
116
+ kind: 'call_unless_score',
117
+ fn: 'test:check',
118
+ a: { player: '$x', obj: '__ns' },
119
+ op: 'ge',
120
+ b: { player: '$y', obj: '__ns' },
121
+ };
122
+ expect(instr.kind).toBe('call_unless_score');
123
+ });
124
+ test('call_context instruction', () => {
125
+ const instr = {
126
+ kind: 'call_context',
127
+ fn: 'test:helper',
128
+ subcommands: [{ kind: 'as', selector: '@e[tag=foo]' }, { kind: 'at_self' }],
129
+ };
130
+ expect(instr.kind).toBe('call_context');
131
+ });
132
+ test('return_value instruction', () => {
133
+ const instr = { kind: 'return_value', slot: { player: '$result', obj: '__ns' } };
134
+ expect(instr.kind).toBe('return_value');
135
+ });
136
+ test('macro_line instruction', () => {
137
+ const instr = { kind: 'macro_line', template: '$particle end_rod ^$(px) ^$(py) ^5' };
138
+ expect(instr.kind).toBe('macro_line');
139
+ });
140
+ test('raw instruction', () => {
141
+ const instr = { kind: 'raw', cmd: 'say hello' };
142
+ expect(instr.kind).toBe('raw');
143
+ });
144
+ });
145
+ describe('LIR types — LIRFunction', () => {
146
+ test('basic function structure', () => {
147
+ const fn = {
148
+ name: 'main',
149
+ instructions: [
150
+ { kind: 'score_set', dst: { player: '$x', obj: '__ns' }, value: 0 },
151
+ ],
152
+ isMacro: false,
153
+ macroParams: [],
154
+ };
155
+ expect(fn.name).toBe('main');
156
+ expect(fn.instructions).toHaveLength(1);
157
+ expect(fn.isMacro).toBe(false);
158
+ expect(fn.macroParams).toEqual([]);
159
+ });
160
+ test('macro function structure', () => {
161
+ const fn = {
162
+ name: 'draw_pt',
163
+ instructions: [
164
+ { kind: 'macro_line', template: '$particle end_rod ^$(px) ^$(py) ^5' },
165
+ ],
166
+ isMacro: true,
167
+ macroParams: ['px', 'py'],
168
+ };
169
+ expect(fn.isMacro).toBe(true);
170
+ expect(fn.macroParams).toEqual(['px', 'py']);
171
+ });
172
+ });
173
+ describe('LIR types — LIRModule', () => {
174
+ test('module structure', () => {
175
+ const mod = {
176
+ functions: [],
177
+ namespace: 'mypack',
178
+ objective: '__mypack',
179
+ };
180
+ expect(mod.namespace).toBe('mypack');
181
+ expect(mod.objective).toBe('__mypack');
182
+ expect(mod.functions).toEqual([]);
183
+ });
184
+ });
185
+ //# sourceMappingURL=types.test.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const verify_1 = require("../../lir/verify");
4
+ const OBJ = '__test';
5
+ const NS = 'test';
6
+ function mkModule(functions) {
7
+ return { functions, namespace: NS, objective: OBJ };
8
+ }
9
+ function mkFn(name, instructions, isMacro = false, macroParams = []) {
10
+ return { name, instructions, isMacro, macroParams };
11
+ }
12
+ function slot(name) {
13
+ return { player: `$${name}`, obj: OBJ };
14
+ }
15
+ // ---------------------------------------------------------------------------
16
+ // Objective checks
17
+ // ---------------------------------------------------------------------------
18
+ describe('LIR verifier — objective checks', () => {
19
+ test('accepts slots with correct objective', () => {
20
+ const mod = mkModule([
21
+ mkFn('main', [
22
+ { kind: 'score_set', dst: slot('x'), value: 42 },
23
+ { kind: 'score_copy', dst: slot('y'), src: slot('x') },
24
+ ]),
25
+ ]);
26
+ expect((0, verify_1.verifyLIR)(mod)).toEqual([]);
27
+ });
28
+ test('rejects slot with wrong objective', () => {
29
+ const mod = mkModule([
30
+ mkFn('main', [
31
+ { kind: 'score_set', dst: { player: '$x', obj: '__wrong' }, value: 42 },
32
+ ]),
33
+ ]);
34
+ const errors = (0, verify_1.verifyLIR)(mod);
35
+ expect(errors.length).toBe(1);
36
+ expect(errors[0].message).toContain('objective');
37
+ expect(errors[0].message).toContain('__wrong');
38
+ });
39
+ test('rejects wrong objective in src slot', () => {
40
+ const mod = mkModule([
41
+ mkFn('main', [
42
+ { kind: 'score_copy', dst: slot('x'), src: { player: '$y', obj: '__bad' } },
43
+ ]),
44
+ ]);
45
+ const errors = (0, verify_1.verifyLIR)(mod);
46
+ expect(errors.length).toBe(1);
47
+ expect(errors[0].message).toContain('__bad');
48
+ });
49
+ test('checks slots in score_swap', () => {
50
+ const mod = mkModule([
51
+ mkFn('main', [
52
+ { kind: 'score_swap', a: { player: '$x', obj: '__bad' }, b: slot('y') },
53
+ ]),
54
+ ]);
55
+ const errors = (0, verify_1.verifyLIR)(mod);
56
+ expect(errors.length).toBe(1);
57
+ expect(errors[0].message).toContain('__bad');
58
+ });
59
+ test('checks slots in store_cmd_to_score (recursive)', () => {
60
+ const mod = mkModule([
61
+ mkFn('main', [
62
+ {
63
+ kind: 'store_cmd_to_score',
64
+ dst: slot('r'),
65
+ cmd: {
66
+ kind: 'call_if_score',
67
+ fn: 'test:main',
68
+ a: { player: '$a', obj: '__bad' },
69
+ op: 'eq',
70
+ b: slot('b'),
71
+ },
72
+ },
73
+ ]),
74
+ ]);
75
+ const errors = (0, verify_1.verifyLIR)(mod);
76
+ expect(errors.length).toBe(1);
77
+ expect(errors[0].message).toContain('__bad');
78
+ });
79
+ test('checks slot in call_if_matches', () => {
80
+ const mod = mkModule([
81
+ mkFn('main', [
82
+ {
83
+ kind: 'call_if_matches',
84
+ fn: 'test:main',
85
+ slot: { player: '$c', obj: '__bad' },
86
+ range: '1',
87
+ },
88
+ ]),
89
+ ]);
90
+ const errors = (0, verify_1.verifyLIR)(mod);
91
+ expect(errors.length).toBe(1);
92
+ });
93
+ test('checks slot in return_value', () => {
94
+ const mod = mkModule([
95
+ mkFn('main', [
96
+ { kind: 'return_value', slot: { player: '$r', obj: '__bad' } },
97
+ ]),
98
+ ]);
99
+ const errors = (0, verify_1.verifyLIR)(mod);
100
+ expect(errors.length).toBe(1);
101
+ });
102
+ });
103
+ // ---------------------------------------------------------------------------
104
+ // Function reference checks
105
+ // ---------------------------------------------------------------------------
106
+ describe('LIR verifier — function references', () => {
107
+ test('accepts call to existing function', () => {
108
+ const mod = mkModule([
109
+ mkFn('main', [{ kind: 'call', fn: 'test:helper' }]),
110
+ mkFn('helper', []),
111
+ ]);
112
+ expect((0, verify_1.verifyLIR)(mod)).toEqual([]);
113
+ });
114
+ test('rejects call to undefined function', () => {
115
+ const mod = mkModule([
116
+ mkFn('main', [{ kind: 'call', fn: 'test:nonexistent' }]),
117
+ ]);
118
+ const errors = (0, verify_1.verifyLIR)(mod);
119
+ expect(errors.length).toBe(1);
120
+ expect(errors[0].message).toContain('undefined function');
121
+ expect(errors[0].message).toContain('nonexistent');
122
+ });
123
+ test('rejects call_macro to undefined function', () => {
124
+ const mod = mkModule([
125
+ mkFn('main', [{ kind: 'call_macro', fn: 'test:missing', storage: 'rs:macro_args' }]),
126
+ ]);
127
+ const errors = (0, verify_1.verifyLIR)(mod);
128
+ expect(errors.length).toBe(1);
129
+ expect(errors[0].message).toContain('undefined function');
130
+ });
131
+ test('rejects call_if_matches to undefined function', () => {
132
+ const mod = mkModule([
133
+ mkFn('main', [
134
+ { kind: 'call_if_matches', fn: 'test:missing', slot: slot('c'), range: '1' },
135
+ ]),
136
+ ]);
137
+ const errors = (0, verify_1.verifyLIR)(mod);
138
+ expect(errors.length).toBe(1);
139
+ expect(errors[0].message).toContain('undefined function');
140
+ });
141
+ test('rejects call_context to undefined function', () => {
142
+ const mod = mkModule([
143
+ mkFn('main', [
144
+ { kind: 'call_context', fn: 'test:missing', subcommands: [{ kind: 'at_self' }] },
145
+ ]),
146
+ ]);
147
+ const errors = (0, verify_1.verifyLIR)(mod);
148
+ expect(errors.length).toBe(1);
149
+ expect(errors[0].message).toContain('undefined function');
150
+ });
151
+ test('checks function refs inside store_cmd_to_score', () => {
152
+ const mod = mkModule([
153
+ mkFn('main', [
154
+ {
155
+ kind: 'store_cmd_to_score',
156
+ dst: slot('r'),
157
+ cmd: { kind: 'call', fn: 'test:missing' },
158
+ },
159
+ ]),
160
+ ]);
161
+ const errors = (0, verify_1.verifyLIR)(mod);
162
+ expect(errors.length).toBe(1);
163
+ expect(errors[0].message).toContain('undefined function');
164
+ });
165
+ });
166
+ // ---------------------------------------------------------------------------
167
+ // Macro line checks
168
+ // ---------------------------------------------------------------------------
169
+ describe('LIR verifier — macro_line', () => {
170
+ test('accepts macro_line in macro function', () => {
171
+ const mod = mkModule([
172
+ mkFn('draw', [
173
+ { kind: 'macro_line', template: '$particle end_rod ^$(px)' },
174
+ ], true, ['px']),
175
+ ]);
176
+ expect((0, verify_1.verifyLIR)(mod)).toEqual([]);
177
+ });
178
+ test('rejects macro_line in non-macro function', () => {
179
+ const mod = mkModule([
180
+ mkFn('main', [
181
+ { kind: 'macro_line', template: '$particle end_rod ^$(px)' },
182
+ ], false),
183
+ ]);
184
+ const errors = (0, verify_1.verifyLIR)(mod);
185
+ expect(errors.length).toBe(1);
186
+ expect(errors[0].message).toContain('macro_line');
187
+ expect(errors[0].message).toContain('non-macro');
188
+ });
189
+ });
190
+ // ---------------------------------------------------------------------------
191
+ // Clean module
192
+ // ---------------------------------------------------------------------------
193
+ describe('LIR verifier — clean module', () => {
194
+ test('accepts a well-formed module', () => {
195
+ const mod = mkModule([
196
+ mkFn('main', [
197
+ { kind: 'score_set', dst: slot('t0'), value: 1 },
198
+ { kind: 'score_set', dst: slot('t1'), value: 2 },
199
+ { kind: 'score_copy', dst: slot('r'), src: slot('t0') },
200
+ { kind: 'score_add', dst: slot('r'), src: slot('t1') },
201
+ { kind: 'call', fn: 'test:helper' },
202
+ { kind: 'return_value', slot: slot('r') },
203
+ ]),
204
+ mkFn('helper', [
205
+ { kind: 'raw', cmd: 'say hello' },
206
+ ]),
207
+ ]);
208
+ expect((0, verify_1.verifyLIR)(mod)).toEqual([]);
209
+ });
210
+ test('raw and nbt instructions do not trigger errors', () => {
211
+ const mod = mkModule([
212
+ mkFn('main', [
213
+ { kind: 'raw', cmd: 'say hi' },
214
+ { kind: 'nbt_set_literal', ns: 'rs:data', path: 'x', value: '42' },
215
+ { kind: 'nbt_copy', srcNs: 'rs:a', srcPath: 'x', dstNs: 'rs:b', dstPath: 'y' },
216
+ ]),
217
+ ]);
218
+ expect((0, verify_1.verifyLIR)(mod)).toEqual([]);
219
+ });
220
+ });
221
+ //# sourceMappingURL=verify.test.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lexer_1 = require("../../../src/lexer");
4
+ const parser_1 = require("../../../src/parser");
5
+ const lower_1 = require("../../hir/lower");
6
+ const lower_2 = require("../../mir/lower");
7
+ const verify_1 = require("../../mir/verify");
8
+ function compile(source) {
9
+ const tokens = new lexer_1.Lexer(source).tokenize();
10
+ const ast = new parser_1.Parser(tokens).parse('test');
11
+ const hir = (0, lower_1.lowerToHIR)(ast);
12
+ return (0, lower_2.lowerToMIR)(hir);
13
+ }
14
+ function getEntryInstrs(mod) {
15
+ const fn = mod.functions[0];
16
+ const entry = fn.blocks.find(b => b.id === fn.entry);
17
+ return entry.instrs;
18
+ }
19
+ describe('MIR lowering — integer arithmetic', () => {
20
+ test('simple addition: let x = a + b', () => {
21
+ const mod = compile('fn f(a: int, b: int): int { return a + b; }');
22
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
23
+ const instrs = getEntryInstrs(mod);
24
+ // Should have an add instruction
25
+ const addInstr = instrs.find(i => i.kind === 'add');
26
+ expect(addInstr).toBeDefined();
27
+ expect(addInstr.kind).toBe('add');
28
+ });
29
+ test('chained arithmetic: a + b * c', () => {
30
+ const mod = compile('fn f(a: int, b: int, c: int): int { return a + b * c; }');
31
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
32
+ const instrs = getEntryInstrs(mod);
33
+ // Should have both mul and add
34
+ const kinds = instrs.map(i => i.kind);
35
+ expect(kinds).toContain('mul');
36
+ expect(kinds).toContain('add');
37
+ // mul should come before add (b*c computed first)
38
+ const mulIdx = kinds.indexOf('mul');
39
+ const addIdx = kinds.indexOf('add');
40
+ expect(mulIdx).toBeLessThan(addIdx);
41
+ });
42
+ test('subtraction and division', () => {
43
+ const mod = compile('fn f(a: int, b: int): int { return (a - b) / b; }');
44
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
45
+ const instrs = getEntryInstrs(mod);
46
+ const kinds = instrs.map(i => i.kind);
47
+ expect(kinds).toContain('sub');
48
+ expect(kinds).toContain('div');
49
+ });
50
+ test('modulo', () => {
51
+ const mod = compile('fn f(a: int, b: int): int { return a % b; }');
52
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
53
+ const instrs = getEntryInstrs(mod);
54
+ expect(instrs.some(i => i.kind === 'mod')).toBe(true);
55
+ });
56
+ test('negation', () => {
57
+ const mod = compile('fn f(a: int): int { return -a; }');
58
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
59
+ const instrs = getEntryInstrs(mod);
60
+ expect(instrs.some(i => i.kind === 'neg')).toBe(true);
61
+ });
62
+ test('not operator', () => {
63
+ const mod = compile('fn f(a: bool): bool { return !a; }');
64
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
65
+ const instrs = getEntryInstrs(mod);
66
+ expect(instrs.some(i => i.kind === 'not')).toBe(true);
67
+ });
68
+ test('comparison operators produce cmp instructions', () => {
69
+ const mod = compile('fn f(a: int, b: int): bool { return a < b; }');
70
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
71
+ const instrs = getEntryInstrs(mod);
72
+ const cmpInstr = instrs.find(i => i.kind === 'cmp');
73
+ expect(cmpInstr).toBeDefined();
74
+ expect(cmpInstr.op).toBe('lt');
75
+ });
76
+ test('let binding produces copy instruction', () => {
77
+ const mod = compile('fn f(a: int): int { let x: int = a; return x; }');
78
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
79
+ const instrs = getEntryInstrs(mod);
80
+ expect(instrs.some(i => i.kind === 'copy')).toBe(true);
81
+ });
82
+ test('constant literal produces const instruction', () => {
83
+ const mod = compile('fn f(): int { return 42; }');
84
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
85
+ // The return terminator should have the const value
86
+ const fn = mod.functions[0];
87
+ const entry = fn.blocks.find(b => b.id === fn.entry);
88
+ expect(entry.term.kind).toBe('return');
89
+ const ret = entry.term;
90
+ expect(ret.value).toEqual({ kind: 'const', value: 42 });
91
+ });
92
+ test('function call produces call instruction', () => {
93
+ const mod = compile('fn add(a: int, b: int): int { return a + b; } fn f(): int { return add(1, 2); }');
94
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
95
+ // f is the second function
96
+ const fn = mod.functions[1];
97
+ const entry = fn.blocks.find(b => b.id === fn.entry);
98
+ const callInstr = entry.instrs.find(i => i.kind === 'call');
99
+ expect(callInstr).toBeDefined();
100
+ expect(callInstr.fn).toBe('add');
101
+ expect(callInstr.args).toHaveLength(2);
102
+ });
103
+ test('3-address form: each instruction has fresh dst', () => {
104
+ const mod = compile('fn f(a: int, b: int, c: int): int { return a + b + c; }');
105
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
106
+ const instrs = getEntryInstrs(mod);
107
+ const dsts = instrs.filter(i => 'dst' in i).map(i => i.dst);
108
+ // All destination temps should be unique
109
+ expect(new Set(dsts).size).toBe(dsts.length);
110
+ });
111
+ });
112
+ describe('MIR lowering — module structure', () => {
113
+ test('namespace and objective set correctly', () => {
114
+ const mod = compile('fn f(): void {}');
115
+ expect(mod.namespace).toBe('test');
116
+ expect(mod.objective).toBe('__test');
117
+ });
118
+ test('multiple functions', () => {
119
+ const mod = compile('fn a(): void {} fn b(): void {} fn c(): void {}');
120
+ expect(mod.functions).toHaveLength(3);
121
+ expect(mod.functions.map(f => f.name)).toEqual(['a', 'b', 'c']);
122
+ });
123
+ test('function params are mapped to temps', () => {
124
+ const mod = compile('fn f(x: int, y: int): int { return x + y; }');
125
+ expect(mod.functions[0].params).toHaveLength(2);
126
+ expect(mod.functions[0].params[0].name).toMatch(/^t\d+$/);
127
+ expect(mod.functions[0].params[1].name).toMatch(/^t\d+$/);
128
+ });
129
+ });
130
+ //# sourceMappingURL=arithmetic.test.js.map
@@ -0,0 +1 @@
1
+ export {};