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.
- package/.claude/commands/build-test.md +10 -0
- package/.claude/commands/deploy-demo.md +12 -0
- package/.claude/commands/stage-status.md +13 -0
- package/.claude/settings.json +12 -0
- package/.github/workflows/ci.yml +1 -0
- package/CLAUDE.md +231 -0
- package/README.md +29 -28
- package/README.zh.md +28 -28
- package/demo.gif +0 -0
- package/dist/cli.js +2 -554
- package/dist/compile.js +2 -266
- package/dist/index.js +2 -159
- package/dist/lexer/index.js +9 -1
- package/dist/lowering/index.js +22 -5
- package/dist/src/__tests__/cli.test.d.ts +1 -0
- package/dist/src/__tests__/cli.test.js +104 -0
- package/dist/src/__tests__/codegen.test.d.ts +1 -0
- package/dist/src/__tests__/codegen.test.js +152 -0
- package/dist/src/__tests__/compile-all.test.d.ts +10 -0
- package/dist/src/__tests__/compile-all.test.js +108 -0
- package/dist/src/__tests__/dce.test.d.ts +1 -0
- package/dist/src/__tests__/dce.test.js +102 -0
- package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
- package/dist/src/__tests__/diagnostics.test.js +177 -0
- package/dist/src/__tests__/e2e.test.d.ts +6 -0
- package/dist/src/__tests__/e2e.test.js +1789 -0
- package/dist/src/__tests__/entity-types.test.d.ts +1 -0
- package/dist/src/__tests__/entity-types.test.js +203 -0
- package/dist/src/__tests__/formatter.test.d.ts +1 -0
- package/dist/src/__tests__/formatter.test.js +40 -0
- package/dist/src/__tests__/lexer.test.d.ts +1 -0
- package/dist/src/__tests__/lexer.test.js +343 -0
- package/dist/src/__tests__/lowering.test.d.ts +1 -0
- package/dist/src/__tests__/lowering.test.js +1015 -0
- package/dist/src/__tests__/macro.test.d.ts +8 -0
- package/dist/src/__tests__/macro.test.js +306 -0
- package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
- package/dist/src/__tests__/mc-integration.test.js +817 -0
- package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
- package/dist/src/__tests__/mc-syntax.test.js +124 -0
- package/dist/src/__tests__/nbt.test.d.ts +1 -0
- package/dist/src/__tests__/nbt.test.js +82 -0
- package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
- package/dist/src/__tests__/optimizer.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer.test.js +149 -0
- package/dist/src/__tests__/parser.test.d.ts +1 -0
- package/dist/src/__tests__/parser.test.js +807 -0
- package/dist/src/__tests__/repl.test.d.ts +1 -0
- package/dist/src/__tests__/repl.test.js +27 -0
- package/dist/src/__tests__/runtime.test.d.ts +1 -0
- package/dist/src/__tests__/runtime.test.js +289 -0
- package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
- package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
- package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
- package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
- package/dist/src/__tests__/stdlib-math.test.js +351 -0
- package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib-vec.test.js +263 -0
- package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
- package/dist/src/__tests__/structure-optimizer.test.js +33 -0
- package/dist/src/__tests__/typechecker.test.d.ts +1 -0
- package/dist/src/__tests__/typechecker.test.js +552 -0
- package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
- package/dist/src/__tests__/var-allocator.test.js +69 -0
- package/dist/src/ast/types.d.ts +515 -0
- package/dist/src/ast/types.js +9 -0
- package/dist/src/builtins/metadata.d.ts +36 -0
- package/dist/src/builtins/metadata.js +1014 -0
- package/dist/src/cli.d.ts +11 -0
- package/dist/src/cli.js +443 -0
- package/dist/src/codegen/cmdblock/index.d.ts +26 -0
- package/dist/src/codegen/cmdblock/index.js +45 -0
- package/dist/src/codegen/mcfunction/index.d.ts +40 -0
- package/dist/src/codegen/mcfunction/index.js +606 -0
- package/dist/src/codegen/structure/index.d.ts +24 -0
- package/dist/src/codegen/structure/index.js +279 -0
- package/dist/src/codegen/var-allocator.d.ts +45 -0
- package/dist/src/codegen/var-allocator.js +104 -0
- package/dist/src/compile.d.ts +37 -0
- package/dist/src/compile.js +165 -0
- package/dist/src/diagnostics/index.d.ts +44 -0
- package/dist/src/diagnostics/index.js +140 -0
- package/dist/src/events/types.d.ts +35 -0
- package/dist/src/events/types.js +59 -0
- package/dist/src/formatter/index.d.ts +1 -0
- package/dist/src/formatter/index.js +26 -0
- package/dist/src/index.d.ts +22 -0
- package/dist/src/index.js +45 -0
- package/dist/src/ir/builder.d.ts +33 -0
- package/dist/src/ir/builder.js +99 -0
- package/dist/src/ir/types.d.ts +132 -0
- package/dist/src/ir/types.js +15 -0
- package/dist/src/lexer/index.d.ts +37 -0
- package/dist/src/lexer/index.js +569 -0
- package/dist/src/lowering/index.d.ts +188 -0
- package/dist/src/lowering/index.js +3405 -0
- package/dist/src/mc-test/client.d.ts +128 -0
- package/dist/src/mc-test/client.js +174 -0
- package/dist/src/mc-test/runner.d.ts +28 -0
- package/dist/src/mc-test/runner.js +151 -0
- package/dist/src/mc-test/setup.d.ts +11 -0
- package/dist/src/mc-test/setup.js +98 -0
- package/dist/src/mc-validator/index.d.ts +17 -0
- package/dist/src/mc-validator/index.js +322 -0
- package/dist/src/nbt/index.d.ts +86 -0
- package/dist/src/nbt/index.js +250 -0
- package/dist/src/optimizer/commands.d.ts +38 -0
- package/dist/src/optimizer/commands.js +451 -0
- package/dist/src/optimizer/dce.d.ts +34 -0
- package/dist/src/optimizer/dce.js +639 -0
- package/dist/src/optimizer/passes.d.ts +34 -0
- package/dist/src/optimizer/passes.js +243 -0
- package/dist/src/optimizer/structure.d.ts +9 -0
- package/dist/src/optimizer/structure.js +356 -0
- package/dist/src/parser/index.d.ts +93 -0
- package/dist/src/parser/index.js +1687 -0
- package/dist/src/repl.d.ts +16 -0
- package/dist/src/repl.js +165 -0
- package/dist/src/runtime/index.d.ts +107 -0
- package/dist/src/runtime/index.js +1409 -0
- package/dist/src/typechecker/index.d.ts +61 -0
- package/dist/src/typechecker/index.js +1034 -0
- package/dist/src/types/entity-hierarchy.d.ts +29 -0
- package/dist/src/types/entity-hierarchy.js +107 -0
- package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
- package/dist/src2/__tests__/e2e/basic.test.js +140 -0
- package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
- package/dist/src2/__tests__/e2e/macros.test.js +182 -0
- package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
- package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
- package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
- package/dist/src2/__tests__/hir/desugar.test.js +234 -0
- package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
- package/dist/src2/__tests__/lir/lower.test.js +559 -0
- package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
- package/dist/src2/__tests__/lir/types.test.js +185 -0
- package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
- package/dist/src2/__tests__/lir/verify.test.js +221 -0
- package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
- package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
- package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
- package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
- package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
- package/dist/src2/__tests__/mir/verify.test.js +223 -0
- package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
- package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
- package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
- package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
- package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
- package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
- package/dist/src2/emit/compile.d.ts +19 -0
- package/dist/src2/emit/compile.js +80 -0
- package/dist/src2/emit/index.d.ts +17 -0
- package/dist/src2/emit/index.js +172 -0
- package/dist/src2/hir/lower.d.ts +15 -0
- package/dist/src2/hir/lower.js +378 -0
- package/dist/src2/hir/types.d.ts +373 -0
- package/dist/src2/hir/types.js +16 -0
- package/dist/src2/lir/lower.d.ts +15 -0
- package/dist/src2/lir/lower.js +453 -0
- package/dist/src2/lir/types.d.ts +136 -0
- package/dist/src2/lir/types.js +11 -0
- package/dist/src2/lir/verify.d.ts +14 -0
- package/dist/src2/lir/verify.js +113 -0
- package/dist/src2/mir/lower.d.ts +9 -0
- package/dist/src2/mir/lower.js +1030 -0
- package/dist/src2/mir/macro.d.ts +22 -0
- package/dist/src2/mir/macro.js +168 -0
- package/dist/src2/mir/types.d.ts +183 -0
- package/dist/src2/mir/types.js +11 -0
- package/dist/src2/mir/verify.d.ts +16 -0
- package/dist/src2/mir/verify.js +216 -0
- package/dist/src2/optimizer/block_merge.d.ts +12 -0
- package/dist/src2/optimizer/block_merge.js +84 -0
- package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
- package/dist/src2/optimizer/branch_simplify.js +28 -0
- package/dist/src2/optimizer/constant_fold.d.ts +10 -0
- package/dist/src2/optimizer/constant_fold.js +85 -0
- package/dist/src2/optimizer/copy_prop.d.ts +9 -0
- package/dist/src2/optimizer/copy_prop.js +113 -0
- package/dist/src2/optimizer/dce.d.ts +8 -0
- package/dist/src2/optimizer/dce.js +155 -0
- package/dist/src2/optimizer/pipeline.d.ts +10 -0
- package/dist/src2/optimizer/pipeline.js +42 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/compiler-pipeline-redesign.md +2243 -0
- package/docs/optimization-ideas.md +1076 -0
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/examples/readme-demo.mcrs +44 -66
- package/jest.config.js +1 -1
- package/package.json +6 -5
- package/scripts/postbuild.js +15 -0
- package/src/__tests__/cli.test.ts +8 -220
- package/src/__tests__/dce.test.ts +11 -56
- package/src/__tests__/diagnostics.test.ts +59 -38
- package/src/__tests__/mc-integration.test.ts +1 -2
- package/src/ast/types.ts +6 -1
- package/src/cli.ts +29 -156
- package/src/compile.ts +6 -162
- package/src/index.ts +14 -178
- package/src/lexer/index.ts +9 -1
- package/src/mc-test/runner.ts +4 -3
- package/src/parser/index.ts +1 -1
- package/src/repl.ts +1 -1
- package/src/runtime/index.ts +1 -1
- package/src2/__tests__/e2e/basic.test.ts +154 -0
- package/src2/__tests__/e2e/macros.test.ts +199 -0
- package/src2/__tests__/e2e/migrate.test.ts +3008 -0
- package/src2/__tests__/hir/desugar.test.ts +263 -0
- package/src2/__tests__/lir/lower.test.ts +619 -0
- package/src2/__tests__/lir/types.test.ts +207 -0
- package/src2/__tests__/lir/verify.test.ts +249 -0
- package/src2/__tests__/mir/arithmetic.test.ts +156 -0
- package/src2/__tests__/mir/control-flow.test.ts +242 -0
- package/src2/__tests__/mir/verify.test.ts +254 -0
- package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
- package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
- package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
- package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
- package/src2/__tests__/optimizer/dce.test.ts +83 -0
- package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
- package/src2/emit/compile.ts +99 -0
- package/src2/emit/index.ts +222 -0
- package/src2/hir/lower.ts +428 -0
- package/src2/hir/types.ts +216 -0
- package/src2/lir/lower.ts +556 -0
- package/src2/lir/types.ts +109 -0
- package/src2/lir/verify.ts +129 -0
- package/src2/mir/lower.ts +1160 -0
- package/src2/mir/macro.ts +167 -0
- package/src2/mir/types.ts +106 -0
- package/src2/mir/verify.ts +218 -0
- package/src2/optimizer/block_merge.ts +93 -0
- package/src2/optimizer/branch_simplify.ts +27 -0
- package/src2/optimizer/constant_fold.ts +88 -0
- package/src2/optimizer/copy_prop.ts +106 -0
- package/src2/optimizer/dce.ts +133 -0
- package/src2/optimizer/pipeline.ts +44 -0
- package/tsconfig.json +2 -2
- package/src/__tests__/codegen.test.ts +0 -161
- package/src/__tests__/e2e.test.ts +0 -2039
- package/src/__tests__/entity-types.test.ts +0 -236
- package/src/__tests__/lowering.test.ts +0 -1185
- package/src/__tests__/macro.test.ts +0 -343
- package/src/__tests__/nbt.test.ts +0 -58
- package/src/__tests__/optimizer-advanced.test.ts +0 -144
- package/src/__tests__/optimizer.test.ts +0 -162
- package/src/__tests__/runtime.test.ts +0 -305
- package/src/__tests__/stdlib-advanced.test.ts +0 -379
- package/src/__tests__/stdlib-bigint.test.ts +0 -427
- package/src/__tests__/stdlib-math.test.ts +0 -374
- package/src/__tests__/stdlib-vec.test.ts +0 -259
- package/src/__tests__/structure-optimizer.test.ts +0 -38
- package/src/__tests__/var-allocator.test.ts +0 -75
- package/src/codegen/cmdblock/index.ts +0 -63
- package/src/codegen/mcfunction/index.ts +0 -662
- package/src/codegen/structure/index.ts +0 -346
- package/src/codegen/var-allocator.ts +0 -104
- package/src/ir/builder.ts +0 -116
- package/src/ir/types.ts +0 -134
- package/src/lowering/index.ts +0 -3860
- package/src/optimizer/commands.ts +0 -534
- package/src/optimizer/dce.ts +0 -679
- package/src/optimizer/passes.ts +0 -250
- 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
|
|
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('
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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('
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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('
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
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>] [--
|
|
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>] [--
|
|
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
|
|
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> = {
|
|
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
|
-
|
|
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
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
|
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
|
|
419
|
-
|
|
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
|
|
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
|
-
*
|
|
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 {
|
|
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
|
-
//
|
|
13
|
+
// Re-export v2 compile
|
|
22
14
|
// ---------------------------------------------------------------------------
|
|
23
15
|
|
|
24
|
-
export
|
|
25
|
-
|
|
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
|
-
//
|
|
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
|
-
}
|