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,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateStructure = generateStructure;
|
|
4
|
+
exports.compileToStructure = compileToStructure;
|
|
5
|
+
const lexer_1 = require("../../lexer");
|
|
6
|
+
const parser_1 = require("../../parser");
|
|
7
|
+
const lowering_1 = require("../../lowering");
|
|
8
|
+
const nbt_1 = require("../../nbt");
|
|
9
|
+
const commands_1 = require("../../optimizer/commands");
|
|
10
|
+
const passes_1 = require("../../optimizer/passes");
|
|
11
|
+
const structure_1 = require("../../optimizer/structure");
|
|
12
|
+
const dce_1 = require("../../optimizer/dce");
|
|
13
|
+
const compile_1 = require("../../compile");
|
|
14
|
+
const types_1 = require("../../events/types");
|
|
15
|
+
const var_allocator_1 = require("../var-allocator");
|
|
16
|
+
const DATA_VERSION = 3953;
|
|
17
|
+
const MAX_WIDTH = 16;
|
|
18
|
+
const OBJ = 'rs';
|
|
19
|
+
const PALETTE_IMPULSE = 0;
|
|
20
|
+
const PALETTE_CHAIN_UNCONDITIONAL = 1;
|
|
21
|
+
const PALETTE_CHAIN_CONDITIONAL = 2;
|
|
22
|
+
const PALETTE_REPEAT = 3;
|
|
23
|
+
const palette = [
|
|
24
|
+
{ Name: 'minecraft:command_block', Properties: { conditional: 'false', facing: 'east' } },
|
|
25
|
+
{ Name: 'minecraft:chain_command_block', Properties: { conditional: 'false', facing: 'east' } },
|
|
26
|
+
{ Name: 'minecraft:chain_command_block', Properties: { conditional: 'true', facing: 'east' } },
|
|
27
|
+
{ Name: 'minecraft:repeating_command_block', Properties: { conditional: 'false', facing: 'east' } },
|
|
28
|
+
{ Name: 'minecraft:air', Properties: {} },
|
|
29
|
+
];
|
|
30
|
+
function escapeJsonString(value) {
|
|
31
|
+
return JSON.stringify(value).slice(1, -1);
|
|
32
|
+
}
|
|
33
|
+
function collectConsts(fn) {
|
|
34
|
+
const consts = new Set();
|
|
35
|
+
for (const block of fn.blocks) {
|
|
36
|
+
for (const instr of block.instrs) {
|
|
37
|
+
if (instr.op === 'assign' && instr.src.kind === 'const')
|
|
38
|
+
consts.add(instr.src.value);
|
|
39
|
+
if (instr.op === 'binop') {
|
|
40
|
+
if (instr.lhs.kind === 'const')
|
|
41
|
+
consts.add(instr.lhs.value);
|
|
42
|
+
if (instr.rhs.kind === 'const')
|
|
43
|
+
consts.add(instr.rhs.value);
|
|
44
|
+
}
|
|
45
|
+
if (instr.op === 'cmp') {
|
|
46
|
+
if (instr.lhs.kind === 'const')
|
|
47
|
+
consts.add(instr.lhs.value);
|
|
48
|
+
if (instr.rhs.kind === 'const')
|
|
49
|
+
consts.add(instr.rhs.value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (block.term.op === 'return' && block.term.value?.kind === 'const') {
|
|
53
|
+
consts.add(block.term.value.value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return consts;
|
|
57
|
+
}
|
|
58
|
+
function collectCommandEntriesFromModule(module, mangle = false) {
|
|
59
|
+
const alloc = new var_allocator_1.VarAllocator(mangle);
|
|
60
|
+
const entries = [];
|
|
61
|
+
const triggerHandlers = module.functions.filter(fn => fn.isTriggerHandler && fn.triggerName);
|
|
62
|
+
const triggerNames = new Set(triggerHandlers.map(fn => fn.triggerName));
|
|
63
|
+
const eventHandlers = module.functions.filter((fn) => !!fn.eventHandler && (0, types_1.isEventTypeName)(fn.eventHandler.eventType));
|
|
64
|
+
const eventTypes = new Set(eventHandlers.map(fn => fn.eventHandler.eventType));
|
|
65
|
+
const loadCommands = [
|
|
66
|
+
`scoreboard objectives add ${OBJ} dummy`,
|
|
67
|
+
...module.globals.map(g => `scoreboard players set ${alloc.alloc(g.name)} ${OBJ} ${g.init}`),
|
|
68
|
+
...Array.from(triggerNames).flatMap(triggerName => [
|
|
69
|
+
`scoreboard objectives add ${triggerName} trigger`,
|
|
70
|
+
`scoreboard players enable @a ${triggerName}`,
|
|
71
|
+
]),
|
|
72
|
+
...Array.from(new Set(module.functions.flatMap(fn => Array.from(collectConsts(fn))))).map(value => `scoreboard players set ${alloc.constant(value)} ${OBJ} ${value}`),
|
|
73
|
+
];
|
|
74
|
+
for (const eventType of eventTypes) {
|
|
75
|
+
if (eventType === 'PlayerDeath') {
|
|
76
|
+
loadCommands.push('scoreboard objectives add rs.deaths deathCount');
|
|
77
|
+
}
|
|
78
|
+
else if (eventType === 'EntityKill') {
|
|
79
|
+
loadCommands.push('scoreboard objectives add rs.kills totalKillCount');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Call @load functions from __load
|
|
83
|
+
for (const fn of module.functions) {
|
|
84
|
+
if (fn.isLoadInit) {
|
|
85
|
+
loadCommands.push(`function ${module.namespace}:${fn.name}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const sections = [];
|
|
89
|
+
if (loadCommands.length > 0) {
|
|
90
|
+
sections.push({
|
|
91
|
+
name: '__load',
|
|
92
|
+
commands: loadCommands.map(cmd => ({ cmd })),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
for (const triggerName of triggerNames) {
|
|
96
|
+
const handlers = triggerHandlers.filter(fn => fn.triggerName === triggerName);
|
|
97
|
+
sections.push({
|
|
98
|
+
name: `__trigger_${triggerName}_dispatch`,
|
|
99
|
+
commands: [
|
|
100
|
+
...handlers.map(handler => ({ cmd: `function ${module.namespace}:${handler.name}` })),
|
|
101
|
+
{ cmd: `scoreboard players set @s ${triggerName} 0` },
|
|
102
|
+
{ cmd: `scoreboard players enable @s ${triggerName}` },
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
for (const fn of module.functions) {
|
|
107
|
+
if (!fn.commands || fn.commands.length === 0)
|
|
108
|
+
continue;
|
|
109
|
+
sections.push({
|
|
110
|
+
name: fn.name,
|
|
111
|
+
commands: fn.commands,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const tickCommands = [];
|
|
115
|
+
for (const fn of module.functions.filter(candidate => candidate.isTickLoop)) {
|
|
116
|
+
tickCommands.push({ cmd: `function ${module.namespace}:${fn.name}` });
|
|
117
|
+
}
|
|
118
|
+
if (triggerNames.size > 0) {
|
|
119
|
+
for (const triggerName of triggerNames) {
|
|
120
|
+
tickCommands.push({
|
|
121
|
+
cmd: `execute as @a[scores={${triggerName}=1..}] run function ${module.namespace}:__trigger_${triggerName}_dispatch`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (eventHandlers.length > 0) {
|
|
126
|
+
for (const eventType of eventTypes) {
|
|
127
|
+
const tag = types_1.EVENT_TYPES[eventType].tag;
|
|
128
|
+
const handlers = eventHandlers.filter(fn => fn.eventHandler?.eventType === eventType);
|
|
129
|
+
for (const handler of handlers) {
|
|
130
|
+
tickCommands.push({
|
|
131
|
+
cmd: `execute as @a[tag=${tag}] run function ${module.namespace}:${handler.name}`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
tickCommands.push({
|
|
135
|
+
cmd: `tag @a[tag=${tag}] remove ${tag}`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (tickCommands.length > 0) {
|
|
140
|
+
sections.push({
|
|
141
|
+
name: '__tick',
|
|
142
|
+
commands: tickCommands,
|
|
143
|
+
repeat: true,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
for (const section of sections) {
|
|
147
|
+
for (let i = 0; i < section.commands.length; i++) {
|
|
148
|
+
const command = section.commands[i];
|
|
149
|
+
const state = i === 0
|
|
150
|
+
? (section.repeat ? PALETTE_REPEAT : PALETTE_IMPULSE)
|
|
151
|
+
: (command.conditional ? PALETTE_CHAIN_CONDITIONAL : PALETTE_CHAIN_UNCONDITIONAL);
|
|
152
|
+
entries.push({
|
|
153
|
+
functionName: section.name,
|
|
154
|
+
lineNumber: i + 1,
|
|
155
|
+
command: command.cmd,
|
|
156
|
+
conditional: Boolean(command.conditional),
|
|
157
|
+
state,
|
|
158
|
+
isRepeat: Boolean(section.repeat && i === 0),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return entries;
|
|
163
|
+
}
|
|
164
|
+
function toFunctionName(file) {
|
|
165
|
+
const match = file.path.match(/^data\/[^/]+\/function\/(.+)\.mcfunction$/);
|
|
166
|
+
return match?.[1] ?? null;
|
|
167
|
+
}
|
|
168
|
+
function collectCommandEntriesFromFiles(files) {
|
|
169
|
+
const entries = [];
|
|
170
|
+
for (const file of files) {
|
|
171
|
+
const functionName = toFunctionName(file);
|
|
172
|
+
if (!functionName)
|
|
173
|
+
continue;
|
|
174
|
+
const lines = file.content.split('\n');
|
|
175
|
+
let isFirstCommand = true;
|
|
176
|
+
const isTickFunction = functionName === '__tick';
|
|
177
|
+
for (let i = 0; i < lines.length; i++) {
|
|
178
|
+
const command = lines[i].trim();
|
|
179
|
+
if (command === '' || command.startsWith('#'))
|
|
180
|
+
continue;
|
|
181
|
+
const state = isFirstCommand
|
|
182
|
+
? (isTickFunction ? PALETTE_REPEAT : PALETTE_IMPULSE)
|
|
183
|
+
: PALETTE_CHAIN_UNCONDITIONAL;
|
|
184
|
+
entries.push({
|
|
185
|
+
functionName,
|
|
186
|
+
lineNumber: i + 1,
|
|
187
|
+
command,
|
|
188
|
+
conditional: false,
|
|
189
|
+
state,
|
|
190
|
+
isRepeat: isTickFunction && isFirstCommand,
|
|
191
|
+
});
|
|
192
|
+
isFirstCommand = false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return entries;
|
|
196
|
+
}
|
|
197
|
+
function createPaletteTag() {
|
|
198
|
+
return palette.map(entry => nbt_1.nbt.compound({
|
|
199
|
+
Name: nbt_1.nbt.string(entry.Name),
|
|
200
|
+
Properties: nbt_1.nbt.compound(Object.fromEntries(Object.entries(entry.Properties).map(([key, value]) => [key, nbt_1.nbt.string(value)]))),
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
function createBlockEntityTag(entry) {
|
|
204
|
+
return nbt_1.nbt.compound({
|
|
205
|
+
id: nbt_1.nbt.string('minecraft:command_block'),
|
|
206
|
+
Command: nbt_1.nbt.string(entry.command),
|
|
207
|
+
auto: nbt_1.nbt.byte(entry.isRepeat ? 1 : 0),
|
|
208
|
+
powered: nbt_1.nbt.byte(0),
|
|
209
|
+
conditionMet: nbt_1.nbt.byte(0),
|
|
210
|
+
UpdateLastExecution: nbt_1.nbt.byte(1),
|
|
211
|
+
LastExecution: nbt_1.nbt.long(0n),
|
|
212
|
+
TrackOutput: nbt_1.nbt.byte(1),
|
|
213
|
+
SuccessCount: nbt_1.nbt.int(0),
|
|
214
|
+
LastOutput: nbt_1.nbt.string(''),
|
|
215
|
+
CustomName: nbt_1.nbt.string(`{"text":"${escapeJsonString(`${entry.functionName}:${entry.lineNumber}`)}"}`),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function createBlockTag(entry, index) {
|
|
219
|
+
const x = index % MAX_WIDTH;
|
|
220
|
+
const z = Math.floor(index / MAX_WIDTH) % MAX_WIDTH;
|
|
221
|
+
const y = Math.floor(index / (MAX_WIDTH * MAX_WIDTH));
|
|
222
|
+
return nbt_1.nbt.compound({
|
|
223
|
+
pos: nbt_1.nbt.list(3 /* TagType.Int */, [nbt_1.nbt.int(x), nbt_1.nbt.int(y), nbt_1.nbt.int(z)]),
|
|
224
|
+
state: nbt_1.nbt.int(entry.state),
|
|
225
|
+
nbt: createBlockEntityTag(entry),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
function generateStructure(input, options) {
|
|
229
|
+
const entries = Array.isArray(input)
|
|
230
|
+
? collectCommandEntriesFromFiles(input)
|
|
231
|
+
: collectCommandEntriesFromModule(input, options?.mangle);
|
|
232
|
+
const blockTags = entries.map(createBlockTag);
|
|
233
|
+
const sizeX = Math.max(1, Math.min(MAX_WIDTH, entries.length || 1));
|
|
234
|
+
const sizeZ = Math.max(1, Math.min(MAX_WIDTH, Math.ceil(entries.length / MAX_WIDTH) || 1));
|
|
235
|
+
const sizeY = Math.max(1, Math.ceil(entries.length / (MAX_WIDTH * MAX_WIDTH)) || 1);
|
|
236
|
+
const root = nbt_1.nbt.compound({
|
|
237
|
+
DataVersion: nbt_1.nbt.int(DATA_VERSION),
|
|
238
|
+
size: nbt_1.nbt.list(3 /* TagType.Int */, [nbt_1.nbt.int(sizeX), nbt_1.nbt.int(sizeY), nbt_1.nbt.int(sizeZ)]),
|
|
239
|
+
palette: nbt_1.nbt.list(10 /* TagType.Compound */, createPaletteTag()),
|
|
240
|
+
blocks: nbt_1.nbt.list(10 /* TagType.Compound */, blockTags),
|
|
241
|
+
entities: nbt_1.nbt.list(10 /* TagType.Compound */, []),
|
|
242
|
+
});
|
|
243
|
+
return {
|
|
244
|
+
buffer: (0, nbt_1.writeNbt)(root, ''),
|
|
245
|
+
blockCount: entries.length,
|
|
246
|
+
blocks: entries.map(entry => ({
|
|
247
|
+
command: entry.command,
|
|
248
|
+
conditional: entry.conditional,
|
|
249
|
+
state: entry.state,
|
|
250
|
+
functionName: entry.functionName,
|
|
251
|
+
lineNumber: entry.lineNumber,
|
|
252
|
+
})),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function compileToStructure(source, namespace, filePath, options = {}) {
|
|
256
|
+
const preprocessedSource = (0, compile_1.preprocessSource)(source, { filePath });
|
|
257
|
+
const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
|
|
258
|
+
const parsedAst = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
|
|
259
|
+
const dceResult = options.dce ?? true ? (0, dce_1.eliminateDeadCode)(parsedAst) : { program: parsedAst, warnings: [] };
|
|
260
|
+
const ast = dceResult.program;
|
|
261
|
+
const ir = new lowering_1.Lowering(namespace).lower(ast);
|
|
262
|
+
const stats = (0, commands_1.createEmptyOptimizationStats)();
|
|
263
|
+
const optimizedIRFunctions = ir.functions.map(fn => {
|
|
264
|
+
const optimized = (0, passes_1.optimizeWithStats)(fn);
|
|
265
|
+
(0, commands_1.mergeOptimizationStats)(stats, optimized.stats);
|
|
266
|
+
return optimized.fn;
|
|
267
|
+
});
|
|
268
|
+
const structureOptimized = (0, structure_1.optimizeForStructureWithStats)(optimizedIRFunctions, namespace);
|
|
269
|
+
(0, commands_1.mergeOptimizationStats)(stats, structureOptimized.stats);
|
|
270
|
+
const optimizedModule = {
|
|
271
|
+
...ir,
|
|
272
|
+
functions: structureOptimized.functions,
|
|
273
|
+
};
|
|
274
|
+
return {
|
|
275
|
+
...generateStructure(optimizedModule, { mangle: options.mangle }),
|
|
276
|
+
stats,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VarAllocator — assigns scoreboard fake-player names to variables.
|
|
3
|
+
*
|
|
4
|
+
* mangle=true: sequential short names ($a, $b, ..., $z, $aa, $ab, ...)
|
|
5
|
+
* mangle=false: legacy names ($<name> for vars, $const_<v> for consts, $p0/$ret for internals)
|
|
6
|
+
*/
|
|
7
|
+
export declare class VarAllocator {
|
|
8
|
+
private readonly mangle;
|
|
9
|
+
private seq;
|
|
10
|
+
private readonly varCache;
|
|
11
|
+
private readonly constCache;
|
|
12
|
+
private readonly internalCache;
|
|
13
|
+
constructor(mangle?: boolean);
|
|
14
|
+
/** Allocate a name for a user variable. Strips leading '$' if present. */
|
|
15
|
+
alloc(originalName: string): string;
|
|
16
|
+
/** Allocate a name for a constant value (content-addressed). */
|
|
17
|
+
constant(value: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Look up the allocated name for a raw scoreboard fake-player name such as
|
|
20
|
+
* "$_2", "$x", "$p0", or "$ret". Returns the mangled name when mangle=true,
|
|
21
|
+
* or the original name when mangle=false or the name is not yet known.
|
|
22
|
+
*
|
|
23
|
+
* Unlike alloc/internal/constant this does NOT create a new slot — it only
|
|
24
|
+
* resolves names that were already registered. Used by the codegen to
|
|
25
|
+
* rewrite variable references inside `raw` IR instructions.
|
|
26
|
+
*/
|
|
27
|
+
resolve(rawName: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Rewrite all $varname tokens in a raw mcfunction command string so that
|
|
30
|
+
* IR variable names are replaced by their allocated (possibly mangled) names.
|
|
31
|
+
* Tokens that are not registered in the allocator are left untouched (they
|
|
32
|
+
* are literal scoreboard fake-player names like "out" or "#rs").
|
|
33
|
+
*/
|
|
34
|
+
resolveRaw(cmd: string): string;
|
|
35
|
+
/** Allocate a name for a compiler internal (e.g. "ret", "p0"). */
|
|
36
|
+
internal(suffix: string): string;
|
|
37
|
+
/** Generate the next sequential name: a, b, ..., z, aa, ab, ..., az, ba, ... */
|
|
38
|
+
private nextSeqName;
|
|
39
|
+
/**
|
|
40
|
+
* Returns a sourcemap object mapping allocated name → original name.
|
|
41
|
+
* Useful for debugging: write to <output>.map.json alongside the datapack.
|
|
42
|
+
* Only meaningful when mangle=true.
|
|
43
|
+
*/
|
|
44
|
+
toSourceMap(): Record<string, string>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* VarAllocator — assigns scoreboard fake-player names to variables.
|
|
4
|
+
*
|
|
5
|
+
* mangle=true: sequential short names ($a, $b, ..., $z, $aa, $ab, ...)
|
|
6
|
+
* mangle=false: legacy names ($<name> for vars, $const_<v> for consts, $p0/$ret for internals)
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.VarAllocator = void 0;
|
|
10
|
+
class VarAllocator {
|
|
11
|
+
constructor(mangle = true) {
|
|
12
|
+
this.seq = 0;
|
|
13
|
+
this.varCache = new Map();
|
|
14
|
+
this.constCache = new Map();
|
|
15
|
+
this.internalCache = new Map();
|
|
16
|
+
this.mangle = mangle;
|
|
17
|
+
}
|
|
18
|
+
/** Allocate a name for a user variable. Strips leading '$' if present. */
|
|
19
|
+
alloc(originalName) {
|
|
20
|
+
const clean = originalName.startsWith('$') ? originalName.slice(1) : originalName;
|
|
21
|
+
const cached = this.varCache.get(clean);
|
|
22
|
+
if (cached)
|
|
23
|
+
return cached;
|
|
24
|
+
const name = this.mangle ? `$${this.nextSeqName()}` : `$${clean}`;
|
|
25
|
+
this.varCache.set(clean, name);
|
|
26
|
+
return name;
|
|
27
|
+
}
|
|
28
|
+
/** Allocate a name for a constant value (content-addressed). */
|
|
29
|
+
constant(value) {
|
|
30
|
+
const cached = this.constCache.get(value);
|
|
31
|
+
if (cached)
|
|
32
|
+
return cached;
|
|
33
|
+
const name = this.mangle ? `$${this.nextSeqName()}` : `$const_${value}`;
|
|
34
|
+
this.constCache.set(value, name);
|
|
35
|
+
return name;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Look up the allocated name for a raw scoreboard fake-player name such as
|
|
39
|
+
* "$_2", "$x", "$p0", or "$ret". Returns the mangled name when mangle=true,
|
|
40
|
+
* or the original name when mangle=false or the name is not yet known.
|
|
41
|
+
*
|
|
42
|
+
* Unlike alloc/internal/constant this does NOT create a new slot — it only
|
|
43
|
+
* resolves names that were already registered. Used by the codegen to
|
|
44
|
+
* rewrite variable references inside `raw` IR instructions.
|
|
45
|
+
*/
|
|
46
|
+
resolve(rawName) {
|
|
47
|
+
const clean = rawName.startsWith('$') ? rawName.slice(1) : rawName;
|
|
48
|
+
// Check every cache in priority order: vars, internals, consts
|
|
49
|
+
return (this.varCache.get(clean) ??
|
|
50
|
+
this.internalCache.get(clean) ??
|
|
51
|
+
rawName // not registered → return as-is (literal fake player, not a var)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Rewrite all $varname tokens in a raw mcfunction command string so that
|
|
56
|
+
* IR variable names are replaced by their allocated (possibly mangled) names.
|
|
57
|
+
* Tokens that are not registered in the allocator are left untouched (they
|
|
58
|
+
* are literal scoreboard fake-player names like "out" or "#rs").
|
|
59
|
+
*/
|
|
60
|
+
resolveRaw(cmd) {
|
|
61
|
+
return cmd.replace(/\$[A-Za-z_][A-Za-z0-9_]*/g, (tok) => this.resolve(tok));
|
|
62
|
+
}
|
|
63
|
+
/** Allocate a name for a compiler internal (e.g. "ret", "p0"). */
|
|
64
|
+
internal(suffix) {
|
|
65
|
+
const cached = this.internalCache.get(suffix);
|
|
66
|
+
if (cached)
|
|
67
|
+
return cached;
|
|
68
|
+
const name = this.mangle ? `$${this.nextSeqName()}` : `$${suffix}`;
|
|
69
|
+
this.internalCache.set(suffix, name);
|
|
70
|
+
return name;
|
|
71
|
+
}
|
|
72
|
+
/** Generate the next sequential name: a, b, ..., z, aa, ab, ..., az, ba, ... */
|
|
73
|
+
nextSeqName() {
|
|
74
|
+
const n = this.seq++;
|
|
75
|
+
let result = '';
|
|
76
|
+
let remaining = n;
|
|
77
|
+
do {
|
|
78
|
+
result = String.fromCharCode(97 + (remaining % 26)) + result;
|
|
79
|
+
remaining = Math.floor(remaining / 26) - 1;
|
|
80
|
+
} while (remaining >= 0);
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns a sourcemap object mapping allocated name → original name.
|
|
85
|
+
* Useful for debugging: write to <output>.map.json alongside the datapack.
|
|
86
|
+
* Only meaningful when mangle=true.
|
|
87
|
+
*/
|
|
88
|
+
toSourceMap() {
|
|
89
|
+
const map = {};
|
|
90
|
+
for (const [orig, alloc] of this.varCache) {
|
|
91
|
+
// Skip compiler-generated temporaries (start with _ followed by digits)
|
|
92
|
+
if (/^_\d+$/.test(orig))
|
|
93
|
+
continue;
|
|
94
|
+
map[alloc] = orig;
|
|
95
|
+
}
|
|
96
|
+
for (const [val, alloc] of this.constCache)
|
|
97
|
+
map[alloc] = `const:${val}`;
|
|
98
|
+
for (const [suf, alloc] of this.internalCache)
|
|
99
|
+
map[alloc] = `internal:${suf}`;
|
|
100
|
+
return map;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.VarAllocator = VarAllocator;
|
|
104
|
+
//# sourceMappingURL=var-allocator.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RedScript Compile API
|
|
3
|
+
*
|
|
4
|
+
* Preprocessing utilities and v2 compile re-export.
|
|
5
|
+
*/
|
|
6
|
+
export { compile, CompileOptions, CompileResult } from '../src2/emit/compile';
|
|
7
|
+
export type { DatapackFile } from '../src2/emit/index';
|
|
8
|
+
export interface SourceRange {
|
|
9
|
+
startLine: number;
|
|
10
|
+
endLine: number;
|
|
11
|
+
filePath: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PreprocessedSource {
|
|
14
|
+
source: string;
|
|
15
|
+
ranges: SourceRange[];
|
|
16
|
+
/** Imported files that declared `module library;` — parsed separately
|
|
17
|
+
* in library mode so their functions are DCE-eligible. Never concatenated
|
|
18
|
+
* into `source`. */
|
|
19
|
+
libraryImports?: Array<{
|
|
20
|
+
source: string;
|
|
21
|
+
filePath: string;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a combined-source line number back to the original file and line.
|
|
26
|
+
* Returns { filePath, line } if a mapping is found, otherwise returns the input unchanged.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveSourceLine(combinedLine: number, ranges: SourceRange[], fallbackFile?: string): {
|
|
29
|
+
filePath?: string;
|
|
30
|
+
line: number;
|
|
31
|
+
};
|
|
32
|
+
interface PreprocessOptions {
|
|
33
|
+
filePath?: string;
|
|
34
|
+
seen?: Set<string>;
|
|
35
|
+
}
|
|
36
|
+
export declare function preprocessSourceWithMetadata(source: string, options?: PreprocessOptions): PreprocessedSource;
|
|
37
|
+
export declare function preprocessSource(source: string, options?: PreprocessOptions): string;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RedScript Compile API
|
|
4
|
+
*
|
|
5
|
+
* Preprocessing utilities and v2 compile re-export.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.compile = void 0;
|
|
42
|
+
exports.resolveSourceLine = resolveSourceLine;
|
|
43
|
+
exports.preprocessSourceWithMetadata = preprocessSourceWithMetadata;
|
|
44
|
+
exports.preprocessSource = preprocessSource;
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const diagnostics_1 = require("./diagnostics");
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Re-export v2 compile
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
var compile_1 = require("../src2/emit/compile");
|
|
52
|
+
Object.defineProperty(exports, "compile", { enumerable: true, get: function () { return compile_1.compile; } });
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a combined-source line number back to the original file and line.
|
|
55
|
+
* Returns { filePath, line } if a mapping is found, otherwise returns the input unchanged.
|
|
56
|
+
*/
|
|
57
|
+
function resolveSourceLine(combinedLine, ranges, fallbackFile) {
|
|
58
|
+
for (const range of ranges) {
|
|
59
|
+
if (combinedLine >= range.startLine && combinedLine <= range.endLine) {
|
|
60
|
+
const localLine = combinedLine - range.startLine + 1;
|
|
61
|
+
return { filePath: range.filePath, line: localLine };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { filePath: fallbackFile, line: combinedLine };
|
|
65
|
+
}
|
|
66
|
+
const IMPORT_RE = /^\s*import\s+"([^"]+)"\s*;?\s*$/;
|
|
67
|
+
/** Returns true if the source file declares `module library;` at its top
|
|
68
|
+
* (before any non-comment/non-blank lines). */
|
|
69
|
+
function isLibrarySource(source) {
|
|
70
|
+
for (const line of source.split('\n')) {
|
|
71
|
+
const trimmed = line.trim();
|
|
72
|
+
if (!trimmed || trimmed.startsWith('//'))
|
|
73
|
+
continue;
|
|
74
|
+
return /^module\s+library\s*;/.test(trimmed);
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function countLines(source) {
|
|
79
|
+
return source === '' ? 0 : source.split('\n').length;
|
|
80
|
+
}
|
|
81
|
+
function offsetRanges(ranges, lineOffset) {
|
|
82
|
+
return ranges.map(range => ({
|
|
83
|
+
startLine: range.startLine + lineOffset,
|
|
84
|
+
endLine: range.endLine + lineOffset,
|
|
85
|
+
filePath: range.filePath,
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
function preprocessSourceWithMetadata(source, options = {}) {
|
|
89
|
+
const { filePath } = options;
|
|
90
|
+
const seen = options.seen ?? new Set();
|
|
91
|
+
if (filePath) {
|
|
92
|
+
seen.add(path.resolve(filePath));
|
|
93
|
+
}
|
|
94
|
+
const lines = source.split('\n');
|
|
95
|
+
const imports = [];
|
|
96
|
+
/** Library imports: `module library;` files routed here instead of concatenated. */
|
|
97
|
+
const libraryImports = [];
|
|
98
|
+
const bodyLines = [];
|
|
99
|
+
let parsingHeader = true;
|
|
100
|
+
for (let i = 0; i < lines.length; i++) {
|
|
101
|
+
const line = lines[i];
|
|
102
|
+
const trimmed = line.trim();
|
|
103
|
+
const match = line.match(IMPORT_RE);
|
|
104
|
+
if (parsingHeader && match) {
|
|
105
|
+
if (!filePath) {
|
|
106
|
+
throw new diagnostics_1.DiagnosticError('ParseError', 'Import statements require a file path', { line: i + 1, col: 1 }, lines);
|
|
107
|
+
}
|
|
108
|
+
const importPath = path.resolve(path.dirname(filePath), match[1]);
|
|
109
|
+
if (!seen.has(importPath)) {
|
|
110
|
+
seen.add(importPath);
|
|
111
|
+
let importedSource;
|
|
112
|
+
try {
|
|
113
|
+
importedSource = fs.readFileSync(importPath, 'utf-8');
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
throw new diagnostics_1.DiagnosticError('ParseError', `Cannot import '${match[1]}'`, { file: filePath, line: i + 1, col: 1 }, lines);
|
|
117
|
+
}
|
|
118
|
+
if (isLibrarySource(importedSource)) {
|
|
119
|
+
// Library file: parse separately so its functions are DCE-eligible.
|
|
120
|
+
// Also collect any transitive library imports inside it.
|
|
121
|
+
const nested = preprocessSourceWithMetadata(importedSource, { filePath: importPath, seen });
|
|
122
|
+
libraryImports.push({ source: importedSource, filePath: importPath });
|
|
123
|
+
// Propagate transitive library imports (e.g. math.mcrs imports vec.mcrs)
|
|
124
|
+
if (nested.libraryImports)
|
|
125
|
+
libraryImports.push(...nested.libraryImports);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
imports.push(preprocessSourceWithMetadata(importedSource, { filePath: importPath, seen }));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (parsingHeader && (trimmed === '' || trimmed.startsWith('//'))) {
|
|
134
|
+
bodyLines.push(line);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
parsingHeader = false;
|
|
138
|
+
bodyLines.push(line);
|
|
139
|
+
}
|
|
140
|
+
const body = bodyLines.join('\n');
|
|
141
|
+
const parts = [...imports.map(entry => entry.source), body].filter(Boolean);
|
|
142
|
+
const combined = parts.join('\n');
|
|
143
|
+
const ranges = [];
|
|
144
|
+
let lineOffset = 0;
|
|
145
|
+
for (const entry of imports) {
|
|
146
|
+
ranges.push(...offsetRanges(entry.ranges, lineOffset));
|
|
147
|
+
lineOffset += countLines(entry.source);
|
|
148
|
+
}
|
|
149
|
+
if (filePath && body) {
|
|
150
|
+
ranges.push({
|
|
151
|
+
startLine: lineOffset + 1,
|
|
152
|
+
endLine: lineOffset + countLines(body),
|
|
153
|
+
filePath: path.resolve(filePath),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
source: combined,
|
|
158
|
+
ranges,
|
|
159
|
+
libraryImports: libraryImports.length > 0 ? libraryImports : undefined,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function preprocessSource(source, options = {}) {
|
|
163
|
+
return preprocessSourceWithMetadata(source, options).source;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=compile.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RedScript Diagnostics
|
|
3
|
+
*
|
|
4
|
+
* Error reporting with file path, line, column, and formatted error messages.
|
|
5
|
+
*/
|
|
6
|
+
export type DiagnosticKind = 'LexError' | 'ParseError' | 'LoweringError' | 'TypeError';
|
|
7
|
+
export interface DiagnosticLocation {
|
|
8
|
+
file?: string;
|
|
9
|
+
line: number;
|
|
10
|
+
col: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class DiagnosticError extends Error {
|
|
13
|
+
readonly kind: DiagnosticKind;
|
|
14
|
+
readonly location: DiagnosticLocation;
|
|
15
|
+
readonly sourceLines?: string[];
|
|
16
|
+
constructor(kind: DiagnosticKind, message: string, location: DiagnosticLocation, sourceLines?: string[]);
|
|
17
|
+
/**
|
|
18
|
+
* Format the error for display:
|
|
19
|
+
* ```
|
|
20
|
+
* Error: [ParseError] line 5, col 12: Expected ';' after statement
|
|
21
|
+
* 5 | let x = 42
|
|
22
|
+
* ^ expected ';'
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
format(): string;
|
|
26
|
+
toString(): string;
|
|
27
|
+
}
|
|
28
|
+
export declare class DiagnosticCollector {
|
|
29
|
+
private diagnostics;
|
|
30
|
+
private sourceLines;
|
|
31
|
+
private filePath?;
|
|
32
|
+
constructor(source?: string, filePath?: string);
|
|
33
|
+
error(kind: DiagnosticKind, message: string, line: number, col: number): void;
|
|
34
|
+
hasErrors(): boolean;
|
|
35
|
+
getErrors(): DiagnosticError[];
|
|
36
|
+
formatAll(): string;
|
|
37
|
+
throwFirst(): never;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a DiagnosticError from a raw error message that includes line/col info
|
|
41
|
+
* e.g., "Expected ';' at line 5, col 12"
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseErrorMessage(kind: DiagnosticKind, rawMessage: string, sourceLines?: string[], filePath?: string): DiagnosticError;
|
|
44
|
+
export declare function formatError(error: Error | DiagnosticError, source?: string): string;
|