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
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Macro function detection — pre-scans HIR to find parameters used in
|
|
3
|
+
* builtin call positions (coordinates, entity types, etc.)
|
|
4
|
+
*
|
|
5
|
+
* A function becomes a "macro function" when one of its params appears
|
|
6
|
+
* in a position that requires literal substitution in the MC command
|
|
7
|
+
* (e.g. summon coords, particle coords, setblock coords, local/relative
|
|
8
|
+
* coords like ^px or ~height).
|
|
9
|
+
*/
|
|
10
|
+
import type { HIRModule } from '../hir/types';
|
|
11
|
+
/** Builtins whose arguments appear literally in MC commands */
|
|
12
|
+
export declare const BUILTIN_SET: Set<string>;
|
|
13
|
+
export interface MacroFunctionInfo {
|
|
14
|
+
macroParams: Set<string>;
|
|
15
|
+
/** param name → param type name (for NBT scale inference) */
|
|
16
|
+
paramTypes: Map<string, string>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Pre-scan HIR functions to detect which params need macro treatment.
|
|
20
|
+
* Returns a map: function name → MacroFunctionInfo.
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectMacroFunctions(hir: HIRModule): Map<string, MacroFunctionInfo>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Macro function detection — pre-scans HIR to find parameters used in
|
|
4
|
+
* builtin call positions (coordinates, entity types, etc.)
|
|
5
|
+
*
|
|
6
|
+
* A function becomes a "macro function" when one of its params appears
|
|
7
|
+
* in a position that requires literal substitution in the MC command
|
|
8
|
+
* (e.g. summon coords, particle coords, setblock coords, local/relative
|
|
9
|
+
* coords like ^px or ~height).
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.BUILTIN_SET = void 0;
|
|
13
|
+
exports.detectMacroFunctions = detectMacroFunctions;
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Known builtins that emit MC commands with inline arguments
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
/** Builtins whose arguments appear literally in MC commands */
|
|
18
|
+
exports.BUILTIN_SET = new Set([
|
|
19
|
+
'say', 'tell', 'tellraw', 'title', 'actionbar', 'subtitle', 'title_times',
|
|
20
|
+
'announce', 'give', 'kill', 'effect', 'effect_clear',
|
|
21
|
+
'summon', 'particle', 'playsound', 'clear', 'weather',
|
|
22
|
+
'time_set', 'time_add', 'gamerule', 'tag_add', 'tag_remove',
|
|
23
|
+
'kick', 'setblock', 'fill', 'clone', 'difficulty', 'xp_add', 'xp_set',
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Pre-scan HIR functions to detect which params need macro treatment.
|
|
27
|
+
* Returns a map: function name → MacroFunctionInfo.
|
|
28
|
+
*/
|
|
29
|
+
function detectMacroFunctions(hir) {
|
|
30
|
+
const result = new Map();
|
|
31
|
+
for (const fn of hir.functions) {
|
|
32
|
+
const paramNames = new Set(fn.params.map(p => p.name));
|
|
33
|
+
const macroParams = new Set();
|
|
34
|
+
scanBlock(fn.body, paramNames, macroParams);
|
|
35
|
+
if (macroParams.size > 0) {
|
|
36
|
+
const paramTypes = new Map();
|
|
37
|
+
for (const p of fn.params) {
|
|
38
|
+
const typeName = p.type?.kind === 'named' ? p.type.name : 'int';
|
|
39
|
+
paramTypes.set(p.name, typeName);
|
|
40
|
+
}
|
|
41
|
+
result.set(fn.name, { macroParams, paramTypes });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const ib of hir.implBlocks) {
|
|
45
|
+
for (const m of ib.methods) {
|
|
46
|
+
const paramNames = new Set(m.params.map(p => p.name));
|
|
47
|
+
const macroParams = new Set();
|
|
48
|
+
scanBlock(m.body, paramNames, macroParams);
|
|
49
|
+
if (macroParams.size > 0) {
|
|
50
|
+
const paramTypes = new Map();
|
|
51
|
+
for (const p of m.params) {
|
|
52
|
+
const typeName = p.type?.kind === 'named' ? p.type.name : 'int';
|
|
53
|
+
paramTypes.set(p.name, typeName);
|
|
54
|
+
}
|
|
55
|
+
result.set(`${ib.typeName}::${m.name}`, { macroParams, paramTypes });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// HIR scanning
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
function scanBlock(stmts, paramNames, macroParams) {
|
|
65
|
+
for (const stmt of stmts)
|
|
66
|
+
scanStmt(stmt, paramNames, macroParams);
|
|
67
|
+
}
|
|
68
|
+
function scanStmt(stmt, paramNames, macroParams) {
|
|
69
|
+
switch (stmt.kind) {
|
|
70
|
+
case 'expr':
|
|
71
|
+
scanExpr(stmt.expr, paramNames, macroParams);
|
|
72
|
+
break;
|
|
73
|
+
case 'let':
|
|
74
|
+
scanExpr(stmt.init, paramNames, macroParams);
|
|
75
|
+
break;
|
|
76
|
+
case 'return':
|
|
77
|
+
if (stmt.value)
|
|
78
|
+
scanExpr(stmt.value, paramNames, macroParams);
|
|
79
|
+
break;
|
|
80
|
+
case 'if':
|
|
81
|
+
scanExpr(stmt.cond, paramNames, macroParams);
|
|
82
|
+
scanBlock(stmt.then, paramNames, macroParams);
|
|
83
|
+
if (stmt.else_)
|
|
84
|
+
scanBlock(stmt.else_, paramNames, macroParams);
|
|
85
|
+
break;
|
|
86
|
+
case 'while':
|
|
87
|
+
scanExpr(stmt.cond, paramNames, macroParams);
|
|
88
|
+
scanBlock(stmt.body, paramNames, macroParams);
|
|
89
|
+
if (stmt.step)
|
|
90
|
+
scanBlock(stmt.step, paramNames, macroParams);
|
|
91
|
+
break;
|
|
92
|
+
case 'foreach':
|
|
93
|
+
scanBlock(stmt.body, paramNames, macroParams);
|
|
94
|
+
break;
|
|
95
|
+
case 'match':
|
|
96
|
+
scanExpr(stmt.expr, paramNames, macroParams);
|
|
97
|
+
for (const arm of stmt.arms)
|
|
98
|
+
scanBlock(arm.body, paramNames, macroParams);
|
|
99
|
+
break;
|
|
100
|
+
case 'execute':
|
|
101
|
+
scanBlock(stmt.body, paramNames, macroParams);
|
|
102
|
+
break;
|
|
103
|
+
case 'raw': break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function scanExpr(expr, paramNames, macroParams) {
|
|
107
|
+
if (expr.kind === 'call' && exports.BUILTIN_SET.has(expr.fn)) {
|
|
108
|
+
// Check if any argument is a param identifier or a coord with a param variable
|
|
109
|
+
for (const arg of expr.args) {
|
|
110
|
+
checkMacroArg(arg, paramNames, macroParams);
|
|
111
|
+
}
|
|
112
|
+
// Recurse into args for nested expressions
|
|
113
|
+
for (const arg of expr.args)
|
|
114
|
+
scanExpr(arg, paramNames, macroParams);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// Recurse into sub-expressions
|
|
118
|
+
switch (expr.kind) {
|
|
119
|
+
case 'call':
|
|
120
|
+
for (const arg of expr.args)
|
|
121
|
+
scanExpr(arg, paramNames, macroParams);
|
|
122
|
+
break;
|
|
123
|
+
case 'invoke':
|
|
124
|
+
scanExpr(expr.callee, paramNames, macroParams);
|
|
125
|
+
for (const arg of expr.args)
|
|
126
|
+
scanExpr(arg, paramNames, macroParams);
|
|
127
|
+
break;
|
|
128
|
+
case 'binary':
|
|
129
|
+
scanExpr(expr.left, paramNames, macroParams);
|
|
130
|
+
scanExpr(expr.right, paramNames, macroParams);
|
|
131
|
+
break;
|
|
132
|
+
case 'unary':
|
|
133
|
+
scanExpr(expr.operand, paramNames, macroParams);
|
|
134
|
+
break;
|
|
135
|
+
case 'assign':
|
|
136
|
+
scanExpr(expr.value, paramNames, macroParams);
|
|
137
|
+
break;
|
|
138
|
+
case 'member_assign':
|
|
139
|
+
scanExpr(expr.obj, paramNames, macroParams);
|
|
140
|
+
scanExpr(expr.value, paramNames, macroParams);
|
|
141
|
+
break;
|
|
142
|
+
case 'member':
|
|
143
|
+
scanExpr(expr.obj, paramNames, macroParams);
|
|
144
|
+
break;
|
|
145
|
+
case 'index':
|
|
146
|
+
scanExpr(expr.obj, paramNames, macroParams);
|
|
147
|
+
scanExpr(expr.index, paramNames, macroParams);
|
|
148
|
+
break;
|
|
149
|
+
case 'static_call':
|
|
150
|
+
for (const arg of expr.args)
|
|
151
|
+
scanExpr(arg, paramNames, macroParams);
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** Check if a single argument expression references a function parameter in a macro position */
|
|
156
|
+
function checkMacroArg(expr, paramNames, macroParams) {
|
|
157
|
+
if (expr.kind === 'ident' && paramNames.has(expr.name)) {
|
|
158
|
+
macroParams.add(expr.name);
|
|
159
|
+
}
|
|
160
|
+
else if (expr.kind === 'local_coord' || expr.kind === 'rel_coord') {
|
|
161
|
+
// ^varname or ~varname — extract the variable part
|
|
162
|
+
const rest = expr.value.slice(1);
|
|
163
|
+
if (rest && /^[a-zA-Z_]\w*$/.test(rest) && paramNames.has(rest)) {
|
|
164
|
+
macroParams.add(rest);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=macro.js.map
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIR (Mid-level IR) Types — Stage 3 of the RedScript compiler pipeline.
|
|
3
|
+
*
|
|
4
|
+
* MIR is a 3-address, explicit-CFG representation with versioned temporaries.
|
|
5
|
+
* Every instruction produces at most one result into a fresh temporary.
|
|
6
|
+
*
|
|
7
|
+
* Spec: docs/compiler-pipeline-redesign.md § "MIR Instruction Set"
|
|
8
|
+
*/
|
|
9
|
+
export type Temp = string;
|
|
10
|
+
export type Operand = {
|
|
11
|
+
kind: 'temp';
|
|
12
|
+
name: Temp;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'const';
|
|
15
|
+
value: number;
|
|
16
|
+
};
|
|
17
|
+
export type BlockId = string;
|
|
18
|
+
export type CmpOp = 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge';
|
|
19
|
+
export type NBTType = 'int' | 'double' | 'float' | 'long' | 'short' | 'byte';
|
|
20
|
+
export type ExecuteSubcmd = {
|
|
21
|
+
kind: 'as';
|
|
22
|
+
selector: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'at';
|
|
25
|
+
selector: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'at_self';
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'positioned';
|
|
30
|
+
x: string;
|
|
31
|
+
y: string;
|
|
32
|
+
z: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'rotated';
|
|
35
|
+
yaw: string;
|
|
36
|
+
pitch: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'in';
|
|
39
|
+
dimension: string;
|
|
40
|
+
} | {
|
|
41
|
+
kind: 'anchored';
|
|
42
|
+
anchor: 'eyes' | 'feet';
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'if_score';
|
|
45
|
+
a: string;
|
|
46
|
+
op: CmpOp;
|
|
47
|
+
b: string;
|
|
48
|
+
} | {
|
|
49
|
+
kind: 'unless_score';
|
|
50
|
+
a: string;
|
|
51
|
+
op: CmpOp;
|
|
52
|
+
b: string;
|
|
53
|
+
} | {
|
|
54
|
+
kind: 'if_matches';
|
|
55
|
+
score: string;
|
|
56
|
+
range: string;
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'unless_matches';
|
|
59
|
+
score: string;
|
|
60
|
+
range: string;
|
|
61
|
+
};
|
|
62
|
+
export type MIRInstr = {
|
|
63
|
+
kind: 'const';
|
|
64
|
+
dst: Temp;
|
|
65
|
+
value: number;
|
|
66
|
+
} | {
|
|
67
|
+
kind: 'copy';
|
|
68
|
+
dst: Temp;
|
|
69
|
+
src: Operand;
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'add';
|
|
72
|
+
dst: Temp;
|
|
73
|
+
a: Operand;
|
|
74
|
+
b: Operand;
|
|
75
|
+
} | {
|
|
76
|
+
kind: 'sub';
|
|
77
|
+
dst: Temp;
|
|
78
|
+
a: Operand;
|
|
79
|
+
b: Operand;
|
|
80
|
+
} | {
|
|
81
|
+
kind: 'mul';
|
|
82
|
+
dst: Temp;
|
|
83
|
+
a: Operand;
|
|
84
|
+
b: Operand;
|
|
85
|
+
} | {
|
|
86
|
+
kind: 'div';
|
|
87
|
+
dst: Temp;
|
|
88
|
+
a: Operand;
|
|
89
|
+
b: Operand;
|
|
90
|
+
} | {
|
|
91
|
+
kind: 'mod';
|
|
92
|
+
dst: Temp;
|
|
93
|
+
a: Operand;
|
|
94
|
+
b: Operand;
|
|
95
|
+
} | {
|
|
96
|
+
kind: 'neg';
|
|
97
|
+
dst: Temp;
|
|
98
|
+
src: Operand;
|
|
99
|
+
} | {
|
|
100
|
+
kind: 'cmp';
|
|
101
|
+
dst: Temp;
|
|
102
|
+
op: CmpOp;
|
|
103
|
+
a: Operand;
|
|
104
|
+
b: Operand;
|
|
105
|
+
} | {
|
|
106
|
+
kind: 'and';
|
|
107
|
+
dst: Temp;
|
|
108
|
+
a: Operand;
|
|
109
|
+
b: Operand;
|
|
110
|
+
} | {
|
|
111
|
+
kind: 'or';
|
|
112
|
+
dst: Temp;
|
|
113
|
+
a: Operand;
|
|
114
|
+
b: Operand;
|
|
115
|
+
} | {
|
|
116
|
+
kind: 'not';
|
|
117
|
+
dst: Temp;
|
|
118
|
+
src: Operand;
|
|
119
|
+
} | {
|
|
120
|
+
kind: 'nbt_read';
|
|
121
|
+
dst: Temp;
|
|
122
|
+
ns: string;
|
|
123
|
+
path: string;
|
|
124
|
+
scale: number;
|
|
125
|
+
} | {
|
|
126
|
+
kind: 'nbt_write';
|
|
127
|
+
ns: string;
|
|
128
|
+
path: string;
|
|
129
|
+
type: NBTType;
|
|
130
|
+
scale: number;
|
|
131
|
+
src: Operand;
|
|
132
|
+
} | {
|
|
133
|
+
kind: 'call';
|
|
134
|
+
dst: Temp | null;
|
|
135
|
+
fn: string;
|
|
136
|
+
args: Operand[];
|
|
137
|
+
} | {
|
|
138
|
+
kind: 'call_macro';
|
|
139
|
+
dst: Temp | null;
|
|
140
|
+
fn: string;
|
|
141
|
+
args: {
|
|
142
|
+
name: string;
|
|
143
|
+
value: Operand;
|
|
144
|
+
type: NBTType;
|
|
145
|
+
scale: number;
|
|
146
|
+
}[];
|
|
147
|
+
} | {
|
|
148
|
+
kind: 'call_context';
|
|
149
|
+
fn: string;
|
|
150
|
+
subcommands: ExecuteSubcmd[];
|
|
151
|
+
} | {
|
|
152
|
+
kind: 'jump';
|
|
153
|
+
target: BlockId;
|
|
154
|
+
} | {
|
|
155
|
+
kind: 'branch';
|
|
156
|
+
cond: Operand;
|
|
157
|
+
then: BlockId;
|
|
158
|
+
else: BlockId;
|
|
159
|
+
} | {
|
|
160
|
+
kind: 'return';
|
|
161
|
+
value: Operand | null;
|
|
162
|
+
};
|
|
163
|
+
export interface MIRBlock {
|
|
164
|
+
id: BlockId;
|
|
165
|
+
instrs: MIRInstr[];
|
|
166
|
+
term: MIRInstr;
|
|
167
|
+
preds: BlockId[];
|
|
168
|
+
}
|
|
169
|
+
export interface MIRFunction {
|
|
170
|
+
name: string;
|
|
171
|
+
params: {
|
|
172
|
+
name: Temp;
|
|
173
|
+
isMacroParam: boolean;
|
|
174
|
+
}[];
|
|
175
|
+
blocks: MIRBlock[];
|
|
176
|
+
entry: BlockId;
|
|
177
|
+
isMacro: boolean;
|
|
178
|
+
}
|
|
179
|
+
export interface MIRModule {
|
|
180
|
+
functions: MIRFunction[];
|
|
181
|
+
namespace: string;
|
|
182
|
+
objective: string;
|
|
183
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MIR (Mid-level IR) Types — Stage 3 of the RedScript compiler pipeline.
|
|
4
|
+
*
|
|
5
|
+
* MIR is a 3-address, explicit-CFG representation with versioned temporaries.
|
|
6
|
+
* Every instruction produces at most one result into a fresh temporary.
|
|
7
|
+
*
|
|
8
|
+
* Spec: docs/compiler-pipeline-redesign.md § "MIR Instruction Set"
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIR Verifier — validates structural invariants of MIR modules.
|
|
3
|
+
*
|
|
4
|
+
* Checks:
|
|
5
|
+
* 1. Every block ends with exactly one terminator (jump | branch | return)
|
|
6
|
+
* 2. Every temp used is defined before use (in the block or as a param)
|
|
7
|
+
* 3. No unreachable blocks (all blocks reachable from entry)
|
|
8
|
+
* 4. Branch/jump targets must exist in the function
|
|
9
|
+
*/
|
|
10
|
+
import type { MIRModule } from './types';
|
|
11
|
+
export interface VerifyError {
|
|
12
|
+
fn: string;
|
|
13
|
+
block?: string;
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function verifyMIR(module: MIRModule): VerifyError[];
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MIR Verifier — validates structural invariants of MIR modules.
|
|
4
|
+
*
|
|
5
|
+
* Checks:
|
|
6
|
+
* 1. Every block ends with exactly one terminator (jump | branch | return)
|
|
7
|
+
* 2. Every temp used is defined before use (in the block or as a param)
|
|
8
|
+
* 3. No unreachable blocks (all blocks reachable from entry)
|
|
9
|
+
* 4. Branch/jump targets must exist in the function
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.verifyMIR = verifyMIR;
|
|
13
|
+
function verifyMIR(module) {
|
|
14
|
+
const errors = [];
|
|
15
|
+
for (const fn of module.functions) {
|
|
16
|
+
errors.push(...verifyFunction(fn));
|
|
17
|
+
}
|
|
18
|
+
return errors;
|
|
19
|
+
}
|
|
20
|
+
function verifyFunction(fn) {
|
|
21
|
+
const errors = [];
|
|
22
|
+
const blockIds = new Set(fn.blocks.map(b => b.id));
|
|
23
|
+
// 1. Check terminators
|
|
24
|
+
for (const block of fn.blocks) {
|
|
25
|
+
if (!isTerminator(block.term)) {
|
|
26
|
+
errors.push({
|
|
27
|
+
fn: fn.name,
|
|
28
|
+
block: block.id,
|
|
29
|
+
message: `block '${block.id}' does not end with a terminator (found '${block.term.kind}')`,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// Check that no non-terminator instruction is a terminator
|
|
33
|
+
for (const instr of block.instrs) {
|
|
34
|
+
if (isTerminator(instr)) {
|
|
35
|
+
errors.push({
|
|
36
|
+
fn: fn.name,
|
|
37
|
+
block: block.id,
|
|
38
|
+
message: `block '${block.id}' has terminator '${instr.kind}' in non-terminal position`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// 2. Check that branch/jump targets exist
|
|
44
|
+
for (const block of fn.blocks) {
|
|
45
|
+
const targets = getTermTargets(block.term);
|
|
46
|
+
for (const target of targets) {
|
|
47
|
+
if (!blockIds.has(target)) {
|
|
48
|
+
errors.push({
|
|
49
|
+
fn: fn.name,
|
|
50
|
+
block: block.id,
|
|
51
|
+
message: `block '${block.id}' references non-existent target '${target}'`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// 3. Check reachability from entry
|
|
57
|
+
const reachable = new Set();
|
|
58
|
+
const entryBlock = fn.blocks.find(b => b.id === fn.entry);
|
|
59
|
+
if (!entryBlock) {
|
|
60
|
+
errors.push({
|
|
61
|
+
fn: fn.name,
|
|
62
|
+
message: `entry block '${fn.entry}' not found`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// BFS from entry
|
|
67
|
+
const queue = [fn.entry];
|
|
68
|
+
while (queue.length > 0) {
|
|
69
|
+
const id = queue.shift();
|
|
70
|
+
if (reachable.has(id))
|
|
71
|
+
continue;
|
|
72
|
+
reachable.add(id);
|
|
73
|
+
const block = fn.blocks.find(b => b.id === id);
|
|
74
|
+
if (block) {
|
|
75
|
+
for (const target of getTermTargets(block.term)) {
|
|
76
|
+
if (!reachable.has(target)) {
|
|
77
|
+
queue.push(target);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const block of fn.blocks) {
|
|
83
|
+
if (!reachable.has(block.id)) {
|
|
84
|
+
errors.push({
|
|
85
|
+
fn: fn.name,
|
|
86
|
+
block: block.id,
|
|
87
|
+
message: `block '${block.id}' is unreachable from entry`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// 4. Check use-before-def for temporaries
|
|
93
|
+
// Collect all defined temps: params + all dst fields in instructions
|
|
94
|
+
const allDefs = new Set();
|
|
95
|
+
for (const p of fn.params)
|
|
96
|
+
allDefs.add(p.name);
|
|
97
|
+
for (const block of fn.blocks) {
|
|
98
|
+
for (const instr of block.instrs) {
|
|
99
|
+
const dst = getDst(instr);
|
|
100
|
+
if (dst)
|
|
101
|
+
allDefs.add(dst);
|
|
102
|
+
}
|
|
103
|
+
const termDst = getDst(block.term);
|
|
104
|
+
if (termDst)
|
|
105
|
+
allDefs.add(termDst);
|
|
106
|
+
}
|
|
107
|
+
// Check that every temp used in an operand is in allDefs
|
|
108
|
+
for (const block of fn.blocks) {
|
|
109
|
+
for (const instr of block.instrs) {
|
|
110
|
+
for (const used of getUsedTemps(instr)) {
|
|
111
|
+
if (!allDefs.has(used)) {
|
|
112
|
+
errors.push({
|
|
113
|
+
fn: fn.name,
|
|
114
|
+
block: block.id,
|
|
115
|
+
message: `temp '${used}' used but never defined`,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (const used of getUsedTemps(block.term)) {
|
|
121
|
+
if (!allDefs.has(used)) {
|
|
122
|
+
errors.push({
|
|
123
|
+
fn: fn.name,
|
|
124
|
+
block: block.id,
|
|
125
|
+
message: `temp '${used}' used in terminator but never defined`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return errors;
|
|
131
|
+
}
|
|
132
|
+
function isTerminator(instr) {
|
|
133
|
+
return instr.kind === 'jump' || instr.kind === 'branch' || instr.kind === 'return';
|
|
134
|
+
}
|
|
135
|
+
function getTermTargets(term) {
|
|
136
|
+
switch (term.kind) {
|
|
137
|
+
case 'jump': return [term.target];
|
|
138
|
+
case 'branch': return [term.then, term.else];
|
|
139
|
+
case 'return': return [];
|
|
140
|
+
default: return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function getDst(instr) {
|
|
144
|
+
switch (instr.kind) {
|
|
145
|
+
case 'const':
|
|
146
|
+
case 'copy':
|
|
147
|
+
case 'add':
|
|
148
|
+
case 'sub':
|
|
149
|
+
case 'mul':
|
|
150
|
+
case 'div':
|
|
151
|
+
case 'mod':
|
|
152
|
+
case 'neg':
|
|
153
|
+
case 'cmp':
|
|
154
|
+
case 'and':
|
|
155
|
+
case 'or':
|
|
156
|
+
case 'not':
|
|
157
|
+
case 'nbt_read':
|
|
158
|
+
return instr.dst;
|
|
159
|
+
case 'call':
|
|
160
|
+
case 'call_macro':
|
|
161
|
+
return instr.dst;
|
|
162
|
+
default:
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function getOperandTemps(op) {
|
|
167
|
+
return op.kind === 'temp' ? [op.name] : [];
|
|
168
|
+
}
|
|
169
|
+
function getUsedTemps(instr) {
|
|
170
|
+
const temps = [];
|
|
171
|
+
switch (instr.kind) {
|
|
172
|
+
case 'const':
|
|
173
|
+
break;
|
|
174
|
+
case 'copy':
|
|
175
|
+
case 'neg':
|
|
176
|
+
case 'not':
|
|
177
|
+
temps.push(...getOperandTemps(instr.src));
|
|
178
|
+
break;
|
|
179
|
+
case 'add':
|
|
180
|
+
case 'sub':
|
|
181
|
+
case 'mul':
|
|
182
|
+
case 'div':
|
|
183
|
+
case 'mod':
|
|
184
|
+
case 'cmp':
|
|
185
|
+
case 'and':
|
|
186
|
+
case 'or':
|
|
187
|
+
temps.push(...getOperandTemps(instr.a), ...getOperandTemps(instr.b));
|
|
188
|
+
break;
|
|
189
|
+
case 'nbt_read':
|
|
190
|
+
break;
|
|
191
|
+
case 'nbt_write':
|
|
192
|
+
temps.push(...getOperandTemps(instr.src));
|
|
193
|
+
break;
|
|
194
|
+
case 'call':
|
|
195
|
+
for (const arg of instr.args)
|
|
196
|
+
temps.push(...getOperandTemps(arg));
|
|
197
|
+
break;
|
|
198
|
+
case 'call_macro':
|
|
199
|
+
for (const arg of instr.args)
|
|
200
|
+
temps.push(...getOperandTemps(arg.value));
|
|
201
|
+
break;
|
|
202
|
+
case 'call_context':
|
|
203
|
+
break;
|
|
204
|
+
case 'jump':
|
|
205
|
+
break;
|
|
206
|
+
case 'branch':
|
|
207
|
+
temps.push(...getOperandTemps(instr.cond));
|
|
208
|
+
break;
|
|
209
|
+
case 'return':
|
|
210
|
+
if (instr.value)
|
|
211
|
+
temps.push(...getOperandTemps(instr.value));
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
return temps;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block Merging — MIR optimization pass.
|
|
3
|
+
*
|
|
4
|
+
* Merges a block B into its sole predecessor A when:
|
|
5
|
+
* - A ends with an unconditional jump to B
|
|
6
|
+
* - B has exactly one predecessor (A)
|
|
7
|
+
* - B is not the entry block
|
|
8
|
+
*
|
|
9
|
+
* The merged block keeps A's id and combines A's instrs + B's instrs + B's terminator.
|
|
10
|
+
*/
|
|
11
|
+
import type { MIRFunction } from '../mir/types';
|
|
12
|
+
export declare function blockMerge(fn: MIRFunction): MIRFunction;
|