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.
Files changed (219) hide show
  1. package/README.md +35 -33
  2. package/README.zh.md +35 -33
  3. package/demo.gif +0 -0
  4. package/dist/__tests__/mc-integration.test.js +85 -0
  5. package/dist/ast/types.d.ts +84 -2
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/lexer/index.d.ts +1 -1
  9. package/dist/lexer/index.js +2 -0
  10. package/dist/lowering/index.d.ts +3 -0
  11. package/dist/lowering/index.js +119 -11
  12. package/dist/optimizer/dce.js +6 -0
  13. package/dist/parser/index.d.ts +4 -0
  14. package/dist/parser/index.js +171 -18
  15. package/package.json +1 -1
  16. package/src/__tests__/fixtures/array-test.mcrs +30 -0
  17. package/src/__tests__/fixtures/break-continue-test.mcrs +46 -0
  18. package/src/__tests__/fixtures/enum-test.mcrs +37 -0
  19. package/src/__tests__/fixtures/foreach-at-test.mcrs +33 -0
  20. package/src/__tests__/fixtures/match-range-test.mcrs +45 -0
  21. package/src/__tests__/fixtures/struct-test.mcrs +34 -0
  22. package/src/__tests__/mc-integration.test.ts +97 -0
  23. package/src/ast/types.ts +24 -1
  24. package/src/index.ts +1 -1
  25. package/src/lexer/index.ts +3 -1
  26. package/src/lowering/index.ts +123 -11
  27. package/src/optimizer/dce.ts +6 -0
  28. package/src/parser/index.ts +159 -18
  29. package/test-datapacks/README.md +67 -0
  30. package/test-datapacks/test_control_flow/data/minecraft/tags/function/load.json +5 -0
  31. package/test-datapacks/test_control_flow/data/test_control_flow/function/__load.mcfunction +41 -0
  32. package/test-datapacks/test_control_flow/data/test_control_flow/function/run_control_flow_tests.mcfunction +21 -0
  33. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/else_7.mcfunction +3 -0
  34. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/else_8.mcfunction +3 -0
  35. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_body_1.mcfunction +5 -0
  36. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_check_0.mcfunction +5 -0
  37. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_continue_2.mcfunction +5 -0
  38. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_exit_2.mcfunction +5 -0
  39. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/for_exit_3.mcfunction +5 -0
  40. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_5.mcfunction +5 -0
  41. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_6.mcfunction +2 -0
  42. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_8.mcfunction +1 -0
  43. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/merge_9.mcfunction +1 -0
  44. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_3.mcfunction +3 -0
  45. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_4.mcfunction +3 -0
  46. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_6.mcfunction +3 -0
  47. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break/then_7.mcfunction +3 -0
  48. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_break.mcfunction +4 -0
  49. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_1.mcfunction +3 -0
  50. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_10.mcfunction +3 -0
  51. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_4.mcfunction +3 -0
  52. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/else_7.mcfunction +3 -0
  53. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_11.mcfunction +1 -0
  54. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_2.mcfunction +9 -0
  55. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_5.mcfunction +7 -0
  56. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/merge_8.mcfunction +13 -0
  57. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_0.mcfunction +3 -0
  58. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_3.mcfunction +3 -0
  59. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_6.mcfunction +3 -0
  60. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions/then_9.mcfunction +3 -0
  61. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_complex_conditions.mcfunction +12 -0
  62. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/else_7.mcfunction +3 -0
  63. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/else_8.mcfunction +3 -0
  64. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_body_1.mcfunction +7 -0
  65. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_check_0.mcfunction +5 -0
  66. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_continue_2.mcfunction +5 -0
  67. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_exit_2.mcfunction +5 -0
  68. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/for_exit_3.mcfunction +5 -0
  69. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_5.mcfunction +8 -0
  70. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_6.mcfunction +5 -0
  71. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_8.mcfunction +1 -0
  72. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/merge_9.mcfunction +1 -0
  73. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_3.mcfunction +2 -0
  74. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_4.mcfunction +2 -0
  75. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_6.mcfunction +3 -0
  76. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue/then_7.mcfunction +3 -0
  77. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_continue.mcfunction +4 -0
  78. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_13.mcfunction +3 -0
  79. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_16.mcfunction +3 -0
  80. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_4.mcfunction +3 -0
  81. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/else_5.mcfunction +3 -0
  82. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_1.mcfunction +5 -0
  83. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_10.mcfunction +8 -0
  84. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_12.mcfunction +5 -0
  85. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_7.mcfunction +3 -0
  86. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_body_8.mcfunction +3 -0
  87. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_0.mcfunction +5 -0
  88. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_11.mcfunction +5 -0
  89. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_6.mcfunction +5 -0
  90. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_7.mcfunction +5 -0
  91. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_check_9.mcfunction +5 -0
  92. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_continue_13.mcfunction +5 -0
  93. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_continue_2.mcfunction +5 -0
  94. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_continue_9.mcfunction +5 -0
  95. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_10.mcfunction +5 -0
  96. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_11.mcfunction +5 -0
  97. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_14.mcfunction +2 -0
  98. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_2.mcfunction +5 -0
  99. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_3.mcfunction +5 -0
  100. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/for_exit_8.mcfunction +5 -0
  101. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_14.mcfunction +1 -0
  102. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_17.mcfunction +1 -0
  103. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_5.mcfunction +4 -0
  104. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/merge_6.mcfunction +4 -0
  105. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_12.mcfunction +3 -0
  106. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_15.mcfunction +3 -0
  107. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_3.mcfunction +3 -0
  108. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop/then_4.mcfunction +3 -0
  109. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_for_loop.mcfunction +4 -0
  110. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_at/foreach_0.mcfunction +2 -0
  111. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_at.mcfunction +5 -0
  112. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/else_1.mcfunction +3 -0
  113. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/foreach_0.mcfunction +4 -0
  114. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/merge_2.mcfunction +2 -0
  115. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector/then_0.mcfunction +3 -0
  116. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_foreach_selector.mcfunction +11 -0
  117. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_1.mcfunction +3 -0
  118. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_13.mcfunction +5 -0
  119. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_16.mcfunction +3 -0
  120. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/else_4.mcfunction +3 -0
  121. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_11.mcfunction +2 -0
  122. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_14.mcfunction +1 -0
  123. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_17.mcfunction +2 -0
  124. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_2.mcfunction +5 -0
  125. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_5.mcfunction +5 -0
  126. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/merge_8.mcfunction +6 -0
  127. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_0.mcfunction +3 -0
  128. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_12.mcfunction +3 -0
  129. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_15.mcfunction +3 -0
  130. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_3.mcfunction +3 -0
  131. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_6.mcfunction +5 -0
  132. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else/then_9.mcfunction +3 -0
  133. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_if_else.mcfunction +6 -0
  134. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_0.mcfunction +3 -0
  135. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_1.mcfunction +3 -0
  136. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_2.mcfunction +3 -0
  137. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_3.mcfunction +2 -0
  138. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_4.mcfunction +3 -0
  139. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_5.mcfunction +3 -0
  140. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_6.mcfunction +3 -0
  141. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_7.mcfunction +3 -0
  142. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_8.mcfunction +3 -0
  143. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match/match_9.mcfunction +2 -0
  144. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_match.mcfunction +15 -0
  145. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/else_13.mcfunction +3 -0
  146. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/else_4.mcfunction +3 -0
  147. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_body_1.mcfunction +5 -0
  148. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_body_7.mcfunction +8 -0
  149. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_check_0.mcfunction +5 -0
  150. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_check_6.mcfunction +4 -0
  151. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_exit_2.mcfunction +5 -0
  152. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/loop_exit_8.mcfunction +5 -0
  153. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/merge_11.mcfunction +2 -0
  154. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/merge_14.mcfunction +1 -0
  155. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/merge_5.mcfunction +3 -0
  156. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/then_12.mcfunction +3 -0
  157. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/then_3.mcfunction +3 -0
  158. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop/then_9.mcfunction +2 -0
  159. package/test-datapacks/test_control_flow/data/test_control_flow/function/test_while_loop.mcfunction +3 -0
  160. package/test-datapacks/test_control_flow/pack.mcmeta +6 -0
  161. package/test-datapacks/test_control_flow.mcrs +242 -0
  162. package/test-datapacks/test_decorators/data/minecraft/tags/function/load.json +5 -0
  163. package/test-datapacks/test_decorators/data/minecraft/tags/function/tick.json +5 -0
  164. package/test-datapacks/test_decorators/data/test_decorators/function/__load.mcfunction +20 -0
  165. package/test-datapacks/test_decorators/data/test_decorators/function/__tick.mcfunction +3 -0
  166. package/test-datapacks/test_decorators/data/test_decorators/function/every_second/merge_2.mcfunction +9 -0
  167. package/test-datapacks/test_decorators/data/test_decorators/function/every_second/merge_5.mcfunction +1 -0
  168. package/test-datapacks/test_decorators/data/test_decorators/function/every_second/then_0.mcfunction +1 -0
  169. package/test-datapacks/test_decorators/data/test_decorators/function/every_second/then_3.mcfunction +4 -0
  170. package/test-datapacks/test_decorators/data/test_decorators/function/every_second/tick_body.mcfunction +6 -0
  171. package/test-datapacks/test_decorators/data/test_decorators/function/every_second/tick_skip.mcfunction +1 -0
  172. package/test-datapacks/test_decorators/data/test_decorators/function/every_second.mcfunction +5 -0
  173. package/test-datapacks/test_decorators/data/test_decorators/function/on_load.mcfunction +2 -0
  174. package/test-datapacks/test_decorators/data/test_decorators/function/on_test_trigger.mcfunction +2 -0
  175. package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/merge_2.mcfunction +10 -0
  176. package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/merge_5.mcfunction +5 -0
  177. package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/merge_8.mcfunction +1 -0
  178. package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/then_0.mcfunction +1 -0
  179. package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/then_3.mcfunction +3 -0
  180. package/test-datapacks/test_decorators/data/test_decorators/function/on_tick/then_6.mcfunction +4 -0
  181. package/test-datapacks/test_decorators/data/test_decorators/function/on_tick.mcfunction +5 -0
  182. package/test-datapacks/test_decorators/data/test_decorators/function/run_decorator_tests.mcfunction +7 -0
  183. package/test-datapacks/test_decorators/data/test_decorators/function/setup_trigger_test.mcfunction +4 -0
  184. package/test-datapacks/test_decorators/data/test_decorators/function/start_slow_tick_test.mcfunction +4 -0
  185. package/test-datapacks/test_decorators/data/test_decorators/function/start_tick_test.mcfunction +4 -0
  186. package/test-datapacks/test_decorators/data/test_decorators/function/stop_tick_test.mcfunction +3 -0
  187. package/test-datapacks/test_decorators/pack.mcmeta +6 -0
  188. package/test-datapacks/test_decorators.mcrs +81 -0
  189. package/test-datapacks/test_events/data/minecraft/tags/function/load.json +5 -0
  190. package/test-datapacks/test_events/data/test_events/advancements/on_death_on_player_death.json +10 -0
  191. package/test-datapacks/test_events/data/test_events/function/__load.mcfunction +3 -0
  192. package/test-datapacks/test_events/data/test_events/function/on_player_death.mcfunction +3 -0
  193. package/test-datapacks/test_events/data/test_events/function/run_event_tests.mcfunction +5 -0
  194. package/test-datapacks/test_events/data/test_events/function/setup_events.mcfunction +3 -0
  195. package/test-datapacks/test_events/data/test_events/function/spawn_test_entity.mcfunction +3 -0
  196. package/test-datapacks/test_events/data/test_events/function/test_advancement_event.mcfunction +4 -0
  197. package/test-datapacks/test_events/pack.mcmeta +6 -0
  198. package/test-datapacks/test_events.mcrs +37 -0
  199. package/test-datapacks/test_fstrings/data/minecraft/tags/function/load.json +5 -0
  200. package/test-datapacks/test_fstrings/data/test_fstrings/function/__load.mcfunction +10 -0
  201. package/test-datapacks/test_fstrings/data/test_fstrings/function/run_fstring_tests.mcfunction +15 -0
  202. package/test-datapacks/test_fstrings/data/test_fstrings/function/test_actionbar_fstring.mcfunction +4 -0
  203. package/test-datapacks/test_fstrings/data/test_fstrings/function/test_announce.mcfunction +3 -0
  204. package/test-datapacks/test_fstrings/data/test_fstrings/function/test_multi_var_fstring.mcfunction +9 -0
  205. package/test-datapacks/test_fstrings/data/test_fstrings/function/test_say_fstring.mcfunction +4 -0
  206. package/test-datapacks/test_fstrings/data/test_fstrings/function/test_tell.mcfunction +3 -0
  207. package/test-datapacks/test_fstrings/data/test_fstrings/function/test_title_fstring.mcfunction +4 -0
  208. package/test-datapacks/test_fstrings/pack.mcmeta +6 -0
  209. package/test-datapacks/test_fstrings.mcrs +58 -0
  210. package/test-datapacks/test_timers/data/minecraft/tags/function/load.json +5 -0
  211. package/test-datapacks/test_timers/data/test_timers/function/__interval_0.mcfunction +3 -0
  212. package/test-datapacks/test_timers/data/test_timers/function/__interval_body_0.mcfunction +5 -0
  213. package/test-datapacks/test_timers/data/test_timers/function/__load.mcfunction +5 -0
  214. package/test-datapacks/test_timers/data/test_timers/function/__timeout_0.mcfunction +2 -0
  215. package/test-datapacks/test_timers/data/test_timers/function/run_timer_tests.mcfunction +5 -0
  216. package/test-datapacks/test_timers/data/test_timers/function/test_set_interval.mcfunction +5 -0
  217. package/test-datapacks/test_timers/data/test_timers/function/test_set_timeout.mcfunction +3 -0
  218. package/test-datapacks/test_timers/pack.mcmeta +6 -0
  219. package/test-datapacks/test_timers.mcrs +35 -0
@@ -209,6 +209,8 @@ class Lowering {
209
209
  this.floatVars = new Set();
210
210
  // World object counter for unique tags
211
211
  this.worldObjCounter = 0;
212
+ // Loop context stack for break/continue
213
+ this.loopStack = [];
212
214
  this.namespace = namespace;
213
215
  this.sourceRanges = sourceRanges;
214
216
  LoweringBuilder.resetTempCounter();
@@ -462,6 +464,12 @@ class Lowering {
462
464
  case 'return':
463
465
  this.lowerReturnStmt(stmt);
464
466
  break;
467
+ case 'break':
468
+ this.lowerBreakStmt();
469
+ break;
470
+ case 'continue':
471
+ this.lowerContinueStmt();
472
+ break;
465
473
  case 'if':
466
474
  this.lowerIfStmt(stmt);
467
475
  break;
@@ -599,6 +607,20 @@ class Lowering {
599
607
  this.builder.emitReturn();
600
608
  }
601
609
  }
610
+ lowerBreakStmt() {
611
+ if (this.loopStack.length === 0) {
612
+ throw new diagnostics_1.DiagnosticError('LoweringError', 'break statement outside of loop', { line: 1, col: 1 });
613
+ }
614
+ const loop = this.loopStack[this.loopStack.length - 1];
615
+ this.builder.emitJump(loop.breakLabel);
616
+ }
617
+ lowerContinueStmt() {
618
+ if (this.loopStack.length === 0) {
619
+ throw new diagnostics_1.DiagnosticError('LoweringError', 'continue statement outside of loop', { line: 1, col: 1 });
620
+ }
621
+ const loop = this.loopStack[this.loopStack.length - 1];
622
+ this.builder.emitJump(loop.continueLabel);
623
+ }
602
624
  lowerIfStmt(stmt) {
603
625
  if (stmt.cond.kind === 'is_check') {
604
626
  this.lowerIsCheckIfStmt(stmt);
@@ -671,12 +693,16 @@ class Lowering {
671
693
  const condVar = this.lowerExpr(stmt.cond);
672
694
  const condName = this.operandToVar(condVar);
673
695
  this.builder.emitJumpIf(condName, bodyLabel, exitLabel);
696
+ // Push loop context for break/continue (while has no step, so continue goes to check)
697
+ this.loopStack.push({ breakLabel: exitLabel, continueLabel: checkLabel });
674
698
  // Body block
675
699
  this.builder.startBlock(bodyLabel);
676
700
  this.lowerBlock(stmt.body);
677
701
  if (!this.builder.isBlockSealed()) {
678
702
  this.builder.emitJump(checkLabel);
679
703
  }
704
+ // Pop loop context
705
+ this.loopStack.pop();
680
706
  // Exit block
681
707
  this.builder.startBlock(exitLabel);
682
708
  }
@@ -688,6 +714,7 @@ class Lowering {
688
714
  }
689
715
  const checkLabel = this.builder.freshLabel('for_check');
690
716
  const bodyLabel = this.builder.freshLabel('for_body');
717
+ const continueLabel = this.builder.freshLabel('for_continue');
691
718
  const exitLabel = this.builder.freshLabel('for_exit');
692
719
  this.builder.emitJump(checkLabel);
693
720
  // Check block
@@ -695,14 +722,20 @@ class Lowering {
695
722
  const condVar = this.lowerExpr(stmt.cond);
696
723
  const condName = this.operandToVar(condVar);
697
724
  this.builder.emitJumpIf(condName, bodyLabel, exitLabel);
725
+ // Push loop context for break/continue
726
+ this.loopStack.push({ breakLabel: exitLabel, continueLabel });
698
727
  // Body block
699
728
  this.builder.startBlock(bodyLabel);
700
729
  this.lowerBlock(stmt.body);
701
- // Step expression
702
- this.lowerExpr(stmt.step);
703
730
  if (!this.builder.isBlockSealed()) {
704
- this.builder.emitJump(checkLabel);
731
+ this.builder.emitJump(continueLabel);
705
732
  }
733
+ // Continue block (step + loop back)
734
+ this.builder.startBlock(continueLabel);
735
+ this.lowerExpr(stmt.step);
736
+ this.builder.emitJump(checkLabel);
737
+ // Pop loop context
738
+ this.loopStack.pop();
706
739
  // Exit block
707
740
  this.builder.startBlock(exitLabel);
708
741
  }
@@ -794,12 +827,32 @@ class Lowering {
794
827
  defaultArm = arm;
795
828
  continue;
796
829
  }
797
- const patternValue = this.lowerExpr(arm.pattern);
798
- if (patternValue.kind !== 'const') {
799
- throw new Error('Match patterns must lower to compile-time constants');
830
+ // Handle range patterns specially
831
+ let matchCondition;
832
+ if (arm.pattern.kind === 'range_lit') {
833
+ const range = arm.pattern.range;
834
+ if (range.min !== undefined && range.max !== undefined) {
835
+ matchCondition = `${range.min}..${range.max}`;
836
+ }
837
+ else if (range.min !== undefined) {
838
+ matchCondition = `${range.min}..`;
839
+ }
840
+ else if (range.max !== undefined) {
841
+ matchCondition = `..${range.max}`;
842
+ }
843
+ else {
844
+ matchCondition = '0..'; // Match any
845
+ }
846
+ }
847
+ else {
848
+ const patternValue = this.lowerExpr(arm.pattern);
849
+ if (patternValue.kind !== 'const') {
850
+ throw new Error('Match patterns must lower to compile-time constants');
851
+ }
852
+ matchCondition = String(patternValue.value);
800
853
  }
801
854
  const subFnName = `${this.currentFn}/match_${this.foreachCounter++}`;
802
- this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 if score ${subject} rs matches ${patternValue.value} run function ${this.namespace}:${subFnName}`);
855
+ this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 if score ${subject} rs matches ${matchCondition} run function ${this.namespace}:${subFnName}`);
803
856
  this.emitMatchArmSubFunction(subFnName, matchedVar, arm.body, true);
804
857
  }
805
858
  if (defaultArm) {
@@ -953,18 +1006,52 @@ class Lowering {
953
1006
  const parts = ['execute'];
954
1007
  for (const sub of stmt.subcommands) {
955
1008
  switch (sub.kind) {
1009
+ // Context modifiers
956
1010
  case 'as':
957
1011
  parts.push(`as ${this.selectorToString(sub.selector)}`);
958
1012
  break;
959
1013
  case 'at':
960
1014
  parts.push(`at ${this.selectorToString(sub.selector)}`);
961
1015
  break;
1016
+ case 'positioned':
1017
+ parts.push(`positioned ${sub.x} ${sub.y} ${sub.z}`);
1018
+ break;
1019
+ case 'positioned_as':
1020
+ parts.push(`positioned as ${this.selectorToString(sub.selector)}`);
1021
+ break;
1022
+ case 'rotated':
1023
+ parts.push(`rotated ${sub.yaw} ${sub.pitch}`);
1024
+ break;
1025
+ case 'rotated_as':
1026
+ parts.push(`rotated as ${this.selectorToString(sub.selector)}`);
1027
+ break;
1028
+ case 'facing':
1029
+ parts.push(`facing ${sub.x} ${sub.y} ${sub.z}`);
1030
+ break;
1031
+ case 'facing_entity':
1032
+ parts.push(`facing entity ${this.selectorToString(sub.selector)} ${sub.anchor}`);
1033
+ break;
1034
+ case 'anchored':
1035
+ parts.push(`anchored ${sub.anchor}`);
1036
+ break;
1037
+ case 'align':
1038
+ parts.push(`align ${sub.axes}`);
1039
+ break;
1040
+ case 'in':
1041
+ parts.push(`in ${sub.dimension}`);
1042
+ break;
1043
+ case 'on':
1044
+ parts.push(`on ${sub.relation}`);
1045
+ break;
1046
+ case 'summon':
1047
+ parts.push(`summon ${sub.entity}`);
1048
+ break;
1049
+ // Conditions
962
1050
  case 'if_entity':
963
1051
  if (sub.selector) {
964
1052
  parts.push(`if entity ${this.selectorToString(sub.selector)}`);
965
1053
  }
966
1054
  else if (sub.varName) {
967
- // Variable with filters - substitute with @s and apply filters
968
1055
  const sel = { kind: '@s', filters: sub.filters };
969
1056
  parts.push(`if entity ${this.selectorToString(sel)}`);
970
1057
  }
@@ -974,13 +1061,34 @@ class Lowering {
974
1061
  parts.push(`unless entity ${this.selectorToString(sub.selector)}`);
975
1062
  }
976
1063
  else if (sub.varName) {
977
- // Variable with filters - substitute with @s and apply filters
978
1064
  const sel = { kind: '@s', filters: sub.filters };
979
1065
  parts.push(`unless entity ${this.selectorToString(sel)}`);
980
1066
  }
981
1067
  break;
982
- case 'in':
983
- parts.push(`in ${sub.dimension}`);
1068
+ case 'if_block':
1069
+ parts.push(`if block ${sub.pos[0]} ${sub.pos[1]} ${sub.pos[2]} ${sub.block}`);
1070
+ break;
1071
+ case 'unless_block':
1072
+ parts.push(`unless block ${sub.pos[0]} ${sub.pos[1]} ${sub.pos[2]} ${sub.block}`);
1073
+ break;
1074
+ case 'if_score':
1075
+ parts.push(`if score ${sub.target} ${sub.targetObj} ${sub.op} ${sub.source} ${sub.sourceObj}`);
1076
+ break;
1077
+ case 'unless_score':
1078
+ parts.push(`unless score ${sub.target} ${sub.targetObj} ${sub.op} ${sub.source} ${sub.sourceObj}`);
1079
+ break;
1080
+ case 'if_score_range':
1081
+ parts.push(`if score ${sub.target} ${sub.targetObj} matches ${sub.range}`);
1082
+ break;
1083
+ case 'unless_score_range':
1084
+ parts.push(`unless score ${sub.target} ${sub.targetObj} matches ${sub.range}`);
1085
+ break;
1086
+ // Store
1087
+ case 'store_result':
1088
+ parts.push(`store result score ${sub.target} ${sub.targetObj}`);
1089
+ break;
1090
+ case 'store_success':
1091
+ parts.push(`store success score ${sub.target} ${sub.targetObj}`);
984
1092
  break;
985
1093
  }
986
1094
  }
@@ -241,6 +241,8 @@ class DeadCodeEliminator {
241
241
  this.collectNestedStmtRefs(stmt, scope);
242
242
  break;
243
243
  case 'raw':
244
+ case 'break':
245
+ case 'continue':
244
246
  break;
245
247
  }
246
248
  }
@@ -508,6 +510,10 @@ class DeadCodeEliminator {
508
510
  return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
509
511
  case 'raw':
510
512
  return [stmt];
513
+ case 'break':
514
+ return [stmt];
515
+ case 'continue':
516
+ return [stmt];
511
517
  }
512
518
  }
513
519
  transformExpr(expr, scope) {
@@ -45,6 +45,10 @@ export declare class Parser {
45
45
  private parseAsStmt;
46
46
  private parseAtStmt;
47
47
  private parseExecuteStmt;
48
+ private parseExecuteCondition;
49
+ private parseCoordToken;
50
+ private parseBlockId;
51
+ private checkIdent;
48
52
  private parseExprStmt;
49
53
  private parseExpr;
50
54
  private parseAssignment;
@@ -397,6 +397,18 @@ class Parser {
397
397
  if (this.check('return')) {
398
398
  return this.parseReturnStmt();
399
399
  }
400
+ // Break statement
401
+ if (this.check('break')) {
402
+ const token = this.advance();
403
+ this.match(';');
404
+ return this.withLoc({ kind: 'break' }, token);
405
+ }
406
+ // Continue statement
407
+ if (this.check('continue')) {
408
+ const token = this.advance();
409
+ this.match(';');
410
+ return this.withLoc({ kind: 'continue' }, token);
411
+ }
400
412
  // If statement
401
413
  if (this.check('if')) {
402
414
  return this.parseIfStmt();
@@ -534,11 +546,11 @@ class Parser {
534
546
  this.expect('in');
535
547
  const iterable = this.parseExpr();
536
548
  this.expect(')');
537
- // Parse optional execute context modifiers (at, positioned, rotated, facing, etc.)
549
+ // Parse optional execute context modifiers (as, at, positioned, rotated, facing, etc.)
538
550
  let executeContext;
539
- // Check for 'at' keyword or identifiers like 'positioned', 'rotated', 'facing', 'anchored', 'align'
540
- const execIdentKeywords = ['positioned', 'rotated', 'facing', 'anchored', 'align'];
541
- if (this.check('at') || this.check('in') || (this.check('ident') && execIdentKeywords.includes(this.peek().value))) {
551
+ // Check for execute subcommand keywords
552
+ const execIdentKeywords = ['positioned', 'rotated', 'facing', 'anchored', 'align', 'on', 'summon'];
553
+ if (this.check('as') || this.check('at') || this.check('in') || (this.check('ident') && execIdentKeywords.includes(this.peek().value))) {
542
554
  // Collect everything until we hit '{'
543
555
  let context = '';
544
556
  while (!this.check('{') && !this.check('eof')) {
@@ -603,34 +615,175 @@ class Parser {
603
615
  const selector = this.parseSelector();
604
616
  subcommands.push({ kind: 'at', selector });
605
617
  }
606
- else if (this.match('if')) {
607
- // Expect 'entity' keyword (as ident) or just parse selector directly
608
- if (this.peek().kind === 'ident' && this.peek().value === 'entity') {
609
- this.advance(); // consume 'entity'
618
+ else if (this.checkIdent('positioned')) {
619
+ this.advance();
620
+ if (this.match('as')) {
621
+ const selector = this.parseSelector();
622
+ subcommands.push({ kind: 'positioned_as', selector });
623
+ }
624
+ else {
625
+ const x = this.parseCoordToken();
626
+ const y = this.parseCoordToken();
627
+ const z = this.parseCoordToken();
628
+ subcommands.push({ kind: 'positioned', x, y, z });
610
629
  }
611
- const selectorOrVar = this.parseSelectorOrVarSelector();
612
- subcommands.push({ kind: 'if_entity', ...selectorOrVar });
613
630
  }
614
- else if (this.match('unless')) {
615
- // Expect 'entity' keyword (as ident) or just parse selector directly
616
- if (this.peek().kind === 'ident' && this.peek().value === 'entity') {
617
- this.advance(); // consume 'entity'
631
+ else if (this.checkIdent('rotated')) {
632
+ this.advance();
633
+ if (this.match('as')) {
634
+ const selector = this.parseSelector();
635
+ subcommands.push({ kind: 'rotated_as', selector });
636
+ }
637
+ else {
638
+ const yaw = this.parseCoordToken();
639
+ const pitch = this.parseCoordToken();
640
+ subcommands.push({ kind: 'rotated', yaw, pitch });
641
+ }
642
+ }
643
+ else if (this.checkIdent('facing')) {
644
+ this.advance();
645
+ if (this.checkIdent('entity')) {
646
+ this.advance();
647
+ const selector = this.parseSelector();
648
+ const anchor = this.checkIdent('eyes') || this.checkIdent('feet') ? this.advance().value : 'feet';
649
+ subcommands.push({ kind: 'facing_entity', selector, anchor });
650
+ }
651
+ else {
652
+ const x = this.parseCoordToken();
653
+ const y = this.parseCoordToken();
654
+ const z = this.parseCoordToken();
655
+ subcommands.push({ kind: 'facing', x, y, z });
656
+ }
657
+ }
658
+ else if (this.checkIdent('anchored')) {
659
+ this.advance();
660
+ const anchor = this.advance().value;
661
+ subcommands.push({ kind: 'anchored', anchor });
662
+ }
663
+ else if (this.checkIdent('align')) {
664
+ this.advance();
665
+ const axes = this.advance().value;
666
+ subcommands.push({ kind: 'align', axes });
667
+ }
668
+ else if (this.checkIdent('on')) {
669
+ this.advance();
670
+ const relation = this.advance().value;
671
+ subcommands.push({ kind: 'on', relation });
672
+ }
673
+ else if (this.checkIdent('summon')) {
674
+ this.advance();
675
+ const entity = this.advance().value;
676
+ subcommands.push({ kind: 'summon', entity });
677
+ }
678
+ else if (this.checkIdent('store')) {
679
+ this.advance();
680
+ const storeType = this.advance().value; // 'result' or 'success'
681
+ if (this.checkIdent('score')) {
682
+ this.advance();
683
+ const target = this.advance().value;
684
+ const targetObj = this.advance().value;
685
+ if (storeType === 'result') {
686
+ subcommands.push({ kind: 'store_result', target, targetObj });
687
+ }
688
+ else {
689
+ subcommands.push({ kind: 'store_success', target, targetObj });
690
+ }
691
+ }
692
+ else {
693
+ this.error('store currently only supports score target');
618
694
  }
619
- const selectorOrVar = this.parseSelectorOrVarSelector();
620
- subcommands.push({ kind: 'unless_entity', ...selectorOrVar });
695
+ }
696
+ else if (this.match('if')) {
697
+ this.parseExecuteCondition(subcommands, 'if');
698
+ }
699
+ else if (this.match('unless')) {
700
+ this.parseExecuteCondition(subcommands, 'unless');
621
701
  }
622
702
  else if (this.match('in')) {
623
- const dim = this.expect('ident').value;
703
+ // Dimension can be namespaced: minecraft:the_nether
704
+ let dim = this.advance().value;
705
+ if (this.match(':')) {
706
+ dim += ':' + this.advance().value;
707
+ }
624
708
  subcommands.push({ kind: 'in', dimension: dim });
625
709
  }
626
710
  else {
627
- this.error(`Unexpected token in execute statement: ${this.peek().kind}`);
711
+ this.error(`Unexpected token in execute statement: ${this.peek().kind} (${this.peek().value})`);
628
712
  }
629
713
  }
630
714
  this.expect('run');
631
715
  const body = this.parseBlock();
632
716
  return this.withLoc({ kind: 'execute', subcommands, body }, executeToken);
633
717
  }
718
+ parseExecuteCondition(subcommands, type) {
719
+ if (this.checkIdent('entity') || this.check('selector')) {
720
+ if (this.checkIdent('entity'))
721
+ this.advance();
722
+ const selectorOrVar = this.parseSelectorOrVarSelector();
723
+ subcommands.push({ kind: type === 'if' ? 'if_entity' : 'unless_entity', ...selectorOrVar });
724
+ }
725
+ else if (this.checkIdent('block')) {
726
+ this.advance();
727
+ const x = this.parseCoordToken();
728
+ const y = this.parseCoordToken();
729
+ const z = this.parseCoordToken();
730
+ const block = this.parseBlockId();
731
+ subcommands.push({ kind: type === 'if' ? 'if_block' : 'unless_block', pos: [x, y, z], block });
732
+ }
733
+ else if (this.checkIdent('score')) {
734
+ this.advance();
735
+ const target = this.advance().value;
736
+ const targetObj = this.advance().value;
737
+ // Check for range or comparison
738
+ if (this.checkIdent('matches')) {
739
+ this.advance();
740
+ const range = this.advance().value;
741
+ subcommands.push({ kind: type === 'if' ? 'if_score_range' : 'unless_score_range', target, targetObj, range });
742
+ }
743
+ else {
744
+ const op = this.advance().value; // <, <=, =, >=, >
745
+ const source = this.advance().value;
746
+ const sourceObj = this.advance().value;
747
+ subcommands.push({
748
+ kind: type === 'if' ? 'if_score' : 'unless_score',
749
+ target, targetObj, op, source, sourceObj
750
+ });
751
+ }
752
+ }
753
+ else {
754
+ this.error(`Unknown condition type after ${type}`);
755
+ }
756
+ }
757
+ parseCoordToken() {
758
+ // Handle ~, ^, numbers, relative coords like ~5, ^-3
759
+ const token = this.peek();
760
+ if (token.kind === 'rel_coord' || token.kind === 'local_coord' ||
761
+ token.kind === 'int_lit' || token.kind === 'float_lit' ||
762
+ token.kind === '-' || token.kind === 'ident') {
763
+ return this.advance().value;
764
+ }
765
+ this.error(`Expected coordinate, got ${token.kind}`);
766
+ return '~';
767
+ }
768
+ parseBlockId() {
769
+ // Parse block ID like minecraft:stone or stone
770
+ let id = this.advance().value;
771
+ if (this.match(':')) {
772
+ id += ':' + this.advance().value;
773
+ }
774
+ // Handle block states [facing=north]
775
+ if (this.check('[')) {
776
+ id += this.advance().value; // [
777
+ while (!this.check(']') && !this.check('eof')) {
778
+ id += this.advance().value;
779
+ }
780
+ id += this.advance().value; // ]
781
+ }
782
+ return id;
783
+ }
784
+ checkIdent(value) {
785
+ return this.check('ident') && this.peek().value === value;
786
+ }
634
787
  parseExprStmt() {
635
788
  const expr = this.parseExpr();
636
789
  this.expect(';');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "redscript-mc",
3
- "version": "1.2.9",
3
+ "version": "1.2.11",
4
4
  "description": "A high-level programming language that compiles to Minecraft datapacks",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -0,0 +1,30 @@
1
+ // Array operations test
2
+
3
+ @keep fn test_array() {
4
+ // Array initialization
5
+ let nums: int[] = [10, 20, 30, 40, 50];
6
+
7
+ // Array access
8
+ scoreboard_set("#arr_0", #rs, nums[0]);
9
+ scoreboard_set("#arr_2", #rs, nums[2]);
10
+ scoreboard_set("#arr_4", #rs, nums[4]);
11
+
12
+ // Array length via .len property
13
+ scoreboard_set("#arr_len", #rs, nums.len);
14
+
15
+ // Sum via foreach
16
+ let sum: int = 0;
17
+ foreach (n in nums) {
18
+ sum = sum + n;
19
+ }
20
+ scoreboard_set("#arr_sum", #rs, sum);
21
+
22
+ // Push operation
23
+ let arr2: int[] = [1, 2, 3];
24
+ arr2.push(4);
25
+ scoreboard_set("#arr_push", #rs, arr2.len);
26
+
27
+ // Pop operation
28
+ let popped: int = arr2.pop();
29
+ scoreboard_set("#arr_pop", #rs, popped);
30
+ }
@@ -0,0 +1,46 @@
1
+ // Break and continue statements test
2
+
3
+ @keep fn test_break_continue() {
4
+ // Test break - should stop at i=5
5
+ let break_at: int = -1;
6
+ for (let i: int = 0; i < 10; i = i + 1) {
7
+ if (i == 5) {
8
+ break_at = i;
9
+ break;
10
+ }
11
+ }
12
+ scoreboard_set("#break_at", #rs, break_at);
13
+
14
+ // Test continue - sum only even numbers
15
+ let sum_evens: int = 0;
16
+ for (let i: int = 0; i < 10; i = i + 1) {
17
+ if (i % 2 != 0) {
18
+ continue;
19
+ }
20
+ sum_evens = sum_evens + i;
21
+ }
22
+ // 0+2+4+6+8 = 20
23
+ scoreboard_set("#sum_evens", #rs, sum_evens);
24
+
25
+ // While with break
26
+ let count: int = 0;
27
+ while (true) {
28
+ count = count + 1;
29
+ if (count >= 7) {
30
+ break;
31
+ }
32
+ }
33
+ scoreboard_set("#while_break", #rs, count);
34
+
35
+ // Nested loop break (breaks inner only)
36
+ let outer_count: int = 0;
37
+ for (let a: int = 0; a < 3; a = a + 1) {
38
+ for (let b: int = 0; b < 10; b = b + 1) {
39
+ if (b == 2) {
40
+ break;
41
+ }
42
+ }
43
+ outer_count = outer_count + 1;
44
+ }
45
+ scoreboard_set("#nested_break", #rs, outer_count);
46
+ }
@@ -0,0 +1,37 @@
1
+ // Enum definition and matching test
2
+
3
+ enum GamePhase {
4
+ Lobby, // 0
5
+ Starting, // 1
6
+ Playing, // 2
7
+ Ended // 3
8
+ }
9
+
10
+ enum Rank {
11
+ Bronze = 1,
12
+ Silver = 2,
13
+ Gold = 3,
14
+ Diamond = 10
15
+ }
16
+
17
+ @keep fn test_enum() {
18
+ // Basic enum value (use . not ::)
19
+ let phase: int = GamePhase.Playing;
20
+ scoreboard_set("#enum_phase", #rs, phase);
21
+
22
+ // Match on enum
23
+ match (phase) {
24
+ GamePhase.Lobby => { scoreboard_set("#enum_match", #rs, 0); }
25
+ GamePhase.Playing => { scoreboard_set("#enum_match", #rs, 2); }
26
+ _ => { scoreboard_set("#enum_match", #rs, -1); }
27
+ }
28
+
29
+ // Custom values
30
+ let rank: int = Rank.Diamond;
31
+ scoreboard_set("#enum_rank", #rs, rank);
32
+
33
+ // Comparison
34
+ if (rank > Rank.Gold) {
35
+ scoreboard_set("#enum_high", #rs, 1);
36
+ }
37
+ }
@@ -0,0 +1,33 @@
1
+ // Foreach with execute context modifiers test
2
+
3
+ @load fn setup() {
4
+ scoreboard_add("rs");
5
+ scoreboard_set("#foreach_count", #rs, 0);
6
+ scoreboard_set("#foreach_at_count", #rs, 0);
7
+ }
8
+
9
+ @keep fn test_foreach_at() {
10
+ // Spawn test entities
11
+ raw("summon minecraft:armor_stand ~ ~ ~ {Tags:[\"test_foreach\"],NoGravity:1b}");
12
+ raw("summon minecraft:armor_stand ~2 ~ ~ {Tags:[\"test_foreach\"],NoGravity:1b}");
13
+ raw("summon minecraft:armor_stand ~4 ~ ~ {Tags:[\"test_foreach\"],NoGravity:1b}");
14
+
15
+ // Basic foreach
16
+ let count: int = 0;
17
+ foreach (e in @e[type=armor_stand,tag=test_foreach]) {
18
+ count = count + 1;
19
+ }
20
+ scoreboard_set("#foreach_count", #rs, count);
21
+
22
+ // Foreach with at @s (execute at entity position)
23
+ let at_count: int = 0;
24
+ foreach (e in @e[type=armor_stand,tag=test_foreach]) at @s {
25
+ // This runs at each entity's position
26
+ at_count = at_count + 1;
27
+ raw("particle minecraft:heart ~ ~1 ~ 0 0 0 0 1");
28
+ }
29
+ scoreboard_set("#foreach_at_count", #rs, at_count);
30
+
31
+ // Cleanup
32
+ raw("kill @e[type=armor_stand,tag=test_foreach]");
33
+ }
@@ -0,0 +1,45 @@
1
+ // Match with range patterns test
2
+
3
+ @keep fn test_match_range() {
4
+ // Test score grading
5
+ let score: int = 85;
6
+ let grade: int = 0;
7
+
8
+ match (score) {
9
+ 0..59 => { grade = 1; } // F
10
+ 60..69 => { grade = 2; } // D
11
+ 70..79 => { grade = 3; } // C
12
+ 80..89 => { grade = 4; } // B
13
+ 90..100 => { grade = 5; } // A
14
+ _ => { grade = 0; }
15
+ }
16
+ scoreboard_set("#grade", #rs, grade);
17
+
18
+ // Test boundary values
19
+ let val1: int = 59;
20
+ let result1: int = 0;
21
+ match (val1) {
22
+ 0..59 => { result1 = 1; }
23
+ 60..100 => { result1 = 2; }
24
+ _ => { result1 = 0; }
25
+ }
26
+ scoreboard_set("#boundary_59", #rs, result1);
27
+
28
+ let val2: int = 60;
29
+ let result2: int = 0;
30
+ match (val2) {
31
+ 0..59 => { result2 = 1; }
32
+ 60..100 => { result2 = 2; }
33
+ _ => { result2 = 0; }
34
+ }
35
+ scoreboard_set("#boundary_60", #rs, result2);
36
+
37
+ // Open-ended ranges
38
+ let neg: int = -5;
39
+ let neg_result: int = 0;
40
+ match (neg) {
41
+ ..0 => { neg_result = 1; }
42
+ 0.. => { neg_result = 2; }
43
+ }
44
+ scoreboard_set("#neg_range", #rs, neg_result);
45
+ }