redscript-mc 1.2.9 → 1.2.11
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 +35 -33
- package/README.zh.md +35 -33
- package/demo.gif +0 -0
- package/dist/__tests__/mc-integration.test.js +85 -0
- package/dist/ast/types.d.ts +84 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lexer/index.d.ts +1 -1
- package/dist/lexer/index.js +2 -0
- package/dist/lowering/index.d.ts +3 -0
- package/dist/lowering/index.js +119 -11
- package/dist/optimizer/dce.js +6 -0
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.js +171 -18
- package/package.json +1 -1
- package/src/__tests__/fixtures/array-test.mcrs +30 -0
- package/src/__tests__/fixtures/break-continue-test.mcrs +46 -0
- package/src/__tests__/fixtures/enum-test.mcrs +37 -0
- package/src/__tests__/fixtures/foreach-at-test.mcrs +33 -0
- package/src/__tests__/fixtures/match-range-test.mcrs +45 -0
- package/src/__tests__/fixtures/struct-test.mcrs +34 -0
- package/src/__tests__/mc-integration.test.ts +97 -0
- package/src/ast/types.ts +24 -1
- package/src/index.ts +1 -1
- package/src/lexer/index.ts +3 -1
- package/src/lowering/index.ts +123 -11
- package/src/optimizer/dce.ts +6 -0
- package/src/parser/index.ts +159 -18
- package/test-datapacks/README.md +67 -0
- package/test-datapacks/test_control_flow/data/minecraft/tags/function/load.json +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/__load.mcfunction +41 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/run_control_flow_tests.mcfunction +21 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/else_7.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/else_8.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_body_1.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_check_0.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_continue_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_exit_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_exit_3.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_5.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_6.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_8.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_9.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_3.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_4.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_6.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_7.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break.mcfunction +4 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_1.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_10.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_4.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_7.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_11.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_2.mcfunction +9 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_5.mcfunction +7 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_8.mcfunction +13 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_0.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_3.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_6.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_9.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions.mcfunction +12 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/else_7.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/else_8.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_body_1.mcfunction +7 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_check_0.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_continue_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_exit_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_exit_3.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_5.mcfunction +8 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_6.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_8.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_9.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_3.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_4.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_6.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_7.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue.mcfunction +4 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_13.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_16.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_4.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_5.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_1.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_10.mcfunction +8 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_12.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_7.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_8.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_0.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_11.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_6.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_7.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_9.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_continue_13.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_continue_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_continue_9.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_10.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_11.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_14.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_3.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_8.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_14.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_17.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_5.mcfunction +4 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_6.mcfunction +4 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_12.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_15.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_3.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_4.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop.mcfunction +4 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_at/foreach_0.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_at.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/else_1.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/foreach_0.mcfunction +4 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/merge_2.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/then_0.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector.mcfunction +11 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_1.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_13.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_16.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_4.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_11.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_14.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_17.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_5.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_8.mcfunction +6 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_0.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_12.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_15.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_3.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_6.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_9.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else.mcfunction +6 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_0.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_1.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_2.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_3.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_4.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_5.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_6.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_7.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_8.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_9.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match.mcfunction +15 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/else_13.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/else_4.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_body_1.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_body_7.mcfunction +8 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_check_0.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_check_6.mcfunction +4 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_exit_2.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_exit_8.mcfunction +5 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/merge_11.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/merge_14.mcfunction +1 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/merge_5.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/then_12.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/then_3.mcfunction +3 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/then_9.mcfunction +2 -0
- package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop.mcfunction +3 -0
- package/test-datapacks/test_control_flow/pack.mcmeta +6 -0
- package/test-datapacks/test_control_flow.mcrs +242 -0
- package/test-datapacks/test_decorators/data/minecraft/tags/function/load.json +5 -0
- package/test-datapacks/test_decorators/data/minecraft/tags/function/tick.json +5 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/__load.mcfunction +20 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/__tick.mcfunction +3 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/every_second/merge_2.mcfunction +9 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/every_second/merge_5.mcfunction +1 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/every_second/then_0.mcfunction +1 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/every_second/then_3.mcfunction +4 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/every_second/tick_body.mcfunction +6 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/every_second/tick_skip.mcfunction +1 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/every_second.mcfunction +5 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_load.mcfunction +2 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_test_trigger.mcfunction +2 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/merge_2.mcfunction +10 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/merge_5.mcfunction +5 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/merge_8.mcfunction +1 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/then_0.mcfunction +1 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/then_3.mcfunction +3 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/then_6.mcfunction +4 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/on_tick.mcfunction +5 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/run_decorator_tests.mcfunction +7 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/setup_trigger_test.mcfunction +4 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/start_slow_tick_test.mcfunction +4 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/start_tick_test.mcfunction +4 -0
- package/test-datapacks/test_decorators/data/test_decorators/function/stop_tick_test.mcfunction +3 -0
- package/test-datapacks/test_decorators/pack.mcmeta +6 -0
- package/test-datapacks/test_decorators.mcrs +81 -0
- package/test-datapacks/test_events/data/minecraft/tags/function/load.json +5 -0
- package/test-datapacks/test_events/data/test_events/advancements/on_death_on_player_death.json +10 -0
- package/test-datapacks/test_events/data/test_events/function/__load.mcfunction +3 -0
- package/test-datapacks/test_events/data/test_events/function/on_player_death.mcfunction +3 -0
- package/test-datapacks/test_events/data/test_events/function/run_event_tests.mcfunction +5 -0
- package/test-datapacks/test_events/data/test_events/function/setup_events.mcfunction +3 -0
- package/test-datapacks/test_events/data/test_events/function/spawn_test_entity.mcfunction +3 -0
- package/test-datapacks/test_events/data/test_events/function/test_advancement_event.mcfunction +4 -0
- package/test-datapacks/test_events/pack.mcmeta +6 -0
- package/test-datapacks/test_events.mcrs +37 -0
- package/test-datapacks/test_fstrings/data/minecraft/tags/function/load.json +5 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/__load.mcfunction +10 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/run_fstring_tests.mcfunction +15 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/test_actionbar_fstring.mcfunction +4 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/test_announce.mcfunction +3 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/test_multi_var_fstring.mcfunction +9 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/test_say_fstring.mcfunction +4 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/test_tell.mcfunction +3 -0
- package/test-datapacks/test_fstrings/data/test_fstrings/function/test_title_fstring.mcfunction +4 -0
- package/test-datapacks/test_fstrings/pack.mcmeta +6 -0
- package/test-datapacks/test_fstrings.mcrs +58 -0
- package/test-datapacks/test_timers/data/minecraft/tags/function/load.json +5 -0
- package/test-datapacks/test_timers/data/test_timers/function/__interval_0.mcfunction +3 -0
- package/test-datapacks/test_timers/data/test_timers/function/__interval_body_0.mcfunction +5 -0
- package/test-datapacks/test_timers/data/test_timers/function/__load.mcfunction +5 -0
- package/test-datapacks/test_timers/data/test_timers/function/__timeout_0.mcfunction +2 -0
- package/test-datapacks/test_timers/data/test_timers/function/run_timer_tests.mcfunction +5 -0
- package/test-datapacks/test_timers/data/test_timers/function/test_set_interval.mcfunction +5 -0
- package/test-datapacks/test_timers/data/test_timers/function/test_set_timeout.mcfunction +3 -0
- package/test-datapacks/test_timers/pack.mcmeta +6 -0
- package/test-datapacks/test_timers.mcrs +35 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Struct instantiation and field access test
|
|
2
|
+
|
|
3
|
+
struct Point {
|
|
4
|
+
x: int,
|
|
5
|
+
y: int,
|
|
6
|
+
z: int
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
struct Player {
|
|
10
|
+
score: int,
|
|
11
|
+
alive: bool
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@keep fn test_struct() {
|
|
15
|
+
// Create struct instance
|
|
16
|
+
let p: Point = { x: 10, y: 64, z: -5 };
|
|
17
|
+
|
|
18
|
+
// Access fields
|
|
19
|
+
scoreboard_set("#struct_x", #rs, p.x);
|
|
20
|
+
scoreboard_set("#struct_y", #rs, p.y);
|
|
21
|
+
scoreboard_set("#struct_z", #rs, p.z);
|
|
22
|
+
|
|
23
|
+
// Modify via new instance
|
|
24
|
+
let p2: Point = { x: p.x + 5, y: p.y, z: p.z * 2 };
|
|
25
|
+
scoreboard_set("#struct_x2", #rs, p2.x);
|
|
26
|
+
scoreboard_set("#struct_z2", #rs, p2.z);
|
|
27
|
+
|
|
28
|
+
// Bool field
|
|
29
|
+
let player: Player = { score: 100, alive: true };
|
|
30
|
+
if (player.alive) {
|
|
31
|
+
scoreboard_set("#struct_alive", #rs, 1);
|
|
32
|
+
}
|
|
33
|
+
scoreboard_set("#struct_score", #rs, player.score);
|
|
34
|
+
}
|
|
@@ -797,3 +797,100 @@ describe('MC Integration - New Features', () => {
|
|
|
797
797
|
expect(tickResult.ok).toBe(true)
|
|
798
798
|
})
|
|
799
799
|
})
|
|
800
|
+
|
|
801
|
+
describe('MC Integration - Extended Coverage', () => {
|
|
802
|
+
test('struct-test.mcrs: struct instantiation and field access', async () => {
|
|
803
|
+
if (!serverOnline) return
|
|
804
|
+
|
|
805
|
+
writeFixtureFile('struct-test.mcrs', 'struct_test')
|
|
806
|
+
await mc.reload()
|
|
807
|
+
await mc.command('/function struct_test:__load').catch(() => {})
|
|
808
|
+
await mc.command('/function struct_test:test_struct')
|
|
809
|
+
await mc.ticks(5)
|
|
810
|
+
|
|
811
|
+
expect(await mc.scoreboard('#struct_x', 'rs')).toBe(10)
|
|
812
|
+
expect(await mc.scoreboard('#struct_y', 'rs')).toBe(64)
|
|
813
|
+
expect(await mc.scoreboard('#struct_z', 'rs')).toBe(-5)
|
|
814
|
+
expect(await mc.scoreboard('#struct_x2', 'rs')).toBe(15) // 10+5
|
|
815
|
+
expect(await mc.scoreboard('#struct_z2', 'rs')).toBe(-10) // -5*2
|
|
816
|
+
expect(await mc.scoreboard('#struct_alive', 'rs')).toBe(1)
|
|
817
|
+
expect(await mc.scoreboard('#struct_score', 'rs')).toBe(100)
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
test('enum-test.mcrs: enum values and match', async () => {
|
|
821
|
+
if (!serverOnline) return
|
|
822
|
+
|
|
823
|
+
writeFixtureFile('enum-test.mcrs', 'enum_test')
|
|
824
|
+
await mc.reload()
|
|
825
|
+
await mc.command('/function enum_test:__load').catch(() => {})
|
|
826
|
+
await mc.command('/function enum_test:test_enum')
|
|
827
|
+
await mc.ticks(5)
|
|
828
|
+
|
|
829
|
+
expect(await mc.scoreboard('#enum_phase', 'rs')).toBe(2) // Playing=2
|
|
830
|
+
expect(await mc.scoreboard('#enum_match', 'rs')).toBe(2) // matched Playing
|
|
831
|
+
expect(await mc.scoreboard('#enum_rank', 'rs')).toBe(10) // Diamond=10
|
|
832
|
+
expect(await mc.scoreboard('#enum_high', 'rs')).toBe(1) // Diamond > Gold
|
|
833
|
+
})
|
|
834
|
+
|
|
835
|
+
test('array-test.mcrs: array operations', async () => {
|
|
836
|
+
if (!serverOnline) return
|
|
837
|
+
|
|
838
|
+
writeFixtureFile('array-test.mcrs', 'array_test')
|
|
839
|
+
await mc.reload()
|
|
840
|
+
await mc.command('/function array_test:__load').catch(() => {})
|
|
841
|
+
await mc.command('/function array_test:test_array')
|
|
842
|
+
await mc.ticks(5)
|
|
843
|
+
|
|
844
|
+
expect(await mc.scoreboard('#arr_0', 'rs')).toBe(10)
|
|
845
|
+
expect(await mc.scoreboard('#arr_2', 'rs')).toBe(30)
|
|
846
|
+
expect(await mc.scoreboard('#arr_4', 'rs')).toBe(50)
|
|
847
|
+
expect(await mc.scoreboard('#arr_len', 'rs')).toBe(5)
|
|
848
|
+
expect(await mc.scoreboard('#arr_sum', 'rs')).toBe(150) // 10+20+30+40+50
|
|
849
|
+
expect(await mc.scoreboard('#arr_push', 'rs')).toBe(4) // [1,2,3,4].len
|
|
850
|
+
expect(await mc.scoreboard('#arr_pop', 'rs')).toBe(4) // popped value
|
|
851
|
+
})
|
|
852
|
+
|
|
853
|
+
test('break-continue-test.mcrs: break and continue statements', async () => {
|
|
854
|
+
if (!serverOnline) return
|
|
855
|
+
|
|
856
|
+
writeFixtureFile('break-continue-test.mcrs', 'break_continue_test')
|
|
857
|
+
await mc.reload()
|
|
858
|
+
await mc.command('/function break_continue_test:__load').catch(() => {})
|
|
859
|
+
await mc.command('/function break_continue_test:test_break_continue')
|
|
860
|
+
await mc.ticks(10)
|
|
861
|
+
|
|
862
|
+
expect(await mc.scoreboard('#break_at', 'rs')).toBe(5)
|
|
863
|
+
expect(await mc.scoreboard('#sum_evens', 'rs')).toBe(20) // 0+2+4+6+8
|
|
864
|
+
expect(await mc.scoreboard('#while_break', 'rs')).toBe(7)
|
|
865
|
+
expect(await mc.scoreboard('#nested_break', 'rs')).toBe(3) // outer completes 3 times
|
|
866
|
+
})
|
|
867
|
+
|
|
868
|
+
test('match-range-test.mcrs: match with range patterns', async () => {
|
|
869
|
+
if (!serverOnline) return
|
|
870
|
+
|
|
871
|
+
writeFixtureFile('match-range-test.mcrs', 'match_range_test')
|
|
872
|
+
await mc.reload()
|
|
873
|
+
await mc.command('/function match_range_test:__load').catch(() => {})
|
|
874
|
+
await mc.command('/function match_range_test:test_match_range')
|
|
875
|
+
await mc.ticks(5)
|
|
876
|
+
|
|
877
|
+
expect(await mc.scoreboard('#grade', 'rs')).toBe(4) // score=85 → B
|
|
878
|
+
expect(await mc.scoreboard('#boundary_59', 'rs')).toBe(1) // 59 matches 0..59
|
|
879
|
+
expect(await mc.scoreboard('#boundary_60', 'rs')).toBe(2) // 60 matches 60..100
|
|
880
|
+
expect(await mc.scoreboard('#neg_range', 'rs')).toBe(1) // -5 matches ..0
|
|
881
|
+
})
|
|
882
|
+
|
|
883
|
+
test('foreach-at-test.mcrs: foreach with at @s context', async () => {
|
|
884
|
+
if (!serverOnline) return
|
|
885
|
+
|
|
886
|
+
writeFixtureFile('foreach-at-test.mcrs', 'foreach_at_test')
|
|
887
|
+
await mc.reload()
|
|
888
|
+
await mc.fullReset({ clearArea: false, killEntities: true, resetScoreboards: false })
|
|
889
|
+
await mc.command('/function foreach_at_test:setup').catch(() => {})
|
|
890
|
+
await mc.command('/function foreach_at_test:test_foreach_at')
|
|
891
|
+
await mc.ticks(10)
|
|
892
|
+
|
|
893
|
+
expect(await mc.scoreboard('#foreach_count', 'rs')).toBe(3)
|
|
894
|
+
expect(await mc.scoreboard('#foreach_at_count', 'rs')).toBe(3)
|
|
895
|
+
})
|
|
896
|
+
})
|
package/src/ast/types.ts
CHANGED
|
@@ -179,16 +179,39 @@ export type LiteralExpr =
|
|
|
179
179
|
// ---------------------------------------------------------------------------
|
|
180
180
|
|
|
181
181
|
export type ExecuteSubcommand =
|
|
182
|
+
// Context modifiers
|
|
182
183
|
| { kind: 'as'; selector: EntitySelector }
|
|
183
184
|
| { kind: 'at'; selector: EntitySelector }
|
|
185
|
+
| { kind: 'positioned'; x: string; y: string; z: string }
|
|
186
|
+
| { kind: 'positioned_as'; selector: EntitySelector }
|
|
187
|
+
| { kind: 'rotated'; yaw: string; pitch: string }
|
|
188
|
+
| { kind: 'rotated_as'; selector: EntitySelector }
|
|
189
|
+
| { kind: 'facing'; x: string; y: string; z: string }
|
|
190
|
+
| { kind: 'facing_entity'; selector: EntitySelector; anchor: 'eyes' | 'feet' }
|
|
191
|
+
| { kind: 'anchored'; anchor: 'eyes' | 'feet' }
|
|
192
|
+
| { kind: 'align'; axes: string }
|
|
193
|
+
| { kind: 'in'; dimension: string }
|
|
194
|
+
| { kind: 'on'; relation: string }
|
|
195
|
+
| { kind: 'summon'; entity: string }
|
|
196
|
+
// Conditions
|
|
184
197
|
| { kind: 'if_entity'; selector?: EntitySelector; varName?: string; filters?: SelectorFilter }
|
|
185
198
|
| { kind: 'unless_entity'; selector?: EntitySelector; varName?: string; filters?: SelectorFilter }
|
|
186
|
-
| { kind: '
|
|
199
|
+
| { kind: 'if_block'; pos: [string, string, string]; block: string }
|
|
200
|
+
| { kind: 'unless_block'; pos: [string, string, string]; block: string }
|
|
201
|
+
| { kind: 'if_score'; target: string; targetObj: string; op: string; source: string; sourceObj: string }
|
|
202
|
+
| { kind: 'unless_score'; target: string; targetObj: string; op: string; source: string; sourceObj: string }
|
|
203
|
+
| { kind: 'if_score_range'; target: string; targetObj: string; range: string }
|
|
204
|
+
| { kind: 'unless_score_range'; target: string; targetObj: string; range: string }
|
|
205
|
+
// Store
|
|
206
|
+
| { kind: 'store_result'; target: string; targetObj: string }
|
|
207
|
+
| { kind: 'store_success'; target: string; targetObj: string }
|
|
187
208
|
|
|
188
209
|
export type Stmt =
|
|
189
210
|
| { kind: 'let'; name: string; type?: TypeNode; init: Expr; span?: Span }
|
|
190
211
|
| { kind: 'expr'; expr: Expr; span?: Span }
|
|
191
212
|
| { kind: 'return'; value?: Expr; span?: Span }
|
|
213
|
+
| { kind: 'break'; span?: Span }
|
|
214
|
+
| { kind: 'continue'; span?: Span }
|
|
192
215
|
| { kind: 'if'; cond: Expr; then: Block; else_?: Block; span?: Span }
|
|
193
216
|
| { kind: 'while'; cond: Expr; body: Block; span?: Span }
|
|
194
217
|
| { kind: 'for'; init?: Stmt; cond: Expr; step: Expr; body: Block; span?: Span }
|
package/src/index.ts
CHANGED
package/src/lexer/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { DiagnosticError } from '../diagnostics'
|
|
|
15
15
|
export type TokenKind =
|
|
16
16
|
// Keywords
|
|
17
17
|
| 'fn' | 'let' | 'const' | 'if' | 'else' | 'while' | 'for' | 'foreach' | 'match'
|
|
18
|
-
| 'return' | 'as' | 'at' | 'in' | 'is' | 'struct' | 'impl' | 'enum' | 'trigger' | 'namespace'
|
|
18
|
+
| 'return' | 'break' | 'continue' | 'as' | 'at' | 'in' | 'is' | 'struct' | 'impl' | 'enum' | 'trigger' | 'namespace'
|
|
19
19
|
| 'execute' | 'run' | 'unless'
|
|
20
20
|
// Types
|
|
21
21
|
| 'int' | 'bool' | 'float' | 'string' | 'void'
|
|
@@ -75,6 +75,8 @@ const KEYWORDS: Record<string, TokenKind> = {
|
|
|
75
75
|
foreach: 'foreach',
|
|
76
76
|
match: 'match',
|
|
77
77
|
return: 'return',
|
|
78
|
+
break: 'break',
|
|
79
|
+
continue: 'continue',
|
|
78
80
|
as: 'as',
|
|
79
81
|
at: 'at',
|
|
80
82
|
in: 'in',
|
package/src/lowering/index.ts
CHANGED
|
@@ -224,6 +224,9 @@ export class Lowering {
|
|
|
224
224
|
// World object counter for unique tags
|
|
225
225
|
private worldObjCounter: number = 0
|
|
226
226
|
|
|
227
|
+
// Loop context stack for break/continue
|
|
228
|
+
private loopStack: Array<{ breakLabel: string; continueLabel: string; stepFn?: () => void }> = []
|
|
229
|
+
|
|
227
230
|
constructor(namespace: string, sourceRanges: SourceRange[] = []) {
|
|
228
231
|
this.namespace = namespace
|
|
229
232
|
this.sourceRanges = sourceRanges
|
|
@@ -530,6 +533,12 @@ export class Lowering {
|
|
|
530
533
|
case 'return':
|
|
531
534
|
this.lowerReturnStmt(stmt)
|
|
532
535
|
break
|
|
536
|
+
case 'break':
|
|
537
|
+
this.lowerBreakStmt()
|
|
538
|
+
break
|
|
539
|
+
case 'continue':
|
|
540
|
+
this.lowerContinueStmt()
|
|
541
|
+
break
|
|
533
542
|
case 'if':
|
|
534
543
|
this.lowerIfStmt(stmt)
|
|
535
544
|
break
|
|
@@ -682,6 +691,22 @@ export class Lowering {
|
|
|
682
691
|
}
|
|
683
692
|
}
|
|
684
693
|
|
|
694
|
+
private lowerBreakStmt(): void {
|
|
695
|
+
if (this.loopStack.length === 0) {
|
|
696
|
+
throw new DiagnosticError('LoweringError', 'break statement outside of loop', { line: 1, col: 1 })
|
|
697
|
+
}
|
|
698
|
+
const loop = this.loopStack[this.loopStack.length - 1]
|
|
699
|
+
this.builder.emitJump(loop.breakLabel)
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private lowerContinueStmt(): void {
|
|
703
|
+
if (this.loopStack.length === 0) {
|
|
704
|
+
throw new DiagnosticError('LoweringError', 'continue statement outside of loop', { line: 1, col: 1 })
|
|
705
|
+
}
|
|
706
|
+
const loop = this.loopStack[this.loopStack.length - 1]
|
|
707
|
+
this.builder.emitJump(loop.continueLabel)
|
|
708
|
+
}
|
|
709
|
+
|
|
685
710
|
private lowerIfStmt(stmt: Extract<Stmt, { kind: 'if' }>): void {
|
|
686
711
|
if (stmt.cond.kind === 'is_check') {
|
|
687
712
|
this.lowerIsCheckIfStmt(stmt)
|
|
@@ -790,6 +815,9 @@ export class Lowering {
|
|
|
790
815
|
const condName = this.operandToVar(condVar)
|
|
791
816
|
this.builder.emitJumpIf(condName, bodyLabel, exitLabel)
|
|
792
817
|
|
|
818
|
+
// Push loop context for break/continue (while has no step, so continue goes to check)
|
|
819
|
+
this.loopStack.push({ breakLabel: exitLabel, continueLabel: checkLabel })
|
|
820
|
+
|
|
793
821
|
// Body block
|
|
794
822
|
this.builder.startBlock(bodyLabel)
|
|
795
823
|
this.lowerBlock(stmt.body)
|
|
@@ -797,6 +825,9 @@ export class Lowering {
|
|
|
797
825
|
this.builder.emitJump(checkLabel)
|
|
798
826
|
}
|
|
799
827
|
|
|
828
|
+
// Pop loop context
|
|
829
|
+
this.loopStack.pop()
|
|
830
|
+
|
|
800
831
|
// Exit block
|
|
801
832
|
this.builder.startBlock(exitLabel)
|
|
802
833
|
}
|
|
@@ -811,6 +842,7 @@ export class Lowering {
|
|
|
811
842
|
|
|
812
843
|
const checkLabel = this.builder.freshLabel('for_check')
|
|
813
844
|
const bodyLabel = this.builder.freshLabel('for_body')
|
|
845
|
+
const continueLabel = this.builder.freshLabel('for_continue')
|
|
814
846
|
const exitLabel = this.builder.freshLabel('for_exit')
|
|
815
847
|
|
|
816
848
|
this.builder.emitJump(checkLabel)
|
|
@@ -821,15 +853,24 @@ export class Lowering {
|
|
|
821
853
|
const condName = this.operandToVar(condVar)
|
|
822
854
|
this.builder.emitJumpIf(condName, bodyLabel, exitLabel)
|
|
823
855
|
|
|
856
|
+
// Push loop context for break/continue
|
|
857
|
+
this.loopStack.push({ breakLabel: exitLabel, continueLabel })
|
|
858
|
+
|
|
824
859
|
// Body block
|
|
825
860
|
this.builder.startBlock(bodyLabel)
|
|
826
861
|
this.lowerBlock(stmt.body)
|
|
827
|
-
// Step expression
|
|
828
|
-
this.lowerExpr(stmt.step)
|
|
829
862
|
if (!this.builder.isBlockSealed()) {
|
|
830
|
-
this.builder.emitJump(
|
|
863
|
+
this.builder.emitJump(continueLabel)
|
|
831
864
|
}
|
|
832
865
|
|
|
866
|
+
// Continue block (step + loop back)
|
|
867
|
+
this.builder.startBlock(continueLabel)
|
|
868
|
+
this.lowerExpr(stmt.step)
|
|
869
|
+
this.builder.emitJump(checkLabel)
|
|
870
|
+
|
|
871
|
+
// Pop loop context
|
|
872
|
+
this.loopStack.pop()
|
|
873
|
+
|
|
833
874
|
// Exit block
|
|
834
875
|
this.builder.startBlock(exitLabel)
|
|
835
876
|
}
|
|
@@ -945,13 +986,29 @@ export class Lowering {
|
|
|
945
986
|
continue
|
|
946
987
|
}
|
|
947
988
|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
989
|
+
// Handle range patterns specially
|
|
990
|
+
let matchCondition: string
|
|
991
|
+
if (arm.pattern.kind === 'range_lit') {
|
|
992
|
+
const range = arm.pattern.range
|
|
993
|
+
if (range.min !== undefined && range.max !== undefined) {
|
|
994
|
+
matchCondition = `${range.min}..${range.max}`
|
|
995
|
+
} else if (range.min !== undefined) {
|
|
996
|
+
matchCondition = `${range.min}..`
|
|
997
|
+
} else if (range.max !== undefined) {
|
|
998
|
+
matchCondition = `..${range.max}`
|
|
999
|
+
} else {
|
|
1000
|
+
matchCondition = '0..' // Match any
|
|
1001
|
+
}
|
|
1002
|
+
} else {
|
|
1003
|
+
const patternValue = this.lowerExpr(arm.pattern)
|
|
1004
|
+
if (patternValue.kind !== 'const') {
|
|
1005
|
+
throw new Error('Match patterns must lower to compile-time constants')
|
|
1006
|
+
}
|
|
1007
|
+
matchCondition = String(patternValue.value)
|
|
951
1008
|
}
|
|
952
1009
|
|
|
953
1010
|
const subFnName = `${this.currentFn}/match_${this.foreachCounter++}`
|
|
954
|
-
this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 if score ${subject} rs matches ${
|
|
1011
|
+
this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 if score ${subject} rs matches ${matchCondition} run function ${this.namespace}:${subFnName}`)
|
|
955
1012
|
this.emitMatchArmSubFunction(subFnName, matchedVar, arm.body, true)
|
|
956
1013
|
}
|
|
957
1014
|
|
|
@@ -1143,17 +1200,51 @@ export class Lowering {
|
|
|
1143
1200
|
const parts: string[] = ['execute']
|
|
1144
1201
|
for (const sub of stmt.subcommands) {
|
|
1145
1202
|
switch (sub.kind) {
|
|
1203
|
+
// Context modifiers
|
|
1146
1204
|
case 'as':
|
|
1147
1205
|
parts.push(`as ${this.selectorToString(sub.selector)}`)
|
|
1148
1206
|
break
|
|
1149
1207
|
case 'at':
|
|
1150
1208
|
parts.push(`at ${this.selectorToString(sub.selector)}`)
|
|
1151
1209
|
break
|
|
1210
|
+
case 'positioned':
|
|
1211
|
+
parts.push(`positioned ${sub.x} ${sub.y} ${sub.z}`)
|
|
1212
|
+
break
|
|
1213
|
+
case 'positioned_as':
|
|
1214
|
+
parts.push(`positioned as ${this.selectorToString(sub.selector)}`)
|
|
1215
|
+
break
|
|
1216
|
+
case 'rotated':
|
|
1217
|
+
parts.push(`rotated ${sub.yaw} ${sub.pitch}`)
|
|
1218
|
+
break
|
|
1219
|
+
case 'rotated_as':
|
|
1220
|
+
parts.push(`rotated as ${this.selectorToString(sub.selector)}`)
|
|
1221
|
+
break
|
|
1222
|
+
case 'facing':
|
|
1223
|
+
parts.push(`facing ${sub.x} ${sub.y} ${sub.z}`)
|
|
1224
|
+
break
|
|
1225
|
+
case 'facing_entity':
|
|
1226
|
+
parts.push(`facing entity ${this.selectorToString(sub.selector)} ${sub.anchor}`)
|
|
1227
|
+
break
|
|
1228
|
+
case 'anchored':
|
|
1229
|
+
parts.push(`anchored ${sub.anchor}`)
|
|
1230
|
+
break
|
|
1231
|
+
case 'align':
|
|
1232
|
+
parts.push(`align ${sub.axes}`)
|
|
1233
|
+
break
|
|
1234
|
+
case 'in':
|
|
1235
|
+
parts.push(`in ${sub.dimension}`)
|
|
1236
|
+
break
|
|
1237
|
+
case 'on':
|
|
1238
|
+
parts.push(`on ${sub.relation}`)
|
|
1239
|
+
break
|
|
1240
|
+
case 'summon':
|
|
1241
|
+
parts.push(`summon ${sub.entity}`)
|
|
1242
|
+
break
|
|
1243
|
+
// Conditions
|
|
1152
1244
|
case 'if_entity':
|
|
1153
1245
|
if (sub.selector) {
|
|
1154
1246
|
parts.push(`if entity ${this.selectorToString(sub.selector)}`)
|
|
1155
1247
|
} else if (sub.varName) {
|
|
1156
|
-
// Variable with filters - substitute with @s and apply filters
|
|
1157
1248
|
const sel: EntitySelector = { kind: '@s', filters: sub.filters }
|
|
1158
1249
|
parts.push(`if entity ${this.selectorToString(sel)}`)
|
|
1159
1250
|
}
|
|
@@ -1162,13 +1253,34 @@ export class Lowering {
|
|
|
1162
1253
|
if (sub.selector) {
|
|
1163
1254
|
parts.push(`unless entity ${this.selectorToString(sub.selector)}`)
|
|
1164
1255
|
} else if (sub.varName) {
|
|
1165
|
-
// Variable with filters - substitute with @s and apply filters
|
|
1166
1256
|
const sel: EntitySelector = { kind: '@s', filters: sub.filters }
|
|
1167
1257
|
parts.push(`unless entity ${this.selectorToString(sel)}`)
|
|
1168
1258
|
}
|
|
1169
1259
|
break
|
|
1170
|
-
case '
|
|
1171
|
-
parts.push(`
|
|
1260
|
+
case 'if_block':
|
|
1261
|
+
parts.push(`if block ${sub.pos[0]} ${sub.pos[1]} ${sub.pos[2]} ${sub.block}`)
|
|
1262
|
+
break
|
|
1263
|
+
case 'unless_block':
|
|
1264
|
+
parts.push(`unless block ${sub.pos[0]} ${sub.pos[1]} ${sub.pos[2]} ${sub.block}`)
|
|
1265
|
+
break
|
|
1266
|
+
case 'if_score':
|
|
1267
|
+
parts.push(`if score ${sub.target} ${sub.targetObj} ${sub.op} ${sub.source} ${sub.sourceObj}`)
|
|
1268
|
+
break
|
|
1269
|
+
case 'unless_score':
|
|
1270
|
+
parts.push(`unless score ${sub.target} ${sub.targetObj} ${sub.op} ${sub.source} ${sub.sourceObj}`)
|
|
1271
|
+
break
|
|
1272
|
+
case 'if_score_range':
|
|
1273
|
+
parts.push(`if score ${sub.target} ${sub.targetObj} matches ${sub.range}`)
|
|
1274
|
+
break
|
|
1275
|
+
case 'unless_score_range':
|
|
1276
|
+
parts.push(`unless score ${sub.target} ${sub.targetObj} matches ${sub.range}`)
|
|
1277
|
+
break
|
|
1278
|
+
// Store
|
|
1279
|
+
case 'store_result':
|
|
1280
|
+
parts.push(`store result score ${sub.target} ${sub.targetObj}`)
|
|
1281
|
+
break
|
|
1282
|
+
case 'store_success':
|
|
1283
|
+
parts.push(`store success score ${sub.target} ${sub.targetObj}`)
|
|
1172
1284
|
break
|
|
1173
1285
|
}
|
|
1174
1286
|
}
|
package/src/optimizer/dce.ts
CHANGED
|
@@ -267,6 +267,8 @@ export class DeadCodeEliminator {
|
|
|
267
267
|
this.collectNestedStmtRefs(stmt, scope)
|
|
268
268
|
break
|
|
269
269
|
case 'raw':
|
|
270
|
+
case 'break':
|
|
271
|
+
case 'continue':
|
|
270
272
|
break
|
|
271
273
|
}
|
|
272
274
|
}
|
|
@@ -542,6 +544,10 @@ export class DeadCodeEliminator {
|
|
|
542
544
|
return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)]
|
|
543
545
|
case 'raw':
|
|
544
546
|
return [stmt]
|
|
547
|
+
case 'break':
|
|
548
|
+
return [stmt]
|
|
549
|
+
case 'continue':
|
|
550
|
+
return [stmt]
|
|
545
551
|
}
|
|
546
552
|
}
|
|
547
553
|
|
package/src/parser/index.ts
CHANGED
|
@@ -470,6 +470,20 @@ export class Parser {
|
|
|
470
470
|
return this.parseReturnStmt()
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
+
// Break statement
|
|
474
|
+
if (this.check('break')) {
|
|
475
|
+
const token = this.advance()
|
|
476
|
+
this.match(';')
|
|
477
|
+
return this.withLoc({ kind: 'break' }, token)
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Continue statement
|
|
481
|
+
if (this.check('continue')) {
|
|
482
|
+
const token = this.advance()
|
|
483
|
+
this.match(';')
|
|
484
|
+
return this.withLoc({ kind: 'continue' }, token)
|
|
485
|
+
}
|
|
486
|
+
|
|
473
487
|
// If statement
|
|
474
488
|
if (this.check('if')) {
|
|
475
489
|
return this.parseIfStmt()
|
|
@@ -646,11 +660,11 @@ export class Parser {
|
|
|
646
660
|
const iterable = this.parseExpr()
|
|
647
661
|
this.expect(')')
|
|
648
662
|
|
|
649
|
-
// Parse optional execute context modifiers (at, positioned, rotated, facing, etc.)
|
|
663
|
+
// Parse optional execute context modifiers (as, at, positioned, rotated, facing, etc.)
|
|
650
664
|
let executeContext: string | undefined
|
|
651
|
-
// Check for
|
|
652
|
-
const execIdentKeywords = ['positioned', 'rotated', 'facing', 'anchored', 'align']
|
|
653
|
-
if (this.check('at') || this.check('in') || (this.check('ident') && execIdentKeywords.includes(this.peek().value))) {
|
|
665
|
+
// Check for execute subcommand keywords
|
|
666
|
+
const execIdentKeywords = ['positioned', 'rotated', 'facing', 'anchored', 'align', 'on', 'summon']
|
|
667
|
+
if (this.check('as') || this.check('at') || this.check('in') || (this.check('ident') && execIdentKeywords.includes(this.peek().value))) {
|
|
654
668
|
// Collect everything until we hit '{'
|
|
655
669
|
let context = ''
|
|
656
670
|
while (!this.check('{') && !this.check('eof')) {
|
|
@@ -724,25 +738,84 @@ export class Parser {
|
|
|
724
738
|
} else if (this.match('at')) {
|
|
725
739
|
const selector = this.parseSelector()
|
|
726
740
|
subcommands.push({ kind: 'at', selector })
|
|
727
|
-
} else if (this.
|
|
728
|
-
|
|
729
|
-
if (this.
|
|
730
|
-
this.
|
|
741
|
+
} else if (this.checkIdent('positioned')) {
|
|
742
|
+
this.advance()
|
|
743
|
+
if (this.match('as')) {
|
|
744
|
+
const selector = this.parseSelector()
|
|
745
|
+
subcommands.push({ kind: 'positioned_as', selector })
|
|
746
|
+
} else {
|
|
747
|
+
const x = this.parseCoordToken()
|
|
748
|
+
const y = this.parseCoordToken()
|
|
749
|
+
const z = this.parseCoordToken()
|
|
750
|
+
subcommands.push({ kind: 'positioned', x, y, z })
|
|
731
751
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
752
|
+
} else if (this.checkIdent('rotated')) {
|
|
753
|
+
this.advance()
|
|
754
|
+
if (this.match('as')) {
|
|
755
|
+
const selector = this.parseSelector()
|
|
756
|
+
subcommands.push({ kind: 'rotated_as', selector })
|
|
757
|
+
} else {
|
|
758
|
+
const yaw = this.parseCoordToken()
|
|
759
|
+
const pitch = this.parseCoordToken()
|
|
760
|
+
subcommands.push({ kind: 'rotated', yaw, pitch })
|
|
761
|
+
}
|
|
762
|
+
} else if (this.checkIdent('facing')) {
|
|
763
|
+
this.advance()
|
|
764
|
+
if (this.checkIdent('entity')) {
|
|
765
|
+
this.advance()
|
|
766
|
+
const selector = this.parseSelector()
|
|
767
|
+
const anchor = this.checkIdent('eyes') || this.checkIdent('feet') ? this.advance().value as 'eyes' | 'feet' : 'feet'
|
|
768
|
+
subcommands.push({ kind: 'facing_entity', selector, anchor })
|
|
769
|
+
} else {
|
|
770
|
+
const x = this.parseCoordToken()
|
|
771
|
+
const y = this.parseCoordToken()
|
|
772
|
+
const z = this.parseCoordToken()
|
|
773
|
+
subcommands.push({ kind: 'facing', x, y, z })
|
|
774
|
+
}
|
|
775
|
+
} else if (this.checkIdent('anchored')) {
|
|
776
|
+
this.advance()
|
|
777
|
+
const anchor = this.advance().value as 'eyes' | 'feet'
|
|
778
|
+
subcommands.push({ kind: 'anchored', anchor })
|
|
779
|
+
} else if (this.checkIdent('align')) {
|
|
780
|
+
this.advance()
|
|
781
|
+
const axes = this.advance().value
|
|
782
|
+
subcommands.push({ kind: 'align', axes })
|
|
783
|
+
} else if (this.checkIdent('on')) {
|
|
784
|
+
this.advance()
|
|
785
|
+
const relation = this.advance().value
|
|
786
|
+
subcommands.push({ kind: 'on', relation })
|
|
787
|
+
} else if (this.checkIdent('summon')) {
|
|
788
|
+
this.advance()
|
|
789
|
+
const entity = this.advance().value
|
|
790
|
+
subcommands.push({ kind: 'summon', entity })
|
|
791
|
+
} else if (this.checkIdent('store')) {
|
|
792
|
+
this.advance()
|
|
793
|
+
const storeType = this.advance().value // 'result' or 'success'
|
|
794
|
+
if (this.checkIdent('score')) {
|
|
795
|
+
this.advance()
|
|
796
|
+
const target = this.advance().value
|
|
797
|
+
const targetObj = this.advance().value
|
|
798
|
+
if (storeType === 'result') {
|
|
799
|
+
subcommands.push({ kind: 'store_result', target, targetObj })
|
|
800
|
+
} else {
|
|
801
|
+
subcommands.push({ kind: 'store_success', target, targetObj })
|
|
802
|
+
}
|
|
803
|
+
} else {
|
|
804
|
+
this.error('store currently only supports score target')
|
|
738
805
|
}
|
|
739
|
-
|
|
740
|
-
|
|
806
|
+
} else if (this.match('if')) {
|
|
807
|
+
this.parseExecuteCondition(subcommands, 'if')
|
|
808
|
+
} else if (this.match('unless')) {
|
|
809
|
+
this.parseExecuteCondition(subcommands, 'unless')
|
|
741
810
|
} else if (this.match('in')) {
|
|
742
|
-
|
|
811
|
+
// Dimension can be namespaced: minecraft:the_nether
|
|
812
|
+
let dim = this.advance().value
|
|
813
|
+
if (this.match(':')) {
|
|
814
|
+
dim += ':' + this.advance().value
|
|
815
|
+
}
|
|
743
816
|
subcommands.push({ kind: 'in', dimension: dim })
|
|
744
817
|
} else {
|
|
745
|
-
this.error(`Unexpected token in execute statement: ${this.peek().kind}`)
|
|
818
|
+
this.error(`Unexpected token in execute statement: ${this.peek().kind} (${this.peek().value})`)
|
|
746
819
|
}
|
|
747
820
|
}
|
|
748
821
|
|
|
@@ -752,6 +825,74 @@ export class Parser {
|
|
|
752
825
|
return this.withLoc({ kind: 'execute', subcommands, body }, executeToken)
|
|
753
826
|
}
|
|
754
827
|
|
|
828
|
+
private parseExecuteCondition(subcommands: ExecuteSubcommand[], type: 'if' | 'unless'): void {
|
|
829
|
+
if (this.checkIdent('entity') || this.check('selector')) {
|
|
830
|
+
if (this.checkIdent('entity')) this.advance()
|
|
831
|
+
const selectorOrVar = this.parseSelectorOrVarSelector()
|
|
832
|
+
subcommands.push({ kind: type === 'if' ? 'if_entity' : 'unless_entity', ...selectorOrVar })
|
|
833
|
+
} else if (this.checkIdent('block')) {
|
|
834
|
+
this.advance()
|
|
835
|
+
const x = this.parseCoordToken()
|
|
836
|
+
const y = this.parseCoordToken()
|
|
837
|
+
const z = this.parseCoordToken()
|
|
838
|
+
const block = this.parseBlockId()
|
|
839
|
+
subcommands.push({ kind: type === 'if' ? 'if_block' : 'unless_block', pos: [x, y, z], block })
|
|
840
|
+
} else if (this.checkIdent('score')) {
|
|
841
|
+
this.advance()
|
|
842
|
+
const target = this.advance().value
|
|
843
|
+
const targetObj = this.advance().value
|
|
844
|
+
// Check for range or comparison
|
|
845
|
+
if (this.checkIdent('matches')) {
|
|
846
|
+
this.advance()
|
|
847
|
+
const range = this.advance().value
|
|
848
|
+
subcommands.push({ kind: type === 'if' ? 'if_score_range' : 'unless_score_range', target, targetObj, range })
|
|
849
|
+
} else {
|
|
850
|
+
const op = this.advance().value // <, <=, =, >=, >
|
|
851
|
+
const source = this.advance().value
|
|
852
|
+
const sourceObj = this.advance().value
|
|
853
|
+
subcommands.push({
|
|
854
|
+
kind: type === 'if' ? 'if_score' : 'unless_score',
|
|
855
|
+
target, targetObj, op, source, sourceObj
|
|
856
|
+
})
|
|
857
|
+
}
|
|
858
|
+
} else {
|
|
859
|
+
this.error(`Unknown condition type after ${type}`)
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
private parseCoordToken(): string {
|
|
864
|
+
// Handle ~, ^, numbers, relative coords like ~5, ^-3
|
|
865
|
+
const token = this.peek()
|
|
866
|
+
if (token.kind === 'rel_coord' || token.kind === 'local_coord' ||
|
|
867
|
+
token.kind === 'int_lit' || token.kind === 'float_lit' ||
|
|
868
|
+
token.kind === '-' || token.kind === 'ident') {
|
|
869
|
+
return this.advance().value
|
|
870
|
+
}
|
|
871
|
+
this.error(`Expected coordinate, got ${token.kind}`)
|
|
872
|
+
return '~'
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
private parseBlockId(): string {
|
|
876
|
+
// Parse block ID like minecraft:stone or stone
|
|
877
|
+
let id = this.advance().value
|
|
878
|
+
if (this.match(':')) {
|
|
879
|
+
id += ':' + this.advance().value
|
|
880
|
+
}
|
|
881
|
+
// Handle block states [facing=north]
|
|
882
|
+
if (this.check('[')) {
|
|
883
|
+
id += this.advance().value // [
|
|
884
|
+
while (!this.check(']') && !this.check('eof')) {
|
|
885
|
+
id += this.advance().value
|
|
886
|
+
}
|
|
887
|
+
id += this.advance().value // ]
|
|
888
|
+
}
|
|
889
|
+
return id
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
private checkIdent(value: string): boolean {
|
|
893
|
+
return this.check('ident') && this.peek().value === value
|
|
894
|
+
}
|
|
895
|
+
|
|
755
896
|
private parseExprStmt(): Stmt {
|
|
756
897
|
const expr = this.parseExpr()
|
|
757
898
|
this.expect(';')
|