redscript-mc 1.2.25 → 1.2.27
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/README.md +67 -9
- package/README.zh.md +61 -4
- package/dist/__tests__/cli.test.js +1 -1
- package/dist/__tests__/codegen.test.js +12 -6
- package/dist/__tests__/e2e.test.js +6 -6
- package/dist/__tests__/lowering.test.js +8 -8
- package/dist/__tests__/optimizer.test.js +31 -0
- package/dist/__tests__/stdlib-advanced.test.d.ts +4 -0
- package/dist/__tests__/stdlib-advanced.test.js +378 -0
- package/dist/__tests__/stdlib-bigint.test.d.ts +7 -0
- package/dist/__tests__/stdlib-bigint.test.js +428 -0
- package/dist/__tests__/stdlib-math.test.d.ts +7 -0
- package/dist/__tests__/stdlib-math.test.js +352 -0
- package/dist/__tests__/stdlib-vec.test.d.ts +4 -0
- package/dist/__tests__/stdlib-vec.test.js +264 -0
- package/dist/ast/types.d.ts +17 -1
- package/dist/codegen/mcfunction/index.js +154 -18
- package/dist/codegen/var-allocator.d.ts +17 -0
- package/dist/codegen/var-allocator.js +26 -0
- package/dist/compile.d.ts +14 -0
- package/dist/compile.js +62 -5
- 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/gcd2/function/__load.mcfunction +3 -0
- package/dist/data/gcd2/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd2/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd2/function/abs.mcfunction +7 -0
- package/dist/data/gcd2/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd2/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd2/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd2/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3/function/__load.mcfunction +3 -0
- package/dist/data/gcd3/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd3/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd3/function/abs.mcfunction +7 -0
- package/dist/data/gcd3/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd3/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd3/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd3/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3/function/test.mcfunction +7 -0
- package/dist/data/gcd3nm/function/__load.mcfunction +3 -0
- package/dist/data/gcd3nm/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd3nm/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd3nm/function/abs.mcfunction +7 -0
- package/dist/data/gcd3nm/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd3nm/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd3nm/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd3nm/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3nm/function/test.mcfunction +7 -0
- package/dist/data/gcd_test/function/__load.mcfunction +3 -0
- package/dist/data/gcd_test/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd_test/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd_test/function/abs.mcfunction +7 -0
- package/dist/data/gcd_test/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd_test/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd_test/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd_test/function/gcd.mcfunction +14 -0
- package/dist/data/isqrttest/function/__load.mcfunction +6 -0
- package/dist/data/isqrttest/function/isqrt/loop_body_4.mcfunction +12 -0
- package/dist/data/isqrttest/function/isqrt/loop_check_3.mcfunction +5 -0
- package/dist/data/isqrttest/function/isqrt/loop_exit_5.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt/merge_2.mcfunction +4 -0
- package/dist/data/isqrttest/function/isqrt/merge_8.mcfunction +6 -0
- package/dist/data/isqrttest/function/isqrt/then_0.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt/then_6.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt.mcfunction +7 -0
- package/dist/data/isqrttest/function/test.mcfunction +6 -0
- package/dist/data/mathtest/function/__load.mcfunction +3 -0
- package/dist/data/mathtest/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/mathtest/function/abs/then_0.mcfunction +5 -0
- package/dist/data/mathtest/function/abs.mcfunction +6 -0
- package/dist/data/mathtest/function/test.mcfunction +5 -0
- package/dist/data/minecraft/tags/function/load.json +5 -0
- package/dist/data/minecraft/tags/function/tick.json +5 -0
- package/dist/data/mypack/function/__load.mcfunction +13 -0
- package/dist/data/mypack/function/_atan_init.mcfunction +2 -0
- package/dist/data/mypack/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/mypack/function/abs/then_0.mcfunction +5 -0
- package/dist/data/mypack/function/abs.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/__sgi_1.mcfunction +2 -0
- package/dist/data/mypack/function/atan2_fixed/else_34.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/loop_body_31.mcfunction +19 -0
- package/dist/data/mypack/function/atan2_fixed/loop_check_30.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/loop_exit_32.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_11.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_14.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/merge_17.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_2.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_20.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_23.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_26.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_29.mcfunction +4 -0
- package/dist/data/mypack/function/atan2_fixed/merge_38.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_41.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_44.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_47.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_5.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_8.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_0.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_12.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_15.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_18.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_21.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_24.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_27.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/then_3.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_33.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_36.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_39.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_42.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_45.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_6.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_9.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed.mcfunction +7 -0
- package/dist/data/mypack/function/my_game.mcfunction +10 -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/reqtest/function/__load.mcfunction +4 -0
- package/dist/data/reqtest/function/_table_init.mcfunction +2 -0
- package/dist/data/reqtest/function/no_trig.mcfunction +3 -0
- package/dist/data/reqtest/function/use_table.mcfunction +4 -0
- package/dist/data/reqtest2/function/__load.mcfunction +3 -0
- package/dist/data/reqtest2/function/no_trig.mcfunction +3 -0
- package/dist/data/runtime/function/__load.mcfunction +5 -0
- package/dist/data/runtime/function/__tick.mcfunction +2 -0
- package/dist/data/runtime/function/counter_tick/then_0.mcfunction +3 -0
- package/dist/data/runtime/function/counter_tick.mcfunction +13 -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/swap_test/function/__load.mcfunction +3 -0
- package/dist/data/swap_test/function/gcd_old/loop_body_1.mcfunction +7 -0
- package/dist/data/swap_test/function/gcd_old/loop_check_0.mcfunction +5 -0
- package/dist/data/swap_test/function/gcd_old/loop_exit_2.mcfunction +3 -0
- package/dist/data/swap_test/function/gcd_old.mcfunction +8 -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/gcd2.map.json +15 -0
- package/dist/gcd3.map.json +17 -0
- package/dist/gcd_test.map.json +15 -0
- package/dist/index.js +20 -1
- package/dist/ir/types.d.ts +4 -0
- package/dist/isqrttest.map.json +15 -0
- package/dist/lexer/index.d.ts +1 -1
- package/dist/lexer/index.js +1 -0
- package/dist/lowering/index.d.ts +5 -0
- package/dist/lowering/index.js +154 -14
- package/dist/mathtest.map.json +6 -0
- package/dist/mypack.map.json +27 -0
- package/dist/optimizer/dce.js +21 -5
- package/dist/optimizer/passes.js +18 -6
- package/dist/optimizer/structure.js +7 -0
- package/dist/pack.mcmeta +6 -0
- package/dist/parser/index.d.ts +5 -0
- package/dist/parser/index.js +43 -2
- package/dist/reqtest.map.json +4 -0
- package/dist/reqtest2.map.json +4 -0
- package/dist/runtime/index.d.ts +6 -0
- package/dist/runtime/index.js +130 -9
- package/dist/runtime.map.json +7 -0
- package/dist/swap_test.map.json +14 -0
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/examples/showcase.mcrs +505 -0
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +1 -1
- package/src/__tests__/codegen.test.ts +12 -6
- package/src/__tests__/e2e.test.ts +6 -6
- package/src/__tests__/lowering.test.ts +8 -8
- package/src/__tests__/optimizer.test.ts +33 -0
- package/src/__tests__/stdlib-advanced.test.ts +379 -0
- package/src/__tests__/stdlib-bigint.test.ts +427 -0
- package/src/__tests__/stdlib-math.test.ts +374 -0
- package/src/__tests__/stdlib-vec.test.ts +259 -0
- package/src/ast/types.ts +11 -1
- package/src/codegen/mcfunction/index.ts +143 -19
- package/src/codegen/var-allocator.ts +29 -0
- package/src/compile.ts +72 -5
- package/src/index.ts +21 -1
- package/src/ir/types.ts +2 -0
- package/src/lexer/index.ts +2 -1
- package/src/lowering/index.ts +171 -14
- package/src/optimizer/dce.ts +22 -5
- package/src/optimizer/passes.ts +18 -5
- package/src/optimizer/structure.ts +6 -1
- package/src/parser/index.ts +47 -2
- package/src/runtime/index.ts +130 -10
- package/src/stdlib/advanced.mcrs +330 -0
- package/src/stdlib/bigint.mcrs +205 -0
- package/src/stdlib/math.mcrs +274 -21
- package/src/stdlib/vec.mcrs +246 -0
package/dist/lexer/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Handles special cases like entity selectors vs decorators,
|
|
6
6
|
* range literals, and raw commands.
|
|
7
7
|
*/
|
|
8
|
-
export type TokenKind = 'fn' | 'let' | 'const' | 'if' | 'else' | 'while' | 'for' | 'foreach' | 'match' | 'return' | 'break' | 'continue' | 'as' | 'at' | 'in' | 'is' | 'struct' | 'impl' | 'enum' | 'trigger' | 'namespace' | 'execute' | 'run' | 'unless' | 'declare' | 'int' | 'bool' | 'float' | 'string' | 'void' | 'BlockPos' | 'true' | 'false' | 'selector' | 'decorator' | 'int_lit' | 'float_lit' | 'byte_lit' | 'short_lit' | 'long_lit' | 'double_lit' | 'string_lit' | 'f_string' | 'range_lit' | 'rel_coord' | 'local_coord' | '+' | '-' | '*' | '/' | '%' | '~' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | '&&' | '||' | '!' | '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '{' | '}' | '(' | ')' | '[' | ']' | ',' | ';' | ':' | '::' | '->' | '=>' | '.' | 'ident' | 'mc_name' | 'raw_cmd' | 'eof';
|
|
8
|
+
export type TokenKind = 'fn' | 'let' | 'const' | 'if' | 'else' | 'while' | 'for' | 'foreach' | 'match' | 'return' | 'break' | 'continue' | 'as' | 'at' | 'in' | 'is' | 'struct' | 'impl' | 'enum' | 'trigger' | 'namespace' | 'module' | 'execute' | 'run' | 'unless' | 'declare' | 'int' | 'bool' | 'float' | 'string' | 'void' | 'BlockPos' | 'true' | 'false' | 'selector' | 'decorator' | 'int_lit' | 'float_lit' | 'byte_lit' | 'short_lit' | 'long_lit' | 'double_lit' | 'string_lit' | 'f_string' | 'range_lit' | 'rel_coord' | 'local_coord' | '+' | '-' | '*' | '/' | '%' | '~' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | '&&' | '||' | '!' | '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '{' | '}' | '(' | ')' | '[' | ']' | ',' | ';' | ':' | '::' | '->' | '=>' | '.' | 'ident' | 'mc_name' | 'raw_cmd' | 'eof';
|
|
9
9
|
export interface Token {
|
|
10
10
|
kind: TokenKind;
|
|
11
11
|
value: string;
|
package/dist/lexer/index.js
CHANGED
package/dist/lowering/index.d.ts
CHANGED
|
@@ -23,6 +23,11 @@ export declare class Lowering {
|
|
|
23
23
|
private implMethods;
|
|
24
24
|
private specializedFunctions;
|
|
25
25
|
private currentFn;
|
|
26
|
+
/** Unique IR variable name for a local variable, scoped to the current function.
|
|
27
|
+
* Prevents cross-function scoreboard slot collisions: $fn_x ≠ $gn_x.
|
|
28
|
+
* Only applies to user-defined locals/params; internal slots ($p0, $ret) are
|
|
29
|
+
* intentionally global (calling convention). */
|
|
30
|
+
private fnVar;
|
|
26
31
|
private currentStdlibCallSite?;
|
|
27
32
|
private foreachCounter;
|
|
28
33
|
private lambdaCounter;
|
package/dist/lowering/index.js
CHANGED
|
@@ -128,6 +128,9 @@ const BUILTINS = {
|
|
|
128
128
|
setTimeout: () => null, // Special handling
|
|
129
129
|
setInterval: () => null, // Special handling
|
|
130
130
|
clearInterval: () => null, // Special handling
|
|
131
|
+
storage_get_int: () => null, // Special handling (dynamic NBT array read via macro)
|
|
132
|
+
storage_set_array: () => null, // Special handling (write literal NBT array to storage)
|
|
133
|
+
storage_set_int: () => null, // Special handling (dynamic NBT array write via macro)
|
|
131
134
|
};
|
|
132
135
|
function getSpan(node) {
|
|
133
136
|
return node?.span;
|
|
@@ -196,6 +199,13 @@ function emitBlockPos(pos) {
|
|
|
196
199
|
// Lowering Class
|
|
197
200
|
// ---------------------------------------------------------------------------
|
|
198
201
|
class Lowering {
|
|
202
|
+
/** Unique IR variable name for a local variable, scoped to the current function.
|
|
203
|
+
* Prevents cross-function scoreboard slot collisions: $fn_x ≠ $gn_x.
|
|
204
|
+
* Only applies to user-defined locals/params; internal slots ($p0, $ret) are
|
|
205
|
+
* intentionally global (calling convention). */
|
|
206
|
+
fnVar(name) {
|
|
207
|
+
return `$${this.currentFn}_${name}`;
|
|
208
|
+
}
|
|
199
209
|
currentEntityContext() {
|
|
200
210
|
return this.entityContextStack.length > 0
|
|
201
211
|
? this.entityContextStack[this.entityContextStack.length - 1]
|
|
@@ -330,12 +340,30 @@ class Lowering {
|
|
|
330
340
|
}
|
|
331
341
|
preScanExpr(expr, paramNames, macroParams) {
|
|
332
342
|
if (expr.kind === 'call' && BUILTINS[expr.fn] !== undefined) {
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
343
|
+
// Only trigger macro param detection for builtins that actually emit
|
|
344
|
+
// MC commands with $(param) inline in the current function body.
|
|
345
|
+
// Special-handled builtins (storage_get_int / storage_set_int / etc.) are
|
|
346
|
+
// declared as `() => null` — they create their own sub-functions for macro
|
|
347
|
+
// indirection and do NOT require the surrounding function to be a macro.
|
|
348
|
+
const handler = BUILTINS[expr.fn];
|
|
349
|
+
const isSpecialHandled = (() => {
|
|
350
|
+
try {
|
|
351
|
+
return handler() === null;
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
})();
|
|
357
|
+
if (!isSpecialHandled) {
|
|
358
|
+
for (const arg of expr.args) {
|
|
359
|
+
if (arg.kind === 'ident' && paramNames.has(arg.name)) {
|
|
360
|
+
macroParams.add(arg.name);
|
|
361
|
+
}
|
|
337
362
|
}
|
|
338
363
|
}
|
|
364
|
+
// Always recurse into args for nested calls/expressions
|
|
365
|
+
for (const arg of expr.args)
|
|
366
|
+
this.preScanExpr(arg, paramNames, macroParams);
|
|
339
367
|
return;
|
|
340
368
|
}
|
|
341
369
|
// Recurse into sub-expressions for other call types
|
|
@@ -564,13 +592,13 @@ class Lowering {
|
|
|
564
592
|
this.stringValues.set(param.name, '');
|
|
565
593
|
continue;
|
|
566
594
|
}
|
|
567
|
-
this.varMap.set(param.name,
|
|
595
|
+
this.varMap.set(param.name, this.fnVar(param.name));
|
|
568
596
|
}
|
|
569
597
|
}
|
|
570
598
|
else {
|
|
571
599
|
for (const param of runtimeParams) {
|
|
572
600
|
const paramName = param.name;
|
|
573
|
-
this.varMap.set(paramName,
|
|
601
|
+
this.varMap.set(paramName, this.fnVar(paramName));
|
|
574
602
|
this.varTypes.set(paramName, this.normalizeType(param.type));
|
|
575
603
|
}
|
|
576
604
|
}
|
|
@@ -581,18 +609,22 @@ class Lowering {
|
|
|
581
609
|
}
|
|
582
610
|
// Start entry block
|
|
583
611
|
this.builder.startBlock('entry');
|
|
584
|
-
// Copy params from
|
|
612
|
+
// Copy params from the parameter-passing slots to named local variables.
|
|
613
|
+
// Use { kind: 'param', index: i } so the codegen resolves to
|
|
614
|
+
// alloc.internal('p{i}') consistently in both mangle and no-mangle modes,
|
|
615
|
+
// avoiding the slot-collision between the internal register and a user variable
|
|
616
|
+
// named 'p0'/'p1' that occurred with { kind: 'var', name: '$p0' }.
|
|
585
617
|
for (let i = 0; i < runtimeParams.length; i++) {
|
|
586
618
|
const paramName = runtimeParams[i].name;
|
|
587
|
-
const varName =
|
|
588
|
-
this.builder.emitAssign(varName, { kind: '
|
|
619
|
+
const varName = this.fnVar(paramName);
|
|
620
|
+
this.builder.emitAssign(varName, { kind: 'param', index: i });
|
|
589
621
|
}
|
|
590
622
|
if (staticEventDec) {
|
|
591
623
|
for (let i = 0; i < fn.params.length; i++) {
|
|
592
624
|
const param = fn.params[i];
|
|
593
625
|
const expected = eventParamSpecs[i];
|
|
594
626
|
if (expected?.type.kind === 'named' && expected.type.name !== 'string') {
|
|
595
|
-
this.builder.emitAssign(
|
|
627
|
+
this.builder.emitAssign(this.fnVar(param.name), { kind: 'const', value: 0 });
|
|
596
628
|
}
|
|
597
629
|
}
|
|
598
630
|
}
|
|
@@ -649,6 +681,22 @@ class Lowering {
|
|
|
649
681
|
if (fn.decorators.some(d => d.name === 'load')) {
|
|
650
682
|
irFn.isLoadInit = true;
|
|
651
683
|
}
|
|
684
|
+
// @requires("dep_fn") — when this function is compiled in, dep_fn is also
|
|
685
|
+
// called from __load. The dep_fn itself does NOT need @load; it can be a
|
|
686
|
+
// private (_) function that only runs at load time when this fn is used.
|
|
687
|
+
const requiredLoads = [];
|
|
688
|
+
for (const d of fn.decorators) {
|
|
689
|
+
if (d.name === 'require_on_load') {
|
|
690
|
+
for (const arg of d.rawArgs ?? []) {
|
|
691
|
+
if (arg.kind === 'string') {
|
|
692
|
+
requiredLoads.push(arg.value);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (requiredLoads.length > 0) {
|
|
698
|
+
irFn.requiredLoads = requiredLoads;
|
|
699
|
+
}
|
|
652
700
|
// Handle tick rate counter if needed
|
|
653
701
|
if (tickRate && tickRate > 1) {
|
|
654
702
|
this.wrapWithTickRate(irFn, tickRate);
|
|
@@ -773,7 +821,7 @@ class Lowering {
|
|
|
773
821
|
if (this.currentContext.binding === stmt.name) {
|
|
774
822
|
throw new diagnostics_1.DiagnosticError('LoweringError', `Cannot redeclare foreach binding '${stmt.name}'`, stmt.span ?? { line: 0, col: 0 });
|
|
775
823
|
}
|
|
776
|
-
const varName =
|
|
824
|
+
const varName = this.fnVar(stmt.name);
|
|
777
825
|
this.varMap.set(stmt.name, varName);
|
|
778
826
|
// Track variable type
|
|
779
827
|
const declaredType = stmt.type ? this.normalizeType(stmt.type) : this.inferExprType(stmt.init);
|
|
@@ -1049,7 +1097,7 @@ class Lowering {
|
|
|
1049
1097
|
this.builder.startBlock(exitLabel);
|
|
1050
1098
|
}
|
|
1051
1099
|
lowerForRangeStmt(stmt) {
|
|
1052
|
-
const loopVar =
|
|
1100
|
+
const loopVar = this.fnVar(stmt.varName);
|
|
1053
1101
|
const subFnName = `${this.currentFn}/__for_${this.foreachCounter++}`;
|
|
1054
1102
|
// Initialize loop variable
|
|
1055
1103
|
this.varMap.set(stmt.varName, loopVar);
|
|
@@ -1208,7 +1256,7 @@ class Lowering {
|
|
|
1208
1256
|
return;
|
|
1209
1257
|
}
|
|
1210
1258
|
const arrayType = this.inferExprType(stmt.iterable);
|
|
1211
|
-
const bindingVar =
|
|
1259
|
+
const bindingVar = this.fnVar(stmt.binding);
|
|
1212
1260
|
const indexVar = this.builder.freshTemp();
|
|
1213
1261
|
const lengthVar = this.builder.freshTemp();
|
|
1214
1262
|
const condVar = this.builder.freshTemp();
|
|
@@ -2216,6 +2264,98 @@ class Lowering {
|
|
|
2216
2264
|
this.builder.emitRaw(`execute store result score ${dst} rs run data get ${targetType} ${target} ${path} ${scale}`);
|
|
2217
2265
|
return { kind: 'var', name: dst };
|
|
2218
2266
|
}
|
|
2267
|
+
// storage_get_int(storage_ns, array_key, index) -> int
|
|
2268
|
+
// Reads one element from an NBT int-array stored in data storage.
|
|
2269
|
+
// storage_ns : e.g. "math:tables"
|
|
2270
|
+
// array_key : e.g. "sin"
|
|
2271
|
+
// index : integer index (const or runtime)
|
|
2272
|
+
//
|
|
2273
|
+
// Const index: execute store result score $dst rs run data get storage math:tables sin[N] 1
|
|
2274
|
+
// Runtime index: macro sub-function via rs:heap, mirrors readArrayElement.
|
|
2275
|
+
if (name === 'storage_get_int') {
|
|
2276
|
+
const storageNs = this.exprToString(args[0]); // "math:tables"
|
|
2277
|
+
const arrayKey = this.exprToString(args[1]); // "sin"
|
|
2278
|
+
const indexOperand = this.lowerExpr(args[2]);
|
|
2279
|
+
const dst = this.builder.freshTemp();
|
|
2280
|
+
if (indexOperand.kind === 'const') {
|
|
2281
|
+
this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${storageNs} ${arrayKey}[${indexOperand.value}] 1`);
|
|
2282
|
+
}
|
|
2283
|
+
else {
|
|
2284
|
+
// Runtime index: store the index into rs:heap under a unique key,
|
|
2285
|
+
// then call a macro sub-function that uses $(key) to index the array.
|
|
2286
|
+
const macroKey = `__sgi_${this.foreachCounter++}`;
|
|
2287
|
+
const subFnName = `${this.currentFn}/__sgi_${this.foreachCounter++}`;
|
|
2288
|
+
const indexVar = indexOperand.kind === 'var'
|
|
2289
|
+
? indexOperand.name
|
|
2290
|
+
: this.operandToVar(indexOperand);
|
|
2291
|
+
this.builder.emitRaw(`execute store result storage rs:heap ${macroKey} int 1 run scoreboard players get ${indexVar} rs`);
|
|
2292
|
+
this.builder.emitRaw(`function ${this.namespace}:${subFnName} with storage rs:heap`);
|
|
2293
|
+
// Prefix \x01 is a sentinel for the MC macro '$' line-start marker.
|
|
2294
|
+
// We avoid using literal '$execute' here so the pre-alloc pass
|
|
2295
|
+
// doesn't mistakenly register 'execute' as a scoreboard variable.
|
|
2296
|
+
// Codegen replaces \x01 → '$' when emitting the mc function file.
|
|
2297
|
+
this.emitRawSubFunction(subFnName, `\x01execute store result score ${dst} rs run data get storage ${storageNs} ${arrayKey}[$(${macroKey})] 1`);
|
|
2298
|
+
}
|
|
2299
|
+
return { kind: 'var', name: dst };
|
|
2300
|
+
}
|
|
2301
|
+
// storage_set_array(storage_ns, array_key, nbt_array_literal)
|
|
2302
|
+
// Writes a literal NBT int array to data storage (used in @load for tables).
|
|
2303
|
+
// storage_set_array("math:tables", "sin", "[0, 17, 35, ...]")
|
|
2304
|
+
if (name === 'storage_set_array') {
|
|
2305
|
+
const storageNs = this.exprToString(args[0]);
|
|
2306
|
+
const arrayKey = this.exprToString(args[1]);
|
|
2307
|
+
const nbtLiteral = this.exprToString(args[2]);
|
|
2308
|
+
this.builder.emitRaw(`data modify storage ${storageNs} ${arrayKey} set value ${nbtLiteral}`);
|
|
2309
|
+
return { kind: 'const', value: 0 };
|
|
2310
|
+
}
|
|
2311
|
+
// storage_set_int(storage_ns, array_key, index, value) -> void
|
|
2312
|
+
// Writes one integer element into an NBT int-array stored in data storage.
|
|
2313
|
+
// storage_ns : e.g. "rs:bigint"
|
|
2314
|
+
// array_key : e.g. "a"
|
|
2315
|
+
// index : element index (const or runtime)
|
|
2316
|
+
// value : integer value to write (const or runtime)
|
|
2317
|
+
//
|
|
2318
|
+
// Const index + const value:
|
|
2319
|
+
// execute store result storage <ns> <key>[N] int 1 run scoreboard players set $const_V rs V
|
|
2320
|
+
// Runtime index or value: macro sub-function via rs:heap
|
|
2321
|
+
if (name === 'storage_set_int') {
|
|
2322
|
+
const storageNs = this.exprToString(args[0]);
|
|
2323
|
+
const arrayKey = this.exprToString(args[1]);
|
|
2324
|
+
const indexOperand = this.lowerExpr(args[2]);
|
|
2325
|
+
const valueOperand = this.lowerExpr(args[3]);
|
|
2326
|
+
if (indexOperand.kind === 'const') {
|
|
2327
|
+
// Static index — use execute store result to write to the fixed slot
|
|
2328
|
+
const valVar = valueOperand.kind === 'var'
|
|
2329
|
+
? valueOperand.name
|
|
2330
|
+
: this.operandToVar(valueOperand);
|
|
2331
|
+
this.builder.emitRaw(`execute store result storage ${storageNs} ${arrayKey}[${indexOperand.value}] int 1 run scoreboard players get ${valVar} rs`);
|
|
2332
|
+
}
|
|
2333
|
+
else {
|
|
2334
|
+
// Runtime index: we need a macro sub-function.
|
|
2335
|
+
// Store index + value into rs:heap, call macro that does:
|
|
2336
|
+
// $data modify storage <ns> <key>[$(idx_key)] set value $(val_key)
|
|
2337
|
+
const macroIdxKey = `__ssi_i_${this.foreachCounter++}`;
|
|
2338
|
+
const macroValKey = `__ssi_v_${this.foreachCounter++}`; // kept to pin valVar in optimizer
|
|
2339
|
+
const subFnName = `${this.currentFn}/__ssi_${this.foreachCounter++}`;
|
|
2340
|
+
const indexVar = indexOperand.kind === 'var'
|
|
2341
|
+
? indexOperand.name
|
|
2342
|
+
: this.operandToVar(indexOperand);
|
|
2343
|
+
const valVar = valueOperand.kind === 'var'
|
|
2344
|
+
? valueOperand.name
|
|
2345
|
+
: this.operandToVar(valueOperand);
|
|
2346
|
+
this.builder.emitRaw(`execute store result storage rs:heap ${macroIdxKey} int 1 run scoreboard players get ${indexVar} rs`);
|
|
2347
|
+
// Pin valVar in the optimizer's read-set so the assignment is not dead-code-eliminated.
|
|
2348
|
+
// The value is stored to rs:heap but NOT used by the macro (the macro reads the scoreboard
|
|
2349
|
+
// slot directly to avoid the MC 'data modify set value $(n)' macro substitution bug).
|
|
2350
|
+
this.builder.emitRaw(`execute store result storage rs:heap ${macroValKey} int 1 run scoreboard players get ${valVar} rs`);
|
|
2351
|
+
this.builder.emitRaw(`function ${this.namespace}:${subFnName} with storage rs:heap`);
|
|
2352
|
+
// Use execute store result (not 'data modify set value $(val)') to avoid MC macro
|
|
2353
|
+
// substitution bugs with numeric values. The scoreboard slot ${valVar} is hardcoded
|
|
2354
|
+
// into the macro sub-function at compile time — only the array index is macro-substituted.
|
|
2355
|
+
this.emitRawSubFunction(subFnName, `\x01execute store result storage ${storageNs} ${arrayKey}[$(${macroIdxKey})] int 1 run scoreboard players get ${valVar} rs`);
|
|
2356
|
+
}
|
|
2357
|
+
return { kind: 'const', value: 0 };
|
|
2358
|
+
}
|
|
2219
2359
|
// data_merge(target, nbt) — merge NBT into entity/block/storage
|
|
2220
2360
|
// data_merge(@s, { Invisible: 1b, Silent: 1b })
|
|
2221
2361
|
if (name === 'data_merge') {
|
|
@@ -3006,7 +3146,7 @@ class Lowering {
|
|
|
3006
3146
|
const indexVar = index.kind === 'var' ? index.name : this.operandToVar(index);
|
|
3007
3147
|
this.builder.emitRaw(`execute store result storage rs:heap ${macroKey} int 1 run scoreboard players get ${indexVar} rs`);
|
|
3008
3148
|
this.builder.emitRaw(`function ${this.namespace}:${subFnName} with storage rs:heap`);
|
|
3009
|
-
this.emitRawSubFunction(subFnName,
|
|
3149
|
+
this.emitRawSubFunction(subFnName, `\x01execute store result score ${dst} rs run data get storage rs:heap ${arrayName}[$(${macroKey})]`);
|
|
3010
3150
|
return { kind: 'var', name: dst };
|
|
3011
3151
|
}
|
|
3012
3152
|
emitRawSubFunction(name, ...commands) {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$o": "x",
|
|
3
|
+
"$r": "execute",
|
|
4
|
+
"$u": "y",
|
|
5
|
+
"$aa": "ax",
|
|
6
|
+
"$ad": "ay",
|
|
7
|
+
"$ai": "swapped",
|
|
8
|
+
"$ak": "tmp",
|
|
9
|
+
"$al": "lo",
|
|
10
|
+
"$am": "hi",
|
|
11
|
+
"$ar": "mid",
|
|
12
|
+
"$as": "t",
|
|
13
|
+
"$ax": "theta",
|
|
14
|
+
"$a": "const:0",
|
|
15
|
+
"$b": "const:1",
|
|
16
|
+
"$c": "const:2",
|
|
17
|
+
"$d": "const:45",
|
|
18
|
+
"$e": "const:90",
|
|
19
|
+
"$f": "const:180",
|
|
20
|
+
"$g": "const:270",
|
|
21
|
+
"$h": "const:360",
|
|
22
|
+
"$i": "const:1000",
|
|
23
|
+
"$j": "const:46340",
|
|
24
|
+
"$k": "internal:ret",
|
|
25
|
+
"$n": "internal:p0",
|
|
26
|
+
"$t": "internal:p1"
|
|
27
|
+
}
|
package/dist/optimizer/dce.js
CHANGED
|
@@ -115,12 +115,17 @@ class DeadCodeEliminator {
|
|
|
115
115
|
findEntryPoints(program) {
|
|
116
116
|
const entries = new Set();
|
|
117
117
|
for (const fn of program.declarations) {
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
// Library functions (from `module library;` or `librarySources`) are
|
|
119
|
+
// NOT MC entry points — they're only kept if reachable from user code.
|
|
120
|
+
// Exception: decorators like @tick / @load / @on / @keep always force inclusion.
|
|
121
|
+
if (!fn.isLibraryFn) {
|
|
122
|
+
// All top-level non-library functions are entry points (callable via /function)
|
|
123
|
+
// Exception: functions starting with _ are considered private/internal
|
|
124
|
+
if (!fn.name.startsWith('_')) {
|
|
125
|
+
entries.add(fn.name);
|
|
126
|
+
}
|
|
122
127
|
}
|
|
123
|
-
// Decorated functions are always entry points
|
|
128
|
+
// Decorated functions are always entry points regardless of library mode or _ prefix
|
|
124
129
|
if (fn.decorators.some(decorator => [
|
|
125
130
|
'tick',
|
|
126
131
|
'load',
|
|
@@ -148,6 +153,17 @@ class DeadCodeEliminator {
|
|
|
148
153
|
}
|
|
149
154
|
this.reachableFunctions.add(fnName);
|
|
150
155
|
this.collectFunctionRefs(fn);
|
|
156
|
+
// @requires("dep") — when fn is reachable, its required dependencies are
|
|
157
|
+
// also pulled into the reachable set so they survive DCE.
|
|
158
|
+
for (const decorator of fn.decorators) {
|
|
159
|
+
if (decorator.name === 'require_on_load') {
|
|
160
|
+
for (const arg of decorator.rawArgs ?? []) {
|
|
161
|
+
if (arg.kind === 'string') {
|
|
162
|
+
this.markReachable(arg.value);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
151
167
|
}
|
|
152
168
|
collectFunctionRefs(fn) {
|
|
153
169
|
const scope = [fn.params.map(param => ({ id: `param:${fn.name}:${param.name}`, name: param.name }))];
|
package/dist/optimizer/passes.js
CHANGED
|
@@ -93,32 +93,44 @@ function copyPropagation(fn) {
|
|
|
93
93
|
return op;
|
|
94
94
|
return copies.get(op.name) ?? op;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Invalidate all copies that became stale because `written` was modified.
|
|
98
|
+
* When $y is overwritten, any mapping copies[$tmp] = $y is now stale:
|
|
99
|
+
* reading $tmp would return the OLD $y value via the copy, but $y now holds
|
|
100
|
+
* a different value. Remove both the direct entry (copies[$y]) and every
|
|
101
|
+
* reverse entry that points at $y.
|
|
102
|
+
*/
|
|
103
|
+
function invalidate(written) {
|
|
104
|
+
copies.delete(written);
|
|
105
|
+
for (const [k, v] of copies) {
|
|
106
|
+
if (v.kind === 'var' && v.name === written)
|
|
107
|
+
copies.delete(k);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
96
110
|
const newInstrs = [];
|
|
97
111
|
for (const instr of block.instrs) {
|
|
98
112
|
switch (instr.op) {
|
|
99
113
|
case 'assign': {
|
|
100
114
|
const src = resolve(instr.src);
|
|
115
|
+
invalidate(instr.dst);
|
|
101
116
|
// Only propagate scalars (var or const), not storage
|
|
102
117
|
if (src.kind === 'var' || src.kind === 'const') {
|
|
103
118
|
copies.set(instr.dst, src);
|
|
104
119
|
}
|
|
105
|
-
else {
|
|
106
|
-
copies.delete(instr.dst);
|
|
107
|
-
}
|
|
108
120
|
newInstrs.push({ ...instr, src });
|
|
109
121
|
break;
|
|
110
122
|
}
|
|
111
123
|
case 'binop':
|
|
112
|
-
|
|
124
|
+
invalidate(instr.dst);
|
|
113
125
|
newInstrs.push({ ...instr, lhs: resolve(instr.lhs), rhs: resolve(instr.rhs) });
|
|
114
126
|
break;
|
|
115
127
|
case 'cmp':
|
|
116
|
-
|
|
128
|
+
invalidate(instr.dst);
|
|
117
129
|
newInstrs.push({ ...instr, lhs: resolve(instr.lhs), rhs: resolve(instr.rhs) });
|
|
118
130
|
break;
|
|
119
131
|
case 'call':
|
|
120
132
|
if (instr.dst)
|
|
121
|
-
|
|
133
|
+
invalidate(instr.dst);
|
|
122
134
|
newInstrs.push({ ...instr, args: instr.args.map(resolve) });
|
|
123
135
|
break;
|
|
124
136
|
default:
|
|
@@ -21,6 +21,8 @@ function operandToScore(op) {
|
|
|
21
21
|
return `${varRef(op.name)} ${OBJ}`;
|
|
22
22
|
if (op.kind === 'const')
|
|
23
23
|
return `$const_${op.value} ${OBJ}`;
|
|
24
|
+
if (op.kind === 'param')
|
|
25
|
+
return `$p${op.index} ${OBJ}`;
|
|
24
26
|
throw new Error(`Cannot convert storage operand to score: ${op.path}`);
|
|
25
27
|
}
|
|
26
28
|
function emitInstr(instr, namespace) {
|
|
@@ -35,6 +37,11 @@ function emitInstr(instr, namespace) {
|
|
|
35
37
|
cmd: `scoreboard players operation ${varRef(instr.dst)} ${OBJ} = ${varRef(instr.src.name)} ${OBJ}`,
|
|
36
38
|
});
|
|
37
39
|
}
|
|
40
|
+
else if (instr.src.kind === 'param') {
|
|
41
|
+
commands.push({
|
|
42
|
+
cmd: `scoreboard players operation ${varRef(instr.dst)} ${OBJ} = $p${instr.src.index} ${OBJ}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
38
45
|
else {
|
|
39
46
|
commands.push({
|
|
40
47
|
cmd: `execute store result score ${varRef(instr.dst)} ${OBJ} run data get storage ${instr.src.path}`,
|
package/dist/pack.mcmeta
ADDED
package/dist/parser/index.d.ts
CHANGED
|
@@ -11,6 +11,11 @@ export declare class Parser {
|
|
|
11
11
|
private pos;
|
|
12
12
|
private sourceLines;
|
|
13
13
|
private filePath?;
|
|
14
|
+
/** Set to true once `module library;` is seen — all subsequent fn declarations
|
|
15
|
+
* will be marked isLibraryFn=true. When library sources are parsed via the
|
|
16
|
+
* `librarySources` compile option, each source is parsed by its own fresh
|
|
17
|
+
* Parser instance, so this flag never bleeds into user code. */
|
|
18
|
+
private inLibraryMode;
|
|
14
19
|
constructor(tokens: Token[], source?: string, filePath?: string);
|
|
15
20
|
private peek;
|
|
16
21
|
private advance;
|
package/dist/parser/index.js
CHANGED
|
@@ -64,6 +64,11 @@ function computeIsSingle(raw) {
|
|
|
64
64
|
class Parser {
|
|
65
65
|
constructor(tokens, source, filePath) {
|
|
66
66
|
this.pos = 0;
|
|
67
|
+
/** Set to true once `module library;` is seen — all subsequent fn declarations
|
|
68
|
+
* will be marked isLibraryFn=true. When library sources are parsed via the
|
|
69
|
+
* `librarySources` compile option, each source is parsed by its own fresh
|
|
70
|
+
* Parser instance, so this flag never bleeds into user code. */
|
|
71
|
+
this.inLibraryMode = false;
|
|
67
72
|
this.tokens = tokens;
|
|
68
73
|
this.sourceLines = source?.split('\n') ?? [];
|
|
69
74
|
this.filePath = filePath;
|
|
@@ -135,6 +140,7 @@ class Parser {
|
|
|
135
140
|
const implBlocks = [];
|
|
136
141
|
const enums = [];
|
|
137
142
|
const consts = [];
|
|
143
|
+
let isLibrary = false;
|
|
138
144
|
// Check for namespace declaration
|
|
139
145
|
if (this.check('namespace')) {
|
|
140
146
|
this.advance();
|
|
@@ -142,6 +148,19 @@ class Parser {
|
|
|
142
148
|
namespace = name.value;
|
|
143
149
|
this.expect(';');
|
|
144
150
|
}
|
|
151
|
+
// Check for module declaration: `module library;`
|
|
152
|
+
// Library-mode: all functions parsed from this point are marked isLibraryFn=true.
|
|
153
|
+
// When using the `librarySources` compile option, each library source is parsed
|
|
154
|
+
// by its own fresh Parser — so this flag never bleeds into user code.
|
|
155
|
+
if (this.check('module')) {
|
|
156
|
+
this.advance();
|
|
157
|
+
const modKind = this.expect('ident');
|
|
158
|
+
if (modKind.value === 'library') {
|
|
159
|
+
isLibrary = true;
|
|
160
|
+
this.inLibraryMode = true;
|
|
161
|
+
}
|
|
162
|
+
this.expect(';');
|
|
163
|
+
}
|
|
145
164
|
// Parse struct and function declarations
|
|
146
165
|
while (!this.check('eof')) {
|
|
147
166
|
if (this.check('let')) {
|
|
@@ -168,7 +187,7 @@ class Parser {
|
|
|
168
187
|
declarations.push(this.parseFnDecl());
|
|
169
188
|
}
|
|
170
189
|
}
|
|
171
|
-
return { namespace, globals, declarations, structs, implBlocks, enums, consts };
|
|
190
|
+
return { namespace, globals, declarations, structs, implBlocks, enums, consts, isLibrary };
|
|
172
191
|
}
|
|
173
192
|
// -------------------------------------------------------------------------
|
|
174
193
|
// Struct Declaration
|
|
@@ -267,7 +286,8 @@ class Parser {
|
|
|
267
286
|
returnType = this.parseType();
|
|
268
287
|
}
|
|
269
288
|
const body = this.parseBlock();
|
|
270
|
-
|
|
289
|
+
const fn = this.withLoc({ name, params, returnType, decorators, body, isLibraryFn: this.inLibraryMode || undefined }, fnToken);
|
|
290
|
+
return fn;
|
|
271
291
|
}
|
|
272
292
|
/** Parse a `declare fn name(params): returnType;` stub — no body, just discard. */
|
|
273
293
|
parseDeclareStub() {
|
|
@@ -336,6 +356,27 @@ class Parser {
|
|
|
336
356
|
return { name, args };
|
|
337
357
|
}
|
|
338
358
|
}
|
|
359
|
+
// @require_on_load(fn_name) — when this fn is used, fn_name is called from __load.
|
|
360
|
+
// Accepts bare identifiers (with optional leading _) or quoted strings.
|
|
361
|
+
if (name === 'require_on_load') {
|
|
362
|
+
const rawArgs = [];
|
|
363
|
+
for (const part of argsStr.split(',')) {
|
|
364
|
+
const trimmed = part.trim();
|
|
365
|
+
// Bare identifier: @require_on_load(_math_init)
|
|
366
|
+
const identMatch = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
367
|
+
if (identMatch) {
|
|
368
|
+
rawArgs.push({ kind: 'string', value: identMatch[1] });
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
// Quoted string fallback: @require_on_load("_math_init")
|
|
372
|
+
const strMatch = trimmed.match(/^"([^"]*)"$/);
|
|
373
|
+
if (strMatch) {
|
|
374
|
+
rawArgs.push({ kind: 'string', value: strMatch[1] });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return { name, rawArgs };
|
|
379
|
+
}
|
|
339
380
|
// Handle key=value format (e.g., rate=20)
|
|
340
381
|
for (const part of argsStr.split(',')) {
|
|
341
382
|
const [key, val] = part.split('=').map(s => s.trim());
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export declare class MCRuntime {
|
|
|
43
43
|
private entityIdCounter;
|
|
44
44
|
private returnValue;
|
|
45
45
|
private shouldReturn;
|
|
46
|
+
private currentMacroContext;
|
|
46
47
|
constructor(namespace: string);
|
|
47
48
|
loadDatapack(dir: string): void;
|
|
48
49
|
loadFunction(name: string, lines: string[]): void;
|
|
@@ -56,8 +57,13 @@ export declare class MCRuntime {
|
|
|
56
57
|
private execExecute;
|
|
57
58
|
private parseNextSelector;
|
|
58
59
|
private execFunctionCmd;
|
|
60
|
+
/** Expand MC macro placeholders: $(key) → value from currentMacroContext */
|
|
61
|
+
private expandMacro;
|
|
59
62
|
private execData;
|
|
60
63
|
private parseDataValue;
|
|
64
|
+
/** Return the whole storage compound at storagePath as a flat key→value map.
|
|
65
|
+
* Used by 'function ... with storage' to provide macro context. */
|
|
66
|
+
private getStorageCompound;
|
|
61
67
|
private getStorageField;
|
|
62
68
|
private setStorageField;
|
|
63
69
|
private removeStorageField;
|