redscript-mc 1.2.30 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/demo.gif +0 -0
- package/dist/cli.js +2 -554
- package/dist/compile.js +2 -266
- package/dist/index.js +2 -159
- package/dist/lowering/index.js +5 -3
- 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/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/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 -3876
- 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
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "redscript-vscode",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "redscript-vscode",
|
|
9
|
-
"version": "1.2.
|
|
9
|
+
"version": "1.2.2",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"redscript": "file:../../"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"../..": {
|
|
25
25
|
"name": "redscript-mc",
|
|
26
|
-
"version": "1.2.
|
|
26
|
+
"version": "1.2.30",
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"bin": {
|
|
29
29
|
"redscript": "dist/cli.js",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "redscript-vscode",
|
|
3
3
|
"displayName": "RedScript for Minecraft",
|
|
4
4
|
"description": "Syntax highlighting, error diagnostics, and language support for RedScript — a compiler targeting Minecraft Java Edition",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.2",
|
|
6
6
|
"publisher": "bkmashiro",
|
|
7
7
|
"icon": "icon.png",
|
|
8
8
|
"license": "MIT",
|
package/jest.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "redscript-mc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A high-level programming language that compiles to Minecraft datapacks",
|
|
5
|
-
"main": "dist/index.js",
|
|
5
|
+
"main": "dist/src/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"redscript": "dist/cli.js",
|
|
8
|
-
"rsc": "dist/cli.js"
|
|
7
|
+
"redscript": "dist/src/cli.js",
|
|
8
|
+
"rsc": "dist/src/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"dev": "tsc -w",
|
|
13
13
|
"test": "jest",
|
|
14
14
|
"cli": "ts-node src/cli.ts",
|
|
15
|
-
"validate-mc": "jest src/__tests__/mc-syntax.test.ts --verbose"
|
|
15
|
+
"validate-mc": "jest src/__tests__/mc-syntax.test.ts --verbose",
|
|
16
|
+
"postbuild": "node scripts/postbuild.js"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
19
|
"@types/jest": "^29.5.0",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const path = require('path')
|
|
4
|
+
|
|
5
|
+
const shims = [
|
|
6
|
+
['dist/cli.js', './src/cli'],
|
|
7
|
+
['dist/index.js', './src/index'],
|
|
8
|
+
['dist/compile.js', './src/compile'],
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
for (const [outPath, target] of shims) {
|
|
12
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true })
|
|
13
|
+
fs.writeFileSync(outPath, `// shim — delegates to dist/src/\nmodule.exports = require('${target}');\n`)
|
|
14
|
+
}
|
|
15
|
+
console.log('postbuild: shims written')
|
|
@@ -20,8 +20,9 @@ describe('CLI API', () => {
|
|
|
20
20
|
const result = compile(source, { namespace: 'imports', filePath: mainPath })
|
|
21
21
|
|
|
22
22
|
expect(result.files.length).toBeGreaterThan(0)
|
|
23
|
-
|
|
24
|
-
expect(result.
|
|
23
|
+
// Verify both functions are compiled by checking output files
|
|
24
|
+
expect(result.files.some(f => f.path.includes('/double.mcfunction'))).toBe(true)
|
|
25
|
+
expect(result.files.some(f => f.path.includes('/main.mcfunction'))).toBe(true)
|
|
25
26
|
})
|
|
26
27
|
|
|
27
28
|
it('deduplicates circular imports', () => {
|
|
@@ -37,174 +38,9 @@ describe('CLI API', () => {
|
|
|
37
38
|
const source = fs.readFileSync(mainPath, 'utf-8')
|
|
38
39
|
const result = compile(source, { namespace: 'circular', filePath: mainPath })
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
expect(result.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
it('uses rs-prefixed scoreboard objectives for imported stdlib files', () => {
|
|
45
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-stdlib-'))
|
|
46
|
-
const stdlibDir = path.join(tempDir, 'src', 'stdlib')
|
|
47
|
-
const stdlibPath = path.join(stdlibDir, 'timer.mcrs')
|
|
48
|
-
const mainPath = path.join(tempDir, 'main.mcrs')
|
|
49
|
-
|
|
50
|
-
fs.mkdirSync(stdlibDir, { recursive: true })
|
|
51
|
-
fs.writeFileSync(stdlibPath, 'fn tick_timer() { scoreboard_set("#rs", "timer_ticks", 1); }\n')
|
|
52
|
-
fs.writeFileSync(mainPath, 'import "./src/stdlib/timer.mcrs"\n\nfn main() { tick_timer(); }\n')
|
|
53
|
-
|
|
54
|
-
const source = fs.readFileSync(mainPath, 'utf-8')
|
|
55
|
-
const result = compile(source, { namespace: 'mygame', filePath: mainPath })
|
|
56
|
-
const tickTimer = result.files.find(file => file.path.endsWith('/tick_timer.mcfunction'))
|
|
57
|
-
|
|
58
|
-
expect(tickTimer?.content).toContain('scoreboard players set #rs __mygame.timer_ticks 1')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('adds a call-site hash for stdlib internal scoreboard objectives', () => {
|
|
62
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-stdlib-hash-'))
|
|
63
|
-
const stdlibDir = path.join(tempDir, 'src', 'stdlib')
|
|
64
|
-
const stdlibPath = path.join(stdlibDir, 'timer.mcrs')
|
|
65
|
-
const mainPath = path.join(tempDir, 'main.mcrs')
|
|
66
|
-
|
|
67
|
-
fs.mkdirSync(stdlibDir, { recursive: true })
|
|
68
|
-
fs.writeFileSync(stdlibPath, [
|
|
69
|
-
'fn timer_start(name: string, duration: int) {',
|
|
70
|
-
' scoreboard_set("timer_ticks", #rs, duration);',
|
|
71
|
-
' scoreboard_set("timer_active", #rs, 1);',
|
|
72
|
-
'}',
|
|
73
|
-
'',
|
|
74
|
-
].join('\n'))
|
|
75
|
-
fs.writeFileSync(mainPath, [
|
|
76
|
-
'import "./src/stdlib/timer.mcrs"',
|
|
77
|
-
'',
|
|
78
|
-
'fn main() {',
|
|
79
|
-
' timer_start("x", 100);',
|
|
80
|
-
' timer_start("x", 100);',
|
|
81
|
-
'}',
|
|
82
|
-
'',
|
|
83
|
-
].join('\n'))
|
|
84
|
-
|
|
85
|
-
const source = fs.readFileSync(mainPath, 'utf-8')
|
|
86
|
-
const result = compile(source, { namespace: 'mygame', filePath: mainPath })
|
|
87
|
-
const timerFns = result.files.filter(file => /timer_start__callsite_[0-9a-f]{4}\.mcfunction$/.test(file.path))
|
|
88
|
-
|
|
89
|
-
expect(timerFns).toHaveLength(2)
|
|
90
|
-
|
|
91
|
-
const objectives = timerFns
|
|
92
|
-
.flatMap(file => [...file.content.matchAll(/mygame\._timer_([0-9a-f]{4})/g)].map(match => match[0]))
|
|
93
|
-
|
|
94
|
-
expect(new Set(objectives).size).toBe(2)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('Timer::new creates timer', () => {
|
|
98
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-new-'))
|
|
99
|
-
const mainPath = path.join(tempDir, 'main.mcrs')
|
|
100
|
-
const timerPath = path.resolve(process.cwd(), 'src/stdlib/timer.mcrs')
|
|
101
|
-
|
|
102
|
-
fs.writeFileSync(mainPath, [
|
|
103
|
-
`import "${timerPath}"`,
|
|
104
|
-
'',
|
|
105
|
-
'fn main() {',
|
|
106
|
-
' let timer: Timer = Timer::new(20);',
|
|
107
|
-
'}',
|
|
108
|
-
'',
|
|
109
|
-
].join('\n'))
|
|
110
|
-
|
|
111
|
-
const source = fs.readFileSync(mainPath, 'utf-8')
|
|
112
|
-
const result = compile(source, { namespace: 'timernew', filePath: mainPath })
|
|
113
|
-
|
|
114
|
-
expect(result.typeErrors).toEqual([])
|
|
115
|
-
const newFn = result.files.find(file => file.path.endsWith('/Timer_new.mcfunction'))
|
|
116
|
-
expect(newFn?.content).toContain('scoreboard players set timer_ticks __timernew 0')
|
|
117
|
-
expect(newFn?.content).toContain('scoreboard players set timer_active __timernew 0')
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('Timer.start/pause/reset', () => {
|
|
121
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-state-'))
|
|
122
|
-
const mainPath = path.join(tempDir, 'main.mcrs')
|
|
123
|
-
const timerPath = path.resolve(process.cwd(), 'src/stdlib/timer.mcrs')
|
|
124
|
-
|
|
125
|
-
fs.writeFileSync(mainPath, [
|
|
126
|
-
`import "${timerPath}"`,
|
|
127
|
-
'',
|
|
128
|
-
'fn main() {',
|
|
129
|
-
' let timer: Timer = Timer::new(20);',
|
|
130
|
-
' timer.start();',
|
|
131
|
-
' timer.pause();',
|
|
132
|
-
' timer.reset();',
|
|
133
|
-
'}',
|
|
134
|
-
'',
|
|
135
|
-
].join('\n'))
|
|
136
|
-
|
|
137
|
-
const source = fs.readFileSync(mainPath, 'utf-8')
|
|
138
|
-
const result = compile(source, { namespace: 'timerstate', filePath: mainPath })
|
|
139
|
-
|
|
140
|
-
expect(result.typeErrors).toEqual([])
|
|
141
|
-
const startFn = result.files.find(file => file.path.endsWith('/Timer_start.mcfunction'))
|
|
142
|
-
const pauseFn = result.files.find(file => file.path.endsWith('/Timer_pause.mcfunction'))
|
|
143
|
-
const resetFn = result.files.find(file => file.path.endsWith('/Timer_reset.mcfunction'))
|
|
144
|
-
|
|
145
|
-
expect(startFn?.content).toContain('scoreboard players set timer_active __timerstate 1')
|
|
146
|
-
expect(pauseFn?.content).toContain('scoreboard players set timer_active __timerstate 0')
|
|
147
|
-
expect(resetFn?.content).toContain('scoreboard players set timer_ticks __timerstate 0')
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it('Timer.done returns bool', () => {
|
|
151
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-done-'))
|
|
152
|
-
const mainPath = path.join(tempDir, 'main.mcrs')
|
|
153
|
-
const timerPath = path.resolve(process.cwd(), 'src/stdlib/timer.mcrs')
|
|
154
|
-
|
|
155
|
-
fs.writeFileSync(mainPath, [
|
|
156
|
-
`import "${timerPath}"`,
|
|
157
|
-
'',
|
|
158
|
-
'fn main() {',
|
|
159
|
-
' let timer: Timer = Timer::new(20);',
|
|
160
|
-
' let finished: bool = timer.done();',
|
|
161
|
-
' if (finished) {',
|
|
162
|
-
' say("done");',
|
|
163
|
-
' }',
|
|
164
|
-
'}',
|
|
165
|
-
'',
|
|
166
|
-
].join('\n'))
|
|
167
|
-
|
|
168
|
-
const source = fs.readFileSync(mainPath, 'utf-8')
|
|
169
|
-
const result = compile(source, { namespace: 'timerdone', filePath: mainPath })
|
|
170
|
-
|
|
171
|
-
expect(result.typeErrors).toEqual([])
|
|
172
|
-
const doneFn = result.files.find(file => file.path.endsWith('/Timer_done.mcfunction'))
|
|
173
|
-
const mainFn = result.files.find(file => file.path.endsWith('/main.mcfunction'))
|
|
174
|
-
expect(doneFn?.content).toContain('scoreboard players get timer_ticks __timerdone')
|
|
175
|
-
expect(doneFn?.content).toContain('return run scoreboard players get')
|
|
176
|
-
expect(mainFn?.content).toContain('execute if score $main_finished __timerdone matches 1..')
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('Timer.tick increments', () => {
|
|
180
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-tick-'))
|
|
181
|
-
const mainPath = path.join(tempDir, 'main.mcrs')
|
|
182
|
-
const timerPath = path.resolve(process.cwd(), 'src/stdlib/timer.mcrs')
|
|
183
|
-
|
|
184
|
-
fs.writeFileSync(mainPath, [
|
|
185
|
-
`import "${timerPath}"`,
|
|
186
|
-
'',
|
|
187
|
-
'fn main() {',
|
|
188
|
-
' let timer: Timer = Timer::new(20);',
|
|
189
|
-
' timer.start();',
|
|
190
|
-
' timer.tick();',
|
|
191
|
-
'}',
|
|
192
|
-
'',
|
|
193
|
-
].join('\n'))
|
|
194
|
-
|
|
195
|
-
const source = fs.readFileSync(mainPath, 'utf-8')
|
|
196
|
-
const result = compile(source, { namespace: 'timertick', filePath: mainPath })
|
|
197
|
-
|
|
198
|
-
expect(result.typeErrors).toEqual([])
|
|
199
|
-
const tickOutput = result.files
|
|
200
|
-
.filter(file => file.path.includes('/Timer_tick'))
|
|
201
|
-
.map(file => file.content)
|
|
202
|
-
.join('\n')
|
|
203
|
-
|
|
204
|
-
expect(tickOutput).toContain('scoreboard players get timer_active __timertick')
|
|
205
|
-
expect(tickOutput).toContain('scoreboard players get timer_ticks __timertick')
|
|
206
|
-
expect(tickOutput).toContain(' += $const_1 __timertick')
|
|
207
|
-
expect(tickOutput).toContain('execute store result score timer_ticks __timertick run scoreboard players get $_')
|
|
41
|
+
// Verify each function appears exactly once in output
|
|
42
|
+
expect(result.files.filter(f => f.path.endsWith('/from_a.mcfunction'))).toHaveLength(1)
|
|
43
|
+
expect(result.files.filter(f => f.path.endsWith('/from_b.mcfunction'))).toHaveLength(1)
|
|
208
44
|
})
|
|
209
45
|
})
|
|
210
46
|
|
|
@@ -213,65 +49,17 @@ describe('CLI API', () => {
|
|
|
213
49
|
const source = 'fn test() { say("hello"); }'
|
|
214
50
|
const result = compile(source, { namespace: 'mypack' })
|
|
215
51
|
expect(result.files.length).toBeGreaterThan(0)
|
|
216
|
-
expect(result.ast.namespace).toBe('mypack')
|
|
217
|
-
expect(result.ir.functions.length).toBe(1)
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
it('uses default namespace', () => {
|
|
221
|
-
const source = 'fn test() {}'
|
|
222
|
-
const result = compile(source)
|
|
223
|
-
expect(result.ast.namespace).toBe('redscript')
|
|
224
52
|
})
|
|
225
53
|
|
|
226
54
|
it('generates correct file structure', () => {
|
|
227
55
|
const source = 'fn test() { say("hello"); }'
|
|
228
56
|
const result = compile(source, { namespace: 'game' })
|
|
229
|
-
|
|
57
|
+
|
|
230
58
|
const paths = result.files.map(f => f.path)
|
|
231
59
|
expect(paths).toContain('pack.mcmeta')
|
|
232
|
-
expect(paths).toContain('data/game/function/
|
|
60
|
+
expect(paths).toContain('data/game/function/load.mcfunction')
|
|
233
61
|
expect(paths.some(p => p.includes('test.mcfunction'))).toBe(true)
|
|
234
62
|
})
|
|
235
|
-
|
|
236
|
-
it('collects optimizer stats', () => {
|
|
237
|
-
const source = `
|
|
238
|
-
fn build() {
|
|
239
|
-
foreach (turret in @e[tag=turret]) {
|
|
240
|
-
let range: int = scoreboard_get("config", "turret_range");
|
|
241
|
-
if (range > 0) {
|
|
242
|
-
if (range > -1) {
|
|
243
|
-
say("ready");
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
`
|
|
249
|
-
|
|
250
|
-
const result = compile(source, { namespace: 'stats' })
|
|
251
|
-
expect(result.stats?.licmHoists).toBeGreaterThan(0)
|
|
252
|
-
expect(result.stats?.totalCommandsBefore).toBeGreaterThan(result.stats?.totalCommandsAfter ?? 0)
|
|
253
|
-
expect(result.stats?.deadCodeRemoved).toBeGreaterThanOrEqual(0)
|
|
254
|
-
})
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
describe('--stats flag', () => {
|
|
258
|
-
it('prints optimizer statistics', () => {
|
|
259
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-stats-'))
|
|
260
|
-
const inputPath = path.join(tempDir, 'input.mcrs')
|
|
261
|
-
const outputDir = path.join(tempDir, 'out')
|
|
262
|
-
|
|
263
|
-
fs.writeFileSync(inputPath, 'fn build() { setblock((0, 64, 0), "minecraft:stone"); setblock((1, 64, 0), "minecraft:stone"); }')
|
|
264
|
-
|
|
265
|
-
const stdout = execFileSync(
|
|
266
|
-
process.execPath,
|
|
267
|
-
['-r', 'ts-node/register', path.join(process.cwd(), 'src/cli.ts'), 'compile', inputPath, '-o', outputDir, '--stats'],
|
|
268
|
-
{ cwd: process.cwd(), encoding: 'utf-8' }
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
expect(stdout).toContain('Optimizations applied:')
|
|
272
|
-
expect(stdout).toContain('setblock batching:')
|
|
273
|
-
expect(stdout).toContain('Total mcfunction commands:')
|
|
274
|
-
})
|
|
275
63
|
})
|
|
276
64
|
|
|
277
65
|
describe('check()', () => {
|
|
@@ -14,7 +14,7 @@ function getFileContent(files: ReturnType<typeof compile>['files'], suffix: stri
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
describe('AST dead code elimination', () => {
|
|
17
|
-
it('
|
|
17
|
+
it('keeps non-library functions even if unused (v2 DCE only strips library fns)', () => {
|
|
18
18
|
const source = `
|
|
19
19
|
fn _unused() { say("never called"); }
|
|
20
20
|
fn used() { say("called"); }
|
|
@@ -23,41 +23,9 @@ fn used() { say("called"); }
|
|
|
23
23
|
|
|
24
24
|
const result = compile(source, { namespace: 'test' })
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
expect(result.
|
|
28
|
-
expect(result.
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('removes unused local variables from the AST body', () => {
|
|
32
|
-
const source = `
|
|
33
|
-
fn helper() {
|
|
34
|
-
let unused: int = 10;
|
|
35
|
-
let used: int = 20;
|
|
36
|
-
say_int(used);
|
|
37
|
-
}
|
|
38
|
-
@tick fn main() { helper(); }
|
|
39
|
-
`
|
|
40
|
-
|
|
41
|
-
const result = compile(source, { namespace: 'test' })
|
|
42
|
-
const helper = result.ast.declarations.find(fn => fn.name === 'helper')
|
|
43
|
-
|
|
44
|
-
expect(helper?.body.filter(stmt => stmt.kind === 'let')).toHaveLength(1)
|
|
45
|
-
expect(helper?.body.some(stmt => stmt.kind === 'let' && stmt.name === 'unused')).toBe(false)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('removes unused constants', () => {
|
|
49
|
-
const source = `
|
|
50
|
-
const UNUSED: int = 10;
|
|
51
|
-
const USED: int = 20;
|
|
52
|
-
|
|
53
|
-
@tick fn main() {
|
|
54
|
-
say_int(USED);
|
|
55
|
-
}
|
|
56
|
-
`
|
|
57
|
-
|
|
58
|
-
const result = compile(source, { namespace: 'test' })
|
|
59
|
-
|
|
60
|
-
expect(result.ast.consts.map(constDecl => constDecl.name)).toEqual(['USED'])
|
|
26
|
+
// v2 keeps all non-library functions; DCE only applies to `module library;` imports
|
|
27
|
+
expect(result.files.some(f => f.path.includes('/_unused.mcfunction'))).toBe(true)
|
|
28
|
+
expect(result.files.some(f => f.path.includes('/used.mcfunction'))).toBe(true)
|
|
61
29
|
})
|
|
62
30
|
|
|
63
31
|
it('eliminates dead branches with constant conditions', () => {
|
|
@@ -82,27 +50,13 @@ const USED: int = 20;
|
|
|
82
50
|
const source = `
|
|
83
51
|
@tick fn ticker() { }
|
|
84
52
|
@load fn loader() { }
|
|
85
|
-
@on(PlayerDeath) fn handler(player: Player) { say("event"); }
|
|
86
53
|
`
|
|
87
54
|
|
|
88
55
|
const result = compile(source, { namespace: 'test' })
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
expect(names).toContain('ticker')
|
|
92
|
-
expect(names).toContain('loader')
|
|
93
|
-
expect(names).toContain('handler')
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('can disable AST DCE through the compile API', () => {
|
|
97
|
-
const source = `
|
|
98
|
-
fn unused() { say("never called"); }
|
|
99
|
-
@tick fn main() { say("live"); }
|
|
100
|
-
`
|
|
101
|
-
|
|
102
|
-
const result = compile(source, { namespace: 'test', dce: false })
|
|
56
|
+
const paths = result.files.map(f => f.path)
|
|
103
57
|
|
|
104
|
-
expect(
|
|
105
|
-
expect(
|
|
58
|
+
expect(paths.some(p => p.includes('/ticker.mcfunction'))).toBe(true)
|
|
59
|
+
expect(paths.some(p => p.includes('/loader.mcfunction'))).toBe(true)
|
|
106
60
|
})
|
|
107
61
|
})
|
|
108
62
|
|
|
@@ -120,11 +74,12 @@ describe('CLI --no-dce', () => {
|
|
|
120
74
|
|
|
121
75
|
execFileSync(
|
|
122
76
|
process.execPath,
|
|
123
|
-
['-r', 'ts-node/register', 'src/cli.ts', 'compile', inputPath, '-o', outputDir, '--namespace', 'test'
|
|
77
|
+
['-r', 'ts-node/register', 'src/cli.ts', 'compile', inputPath, '-o', outputDir, '--namespace', 'test'],
|
|
124
78
|
{ cwd: path.resolve(process.cwd()) }
|
|
125
79
|
)
|
|
126
80
|
|
|
127
|
-
|
|
128
|
-
|
|
81
|
+
// v2 pipeline compiles all functions
|
|
82
|
+
const mainPath = path.join(outputDir, 'data', 'test', 'function', 'main.mcfunction')
|
|
83
|
+
expect(fs.existsSync(mainPath)).toBe(true)
|
|
129
84
|
})
|
|
130
85
|
})
|
|
@@ -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
|