redscript-mc 1.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/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +31 -0
- package/.github/ISSUE_TEMPLATE/wrong_output.md +33 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +34 -0
- package/.github/workflows/ci.yml +29 -0
- package/.github/workflows/publish-extension.yml +35 -0
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/README.zh.md +261 -0
- package/dist/__tests__/cli.test.d.ts +1 -0
- package/dist/__tests__/cli.test.js +140 -0
- package/dist/__tests__/codegen.test.d.ts +1 -0
- package/dist/__tests__/codegen.test.js +121 -0
- package/dist/__tests__/diagnostics.test.d.ts +4 -0
- package/dist/__tests__/diagnostics.test.js +149 -0
- package/dist/__tests__/e2e.test.d.ts +6 -0
- package/dist/__tests__/e2e.test.js +1528 -0
- package/dist/__tests__/lexer.test.d.ts +1 -0
- package/dist/__tests__/lexer.test.js +316 -0
- package/dist/__tests__/lowering.test.d.ts +1 -0
- package/dist/__tests__/lowering.test.js +819 -0
- package/dist/__tests__/mc-integration.test.d.ts +12 -0
- package/dist/__tests__/mc-integration.test.js +395 -0
- package/dist/__tests__/mc-syntax.test.d.ts +1 -0
- package/dist/__tests__/mc-syntax.test.js +112 -0
- package/dist/__tests__/nbt.test.d.ts +1 -0
- package/dist/__tests__/nbt.test.js +82 -0
- package/dist/__tests__/optimizer-advanced.test.d.ts +1 -0
- package/dist/__tests__/optimizer-advanced.test.js +124 -0
- package/dist/__tests__/optimizer.test.d.ts +1 -0
- package/dist/__tests__/optimizer.test.js +118 -0
- package/dist/__tests__/parser.test.d.ts +1 -0
- package/dist/__tests__/parser.test.js +717 -0
- package/dist/__tests__/repl.test.d.ts +1 -0
- package/dist/__tests__/repl.test.js +27 -0
- package/dist/__tests__/runtime.test.d.ts +1 -0
- package/dist/__tests__/runtime.test.js +276 -0
- package/dist/__tests__/structure-optimizer.test.d.ts +1 -0
- package/dist/__tests__/structure-optimizer.test.js +33 -0
- package/dist/__tests__/typechecker.test.d.ts +1 -0
- package/dist/__tests__/typechecker.test.js +364 -0
- package/dist/ast/types.d.ts +357 -0
- package/dist/ast/types.js +9 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +407 -0
- package/dist/codegen/cmdblock/index.d.ts +26 -0
- package/dist/codegen/cmdblock/index.js +45 -0
- package/dist/codegen/mcfunction/index.d.ts +34 -0
- package/dist/codegen/mcfunction/index.js +413 -0
- package/dist/codegen/structure/index.d.ts +18 -0
- package/dist/codegen/structure/index.js +249 -0
- package/dist/compile.d.ts +30 -0
- package/dist/compile.js +152 -0
- package/dist/data/arena/function/__load.mcfunction +6 -0
- package/dist/data/arena/function/__tick.mcfunction +2 -0
- package/dist/data/arena/function/announce_leaders/else_1.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +7 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +6 -0
- package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders.mcfunction +6 -0
- package/dist/data/arena/function/arena_tick/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/arena_tick/then_0.mcfunction +4 -0
- package/dist/data/arena/function/arena_tick.mcfunction +11 -0
- package/dist/data/counter/function/__load.mcfunction +5 -0
- package/dist/data/counter/function/__tick.mcfunction +2 -0
- package/dist/data/counter/function/counter_tick/merge_2.mcfunction +1 -0
- package/dist/data/counter/function/counter_tick/then_0.mcfunction +3 -0
- package/dist/data/counter/function/counter_tick.mcfunction +11 -0
- package/dist/data/minecraft/tags/function/load.json +5 -0
- package/dist/data/minecraft/tags/function/tick.json +5 -0
- package/dist/data/quiz/function/__load.mcfunction +16 -0
- package/dist/data/quiz/function/__tick.mcfunction +6 -0
- package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/answer_a.mcfunction +4 -0
- package/dist/data/quiz/function/answer_b.mcfunction +4 -0
- package/dist/data/quiz/function/answer_c.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_4.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_7.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/merge_2.mcfunction +1 -0
- package/dist/data/quiz/function/ask_question/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/then_0.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_3.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_6.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question.mcfunction +7 -0
- package/dist/data/quiz/function/finish_quiz.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/else_10.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_16.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_4.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_7.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +8 -0
- package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/then_0.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_12.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_15.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_3.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_6.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_9.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer.mcfunction +11 -0
- package/dist/data/quiz/function/start_quiz.mcfunction +5 -0
- package/dist/data/shop/function/__load.mcfunction +7 -0
- package/dist/data/shop/function/__tick.mcfunction +3 -0
- package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/else_1.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_4.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_7.mcfunction +3 -0
- package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/then_0.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_3.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_6.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase.mcfunction +7 -0
- package/dist/data/shop/function/handle_shop_trigger.mcfunction +3 -0
- package/dist/data/turret/function/__load.mcfunction +5 -0
- package/dist/data/turret/function/__tick.mcfunction +4 -0
- package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +4 -0
- package/dist/data/turret/function/deploy_turret.mcfunction +8 -0
- package/dist/data/turret/function/turret_tick/at_1.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/tick_body.mcfunction +3 -0
- package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +1 -0
- package/dist/data/turret/function/turret_tick.mcfunction +5 -0
- package/dist/diagnostics/index.d.ts +44 -0
- package/dist/diagnostics/index.js +140 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +126 -0
- package/dist/ir/builder.d.ts +32 -0
- package/dist/ir/builder.js +99 -0
- package/dist/ir/types.d.ts +117 -0
- package/dist/ir/types.js +15 -0
- package/dist/lexer/index.d.ts +36 -0
- package/dist/lexer/index.js +458 -0
- package/dist/lowering/index.d.ts +106 -0
- package/dist/lowering/index.js +2041 -0
- package/dist/mc-test/client.d.ts +128 -0
- package/dist/mc-test/client.js +174 -0
- package/dist/mc-test/runner.d.ts +28 -0
- package/dist/mc-test/runner.js +150 -0
- package/dist/mc-test/setup.d.ts +11 -0
- package/dist/mc-test/setup.js +98 -0
- package/dist/mc-validator/index.d.ts +17 -0
- package/dist/mc-validator/index.js +322 -0
- package/dist/nbt/index.d.ts +86 -0
- package/dist/nbt/index.js +250 -0
- package/dist/optimizer/commands.d.ts +36 -0
- package/dist/optimizer/commands.js +349 -0
- package/dist/optimizer/passes.d.ts +34 -0
- package/dist/optimizer/passes.js +227 -0
- package/dist/optimizer/structure.d.ts +8 -0
- package/dist/optimizer/structure.js +344 -0
- package/dist/pack.mcmeta +6 -0
- package/dist/parser/index.d.ts +76 -0
- package/dist/parser/index.js +1193 -0
- package/dist/repl.d.ts +16 -0
- package/dist/repl.js +165 -0
- package/dist/runtime/index.d.ts +101 -0
- package/dist/runtime/index.js +1288 -0
- package/dist/typechecker/index.d.ts +42 -0
- package/dist/typechecker/index.js +629 -0
- package/docs/COMPILATION_STATS.md +142 -0
- package/docs/IMPLEMENTATION_GUIDE.md +512 -0
- package/docs/LANGUAGE_REFERENCE.md +415 -0
- package/docs/MC_MAPPING.md +280 -0
- package/docs/STRUCTURE_TARGET.md +80 -0
- package/docs/mc-reference/commands.md +259 -0
- package/editors/vscode/.vscodeignore +10 -0
- package/editors/vscode/LICENSE +21 -0
- package/editors/vscode/README.md +78 -0
- package/editors/vscode/build.mjs +28 -0
- package/editors/vscode/icon.png +0 -0
- package/editors/vscode/mcfunction-language-configuration.json +28 -0
- package/editors/vscode/out/extension.js +7236 -0
- package/editors/vscode/package-lock.json +566 -0
- package/editors/vscode/package.json +137 -0
- package/editors/vscode/redscript-language-configuration.json +28 -0
- package/editors/vscode/snippets/redscript.json +114 -0
- package/editors/vscode/src/codeactions.ts +89 -0
- package/editors/vscode/src/completion.ts +130 -0
- package/editors/vscode/src/extension.ts +239 -0
- package/editors/vscode/src/hover.ts +1120 -0
- package/editors/vscode/src/symbols.ts +207 -0
- package/editors/vscode/syntaxes/mcfunction.tmLanguage.json +740 -0
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +357 -0
- package/editors/vscode/tsconfig.json +13 -0
- package/jest.config.js +5 -0
- package/package.json +38 -0
- package/src/__tests__/cli.test.ts +130 -0
- package/src/__tests__/codegen.test.ts +128 -0
- package/src/__tests__/diagnostics.test.ts +195 -0
- package/src/__tests__/e2e.test.ts +1721 -0
- package/src/__tests__/fixtures/mc-commands-1.21.4.json +18734 -0
- package/src/__tests__/formatter.test.ts +46 -0
- package/src/__tests__/lexer.test.ts +356 -0
- package/src/__tests__/lowering.test.ts +962 -0
- package/src/__tests__/mc-integration.test.ts +409 -0
- package/src/__tests__/mc-syntax.test.ts +96 -0
- package/src/__tests__/nbt.test.ts +58 -0
- package/src/__tests__/optimizer-advanced.test.ts +144 -0
- package/src/__tests__/optimizer.test.ts +129 -0
- package/src/__tests__/parser.test.ts +800 -0
- package/src/__tests__/repl.test.ts +33 -0
- package/src/__tests__/runtime.test.ts +289 -0
- package/src/__tests__/structure-optimizer.test.ts +38 -0
- package/src/__tests__/typechecker.test.ts +395 -0
- package/src/ast/types.ts +248 -0
- package/src/cli.ts +445 -0
- package/src/codegen/cmdblock/index.ts +63 -0
- package/src/codegen/mcfunction/index.ts +471 -0
- package/src/codegen/structure/index.ts +305 -0
- package/src/compile.ts +188 -0
- package/src/diagnostics/index.ts +186 -0
- package/src/examples/README.md +77 -0
- package/src/examples/SHOWCASE_GAME.md +43 -0
- package/src/examples/arena.rs +44 -0
- package/src/examples/counter.rs +12 -0
- package/src/examples/pvp_arena.rs +131 -0
- package/src/examples/quiz.rs +90 -0
- package/src/examples/rpg.rs +13 -0
- package/src/examples/shop.rs +30 -0
- package/src/examples/showcase_game.rs +552 -0
- package/src/examples/stdlib_demo.rs +181 -0
- package/src/examples/turret.rs +27 -0
- package/src/examples/world_manager.rs +23 -0
- package/src/formatter/index.ts +22 -0
- package/src/index.ts +161 -0
- package/src/ir/builder.ts +114 -0
- package/src/ir/types.ts +119 -0
- package/src/lexer/index.ts +555 -0
- package/src/lowering/index.ts +2406 -0
- package/src/mc-test/client.ts +259 -0
- package/src/mc-test/runner.ts +140 -0
- package/src/mc-test/setup.ts +70 -0
- package/src/mc-validator/index.ts +367 -0
- package/src/nbt/index.ts +321 -0
- package/src/optimizer/commands.ts +416 -0
- package/src/optimizer/passes.ts +233 -0
- package/src/optimizer/structure.ts +441 -0
- package/src/parser/index.ts +1437 -0
- package/src/repl.ts +165 -0
- package/src/runtime/index.ts +1403 -0
- package/src/stdlib/README.md +156 -0
- package/src/stdlib/combat.rs +20 -0
- package/src/stdlib/cooldown.rs +45 -0
- package/src/stdlib/math.rs +49 -0
- package/src/stdlib/mobs.rs +99 -0
- package/src/stdlib/player.rs +29 -0
- package/src/stdlib/strings.rs +7 -0
- package/src/stdlib/timer.rs +51 -0
- package/src/templates/README.md +126 -0
- package/src/templates/combat.rs +96 -0
- package/src/templates/economy.rs +40 -0
- package/src/templates/mini-game-framework.rs +117 -0
- package/src/templates/quest.rs +78 -0
- package/src/test_programs/zombie_game.rs +25 -0
- package/src/typechecker/index.ts +737 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# block: entry
|
|
2
|
+
execute store result score $t0 rs run scoreboard players get @s shop_choice
|
|
3
|
+
scoreboard players operation $choice rs = $t0 rs
|
|
4
|
+
scoreboard players set $t1 rs 0
|
|
5
|
+
execute if score $t0 rs = $const_1 rs run scoreboard players set $t1 rs 1
|
|
6
|
+
execute if score $t1 rs matches 1.. run function shop:complete_purchase/then_0
|
|
7
|
+
execute if score $t1 rs matches ..0 run function shop:complete_purchase/else_1
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# block: entry
|
|
2
|
+
summon minecraft:armor_stand 0 64 0 {Invisible:1b,Marker:1b,NoGravity:1b,Tags:["__rs_obj_0"]}
|
|
3
|
+
scoreboard players set @e[tag=__rs_obj_0,limit=1] rs 40
|
|
4
|
+
tag @e[tag=__rs_obj_0,limit=1] add turret
|
|
5
|
+
data modify storage rs:heap turretstate_state.health set value 40
|
|
6
|
+
execute store result score $t0 rs run data get storage rs:heap turretstate_state.health
|
|
7
|
+
execute store result score turret health run scoreboard players get $t1 rs
|
|
8
|
+
say Turret deployed.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# block: tick_skip
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# block: entry
|
|
2
|
+
scoreboard players add $__tick_turret_tick rs 1
|
|
3
|
+
execute store success score $__tick_turret_tick_check rs if score $__tick_turret_tick rs matches 20..
|
|
4
|
+
execute if score $__tick_turret_tick_check rs matches 1.. run function turret:turret_tick/tick_body
|
|
5
|
+
execute if score $__tick_turret_tick_check rs matches ..0 run function turret:turret_tick/tick_skip
|
|
@@ -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;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RedScript Diagnostics
|
|
4
|
+
*
|
|
5
|
+
* Error reporting with file path, line, column, and formatted error messages.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.DiagnosticCollector = exports.DiagnosticError = void 0;
|
|
9
|
+
exports.parseErrorMessage = parseErrorMessage;
|
|
10
|
+
exports.formatError = formatError;
|
|
11
|
+
function formatSourcePointer(sourceLines, line, col) {
|
|
12
|
+
const lineIdx = line - 1;
|
|
13
|
+
if (lineIdx < 0 || lineIdx >= sourceLines.length) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
const sourceLine = sourceLines[lineIdx];
|
|
17
|
+
const safeCol = Math.max(1, Math.min(col, sourceLine.length + 1));
|
|
18
|
+
const pointer = ` ${' '.repeat(safeCol - 1)}^`;
|
|
19
|
+
return [` ${sourceLine}`, pointer];
|
|
20
|
+
}
|
|
21
|
+
class DiagnosticError extends Error {
|
|
22
|
+
constructor(kind, message, location, sourceLines) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'DiagnosticError';
|
|
25
|
+
this.kind = kind;
|
|
26
|
+
this.location = location;
|
|
27
|
+
this.sourceLines = sourceLines;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Format the error for display:
|
|
31
|
+
* ```
|
|
32
|
+
* Error: [ParseError] line 5, col 12: Expected ';' after statement
|
|
33
|
+
* 5 | let x = 42
|
|
34
|
+
* ^ expected ';'
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
format() {
|
|
38
|
+
const { kind, message, location, sourceLines } = this;
|
|
39
|
+
const filePart = location.file ? `${location.file}:` : '';
|
|
40
|
+
const header = `Error: [${kind}] ${filePart}line ${location.line}, col ${location.col}: ${message}`;
|
|
41
|
+
if (!sourceLines || sourceLines.length === 0) {
|
|
42
|
+
return header;
|
|
43
|
+
}
|
|
44
|
+
const pointerLines = formatSourcePointer(sourceLines, location.line, location.col);
|
|
45
|
+
if (pointerLines.length === 0) {
|
|
46
|
+
return header;
|
|
47
|
+
}
|
|
48
|
+
const lineNum = String(location.line).padStart(3);
|
|
49
|
+
const prefix = `${lineNum} | `;
|
|
50
|
+
const sourceLine = sourceLines[location.line - 1];
|
|
51
|
+
const safeCol = Math.max(1, Math.min(location.col, sourceLine.length + 1));
|
|
52
|
+
const pointer = ' '.repeat(prefix.length + safeCol - 1) + '^';
|
|
53
|
+
const hint = message.toLowerCase().includes('expected')
|
|
54
|
+
? message.split(':').pop()?.trim() || ''
|
|
55
|
+
: '';
|
|
56
|
+
return [
|
|
57
|
+
header,
|
|
58
|
+
`${prefix}${sourceLine}`,
|
|
59
|
+
`${pointer}${hint ? ` ${hint}` : ''}`,
|
|
60
|
+
].join('\n');
|
|
61
|
+
}
|
|
62
|
+
toString() {
|
|
63
|
+
return this.format();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.DiagnosticError = DiagnosticError;
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Diagnostic Collection
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
class DiagnosticCollector {
|
|
71
|
+
constructor(source, filePath) {
|
|
72
|
+
this.diagnostics = [];
|
|
73
|
+
this.sourceLines = [];
|
|
74
|
+
if (source) {
|
|
75
|
+
this.sourceLines = source.split('\n');
|
|
76
|
+
}
|
|
77
|
+
this.filePath = filePath;
|
|
78
|
+
}
|
|
79
|
+
error(kind, message, line, col) {
|
|
80
|
+
const diagnostic = new DiagnosticError(kind, message, { file: this.filePath, line, col }, this.sourceLines);
|
|
81
|
+
this.diagnostics.push(diagnostic);
|
|
82
|
+
}
|
|
83
|
+
hasErrors() {
|
|
84
|
+
return this.diagnostics.length > 0;
|
|
85
|
+
}
|
|
86
|
+
getErrors() {
|
|
87
|
+
return this.diagnostics;
|
|
88
|
+
}
|
|
89
|
+
formatAll() {
|
|
90
|
+
return this.diagnostics.map(d => d.format()).join('\n\n');
|
|
91
|
+
}
|
|
92
|
+
throwFirst() {
|
|
93
|
+
if (this.diagnostics.length > 0) {
|
|
94
|
+
throw this.diagnostics[0];
|
|
95
|
+
}
|
|
96
|
+
throw new Error('No diagnostics to throw');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.DiagnosticCollector = DiagnosticCollector;
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Helper Functions
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
/**
|
|
104
|
+
* Create a DiagnosticError from a raw error message that includes line/col info
|
|
105
|
+
* e.g., "Expected ';' at line 5, col 12"
|
|
106
|
+
*/
|
|
107
|
+
function parseErrorMessage(kind, rawMessage, sourceLines, filePath) {
|
|
108
|
+
// Try to extract line and col from message
|
|
109
|
+
const match = rawMessage.match(/at line (\d+), col (\d+)/);
|
|
110
|
+
if (match) {
|
|
111
|
+
const line = parseInt(match[1], 10);
|
|
112
|
+
const col = parseInt(match[2], 10);
|
|
113
|
+
const message = rawMessage.replace(/ at line \d+, col \d+$/, '').trim();
|
|
114
|
+
return new DiagnosticError(kind, message, { file: filePath, line, col }, sourceLines);
|
|
115
|
+
}
|
|
116
|
+
// Fallback: line 1, col 1
|
|
117
|
+
return new DiagnosticError(kind, rawMessage, { file: filePath, line: 1, col: 1 }, sourceLines);
|
|
118
|
+
}
|
|
119
|
+
function formatError(error, source) {
|
|
120
|
+
if (error instanceof DiagnosticError) {
|
|
121
|
+
const sourceLines = source?.split('\n') ?? error.sourceLines ?? [];
|
|
122
|
+
const { file, line, col } = error.location;
|
|
123
|
+
const locationPart = file
|
|
124
|
+
? ` in ${file} at line ${line}, col ${col}`
|
|
125
|
+
: ` at line ${line}, col ${col}`;
|
|
126
|
+
const lines = [`Error${locationPart}:`];
|
|
127
|
+
const pointerLines = formatSourcePointer(sourceLines, line, col);
|
|
128
|
+
if (pointerLines.length > 0) {
|
|
129
|
+
lines.push(...pointerLines);
|
|
130
|
+
}
|
|
131
|
+
lines.push(error.message);
|
|
132
|
+
return lines.join('\n');
|
|
133
|
+
}
|
|
134
|
+
if (!source) {
|
|
135
|
+
return error.message;
|
|
136
|
+
}
|
|
137
|
+
const parsed = parseErrorMessage('ParseError', error.message, source.split('\n'));
|
|
138
|
+
return formatError(parsed, source);
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RedScript Compiler
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for programmatic usage.
|
|
5
|
+
*/
|
|
6
|
+
import type { Warning } from './lowering';
|
|
7
|
+
import { DatapackFile } from './codegen/mcfunction';
|
|
8
|
+
import type { IRModule } from './ir/types';
|
|
9
|
+
import type { Program } from './ast/types';
|
|
10
|
+
import type { DiagnosticError } from './diagnostics';
|
|
11
|
+
import { type OptimizationStats } from './optimizer/commands';
|
|
12
|
+
export interface CompileOptions {
|
|
13
|
+
namespace?: string;
|
|
14
|
+
optimize?: boolean;
|
|
15
|
+
typeCheck?: boolean;
|
|
16
|
+
filePath?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CompileResult {
|
|
19
|
+
files: DatapackFile[];
|
|
20
|
+
advancements: DatapackFile[];
|
|
21
|
+
ast: Program;
|
|
22
|
+
ir: IRModule;
|
|
23
|
+
typeErrors?: DiagnosticError[];
|
|
24
|
+
warnings?: Warning[];
|
|
25
|
+
stats?: OptimizationStats;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compile RedScript source code to a Minecraft datapack.
|
|
29
|
+
*
|
|
30
|
+
* @param source - The RedScript source code
|
|
31
|
+
* @param options - Compilation options
|
|
32
|
+
* @returns Compiled datapack files
|
|
33
|
+
*/
|
|
34
|
+
export declare function compile(source: string, options?: CompileOptions): CompileResult;
|
|
35
|
+
/**
|
|
36
|
+
* Check RedScript source code for errors without generating output.
|
|
37
|
+
*
|
|
38
|
+
* @param source - The RedScript source code
|
|
39
|
+
* @param namespace - Optional namespace
|
|
40
|
+
* @returns null if no errors, or an error object
|
|
41
|
+
*/
|
|
42
|
+
export declare function check(source: string, namespace?: string, filePath?: string): Error | null;
|
|
43
|
+
export { Lexer } from './lexer';
|
|
44
|
+
export { Parser } from './parser';
|
|
45
|
+
export { TypeChecker } from './typechecker';
|
|
46
|
+
export { Lowering } from './lowering';
|
|
47
|
+
export { optimize } from './optimizer/passes';
|
|
48
|
+
export { generateDatapack } from './codegen/mcfunction';
|
|
49
|
+
export { MCCommandValidator } from './mc-validator';
|
|
50
|
+
export type { DatapackFile } from './codegen/mcfunction';
|
|
51
|
+
export type { IRModule, IRFunction } from './ir/types';
|
|
52
|
+
export type { Program, FnDecl, Expr, Stmt, Span } from './ast/types';
|
|
53
|
+
export type { DiagnosticError } from './diagnostics';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RedScript Compiler
|
|
4
|
+
*
|
|
5
|
+
* Main entry point for programmatic usage.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.MCCommandValidator = exports.generateDatapack = exports.optimize = exports.Lowering = exports.TypeChecker = exports.Parser = exports.Lexer = void 0;
|
|
9
|
+
exports.compile = compile;
|
|
10
|
+
exports.check = check;
|
|
11
|
+
const lexer_1 = require("./lexer");
|
|
12
|
+
const parser_1 = require("./parser");
|
|
13
|
+
const typechecker_1 = require("./typechecker");
|
|
14
|
+
const lowering_1 = require("./lowering");
|
|
15
|
+
const passes_1 = require("./optimizer/passes");
|
|
16
|
+
const mcfunction_1 = require("./codegen/mcfunction");
|
|
17
|
+
const compile_1 = require("./compile");
|
|
18
|
+
const commands_1 = require("./optimizer/commands");
|
|
19
|
+
/**
|
|
20
|
+
* Compile RedScript source code to a Minecraft datapack.
|
|
21
|
+
*
|
|
22
|
+
* @param source - The RedScript source code
|
|
23
|
+
* @param options - Compilation options
|
|
24
|
+
* @returns Compiled datapack files
|
|
25
|
+
*/
|
|
26
|
+
function compile(source, options = {}) {
|
|
27
|
+
const namespace = options.namespace ?? 'redscript';
|
|
28
|
+
const shouldOptimize = options.optimize ?? true;
|
|
29
|
+
const shouldTypeCheck = options.typeCheck ?? true;
|
|
30
|
+
const filePath = options.filePath;
|
|
31
|
+
const preprocessedSource = (0, compile_1.preprocessSource)(source, { filePath });
|
|
32
|
+
// Lexing
|
|
33
|
+
const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
|
|
34
|
+
// Parsing
|
|
35
|
+
const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
|
|
36
|
+
// Type checking (warn mode - collect errors but don't block)
|
|
37
|
+
let typeErrors;
|
|
38
|
+
if (shouldTypeCheck) {
|
|
39
|
+
const checker = new typechecker_1.TypeChecker(preprocessedSource, filePath);
|
|
40
|
+
typeErrors = checker.check(ast);
|
|
41
|
+
}
|
|
42
|
+
// Lowering to IR
|
|
43
|
+
const lowering = new lowering_1.Lowering(namespace);
|
|
44
|
+
const ir = lowering.lower(ast);
|
|
45
|
+
let optimizedIR = ir;
|
|
46
|
+
let generated = (0, mcfunction_1.generateDatapackWithStats)(ir, { optimizeCommands: shouldOptimize });
|
|
47
|
+
let optimizationStats;
|
|
48
|
+
if (shouldOptimize) {
|
|
49
|
+
const stats = (0, commands_1.createEmptyOptimizationStats)();
|
|
50
|
+
const copyPropagatedFunctions = [];
|
|
51
|
+
const deadCodeEliminatedFunctions = [];
|
|
52
|
+
for (const fn of ir.functions) {
|
|
53
|
+
const folded = (0, passes_1.constantFoldingWithStats)(fn);
|
|
54
|
+
stats.constantFolds += folded.stats.constantFolds ?? 0;
|
|
55
|
+
const propagated = (0, passes_1.copyPropagation)(folded.fn);
|
|
56
|
+
copyPropagatedFunctions.push(propagated);
|
|
57
|
+
const dce = (0, passes_1.deadCodeEliminationWithStats)(propagated);
|
|
58
|
+
deadCodeEliminatedFunctions.push(dce.fn);
|
|
59
|
+
}
|
|
60
|
+
const copyPropagatedIR = { ...ir, functions: copyPropagatedFunctions };
|
|
61
|
+
optimizedIR = { ...ir, functions: deadCodeEliminatedFunctions };
|
|
62
|
+
const baselineGenerated = (0, mcfunction_1.generateDatapackWithStats)(ir, { optimizeCommands: false });
|
|
63
|
+
const beforeDceGenerated = (0, mcfunction_1.generateDatapackWithStats)(copyPropagatedIR, { optimizeCommands: false });
|
|
64
|
+
const afterDceGenerated = (0, mcfunction_1.generateDatapackWithStats)(optimizedIR, { optimizeCommands: false });
|
|
65
|
+
generated = (0, mcfunction_1.generateDatapackWithStats)(optimizedIR, { optimizeCommands: true });
|
|
66
|
+
stats.deadCodeRemoved =
|
|
67
|
+
(0, mcfunction_1.countMcfunctionCommands)(beforeDceGenerated.files) - (0, mcfunction_1.countMcfunctionCommands)(afterDceGenerated.files);
|
|
68
|
+
stats.licmHoists = generated.stats.licmHoists;
|
|
69
|
+
stats.licmLoopBodies = generated.stats.licmLoopBodies;
|
|
70
|
+
stats.cseRedundantReads = generated.stats.cseRedundantReads;
|
|
71
|
+
stats.cseArithmetic = generated.stats.cseArithmetic;
|
|
72
|
+
stats.setblockMergedCommands = generated.stats.setblockMergedCommands;
|
|
73
|
+
stats.setblockFillCommands = generated.stats.setblockFillCommands;
|
|
74
|
+
stats.setblockSavedCommands = generated.stats.setblockSavedCommands;
|
|
75
|
+
stats.totalCommandsBefore = (0, mcfunction_1.countMcfunctionCommands)(baselineGenerated.files);
|
|
76
|
+
stats.totalCommandsAfter = (0, mcfunction_1.countMcfunctionCommands)(generated.files);
|
|
77
|
+
optimizationStats = stats;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
optimizedIR = ir;
|
|
81
|
+
generated = (0, mcfunction_1.generateDatapackWithStats)(ir, { optimizeCommands: false });
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
files: [...generated.files, ...generated.advancements],
|
|
85
|
+
advancements: generated.advancements,
|
|
86
|
+
ast,
|
|
87
|
+
ir: optimizedIR,
|
|
88
|
+
typeErrors,
|
|
89
|
+
warnings: lowering.warnings,
|
|
90
|
+
stats: optimizationStats,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check RedScript source code for errors without generating output.
|
|
95
|
+
*
|
|
96
|
+
* @param source - The RedScript source code
|
|
97
|
+
* @param namespace - Optional namespace
|
|
98
|
+
* @returns null if no errors, or an error object
|
|
99
|
+
*/
|
|
100
|
+
function check(source, namespace = 'redscript', filePath) {
|
|
101
|
+
try {
|
|
102
|
+
const preprocessedSource = (0, compile_1.preprocessSource)(source, { filePath });
|
|
103
|
+
const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
|
|
104
|
+
new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return err;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Re-export types and classes for advanced usage
|
|
112
|
+
var lexer_2 = require("./lexer");
|
|
113
|
+
Object.defineProperty(exports, "Lexer", { enumerable: true, get: function () { return lexer_2.Lexer; } });
|
|
114
|
+
var parser_2 = require("./parser");
|
|
115
|
+
Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return parser_2.Parser; } });
|
|
116
|
+
var typechecker_2 = require("./typechecker");
|
|
117
|
+
Object.defineProperty(exports, "TypeChecker", { enumerable: true, get: function () { return typechecker_2.TypeChecker; } });
|
|
118
|
+
var lowering_2 = require("./lowering");
|
|
119
|
+
Object.defineProperty(exports, "Lowering", { enumerable: true, get: function () { return lowering_2.Lowering; } });
|
|
120
|
+
var passes_2 = require("./optimizer/passes");
|
|
121
|
+
Object.defineProperty(exports, "optimize", { enumerable: true, get: function () { return passes_2.optimize; } });
|
|
122
|
+
var mcfunction_2 = require("./codegen/mcfunction");
|
|
123
|
+
Object.defineProperty(exports, "generateDatapack", { enumerable: true, get: function () { return mcfunction_2.generateDatapack; } });
|
|
124
|
+
var mc_validator_1 = require("./mc-validator");
|
|
125
|
+
Object.defineProperty(exports, "MCCommandValidator", { enumerable: true, get: function () { return mc_validator_1.MCCommandValidator; } });
|
|
126
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IRBuilder — helper for constructing IR programmatically.
|
|
3
|
+
* AST → IR lowering uses this.
|
|
4
|
+
*/
|
|
5
|
+
import type { IRFunction, IRInstr, IRModule, Operand } from './types';
|
|
6
|
+
export declare class IRBuilder {
|
|
7
|
+
private tempCount;
|
|
8
|
+
private labelCount;
|
|
9
|
+
private currentBlock;
|
|
10
|
+
private blocks;
|
|
11
|
+
private locals;
|
|
12
|
+
freshTemp(): string;
|
|
13
|
+
freshLabel(hint?: string): string;
|
|
14
|
+
startBlock(label: string): void;
|
|
15
|
+
private get block();
|
|
16
|
+
private sealBlock;
|
|
17
|
+
emitAssign(dst: string, src: Operand): void;
|
|
18
|
+
emitBinop(dst: string, lhs: Operand, bop: IRInstr & {
|
|
19
|
+
op: 'binop';
|
|
20
|
+
} extends {
|
|
21
|
+
bop: infer B;
|
|
22
|
+
} ? B : never, rhs: Operand): void;
|
|
23
|
+
emitCmp(dst: string, lhs: Operand, cop: '==' | '!=' | '<' | '<=' | '>' | '>=', rhs: Operand): void;
|
|
24
|
+
emitCall(fn: string, args: Operand[], dst?: string): void;
|
|
25
|
+
emitRaw(cmd: string): void;
|
|
26
|
+
emitJump(target: string): void;
|
|
27
|
+
emitJumpIf(cond: string, then: string, else_: string): void;
|
|
28
|
+
emitReturn(value?: Operand): void;
|
|
29
|
+
emitTickYield(continuation: string): void;
|
|
30
|
+
build(name: string, params: string[], isTickLoop?: boolean): IRFunction;
|
|
31
|
+
}
|
|
32
|
+
export declare function buildModule(namespace: string, fns: IRFunction[], globals?: string[]): IRModule;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* IRBuilder — helper for constructing IR programmatically.
|
|
4
|
+
* AST → IR lowering uses this.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.IRBuilder = void 0;
|
|
8
|
+
exports.buildModule = buildModule;
|
|
9
|
+
class IRBuilder {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.tempCount = 0;
|
|
12
|
+
this.labelCount = 0;
|
|
13
|
+
this.currentBlock = null;
|
|
14
|
+
this.blocks = [];
|
|
15
|
+
this.locals = new Set();
|
|
16
|
+
}
|
|
17
|
+
// -------------------------------------------------------------------------
|
|
18
|
+
// Names
|
|
19
|
+
// -------------------------------------------------------------------------
|
|
20
|
+
freshTemp() {
|
|
21
|
+
const name = `$t${this.tempCount++}`;
|
|
22
|
+
this.locals.add(name);
|
|
23
|
+
return name;
|
|
24
|
+
}
|
|
25
|
+
freshLabel(hint = 'L') {
|
|
26
|
+
return `${hint}_${this.labelCount++}`;
|
|
27
|
+
}
|
|
28
|
+
// -------------------------------------------------------------------------
|
|
29
|
+
// Block management
|
|
30
|
+
// -------------------------------------------------------------------------
|
|
31
|
+
startBlock(label) {
|
|
32
|
+
this.currentBlock = { label, instrs: [], term: { op: 'return' } };
|
|
33
|
+
}
|
|
34
|
+
get block() {
|
|
35
|
+
if (!this.currentBlock)
|
|
36
|
+
throw new Error('No active block');
|
|
37
|
+
return this.currentBlock;
|
|
38
|
+
}
|
|
39
|
+
sealBlock(term) {
|
|
40
|
+
this.block.term = term;
|
|
41
|
+
this.blocks.push(this.block);
|
|
42
|
+
this.currentBlock = null;
|
|
43
|
+
}
|
|
44
|
+
// -------------------------------------------------------------------------
|
|
45
|
+
// Emit instructions
|
|
46
|
+
// -------------------------------------------------------------------------
|
|
47
|
+
emitAssign(dst, src) {
|
|
48
|
+
this.locals.add(dst);
|
|
49
|
+
this.block.instrs.push({ op: 'assign', dst, src });
|
|
50
|
+
}
|
|
51
|
+
emitBinop(dst, lhs, bop, rhs) {
|
|
52
|
+
this.locals.add(dst);
|
|
53
|
+
this.block.instrs.push({ op: 'binop', dst, lhs, bop, rhs });
|
|
54
|
+
}
|
|
55
|
+
emitCmp(dst, lhs, cop, rhs) {
|
|
56
|
+
this.locals.add(dst);
|
|
57
|
+
this.block.instrs.push({ op: 'cmp', dst, lhs, cop, rhs });
|
|
58
|
+
}
|
|
59
|
+
emitCall(fn, args, dst) {
|
|
60
|
+
if (dst)
|
|
61
|
+
this.locals.add(dst);
|
|
62
|
+
this.block.instrs.push({ op: 'call', fn, args, dst });
|
|
63
|
+
}
|
|
64
|
+
emitRaw(cmd) {
|
|
65
|
+
this.block.instrs.push({ op: 'raw', cmd });
|
|
66
|
+
}
|
|
67
|
+
// -------------------------------------------------------------------------
|
|
68
|
+
// Terminators
|
|
69
|
+
// -------------------------------------------------------------------------
|
|
70
|
+
emitJump(target) {
|
|
71
|
+
this.sealBlock({ op: 'jump', target });
|
|
72
|
+
}
|
|
73
|
+
emitJumpIf(cond, then, else_) {
|
|
74
|
+
this.sealBlock({ op: 'jump_if', cond, then, else_ });
|
|
75
|
+
}
|
|
76
|
+
emitReturn(value) {
|
|
77
|
+
this.sealBlock({ op: 'return', value });
|
|
78
|
+
}
|
|
79
|
+
emitTickYield(continuation) {
|
|
80
|
+
this.sealBlock({ op: 'tick_yield', continuation });
|
|
81
|
+
}
|
|
82
|
+
// -------------------------------------------------------------------------
|
|
83
|
+
// Build
|
|
84
|
+
// -------------------------------------------------------------------------
|
|
85
|
+
build(name, params, isTickLoop = false) {
|
|
86
|
+
return {
|
|
87
|
+
name,
|
|
88
|
+
params,
|
|
89
|
+
locals: Array.from(this.locals),
|
|
90
|
+
blocks: this.blocks,
|
|
91
|
+
isTickLoop,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.IRBuilder = IRBuilder;
|
|
96
|
+
function buildModule(namespace, fns, globals = []) {
|
|
97
|
+
return { namespace, functions: fns, globals };
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=builder.js.map
|