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/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<img src="./logo.png" alt="RedScript Logo" width="64" />
|
|
4
4
|
|
|
5
|
-
<img src="https://img.shields.io/badge/RedScript-1.2-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
|
|
5
|
+
<img src="https://img.shields.io/badge/RedScript-1.2.26-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
|
|
6
6
|
|
|
7
7
|
**A typed scripting language that compiles to Minecraft datapacks.**
|
|
8
8
|
|
|
9
9
|
Write clean game logic. RedScript handles the scoreboard spaghetti.
|
|
10
10
|
|
|
11
11
|
[](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml)
|
|
12
|
-
[](https://github.com/bkmashiro/redscript)
|
|
13
13
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
14
14
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
15
15
|
[](https://marketplace.visualstudio.com/items?itemName=bkmashiro.redscript-vscode)
|
|
@@ -76,7 +76,18 @@ fn stop() {
|
|
|
76
76
|
|
|
77
77
|
---
|
|
78
78
|
|
|
79
|
-
### What's New in v1.2
|
|
79
|
+
### What's New in v1.2.26
|
|
80
|
+
|
|
81
|
+
- **Math stdlib** (`math.mcrs`): 18 fixed-point functions — `abs`, `sign`, `min`, `max`, `clamp`, `lerp`, `isqrt`, `sqrt_fixed`, `pow_int`, `gcd`, `lcm`, `sin_fixed`, `cos_fixed`, `map`, `ceil_div`, `log2_int`, `mulfix`, `divfix`, `smoothstep`, `smootherstep`
|
|
82
|
+
- **Vector stdlib** (`vec.mcrs`): 2D and 3D geometry — dot/cross products, `length2d_fixed`, `atan2_fixed` (binary search, O(log 46)), `normalize2d`, `rotate2d`, `lerp2d`, full 3D cross product
|
|
83
|
+
- **Advanced stdlib** (`advanced.mcrs`): number theory (`fib`, `is_prime`, `collatz_steps`, `gcd`, `mod_pow`), hash/noise (`hash_int` splitmix32, `noise1d`), curves (`bezier_quad`), fractals (`mandelbrot_iter`, `julia_iter`), geometry experiments
|
|
84
|
+
- **BigInt** (`bigint.mcrs`): arbitrary precision integers — base 10,000 × 8 limbs = up to 32 decimal digits; `bigint_add/sub/compare/mul/fib` running on MC scoreboard + NBT storage
|
|
85
|
+
- **`module library;` pragma**: declare a file as a library; functions are tree-shaken out unless called — stdlib never bloats your pack
|
|
86
|
+
- **`storage_get_int` / `storage_set_int` builtins**: dynamic NBT int array read/write with runtime indices via MC 1.20.2 macro sub-functions
|
|
87
|
+
- **`@require_on_load(fn)` decorator**: declarative load-time dependency tracking for stdlib initializers (sin/cos table setup etc.)
|
|
88
|
+
- **Compiler fixes**: `isqrt` large-number convergence, optimizer copy propagation alias invalidation, cross-function variable collision, MCRuntime array-index regex
|
|
89
|
+
|
|
90
|
+
### What's New in v1.2.25
|
|
80
91
|
|
|
81
92
|
- `impl` blocks and methods for object-style APIs on structs
|
|
82
93
|
- `is` type narrowing for safer entity checks
|
|
@@ -275,14 +286,48 @@ redscript validate <file> Validate MC commands
|
|
|
275
286
|
|
|
276
287
|
### Standard Library
|
|
277
288
|
|
|
289
|
+
All stdlib files use `module library;` — only the functions you actually call are compiled in.
|
|
290
|
+
|
|
278
291
|
```rs
|
|
279
|
-
import "stdlib/math.mcrs" // abs, min, max, clamp
|
|
292
|
+
import "stdlib/math.mcrs" // abs, sign, min, max, clamp, lerp, isqrt, sqrt_fixed,
|
|
293
|
+
// pow_int, gcd, lcm, sin_fixed, cos_fixed, map, ceil_div,
|
|
294
|
+
// log2_int, mulfix, divfix, smoothstep, smootherstep
|
|
295
|
+
|
|
296
|
+
import "stdlib/vec.mcrs" // dot2d, cross2d, length2d_fixed, distance2d_fixed,
|
|
297
|
+
// manhattan, chebyshev, atan2_fixed, normalize2d_x/y,
|
|
298
|
+
// rotate2d_x/y, lerp2d_x/y, dot3d, cross3d_x/y/z,
|
|
299
|
+
// length3d_fixed
|
|
300
|
+
|
|
301
|
+
import "stdlib/advanced.mcrs" // fib, is_prime, collatz_steps, digit_sum, reverse_int,
|
|
302
|
+
// mod_pow, hash_int, noise1d, bezier_quad,
|
|
303
|
+
// mandelbrot_iter, julia_iter, angle_between,
|
|
304
|
+
// clamp_circle_x/y, newton_sqrt, digital_root
|
|
305
|
+
|
|
306
|
+
import "stdlib/bigint.mcrs" // bigint_init, bigint_from_int_a/b, bigint_add/sub/mul,
|
|
307
|
+
// bigint_compare, bigint_mul_small, bigint_fib
|
|
308
|
+
// — up to 32 decimal digits, runs on MC scoreboard
|
|
309
|
+
|
|
280
310
|
import "stdlib/player.mcrs" // is_alive, in_range, get_health
|
|
281
311
|
import "stdlib/timer.mcrs" // start_timer, tick_timer, has_elapsed
|
|
282
312
|
import "stdlib/cooldown.mcrs" // set_cooldown, check_cooldown
|
|
283
313
|
import "stdlib/mobs.mcrs" // ZOMBIE, SKELETON, CREEPER, ... (60+ constants)
|
|
284
314
|
```
|
|
285
315
|
|
|
316
|
+
**Example — computing Fibonacci(50) in-game:**
|
|
317
|
+
|
|
318
|
+
```rs
|
|
319
|
+
import "stdlib/bigint.mcrs"
|
|
320
|
+
|
|
321
|
+
fn show_fib() {
|
|
322
|
+
bigint_fib(50);
|
|
323
|
+
// F(50) = 12,586,269,025 — too big for int32, stored across 3 limbs:
|
|
324
|
+
let l0: int = bigint_get_a(0); // 9025
|
|
325
|
+
let l1: int = bigint_get_a(1); // 8626
|
|
326
|
+
let l2: int = bigint_get_a(2); // 125
|
|
327
|
+
say(f"F(50) limbs: {l2} {l1} {l0}");
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
286
331
|
---
|
|
287
332
|
|
|
288
333
|
### Further Reading
|
|
@@ -300,14 +345,27 @@ import "stdlib/mobs.mcrs" // ZOMBIE, SKELETON, CREEPER, ... (60+ constants
|
|
|
300
345
|
|
|
301
346
|
### Changelog Highlights
|
|
302
347
|
|
|
348
|
+
#### v1.2.26 (2026-03-14)
|
|
349
|
+
|
|
350
|
+
- Full math/vector/advanced/bigint standard library (see above)
|
|
351
|
+
- `module library;` pragma for zero-cost tree-shaking
|
|
352
|
+
- `storage_get_int` / `storage_set_int` dynamic NBT array builtins
|
|
353
|
+
- Compiler bug fixes: `isqrt` convergence, copy propagation, variable scoping
|
|
354
|
+
|
|
355
|
+
#### v1.2.25 (2026-03-13)
|
|
356
|
+
|
|
357
|
+
- Entity type hierarchy with `W_IMPOSSIBLE_AS` warnings
|
|
358
|
+
- Variable name mangling (`$a`, `$b`, `$c`, ...) for minimal scoreboard footprint
|
|
359
|
+
- Automated CI/CD: npm publish + VSCode extension on every push
|
|
360
|
+
|
|
303
361
|
#### v1.2.0
|
|
304
362
|
|
|
305
|
-
-
|
|
306
|
-
-
|
|
307
|
-
-
|
|
308
|
-
-
|
|
363
|
+
- `impl` blocks, methods, and static constructors
|
|
364
|
+
- `is` type narrowing for entity-safe control flow
|
|
365
|
+
- `@on(Event)` static events and callback scheduling builtins
|
|
366
|
+
- Runtime f-strings for output functions
|
|
309
367
|
- Expanded stdlib with Timer OOP APIs and 313 MC tag constants
|
|
310
|
-
-
|
|
368
|
+
- Dead code elimination
|
|
311
369
|
|
|
312
370
|
See [CHANGELOG.md](./CHANGELOG.md) for the full release notes.
|
|
313
371
|
|
package/README.zh.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<img src="./logo.png" alt="RedScript Logo" width="64" />
|
|
4
4
|
|
|
5
|
-
<img src="https://img.shields.io/badge/RedScript-1.2-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
|
|
5
|
+
<img src="https://img.shields.io/badge/RedScript-1.2.26-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
|
|
6
6
|
|
|
7
7
|
**一个编译到 Minecraft Datapack 的类型化脚本语言。**
|
|
8
8
|
|
|
9
9
|
写干净的游戏逻辑,把记分板的面条代码交给 RedScript 处理。
|
|
10
10
|
|
|
11
11
|
[](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml)
|
|
12
|
-
[](https://github.com/bkmashiro/redscript)
|
|
13
13
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
14
14
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
15
15
|
[](https://marketplace.visualstudio.com/items?itemName=bkmashiro.redscript-vscode)
|
|
@@ -73,7 +73,17 @@ let running: bool = false;
|
|
|
73
73
|
|
|
74
74
|
---
|
|
75
75
|
|
|
76
|
-
### v1.2 新增内容
|
|
76
|
+
### v1.2.26 新增内容
|
|
77
|
+
|
|
78
|
+
- **数学标准库** (`math.mcrs`):18 个定点数函数 — `abs`、`sign`、`min`、`max`、`clamp`、`lerp`、`isqrt`、`sqrt_fixed`、`pow_int`、`gcd`、`lcm`、`sin_fixed`、`cos_fixed`、`map`、`ceil_div`、`log2_int`、`mulfix`、`divfix`、`smoothstep`、`smootherstep`
|
|
79
|
+
- **向量标准库** (`vec.mcrs`):2D / 3D 几何 — 点积/叉积、`length2d_fixed`、`atan2_fixed`(二分搜索正切表,O(log 46))、`normalize2d`、`rotate2d`、`lerp2d`、完整 3D 叉积
|
|
80
|
+
- **高级标准库** (`advanced.mcrs`):数论(`fib`、`is_prime`、`collatz_steps`、`mod_pow`)、哈希/噪声(splitmix32 `hash_int`、`noise1d`)、曲线(`bezier_quad`)、分形(`mandelbrot_iter`、`julia_iter`)、几何实验
|
|
81
|
+
- **BigInt** (`bigint.mcrs`):任意精度整数 — base 10000 × 8 limbs = 最多 32 位十进制数;`bigint_add/sub/compare/mul/fib` 全部运行在 MC 记分板 + NBT storage 上
|
|
82
|
+
- **`module library;` pragma**:将文件声明为库,未被调用的函数会被树摇消除 — 标准库永远不会撑大你的数据包
|
|
83
|
+
- **`storage_get_int` / `storage_set_int` 内置函数**:通过 MC 1.20.2 宏子函数实现动态 NBT int 数组读写
|
|
84
|
+
- **编译器修复**:`isqrt` 大数收敛、优化器拷贝传播别名失效、跨函数变量命名冲突、MCRuntime 数组索引正则
|
|
85
|
+
|
|
86
|
+
### v1.2.25 新增内容
|
|
77
87
|
|
|
78
88
|
- `impl` 块与方法,支持围绕结构体构建面向对象风格 API
|
|
79
89
|
- `is` 类型收窄,实体判断更安全
|
|
@@ -268,14 +278,48 @@ redscript validate <file> 验证 MC 命令语法
|
|
|
268
278
|
|
|
269
279
|
### 标准库
|
|
270
280
|
|
|
281
|
+
所有标准库文件都使用 `module library;` —— 只有你实际调用的函数才会编译进去。
|
|
282
|
+
|
|
271
283
|
```rs
|
|
272
|
-
import "stdlib/math.mcrs" // abs, min, max, clamp
|
|
284
|
+
import "stdlib/math.mcrs" // abs, sign, min, max, clamp, lerp, isqrt, sqrt_fixed,
|
|
285
|
+
// pow_int, gcd, lcm, sin_fixed, cos_fixed, map, ceil_div,
|
|
286
|
+
// log2_int, mulfix, divfix, smoothstep, smootherstep
|
|
287
|
+
|
|
288
|
+
import "stdlib/vec.mcrs" // dot2d, cross2d, length2d_fixed, distance2d_fixed,
|
|
289
|
+
// manhattan, chebyshev, atan2_fixed, normalize2d_x/y,
|
|
290
|
+
// rotate2d_x/y, lerp2d_x/y, dot3d, cross3d_x/y/z,
|
|
291
|
+
// length3d_fixed
|
|
292
|
+
|
|
293
|
+
import "stdlib/advanced.mcrs" // fib, is_prime, collatz_steps, digit_sum, reverse_int,
|
|
294
|
+
// mod_pow, hash_int, noise1d, bezier_quad,
|
|
295
|
+
// mandelbrot_iter, julia_iter, angle_between,
|
|
296
|
+
// clamp_circle_x/y, newton_sqrt, digital_root
|
|
297
|
+
|
|
298
|
+
import "stdlib/bigint.mcrs" // bigint_init, bigint_from_int_a/b, bigint_add/sub/mul,
|
|
299
|
+
// bigint_compare, bigint_mul_small, bigint_fib
|
|
300
|
+
// — 最多 32 位十进制数,纯记分板运行
|
|
301
|
+
|
|
273
302
|
import "stdlib/player.mcrs" // is_alive, in_range, get_health
|
|
274
303
|
import "stdlib/timer.mcrs" // start_timer, tick_timer, has_elapsed
|
|
275
304
|
import "stdlib/cooldown.mcrs" // set_cooldown, check_cooldown
|
|
276
305
|
import "stdlib/mobs.mcrs" // ZOMBIE, SKELETON, CREEPER ... (60+ 实体常量)
|
|
277
306
|
```
|
|
278
307
|
|
|
308
|
+
**示例 — 游戏内计算斐波那契数列第 50 项:**
|
|
309
|
+
|
|
310
|
+
```rs
|
|
311
|
+
import "stdlib/bigint.mcrs"
|
|
312
|
+
|
|
313
|
+
fn show_fib() {
|
|
314
|
+
bigint_fib(50);
|
|
315
|
+
// F(50) = 12,586,269,025 — 超过 int32,分 3 个 limb 存储:
|
|
316
|
+
let l0: int = bigint_get_a(0); // 9025
|
|
317
|
+
let l1: int = bigint_get_a(1); // 8626
|
|
318
|
+
let l2: int = bigint_get_a(2); // 125
|
|
319
|
+
say(f"F(50) limbs: {l2} {l1} {l0}");
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
279
323
|
---
|
|
280
324
|
|
|
281
325
|
### 更多文档
|
|
@@ -293,6 +337,19 @@ import "stdlib/mobs.mcrs" // ZOMBIE, SKELETON, CREEPER ... (60+ 实体常
|
|
|
293
337
|
|
|
294
338
|
### 更新日志亮点
|
|
295
339
|
|
|
340
|
+
#### v1.2.26(2026-03-14)
|
|
341
|
+
|
|
342
|
+
- 完整的数学/向量/高级/BigInt 标准库(详见上方)
|
|
343
|
+
- `module library;` pragma,实现零成本树摇
|
|
344
|
+
- `storage_get_int` / `storage_set_int` 动态 NBT 数组内置函数
|
|
345
|
+
- 编译器修复:`isqrt` 收敛、拷贝传播、变量作用域命名
|
|
346
|
+
|
|
347
|
+
#### v1.2.25(2026-03-13)
|
|
348
|
+
|
|
349
|
+
- 实体类型层级与 `W_IMPOSSIBLE_AS` 警告
|
|
350
|
+
- 变量名混淆(`$a`、`$b`、`$c` ...),最小化记分板占用
|
|
351
|
+
- CI/CD 自动化:每次推送自动发布 npm + VSCode 插件
|
|
352
|
+
|
|
296
353
|
#### v1.2.0
|
|
297
354
|
|
|
298
355
|
- 新增 `impl` 块、实例方法与静态构造函数
|
|
@@ -176,7 +176,7 @@ describe('CLI API', () => {
|
|
|
176
176
|
const mainFn = result.files.find(file => file.path.endsWith('/main.mcfunction'));
|
|
177
177
|
expect(doneFn?.content).toContain('scoreboard players get timer_ticks rs');
|
|
178
178
|
expect(doneFn?.content).toContain('return run scoreboard players get');
|
|
179
|
-
expect(mainFn?.content).toContain('execute if score $
|
|
179
|
+
expect(mainFn?.content).toContain('execute if score $main_finished rs matches 1..');
|
|
180
180
|
});
|
|
181
181
|
it('Timer.tick increments', () => {
|
|
182
182
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-tick-'));
|
|
@@ -17,26 +17,32 @@ describe('generateDatapack', () => {
|
|
|
17
17
|
expect(load?.content).toContain('scoreboard players set $counter rs 0');
|
|
18
18
|
});
|
|
19
19
|
it('generates function file for simple add(a, b)', () => {
|
|
20
|
+
// IR now uses { kind: 'param', index: i } for param-copy instructions,
|
|
21
|
+
// matching what the lowering emits. Pass mangle:false so we can check
|
|
22
|
+
// readable names without worrying about sequential mangled names.
|
|
20
23
|
const mod = {
|
|
21
24
|
namespace: 'mypack',
|
|
22
25
|
globals: [],
|
|
23
26
|
functions: [{
|
|
24
27
|
name: 'add',
|
|
25
|
-
params: ['a', 'b'],
|
|
26
|
-
locals: ['a', 'b', 'result'],
|
|
28
|
+
params: ['$a', '$b'],
|
|
29
|
+
locals: ['$a', '$b', '$result'],
|
|
27
30
|
blocks: [{
|
|
28
31
|
label: 'entry',
|
|
29
32
|
instrs: [
|
|
30
|
-
|
|
33
|
+
// param-copy instructions (what the lowering now emits)
|
|
34
|
+
{ op: 'assign', dst: '$a', src: { kind: 'param', index: 0 } },
|
|
35
|
+
{ op: 'assign', dst: '$b', src: { kind: 'param', index: 1 } },
|
|
36
|
+
{ op: 'binop', dst: '$result', lhs: { kind: 'var', name: '$a' }, bop: '+', rhs: { kind: 'var', name: '$b' } },
|
|
31
37
|
],
|
|
32
|
-
term: { op: 'return', value: { kind: 'var', name: 'result' } },
|
|
38
|
+
term: { op: 'return', value: { kind: 'var', name: '$result' } },
|
|
33
39
|
}],
|
|
34
40
|
}],
|
|
35
41
|
};
|
|
36
|
-
const files = (0, mcfunction_1.
|
|
42
|
+
const files = (0, mcfunction_1.generateDatapackWithStats)(mod, { mangle: false }).files;
|
|
37
43
|
const fn = files.find(f => f.path.includes('add.mcfunction'));
|
|
38
44
|
expect(fn).toBeDefined();
|
|
39
|
-
//
|
|
45
|
+
// param setup emitted from the IR
|
|
40
46
|
expect(fn.content).toContain('scoreboard players operation $a rs = $p0 rs');
|
|
41
47
|
expect(fn.content).toContain('scoreboard players operation $b rs = $p1 rs');
|
|
42
48
|
// Should have add operation
|
|
@@ -104,7 +104,7 @@ fn main() {
|
|
|
104
104
|
`);
|
|
105
105
|
const mainFn = getFunction(files, 'main');
|
|
106
106
|
expect(mainFn).toBeDefined();
|
|
107
|
-
expect(mainFn).toContain('scoreboard players set $
|
|
107
|
+
expect(mainFn).toContain('scoreboard players set $main_hp rs 105');
|
|
108
108
|
expect(mainFn).toContain('Arena Battle');
|
|
109
109
|
});
|
|
110
110
|
});
|
|
@@ -1683,7 +1683,7 @@ describe('for-range loop', () => {
|
|
|
1683
1683
|
const src = `fn test() { for i in 0..5 { say("hi"); } }`;
|
|
1684
1684
|
const files = compile(src, 'forloop');
|
|
1685
1685
|
const fn = getFunction(files, 'test');
|
|
1686
|
-
expect(fn).toContain('scoreboard players set $
|
|
1686
|
+
expect(fn).toContain('scoreboard players set $test_i rs 0');
|
|
1687
1687
|
});
|
|
1688
1688
|
it('generates loop sub-function with increment and condition', () => {
|
|
1689
1689
|
const src = `fn test() { for i in 0..5 { say("hi"); } }`;
|
|
@@ -1691,16 +1691,16 @@ describe('for-range loop', () => {
|
|
|
1691
1691
|
const subFn = files.find(f => f.path.includes('__for_0'));
|
|
1692
1692
|
expect(subFn).toBeDefined();
|
|
1693
1693
|
expect(subFn?.content).toContain('say hi');
|
|
1694
|
-
expect(subFn?.content).toContain('scoreboard players add $
|
|
1695
|
-
expect(subFn?.content).toContain('execute if score $
|
|
1694
|
+
expect(subFn?.content).toContain('scoreboard players add $test_i rs 1');
|
|
1695
|
+
expect(subFn?.content).toContain('execute if score $test_i rs matches ..4 run function forloop:test/__for_0');
|
|
1696
1696
|
});
|
|
1697
1697
|
it('supports non-zero start', () => {
|
|
1698
1698
|
const src = `fn test() { for x in 3..8 { say("loop"); } }`;
|
|
1699
1699
|
const files = compile(src, 'forloop2');
|
|
1700
1700
|
const fn = getFunction(files, 'test');
|
|
1701
|
-
expect(fn).toContain('scoreboard players set $
|
|
1701
|
+
expect(fn).toContain('scoreboard players set $test_x rs 3');
|
|
1702
1702
|
const subFn = files.find(f => f.path.includes('__for_0'));
|
|
1703
|
-
expect(subFn?.content).toContain('execute if score $
|
|
1703
|
+
expect(subFn?.content).toContain('execute if score $test_x rs matches ..7 run function forloop2:test/__for_0');
|
|
1704
1704
|
});
|
|
1705
1705
|
});
|
|
1706
1706
|
// ---------------------------------------------------------------------------
|
|
@@ -42,7 +42,7 @@ describe('Lowering', () => {
|
|
|
42
42
|
const ir = compile('fn foo(x: int) {}');
|
|
43
43
|
const fn = getFunction(ir, 'foo');
|
|
44
44
|
const instrs = getInstructions(fn);
|
|
45
|
-
expect(instrs.some(i => i.op === 'assign' && i.dst === '$
|
|
45
|
+
expect(instrs.some(i => i.op === 'assign' && i.dst === '$foo_x' && i.src.kind === 'param' && i.src.index === 0)).toBe(true);
|
|
46
46
|
});
|
|
47
47
|
it('fills in missing default arguments at call sites', () => {
|
|
48
48
|
const ir = compile(`
|
|
@@ -124,14 +124,14 @@ fn foo() {
|
|
|
124
124
|
`);
|
|
125
125
|
const fn = getFunction(ir, 'foo');
|
|
126
126
|
const instrs = getInstructions(fn);
|
|
127
|
-
expect(instrs.some(i => i.op === 'assign' && i.dst === '$
|
|
127
|
+
expect(instrs.some(i => i.op === 'assign' && i.dst === '$foo_x' && i.src.kind === 'const' && i.src.value === 100)).toBe(true);
|
|
128
128
|
expect(ir.globals).not.toContain('$MAX_HP');
|
|
129
129
|
});
|
|
130
130
|
it('lowers let with literal', () => {
|
|
131
131
|
const ir = compile('fn foo() { let x: int = 42; }');
|
|
132
132
|
const fn = getFunction(ir, 'foo');
|
|
133
133
|
const instrs = getInstructions(fn);
|
|
134
|
-
expect(instrs.some(i => i.op === 'assign' && i.dst === '$
|
|
134
|
+
expect(instrs.some(i => i.op === 'assign' && i.dst === '$foo_x' && i.src.value === 42)).toBe(true);
|
|
135
135
|
});
|
|
136
136
|
it('lowers let with expression', () => {
|
|
137
137
|
const ir = compile('fn foo(a: int) { let x: int = a + 1; }');
|
|
@@ -496,15 +496,15 @@ fn choose(dir: Direction) {
|
|
|
496
496
|
const ir = compile('fn test() { let score: int = 7; say("You have ${score} points"); }');
|
|
497
497
|
const fn = getFunction(ir, 'test');
|
|
498
498
|
const rawCmds = getRawCommands(fn);
|
|
499
|
-
expect(rawCmds).toContain('tellraw @a ["",{"text":"You have "},{"score":{"name":"$
|
|
499
|
+
expect(rawCmds).toContain('tellraw @a ["",{"text":"You have "},{"score":{"name":"$test_score","objective":"rs"}},{"text":" points"}]');
|
|
500
500
|
});
|
|
501
501
|
it('lowers f-string output builtins to tellraw/title JSON components', () => {
|
|
502
502
|
const ir = compile('fn test() { let score: int = 7; say(f"Score: {score}"); tellraw(@a, f"Score: {score}"); actionbar(@s, f"Score: {score}"); title(@s, f"Score: {score}"); }');
|
|
503
503
|
const fn = getFunction(ir, 'test');
|
|
504
504
|
const rawCmds = getRawCommands(fn);
|
|
505
|
-
expect(rawCmds).toContain('tellraw @a ["",{"text":"Score: "},{"score":{"name":"$
|
|
506
|
-
expect(rawCmds).toContain('title @s actionbar ["",{"text":"Score: "},{"score":{"name":"$
|
|
507
|
-
expect(rawCmds).toContain('title @s title ["",{"text":"Score: "},{"score":{"name":"$
|
|
505
|
+
expect(rawCmds).toContain('tellraw @a ["",{"text":"Score: "},{"score":{"name":"$test_score","objective":"rs"}}]');
|
|
506
|
+
expect(rawCmds).toContain('title @s actionbar ["",{"text":"Score: "},{"score":{"name":"$test_score","objective":"rs"}}]');
|
|
507
|
+
expect(rawCmds).toContain('title @s title ["",{"text":"Score: "},{"score":{"name":"$test_score","objective":"rs"}}]');
|
|
508
508
|
});
|
|
509
509
|
it('lowers summon()', () => {
|
|
510
510
|
const ir = compile('fn test() { summon("zombie"); }');
|
|
@@ -987,7 +987,7 @@ fn count_down() {
|
|
|
987
987
|
const ir = compile('let count: int = 0;\nfn test() { let y: int = count; }');
|
|
988
988
|
const fn = getFunction(ir, 'test');
|
|
989
989
|
const instrs = getInstructions(fn);
|
|
990
|
-
expect(instrs.some(i => i.op === 'assign' && i.dst === '$
|
|
990
|
+
expect(instrs.some(i => i.op === 'assign' && i.dst === '$test_y' && i.src.kind === 'var' && i.src.name === '$count')).toBe(true);
|
|
991
991
|
});
|
|
992
992
|
it('writes global variable in function body', () => {
|
|
993
993
|
const ir = compile('let count: int = 0;\nfn inc() { count = 5; }');
|
|
@@ -95,6 +95,37 @@ describe('deadCodeElimination', () => {
|
|
|
95
95
|
expect(opt.blocks[0].instrs[0].dst).toBe('$used_by_raw');
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
|
+
describe('copyPropagation – stale alias invalidation', () => {
|
|
99
|
+
it('does not propagate $tmp = $y after $y is overwritten (swap pattern)', () => {
|
|
100
|
+
// Simulates: let tmp = y; y = x % y; x = tmp
|
|
101
|
+
// The copy $tmp = $y must be invalidated when $y is reassigned.
|
|
102
|
+
// Before fix: x = tmp was propagated to x = y (new y, wrong value).
|
|
103
|
+
const fn = makeFn([
|
|
104
|
+
{ op: 'assign', dst: '$tmp', src: { kind: 'var', name: '$y' } }, // tmp = y
|
|
105
|
+
{ op: 'binop', dst: '$r', lhs: { kind: 'var', name: '$x' }, bop: '%', rhs: { kind: 'var', name: '$y' } }, // r = x%y
|
|
106
|
+
{ op: 'assign', dst: '$y', src: { kind: 'var', name: '$r' } }, // y = r ← stale: tmp still points to OLD y
|
|
107
|
+
{ op: 'assign', dst: '$x', src: { kind: 'var', name: '$tmp' } }, // x = tmp (should NOT be x = y)
|
|
108
|
+
]);
|
|
109
|
+
const opt = (0, passes_1.copyPropagation)(fn);
|
|
110
|
+
const instrs = opt.blocks[0].instrs;
|
|
111
|
+
const xAssign = instrs.find((i) => i.dst === '$x');
|
|
112
|
+
// x = tmp must NOT be optimised to x = $y (stale) or x = $r (new y).
|
|
113
|
+
// It should stay as x = $tmp (the original copy).
|
|
114
|
+
expect(xAssign.src).toEqual({ kind: 'var', name: '$tmp' });
|
|
115
|
+
});
|
|
116
|
+
it('still propagates simple non-conflicting copies', () => {
|
|
117
|
+
// a = 5; b = a; c = b → after propagation b and c should both be const 5
|
|
118
|
+
const fn = makeFn([
|
|
119
|
+
{ op: 'assign', dst: '$a', src: { kind: 'const', value: 5 } },
|
|
120
|
+
{ op: 'assign', dst: '$b', src: { kind: 'var', name: '$a' } },
|
|
121
|
+
{ op: 'assign', dst: '$c', src: { kind: 'var', name: '$b' } },
|
|
122
|
+
]);
|
|
123
|
+
const opt = (0, passes_1.copyPropagation)(fn);
|
|
124
|
+
const instrs = opt.blocks[0].instrs;
|
|
125
|
+
const cAssign = instrs.find((i) => i.dst === '$c');
|
|
126
|
+
expect(cAssign.src).toEqual({ kind: 'const', value: 5 });
|
|
127
|
+
});
|
|
128
|
+
});
|
|
98
129
|
describe('optimize pipeline', () => {
|
|
99
130
|
it('combines all passes', () => {
|
|
100
131
|
// t0 = 2 + 3 (→ constant fold → t0 = 5)
|