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
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import { DiagnosticError, DiagnosticCollector, formatError, parseErrorMessage } from '../diagnostics'
6
- import { compile, formatCompileError } from '../compile'
6
+ import { compile } from '../compile'
7
7
 
8
8
  describe('DiagnosticError', () => {
9
9
  describe('formatError', () => {
@@ -126,70 +126,91 @@ describe('parseErrorMessage', () => {
126
126
 
127
127
  describe('compile function', () => {
128
128
  it('returns success for valid code', () => {
129
- const result = compile('fn main() { let x = 1; }')
129
+ const result = compile('fn main() { let x = 1; }', { namespace: 'test' })
130
130
  expect(result.success).toBe(true)
131
131
  expect(result.files).toBeDefined()
132
132
  })
133
133
 
134
- it('returns DiagnosticError for lex errors', () => {
135
- const result = compile('fn main() { let x = $ }')
136
- expect(result.success).toBe(false)
137
- expect(result.error).toBeInstanceOf(DiagnosticError)
138
- expect(result.error?.kind).toBe('LexError')
134
+ it('throws DiagnosticError for lex errors', () => {
135
+ expect(() => compile('fn main() { let x = $ }', { namespace: 'test' }))
136
+ .toThrow()
137
+ try {
138
+ compile('fn main() { let x = $ }', { namespace: 'test' })
139
+ } catch (e) {
140
+ expect(e).toBeInstanceOf(DiagnosticError)
141
+ expect((e as DiagnosticError).kind).toBe('LexError')
142
+ }
139
143
  })
140
144
 
141
- it('returns DiagnosticError for parse errors', () => {
142
- const result = compile('fn main() { let x = }')
143
- expect(result.success).toBe(false)
144
- expect(result.error).toBeInstanceOf(DiagnosticError)
145
- expect(result.error?.kind).toBe('ParseError')
145
+ it('throws DiagnosticError for parse errors', () => {
146
+ expect(() => compile('fn main() { let x = }', { namespace: 'test' }))
147
+ .toThrow()
148
+ try {
149
+ compile('fn main() { let x = }', { namespace: 'test' })
150
+ } catch (e) {
151
+ expect(e).toBeInstanceOf(DiagnosticError)
152
+ expect((e as DiagnosticError).kind).toBe('ParseError')
153
+ }
146
154
  })
147
155
 
148
- it('returns DiagnosticError for missing semicolon', () => {
149
- const result = compile('fn main() { let x = 42 }')
150
- expect(result.success).toBe(false)
151
- expect(result.error?.kind).toBe('ParseError')
152
- expect(result.error?.message).toContain("Expected ';'")
156
+ it('throws DiagnosticError for missing semicolon', () => {
157
+ try {
158
+ compile('fn main() { let x = 42 }', { namespace: 'test' })
159
+ fail('Expected compile to throw')
160
+ } catch (e) {
161
+ expect((e as DiagnosticError).kind).toBe('ParseError')
162
+ expect((e as DiagnosticError).message).toContain("Expected ';'")
163
+ }
153
164
  })
154
165
 
155
166
  it('includes file path in error', () => {
156
- const result = compile('fn main() { }', { filePath: 'test.mcrs' })
157
- // This is valid, but test that filePath is passed through
167
+ const result = compile('fn main() { }', { filePath: 'test.mcrs', namespace: 'test' })
158
168
  expect(result.success).toBe(true)
159
169
  })
160
170
 
161
171
  it('formats error nicely', () => {
162
- const result = compile('fn main() {\n let x = 42\n}')
163
- expect(result.success).toBe(false)
164
- const formatted = formatCompileError(result)
165
- expect(formatted).toContain('Error at line')
166
- expect(formatted).toContain('^')
167
- // Error points to } on line 3, which is where semicolon was expected
168
- expect(formatted).toContain('}')
172
+ try {
173
+ compile('fn main() {\n let x = 42\n}', { namespace: 'test' })
174
+ fail('Expected compile to throw')
175
+ } catch (e) {
176
+ expect(e).toBeInstanceOf(DiagnosticError)
177
+ const formatted = (e as DiagnosticError).format()
178
+ expect(formatted).toContain('line')
179
+ expect(formatted).toContain('^')
180
+ }
169
181
  })
170
182
  })
171
183
 
172
184
  describe('Lexer DiagnosticError', () => {
173
185
  it('throws DiagnosticError for unexpected character', () => {
174
- const result = compile('fn main() { let x = $ }')
175
- expect(result.success).toBe(false)
176
- expect(result.error?.kind).toBe('LexError')
177
- expect(result.error?.message).toContain('Unexpected character')
186
+ try {
187
+ compile('fn main() { let x = $ }', { namespace: 'test' })
188
+ fail('Expected compile to throw')
189
+ } catch (e) {
190
+ expect((e as DiagnosticError).kind).toBe('LexError')
191
+ expect((e as DiagnosticError).message).toContain('Unexpected character')
192
+ }
178
193
  })
179
194
 
180
195
  it('throws DiagnosticError for unterminated string', () => {
181
- const result = compile('fn main() { let x = "hello }')
182
- expect(result.success).toBe(false)
183
- expect(result.error?.kind).toBe('LexError')
184
- expect(result.error?.message).toContain('Unterminated string')
196
+ try {
197
+ compile('fn main() { let x = "hello }', { namespace: 'test' })
198
+ fail('Expected compile to throw')
199
+ } catch (e) {
200
+ expect((e as DiagnosticError).kind).toBe('LexError')
201
+ expect((e as DiagnosticError).message).toContain('Unterminated string')
202
+ }
185
203
  })
186
204
  })
187
205
 
188
206
  describe('Parser DiagnosticError', () => {
189
207
  it('includes line and column info', () => {
190
- const result = compile('fn main() { return }')
191
- expect(result.success).toBe(false)
192
- expect(result.error?.location.line).toBeGreaterThan(0)
193
- expect(result.error?.location.col).toBeGreaterThan(0)
208
+ try {
209
+ compile('fn main() { return }', { namespace: 'test' })
210
+ fail('Expected compile to throw')
211
+ } catch (e) {
212
+ expect((e as DiagnosticError).location.line).toBeGreaterThan(0)
213
+ expect((e as DiagnosticError).location.col).toBeGreaterThan(0)
214
+ }
194
215
  })
195
216
  })
@@ -36,9 +36,8 @@ function writeFixture(source: string, namespace: string): void {
36
36
  }
37
37
 
38
38
  const result = compile(source, { namespace })
39
- if (result.error) throw new Error(`Compile error in ${namespace}: ${result.error}`)
40
39
 
41
- for (const file of result.files ?? []) {
40
+ for (const file of result.files) {
42
41
  if (file.path === 'pack.mcmeta') continue
43
42
  const filePath = path.join(DATAPACK_DIR, file.path)
44
43
  fs.mkdirSync(path.dirname(filePath), { recursive: true })
package/src/ast/types.ts CHANGED
@@ -5,7 +5,12 @@
5
5
  * The AST is produced by the parser and consumed by the lowering pass.
6
6
  */
7
7
 
8
- import type { BinOp, CmpOp } from '../ir/types'
8
+ // ---------------------------------------------------------------------------
9
+ // Binary / comparison operators (shared across AST, HIR, MIR)
10
+ // ---------------------------------------------------------------------------
11
+
12
+ export type BinOp = '+' | '-' | '*' | '/' | '%'
13
+ export type CmpOp = '==' | '!=' | '<' | '<=' | '>' | '>='
9
14
 
10
15
  // ---------------------------------------------------------------------------
11
16
  // Source Span
package/src/cli.ts CHANGED
@@ -1,21 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * RedScript CLI
4
- *
4
+ *
5
5
  * Usage:
6
- * redscript compile <file> [-o <out>] [--output-nbt <file>] [--namespace <ns>]
6
+ * redscript compile <file> [-o <out>] [--namespace <ns>]
7
7
  * redscript check <file>
8
8
  * redscript repl
9
9
  * redscript version
10
10
  */
11
11
 
12
12
  import { compile, check } from './index'
13
- import { generateCommandBlocks } from './codegen/cmdblock'
14
- import { compileToStructure } from './codegen/structure'
15
13
  import { formatError } from './diagnostics'
16
14
  import { startRepl } from './repl'
17
15
  import { generateDts } from './builtins/metadata'
18
- import type { OptimizationStats } from './optimizer/commands'
19
16
  import * as fs from 'fs'
20
17
  import * as path from 'path'
21
18
  import * as https from 'https'
@@ -26,10 +23,10 @@ const args = process.argv.slice(2)
26
23
 
27
24
  function printUsage(): void {
28
25
  console.log(`
29
- RedScript Compiler
26
+ RedScript Compiler v2
30
27
 
31
28
  Usage:
32
- redscript compile <file> [-o <out>] [--output-nbt <file>] [--namespace <ns>] [--scoreboard <obj>] [--target <target>] [--no-dce]
29
+ redscript compile <file> [-o <out>] [--namespace <ns>]
33
30
  redscript watch <dir> [-o <outdir>] [--namespace <ns>] [--hot-reload <url>]
34
31
  redscript check <file>
35
32
  redscript fmt <file.mcrs> [file2.mcrs ...]
@@ -48,24 +45,11 @@ Commands:
48
45
  upgrade Upgrade to the latest version (npm install -g redscript-mc@latest)
49
46
 
50
47
  Options:
51
- -o, --output <path> Output directory or file path, depending on target
52
- --output-nbt <file> Output .nbt file path for structure target
48
+ -o, --output <path> Output directory or file path
53
49
  --namespace <ns> Datapack namespace (default: derived from filename)
54
- --target <target> Output target: datapack (default), cmdblock, or structure
55
- --no-dce Disable AST dead code elimination
56
- --no-mangle Disable variable name mangling (use readable names)
57
- --scoreboard <obj> Scoreboard objective for variables (default: namespace).
58
- Each datapack automatically uses its namespace as the objective
59
- so multiple datapacks can coexist without collisions.
60
- --stats Print optimizer statistics
61
50
  --hot-reload <url> After each successful compile, POST to <url>/reload
62
51
  (use with redscript-testharness; e.g. http://localhost:25561)
63
52
  -h, --help Show this help message
64
-
65
- Targets:
66
- datapack Generate a full Minecraft datapack (default)
67
- cmdblock Generate JSON structure for command block placement
68
- structure Generate a Minecraft structure .nbt file with command blocks
69
53
  `)
70
54
  }
71
55
 
@@ -163,17 +147,11 @@ function parseArgs(args: string[]): {
163
147
  command?: string
164
148
  file?: string
165
149
  output?: string
166
- outputNbt?: string
167
150
  namespace?: string
168
- target?: string
169
- stats?: boolean
170
151
  help?: boolean
171
152
  hotReload?: string
172
- dce?: boolean
173
- mangle?: boolean
174
- scoreboardObjective?: string
175
153
  } {
176
- const result: ReturnType<typeof parseArgs> = { dce: true, mangle: true }
154
+ const result: ReturnType<typeof parseArgs> = {}
177
155
  let i = 0
178
156
 
179
157
  while (i < args.length) {
@@ -185,27 +163,9 @@ function parseArgs(args: string[]): {
185
163
  } else if (arg === '-o' || arg === '--output') {
186
164
  result.output = args[++i]
187
165
  i++
188
- } else if (arg === '--output-nbt') {
189
- result.outputNbt = args[++i]
190
- i++
191
166
  } else if (arg === '--namespace') {
192
167
  result.namespace = args[++i]
193
168
  i++
194
- } else if (arg === '--target') {
195
- result.target = args[++i]
196
- i++
197
- } else if (arg === '--stats') {
198
- result.stats = true
199
- i++
200
- } else if (arg === '--no-dce') {
201
- result.dce = false
202
- i++
203
- } else if (arg === '--no-mangle') {
204
- result.mangle = false
205
- i++
206
- } else if (arg === '--scoreboard') {
207
- result.scoreboardObjective = args[++i]
208
- i++
209
169
  } else if (arg === '--hot-reload') {
210
170
  result.hotReload = args[++i]
211
171
  i++
@@ -229,48 +189,10 @@ function deriveNamespace(filePath: string): string {
229
189
  return basename.toLowerCase().replace(/[^a-z0-9]/g, '_')
230
190
  }
231
191
 
232
- function printWarnings(warnings: Array<{ code: string; message: string; line?: number; col?: number; filePath?: string }> | undefined): void {
233
- if (!warnings || warnings.length === 0) {
234
- return
235
- }
236
-
237
- for (const warning of warnings) {
238
- const loc = warning.filePath
239
- ? `${warning.filePath}:${warning.line ?? '?'}`
240
- : warning.line != null
241
- ? `line ${warning.line}`
242
- : null
243
- const locStr = loc ? ` (${loc})` : ''
244
- console.error(`Warning [${warning.code}]: ${warning.message}${locStr}`)
245
- }
246
- }
247
-
248
- function formatReduction(before: number, after: number): string {
249
- if (before === 0) return '0%'
250
- return `${Math.round(((before - after) / before) * 100)}%`
251
- }
252
-
253
- function printOptimizationStats(stats: OptimizationStats | undefined): void {
254
- if (!stats) return
255
-
256
- console.log('Optimizations applied:')
257
- console.log(` LICM: ${stats.licmHoists} reads hoisted from ${stats.licmLoopBodies} loop bodies`)
258
- console.log(` CSE: ${stats.cseRedundantReads + stats.cseArithmetic} expressions eliminated`)
259
- console.log(` setblock batching: ${stats.setblockMergedCommands} setblocks -> ${stats.setblockFillCommands} fills (saved ${stats.setblockSavedCommands} commands)`)
260
- console.log(` dead code: ${stats.deadCodeRemoved} commands removed`)
261
- console.log(` constant folding: ${stats.constantFolds} constants folded`)
262
- console.log(` Total mcfunction commands: ${stats.totalCommandsBefore} -> ${stats.totalCommandsAfter} (${formatReduction(stats.totalCommandsBefore, stats.totalCommandsAfter)} reduction)`)
263
- }
264
-
265
192
  function compileCommand(
266
193
  file: string,
267
194
  output: string,
268
195
  namespace: string,
269
- target: string = 'datapack',
270
- showStats = false,
271
- dce = true,
272
- mangle = true,
273
- scoreboardObjective: string | undefined = undefined
274
196
  ): void {
275
197
  // Read source file
276
198
  if (!fs.existsSync(file)) {
@@ -281,68 +203,26 @@ function compileCommand(
281
203
  const source = fs.readFileSync(file, 'utf-8')
282
204
 
283
205
  try {
284
- if (target === 'cmdblock') {
285
- const result = compile(source, { namespace, filePath: file, dce, mangle, scoreboardObjective })
286
- printWarnings(result.warnings)
287
-
288
- // Generate command block JSON
289
- const hasTick = result.files.some(f => f.path.includes('__tick.mcfunction'))
290
- const hasLoad = result.files.some(f => f.path.includes('__load.mcfunction'))
291
- const cmdBlocks = generateCommandBlocks(namespace, hasTick, hasLoad)
292
-
293
- // Write command block JSON
294
- fs.mkdirSync(output, { recursive: true })
295
- const outputFile = path.join(output, `${namespace}_cmdblocks.json`)
296
- fs.writeFileSync(outputFile, JSON.stringify(cmdBlocks, null, 2))
297
-
298
- console.log(`✓ Generated command blocks for ${file}`)
299
- console.log(` Output: ${outputFile}`)
300
- console.log(` Blocks: ${cmdBlocks.blocks.length}`)
301
- if (showStats) {
302
- printOptimizationStats(result.stats)
303
- }
304
- } else if (target === 'structure') {
305
- const structure = compileToStructure(source, namespace, file, { dce, mangle })
306
- fs.mkdirSync(path.dirname(output), { recursive: true })
307
- fs.writeFileSync(output, structure.buffer)
308
-
309
- console.log(`✓ Generated structure for ${file}`)
310
- console.log(` Output: ${output}`)
311
- console.log(` Blocks: ${structure.blockCount}`)
312
- if (showStats) {
313
- printOptimizationStats(structure.stats)
314
- }
315
- } else {
316
- const result = compile(source, { namespace, filePath: file, dce, mangle, scoreboardObjective })
317
- printWarnings(result.warnings)
318
-
319
- // Default: generate datapack
320
- // Create output directory
321
- fs.mkdirSync(output, { recursive: true })
322
-
323
- // Write all files
324
- for (const dataFile of result.files) {
325
- const filePath = path.join(output, dataFile.path)
326
- const dir = path.dirname(filePath)
327
- fs.mkdirSync(dir, { recursive: true })
328
- fs.writeFileSync(filePath, dataFile.content)
329
- }
206
+ const result = compile(source, { namespace, filePath: file })
330
207
 
331
- // Write sourcemap alongside datapack when mangle mode is active
332
- if (mangle && result.sourceMap && Object.keys(result.sourceMap).length > 0) {
333
- const mapPath = path.join(output, `${namespace}.map.json`)
334
- fs.writeFileSync(mapPath, JSON.stringify(result.sourceMap, null, 2))
335
- console.log(` Sourcemap: ${mapPath}`)
336
- }
208
+ for (const w of result.warnings) {
209
+ console.error(`Warning: ${w}`)
210
+ }
337
211
 
338
- console.log(`✓ Compiled ${file} to ${output}/`)
339
- console.log(` Namespace: ${namespace}`)
340
- console.log(` Functions: ${result.ir.functions.length}`)
341
- console.log(` Files: ${result.files.length}`)
342
- if (showStats) {
343
- printOptimizationStats(result.stats)
344
- }
212
+ // Create output directory
213
+ fs.mkdirSync(output, { recursive: true })
214
+
215
+ // Write all files
216
+ for (const dataFile of result.files) {
217
+ const filePath = path.join(output, dataFile.path)
218
+ const dir = path.dirname(filePath)
219
+ fs.mkdirSync(dir, { recursive: true })
220
+ fs.writeFileSync(filePath, dataFile.content)
345
221
  }
222
+
223
+ console.log(`✓ Compiled ${file} to ${output}/`)
224
+ console.log(` Namespace: ${namespace}`)
225
+ console.log(` Files: ${result.files.length}`)
346
226
  } catch (err) {
347
227
  console.error(formatError(err as Error, source))
348
228
  process.exit(1)
@@ -380,7 +260,7 @@ async function hotReload(url: string): Promise<void> {
380
260
  }
381
261
  }
382
262
 
383
- function watchCommand(dir: string, output: string, namespace?: string, hotReloadUrl?: string, dce = true): void {
263
+ function watchCommand(dir: string, output: string, namespace?: string, hotReloadUrl?: string): void {
384
264
  // Check if directory exists
385
265
  if (!fs.existsSync(dir)) {
386
266
  console.error(`Error: Directory not found: ${dir}`)
@@ -415,8 +295,10 @@ function watchCommand(dir: string, output: string, namespace?: string, hotReload
415
295
  try {
416
296
  source = fs.readFileSync(file, 'utf-8')
417
297
  const ns = namespace ?? deriveNamespace(file)
418
- const result = compile(source, { namespace: ns, filePath: file, dce })
419
- printWarnings(result.warnings)
298
+ const result = compile(source, { namespace: ns, filePath: file })
299
+ for (const w of result.warnings) {
300
+ console.error(`Warning: ${w}`)
301
+ }
420
302
 
421
303
  // Create output directory
422
304
  fs.mkdirSync(output, { recursive: true })
@@ -504,20 +386,12 @@ async function main(): Promise<void> {
504
386
  }
505
387
  {
506
388
  const namespace = parsed.namespace ?? deriveNamespace(parsed.file)
507
- const target = parsed.target ?? 'datapack'
508
- const output = target === 'structure'
509
- ? (parsed.outputNbt ?? parsed.output ?? `./${namespace}.nbt`)
510
- : (parsed.output ?? './dist')
389
+ const output = parsed.output ?? './dist'
511
390
 
512
391
  compileCommand(
513
392
  parsed.file,
514
393
  output,
515
394
  namespace,
516
- target,
517
- parsed.stats,
518
- parsed.dce,
519
- parsed.mangle,
520
- parsed.scoreboardObjective // undefined = derive from namespace in compile()
521
395
  )
522
396
  }
523
397
  break
@@ -533,7 +407,6 @@ async function main(): Promise<void> {
533
407
  parsed.output ?? './dist',
534
408
  parsed.namespace,
535
409
  parsed.hotReload,
536
- parsed.dce
537
410
  )
538
411
  break
539
412
 
package/src/compile.ts CHANGED
@@ -1,58 +1,25 @@
1
1
  /**
2
2
  * RedScript Compile API
3
3
  *
4
- * Main compile function with proper error handling and diagnostics.
4
+ * Preprocessing utilities and v2 compile re-export.
5
5
  */
6
6
 
7
7
  import * as fs from 'fs'
8
8
  import * as path from 'path'
9
9
 
10
- import { Lexer } from './lexer'
11
- import { Parser } from './parser'
12
- import { Lowering, setScoreboardObjective } from './lowering'
13
- import { optimize } from './optimizer/passes'
14
- import { eliminateDeadCode } from './optimizer/dce'
15
- import { generateDatapackWithStats, DatapackFile } from './codegen/mcfunction'
16
- import { DiagnosticError, formatError, parseErrorMessage } from './diagnostics'
17
- import type { IRModule } from './ir/types'
18
- import type { Program } from './ast/types'
10
+ import { DiagnosticError } from './diagnostics'
19
11
 
20
12
  // ---------------------------------------------------------------------------
21
- // Compile Options
13
+ // Re-export v2 compile
22
14
  // ---------------------------------------------------------------------------
23
15
 
24
- export interface CompileOptions {
25
- namespace?: string
26
- filePath?: string
27
- optimize?: boolean
28
- dce?: boolean
29
- mangle?: boolean
30
- /** Scoreboard objective used for all variable slots.
31
- * Defaults to '__<namespace>' (e.g. '__mathshow') — the double-underscore
32
- * prefix signals compiler-internal and avoids occupying the user's namespace.
33
- * Each datapack gets a unique objective automatically; no manual setup needed. */
34
- scoreboardObjective?: string
35
- /** Additional source files that should be treated as *library* code.
36
- * Functions in these files are DCE-eligible: they are only compiled into
37
- * the datapack when actually called from user code. Each string is parsed
38
- * independently (as if it had `module library;` at the top), so library
39
- * mode never bleeds into the main `source`. */
40
- librarySources?: string[]
41
- }
16
+ export { compile, CompileOptions, CompileResult } from '../src2/emit/compile'
17
+ export type { DatapackFile } from '../src2/emit/index'
42
18
 
43
19
  // ---------------------------------------------------------------------------
44
- // Compile Result
20
+ // Source Range / Preprocessing
45
21
  // ---------------------------------------------------------------------------
46
22
 
47
- export interface CompileResult {
48
- success: boolean
49
- files?: DatapackFile[]
50
- advancements?: DatapackFile[]
51
- ast?: Program
52
- ir?: IRModule
53
- error?: DiagnosticError
54
- }
55
-
56
23
  export interface SourceRange {
57
24
  startLine: number
58
25
  endLine: number
@@ -215,126 +182,3 @@ export function preprocessSourceWithMetadata(source: string, options: Preprocess
215
182
  export function preprocessSource(source: string, options: PreprocessOptions = {}): string {
216
183
  return preprocessSourceWithMetadata(source, options).source
217
184
  }
218
-
219
- // ---------------------------------------------------------------------------
220
- // Main Compile Function
221
- // ---------------------------------------------------------------------------
222
-
223
- export function compile(source: string, options: CompileOptions = {}): CompileResult {
224
- const { namespace = 'redscript', filePath, optimize: shouldOptimize = true } = options
225
- const shouldRunDce = options.dce ?? shouldOptimize
226
- let sourceLines = source.split('\n')
227
-
228
- try {
229
- const preprocessed = preprocessSourceWithMetadata(source, { filePath })
230
- const preprocessedSource = preprocessed.source
231
- sourceLines = preprocessedSource.split('\n')
232
-
233
- // Lexing
234
- const tokens = new Lexer(preprocessedSource, filePath).tokenize()
235
-
236
- // Parsing — user source
237
- const parsedAst = new Parser(tokens, preprocessedSource, filePath).parse(namespace)
238
-
239
- // Collect all library sources: explicit `librarySources` option +
240
- // auto-detected imports (files with `module library;` pulled out by the
241
- // preprocessor rather than concatenated).
242
- const allLibrarySources: Array<{ src: string; fp?: string }> = []
243
- for (const libSrc of options.librarySources ?? []) {
244
- allLibrarySources.push({ src: libSrc })
245
- }
246
- for (const li of preprocessed.libraryImports ?? []) {
247
- allLibrarySources.push({ src: li.source, fp: li.filePath })
248
- }
249
-
250
- // Parse library sources independently (fresh Parser per source) so that
251
- // `inLibraryMode` never bleeds into user code. All resulting functions get
252
- // isLibraryFn=true (either via `module library;` in the source, or forced below).
253
- for (const { src, fp } of allLibrarySources) {
254
- const libPreprocessed = preprocessSourceWithMetadata(src, fp ? { filePath: fp } : {})
255
- const libTokens = new Lexer(libPreprocessed.source, fp).tokenize()
256
- const libAst = new Parser(libTokens, libPreprocessed.source, fp).parse(namespace)
257
- // Force all functions to library mode (even if source lacks `module library;`)
258
- for (const fn of libAst.declarations) fn.isLibraryFn = true
259
- // Merge into main AST
260
- parsedAst.declarations.push(...libAst.declarations)
261
- parsedAst.structs.push(...libAst.structs)
262
- parsedAst.implBlocks.push(...libAst.implBlocks)
263
- parsedAst.enums.push(...libAst.enums)
264
- parsedAst.consts.push(...libAst.consts)
265
- parsedAst.globals.push(...libAst.globals)
266
- }
267
- const dceResult = shouldRunDce ? eliminateDeadCode(parsedAst) : { program: parsedAst, warnings: [] }
268
- const ast = dceResult.program
269
-
270
- // Configure scoreboard objective for this compilation.
271
- // Default: use the datapack namespace so each datapack gets its own objective
272
- // automatically, preventing variable collisions when multiple datapacks coexist.
273
- const scoreboardObj = options.scoreboardObjective ?? `__${namespace}`
274
- setScoreboardObjective(scoreboardObj)
275
-
276
- // Lowering
277
- const ir = new Lowering(namespace, preprocessed.ranges).lower(ast)
278
-
279
- // Optimization
280
- const optimized: IRModule = shouldOptimize
281
- ? { ...ir, functions: ir.functions.map(fn => optimize(fn)) }
282
- : ir
283
-
284
- // Code generation — mangle=true by default to prevent cross-function
285
- // scoreboard variable collisions in the global MC scoreboard namespace.
286
- const generated = generateDatapackWithStats(optimized, {
287
- mangle: options.mangle ?? true,
288
- scoreboardObjective: scoreboardObj,
289
- })
290
-
291
- return {
292
- success: true,
293
- files: [...generated.files, ...generated.advancements],
294
- advancements: generated.advancements,
295
- ast,
296
- ir: optimized,
297
- }
298
- } catch (err) {
299
- // Already a DiagnosticError
300
- if (err instanceof DiagnosticError) {
301
- return { success: false, error: err }
302
- }
303
-
304
- // Try to parse the error message for line/col info
305
- if (err instanceof Error) {
306
- const diagnostic = parseErrorMessage(
307
- 'ParseError',
308
- err.message,
309
- sourceLines,
310
- filePath
311
- )
312
- return { success: false, error: diagnostic }
313
- }
314
-
315
- // Unknown error
316
- return {
317
- success: false,
318
- error: new DiagnosticError(
319
- 'ParseError',
320
- String(err),
321
- { file: filePath, line: 1, col: 1 },
322
- sourceLines
323
- )
324
- }
325
- }
326
- }
327
-
328
- // ---------------------------------------------------------------------------
329
- // Format Compile Error
330
- // ---------------------------------------------------------------------------
331
-
332
- export function formatCompileError(result: CompileResult): string {
333
- if (result.success) {
334
- return 'Compilation successful'
335
- }
336
- if (result.error) {
337
- return formatError(result.error, result.error.sourceLines?.join('\n'))
338
- }
339
- return 'Unknown error'
340
- }