redscript-mc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +31 -0
  3. package/.github/ISSUE_TEMPLATE/wrong_output.md +33 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +34 -0
  5. package/.github/workflows/ci.yml +29 -0
  6. package/.github/workflows/publish-extension.yml +35 -0
  7. package/LICENSE +21 -0
  8. package/README.md +261 -0
  9. package/README.zh.md +261 -0
  10. package/dist/__tests__/cli.test.d.ts +1 -0
  11. package/dist/__tests__/cli.test.js +140 -0
  12. package/dist/__tests__/codegen.test.d.ts +1 -0
  13. package/dist/__tests__/codegen.test.js +121 -0
  14. package/dist/__tests__/diagnostics.test.d.ts +4 -0
  15. package/dist/__tests__/diagnostics.test.js +149 -0
  16. package/dist/__tests__/e2e.test.d.ts +6 -0
  17. package/dist/__tests__/e2e.test.js +1528 -0
  18. package/dist/__tests__/lexer.test.d.ts +1 -0
  19. package/dist/__tests__/lexer.test.js +316 -0
  20. package/dist/__tests__/lowering.test.d.ts +1 -0
  21. package/dist/__tests__/lowering.test.js +819 -0
  22. package/dist/__tests__/mc-integration.test.d.ts +12 -0
  23. package/dist/__tests__/mc-integration.test.js +395 -0
  24. package/dist/__tests__/mc-syntax.test.d.ts +1 -0
  25. package/dist/__tests__/mc-syntax.test.js +112 -0
  26. package/dist/__tests__/nbt.test.d.ts +1 -0
  27. package/dist/__tests__/nbt.test.js +82 -0
  28. package/dist/__tests__/optimizer-advanced.test.d.ts +1 -0
  29. package/dist/__tests__/optimizer-advanced.test.js +124 -0
  30. package/dist/__tests__/optimizer.test.d.ts +1 -0
  31. package/dist/__tests__/optimizer.test.js +118 -0
  32. package/dist/__tests__/parser.test.d.ts +1 -0
  33. package/dist/__tests__/parser.test.js +717 -0
  34. package/dist/__tests__/repl.test.d.ts +1 -0
  35. package/dist/__tests__/repl.test.js +27 -0
  36. package/dist/__tests__/runtime.test.d.ts +1 -0
  37. package/dist/__tests__/runtime.test.js +276 -0
  38. package/dist/__tests__/structure-optimizer.test.d.ts +1 -0
  39. package/dist/__tests__/structure-optimizer.test.js +33 -0
  40. package/dist/__tests__/typechecker.test.d.ts +1 -0
  41. package/dist/__tests__/typechecker.test.js +364 -0
  42. package/dist/ast/types.d.ts +357 -0
  43. package/dist/ast/types.js +9 -0
  44. package/dist/cli.d.ts +11 -0
  45. package/dist/cli.js +407 -0
  46. package/dist/codegen/cmdblock/index.d.ts +26 -0
  47. package/dist/codegen/cmdblock/index.js +45 -0
  48. package/dist/codegen/mcfunction/index.d.ts +34 -0
  49. package/dist/codegen/mcfunction/index.js +413 -0
  50. package/dist/codegen/structure/index.d.ts +18 -0
  51. package/dist/codegen/structure/index.js +249 -0
  52. package/dist/compile.d.ts +30 -0
  53. package/dist/compile.js +152 -0
  54. package/dist/data/arena/function/__load.mcfunction +6 -0
  55. package/dist/data/arena/function/__tick.mcfunction +2 -0
  56. package/dist/data/arena/function/announce_leaders/else_1.mcfunction +3 -0
  57. package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +1 -0
  58. package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +3 -0
  59. package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +7 -0
  60. package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +1 -0
  61. package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +4 -0
  62. package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +6 -0
  63. package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +1 -0
  64. package/dist/data/arena/function/announce_leaders/then_0.mcfunction +4 -0
  65. package/dist/data/arena/function/announce_leaders.mcfunction +6 -0
  66. package/dist/data/arena/function/arena_tick/merge_2.mcfunction +1 -0
  67. package/dist/data/arena/function/arena_tick/then_0.mcfunction +4 -0
  68. package/dist/data/arena/function/arena_tick.mcfunction +11 -0
  69. package/dist/data/counter/function/__load.mcfunction +5 -0
  70. package/dist/data/counter/function/__tick.mcfunction +2 -0
  71. package/dist/data/counter/function/counter_tick/merge_2.mcfunction +1 -0
  72. package/dist/data/counter/function/counter_tick/then_0.mcfunction +3 -0
  73. package/dist/data/counter/function/counter_tick.mcfunction +11 -0
  74. package/dist/data/minecraft/tags/function/load.json +5 -0
  75. package/dist/data/minecraft/tags/function/tick.json +5 -0
  76. package/dist/data/quiz/function/__load.mcfunction +16 -0
  77. package/dist/data/quiz/function/__tick.mcfunction +6 -0
  78. package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +4 -0
  79. package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +4 -0
  80. package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +4 -0
  81. package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +4 -0
  82. package/dist/data/quiz/function/answer_a.mcfunction +4 -0
  83. package/dist/data/quiz/function/answer_b.mcfunction +4 -0
  84. package/dist/data/quiz/function/answer_c.mcfunction +4 -0
  85. package/dist/data/quiz/function/ask_question/else_1.mcfunction +5 -0
  86. package/dist/data/quiz/function/ask_question/else_4.mcfunction +5 -0
  87. package/dist/data/quiz/function/ask_question/else_7.mcfunction +4 -0
  88. package/dist/data/quiz/function/ask_question/merge_2.mcfunction +1 -0
  89. package/dist/data/quiz/function/ask_question/merge_5.mcfunction +2 -0
  90. package/dist/data/quiz/function/ask_question/merge_8.mcfunction +2 -0
  91. package/dist/data/quiz/function/ask_question/then_0.mcfunction +4 -0
  92. package/dist/data/quiz/function/ask_question/then_3.mcfunction +4 -0
  93. package/dist/data/quiz/function/ask_question/then_6.mcfunction +4 -0
  94. package/dist/data/quiz/function/ask_question.mcfunction +7 -0
  95. package/dist/data/quiz/function/finish_quiz.mcfunction +6 -0
  96. package/dist/data/quiz/function/handle_answer/else_1.mcfunction +5 -0
  97. package/dist/data/quiz/function/handle_answer/else_10.mcfunction +3 -0
  98. package/dist/data/quiz/function/handle_answer/else_16.mcfunction +3 -0
  99. package/dist/data/quiz/function/handle_answer/else_4.mcfunction +3 -0
  100. package/dist/data/quiz/function/handle_answer/else_7.mcfunction +5 -0
  101. package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +2 -0
  102. package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +2 -0
  103. package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +2 -0
  104. package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +8 -0
  105. package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +2 -0
  106. package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +2 -0
  107. package/dist/data/quiz/function/handle_answer/then_0.mcfunction +5 -0
  108. package/dist/data/quiz/function/handle_answer/then_12.mcfunction +5 -0
  109. package/dist/data/quiz/function/handle_answer/then_15.mcfunction +6 -0
  110. package/dist/data/quiz/function/handle_answer/then_3.mcfunction +6 -0
  111. package/dist/data/quiz/function/handle_answer/then_6.mcfunction +5 -0
  112. package/dist/data/quiz/function/handle_answer/then_9.mcfunction +6 -0
  113. package/dist/data/quiz/function/handle_answer.mcfunction +11 -0
  114. package/dist/data/quiz/function/start_quiz.mcfunction +5 -0
  115. package/dist/data/shop/function/__load.mcfunction +7 -0
  116. package/dist/data/shop/function/__tick.mcfunction +3 -0
  117. package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +4 -0
  118. package/dist/data/shop/function/complete_purchase/else_1.mcfunction +5 -0
  119. package/dist/data/shop/function/complete_purchase/else_4.mcfunction +5 -0
  120. package/dist/data/shop/function/complete_purchase/else_7.mcfunction +3 -0
  121. package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +2 -0
  122. package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +2 -0
  123. package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +2 -0
  124. package/dist/data/shop/function/complete_purchase/then_0.mcfunction +4 -0
  125. package/dist/data/shop/function/complete_purchase/then_3.mcfunction +4 -0
  126. package/dist/data/shop/function/complete_purchase/then_6.mcfunction +4 -0
  127. package/dist/data/shop/function/complete_purchase.mcfunction +7 -0
  128. package/dist/data/shop/function/handle_shop_trigger.mcfunction +3 -0
  129. package/dist/data/turret/function/__load.mcfunction +5 -0
  130. package/dist/data/turret/function/__tick.mcfunction +4 -0
  131. package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +4 -0
  132. package/dist/data/turret/function/deploy_turret.mcfunction +8 -0
  133. package/dist/data/turret/function/turret_tick/at_1.mcfunction +2 -0
  134. package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +2 -0
  135. package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +2 -0
  136. package/dist/data/turret/function/turret_tick/tick_body.mcfunction +3 -0
  137. package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +1 -0
  138. package/dist/data/turret/function/turret_tick.mcfunction +5 -0
  139. package/dist/diagnostics/index.d.ts +44 -0
  140. package/dist/diagnostics/index.js +140 -0
  141. package/dist/index.d.ts +53 -0
  142. package/dist/index.js +126 -0
  143. package/dist/ir/builder.d.ts +32 -0
  144. package/dist/ir/builder.js +99 -0
  145. package/dist/ir/types.d.ts +117 -0
  146. package/dist/ir/types.js +15 -0
  147. package/dist/lexer/index.d.ts +36 -0
  148. package/dist/lexer/index.js +458 -0
  149. package/dist/lowering/index.d.ts +106 -0
  150. package/dist/lowering/index.js +2041 -0
  151. package/dist/mc-test/client.d.ts +128 -0
  152. package/dist/mc-test/client.js +174 -0
  153. package/dist/mc-test/runner.d.ts +28 -0
  154. package/dist/mc-test/runner.js +150 -0
  155. package/dist/mc-test/setup.d.ts +11 -0
  156. package/dist/mc-test/setup.js +98 -0
  157. package/dist/mc-validator/index.d.ts +17 -0
  158. package/dist/mc-validator/index.js +322 -0
  159. package/dist/nbt/index.d.ts +86 -0
  160. package/dist/nbt/index.js +250 -0
  161. package/dist/optimizer/commands.d.ts +36 -0
  162. package/dist/optimizer/commands.js +349 -0
  163. package/dist/optimizer/passes.d.ts +34 -0
  164. package/dist/optimizer/passes.js +227 -0
  165. package/dist/optimizer/structure.d.ts +8 -0
  166. package/dist/optimizer/structure.js +344 -0
  167. package/dist/pack.mcmeta +6 -0
  168. package/dist/parser/index.d.ts +76 -0
  169. package/dist/parser/index.js +1193 -0
  170. package/dist/repl.d.ts +16 -0
  171. package/dist/repl.js +165 -0
  172. package/dist/runtime/index.d.ts +101 -0
  173. package/dist/runtime/index.js +1288 -0
  174. package/dist/typechecker/index.d.ts +42 -0
  175. package/dist/typechecker/index.js +629 -0
  176. package/docs/COMPILATION_STATS.md +142 -0
  177. package/docs/IMPLEMENTATION_GUIDE.md +512 -0
  178. package/docs/LANGUAGE_REFERENCE.md +415 -0
  179. package/docs/MC_MAPPING.md +280 -0
  180. package/docs/STRUCTURE_TARGET.md +80 -0
  181. package/docs/mc-reference/commands.md +259 -0
  182. package/editors/vscode/.vscodeignore +10 -0
  183. package/editors/vscode/LICENSE +21 -0
  184. package/editors/vscode/README.md +78 -0
  185. package/editors/vscode/build.mjs +28 -0
  186. package/editors/vscode/icon.png +0 -0
  187. package/editors/vscode/mcfunction-language-configuration.json +28 -0
  188. package/editors/vscode/out/extension.js +7236 -0
  189. package/editors/vscode/package-lock.json +566 -0
  190. package/editors/vscode/package.json +137 -0
  191. package/editors/vscode/redscript-language-configuration.json +28 -0
  192. package/editors/vscode/snippets/redscript.json +114 -0
  193. package/editors/vscode/src/codeactions.ts +89 -0
  194. package/editors/vscode/src/completion.ts +130 -0
  195. package/editors/vscode/src/extension.ts +239 -0
  196. package/editors/vscode/src/hover.ts +1120 -0
  197. package/editors/vscode/src/symbols.ts +207 -0
  198. package/editors/vscode/syntaxes/mcfunction.tmLanguage.json +740 -0
  199. package/editors/vscode/syntaxes/redscript.tmLanguage.json +357 -0
  200. package/editors/vscode/tsconfig.json +13 -0
  201. package/jest.config.js +5 -0
  202. package/package.json +38 -0
  203. package/src/__tests__/cli.test.ts +130 -0
  204. package/src/__tests__/codegen.test.ts +128 -0
  205. package/src/__tests__/diagnostics.test.ts +195 -0
  206. package/src/__tests__/e2e.test.ts +1721 -0
  207. package/src/__tests__/fixtures/mc-commands-1.21.4.json +18734 -0
  208. package/src/__tests__/formatter.test.ts +46 -0
  209. package/src/__tests__/lexer.test.ts +356 -0
  210. package/src/__tests__/lowering.test.ts +962 -0
  211. package/src/__tests__/mc-integration.test.ts +409 -0
  212. package/src/__tests__/mc-syntax.test.ts +96 -0
  213. package/src/__tests__/nbt.test.ts +58 -0
  214. package/src/__tests__/optimizer-advanced.test.ts +144 -0
  215. package/src/__tests__/optimizer.test.ts +129 -0
  216. package/src/__tests__/parser.test.ts +800 -0
  217. package/src/__tests__/repl.test.ts +33 -0
  218. package/src/__tests__/runtime.test.ts +289 -0
  219. package/src/__tests__/structure-optimizer.test.ts +38 -0
  220. package/src/__tests__/typechecker.test.ts +395 -0
  221. package/src/ast/types.ts +248 -0
  222. package/src/cli.ts +445 -0
  223. package/src/codegen/cmdblock/index.ts +63 -0
  224. package/src/codegen/mcfunction/index.ts +471 -0
  225. package/src/codegen/structure/index.ts +305 -0
  226. package/src/compile.ts +188 -0
  227. package/src/diagnostics/index.ts +186 -0
  228. package/src/examples/README.md +77 -0
  229. package/src/examples/SHOWCASE_GAME.md +43 -0
  230. package/src/examples/arena.rs +44 -0
  231. package/src/examples/counter.rs +12 -0
  232. package/src/examples/pvp_arena.rs +131 -0
  233. package/src/examples/quiz.rs +90 -0
  234. package/src/examples/rpg.rs +13 -0
  235. package/src/examples/shop.rs +30 -0
  236. package/src/examples/showcase_game.rs +552 -0
  237. package/src/examples/stdlib_demo.rs +181 -0
  238. package/src/examples/turret.rs +27 -0
  239. package/src/examples/world_manager.rs +23 -0
  240. package/src/formatter/index.ts +22 -0
  241. package/src/index.ts +161 -0
  242. package/src/ir/builder.ts +114 -0
  243. package/src/ir/types.ts +119 -0
  244. package/src/lexer/index.ts +555 -0
  245. package/src/lowering/index.ts +2406 -0
  246. package/src/mc-test/client.ts +259 -0
  247. package/src/mc-test/runner.ts +140 -0
  248. package/src/mc-test/setup.ts +70 -0
  249. package/src/mc-validator/index.ts +367 -0
  250. package/src/nbt/index.ts +321 -0
  251. package/src/optimizer/commands.ts +416 -0
  252. package/src/optimizer/passes.ts +233 -0
  253. package/src/optimizer/structure.ts +441 -0
  254. package/src/parser/index.ts +1437 -0
  255. package/src/repl.ts +165 -0
  256. package/src/runtime/index.ts +1403 -0
  257. package/src/stdlib/README.md +156 -0
  258. package/src/stdlib/combat.rs +20 -0
  259. package/src/stdlib/cooldown.rs +45 -0
  260. package/src/stdlib/math.rs +49 -0
  261. package/src/stdlib/mobs.rs +99 -0
  262. package/src/stdlib/player.rs +29 -0
  263. package/src/stdlib/strings.rs +7 -0
  264. package/src/stdlib/timer.rs +51 -0
  265. package/src/templates/README.md +126 -0
  266. package/src/templates/combat.rs +96 -0
  267. package/src/templates/economy.rs +40 -0
  268. package/src/templates/mini-game-framework.rs +117 -0
  269. package/src/templates/quest.rs +78 -0
  270. package/src/test_programs/zombie_game.rs +25 -0
  271. package/src/typechecker/index.ts +737 -0
  272. package/tsconfig.json +16 -0
@@ -0,0 +1,364 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lexer_1 = require("../lexer");
4
+ const parser_1 = require("../parser");
5
+ const typechecker_1 = require("../typechecker");
6
+ function typeCheck(source) {
7
+ const tokens = new lexer_1.Lexer(source).tokenize();
8
+ const ast = new parser_1.Parser(tokens).parse('test');
9
+ const checker = new typechecker_1.TypeChecker(source);
10
+ return checker.check(ast);
11
+ }
12
+ describe('TypeChecker', () => {
13
+ describe('variable declaration', () => {
14
+ it('allows using top-level consts inside functions', () => {
15
+ const errors = typeCheck(`
16
+ const MAX_HP: int = 100
17
+
18
+ fn test() {
19
+ let hp: int = MAX_HP;
20
+ }
21
+ `);
22
+ expect(errors).toHaveLength(0);
23
+ });
24
+ it('allows using declared variables', () => {
25
+ const errors = typeCheck(`
26
+ fn test() {
27
+ let x: int = 5;
28
+ let y: int = x;
29
+ }
30
+ `);
31
+ expect(errors).toHaveLength(0);
32
+ });
33
+ it('detects undeclared variable usage', () => {
34
+ const errors = typeCheck(`
35
+ fn test() {
36
+ let x: int = y;
37
+ }
38
+ `);
39
+ expect(errors.length).toBeGreaterThan(0);
40
+ expect(errors[0].message).toContain("'y' used before declaration");
41
+ expect(errors[0].location.line).toBe(3);
42
+ expect(errors[0].location.col).toBe(18);
43
+ });
44
+ it('detects undeclared variable in expression', () => {
45
+ const errors = typeCheck(`
46
+ fn test() {
47
+ let x: int = 5 + undeclared;
48
+ }
49
+ `);
50
+ expect(errors.length).toBeGreaterThan(0);
51
+ expect(errors[0].message).toContain("'undeclared' used before declaration");
52
+ });
53
+ it('accepts BlockPos literals for BlockPos variables', () => {
54
+ const errors = typeCheck(`
55
+ fn test() {
56
+ let spawn: BlockPos = (~0, 64, ~0);
57
+ }
58
+ `);
59
+ expect(errors).toHaveLength(0);
60
+ });
61
+ it('rejects assigning to const', () => {
62
+ const errors = typeCheck(`
63
+ const MAX_HP: int = 100
64
+
65
+ fn test() {
66
+ MAX_HP = 50;
67
+ }
68
+ `);
69
+ expect(errors.length).toBeGreaterThan(0);
70
+ expect(errors[0].message).toContain("Cannot assign to const 'MAX_HP'");
71
+ });
72
+ });
73
+ describe('function calls', () => {
74
+ it('allows correct number of arguments', () => {
75
+ const errors = typeCheck(`
76
+ fn add(a: int, b: int) -> int {
77
+ return a + b;
78
+ }
79
+
80
+ fn test() {
81
+ let x: int = add(1, 2);
82
+ }
83
+ `);
84
+ expect(errors).toHaveLength(0);
85
+ });
86
+ it('detects wrong number of arguments', () => {
87
+ const errors = typeCheck(`
88
+ fn add(a: int, b: int) -> int {
89
+ return a + b;
90
+ }
91
+
92
+ fn test() {
93
+ let x: int = add(1);
94
+ }
95
+ `);
96
+ expect(errors.length).toBeGreaterThan(0);
97
+ expect(errors[0].message).toContain("expects 2 arguments, got 1");
98
+ expect(errors[0].location.line).toBe(7);
99
+ });
100
+ it('allows omitting trailing default arguments', () => {
101
+ const errors = typeCheck(`
102
+ fn greet(name: string, formal: bool = false) {
103
+ say(name);
104
+ }
105
+
106
+ fn test() {
107
+ greet("Player");
108
+ greet("Player", true);
109
+ }
110
+ `);
111
+ expect(errors).toHaveLength(0);
112
+ });
113
+ it('detects too many arguments', () => {
114
+ const errors = typeCheck(`
115
+ fn greet() {
116
+ say("hello");
117
+ }
118
+
119
+ fn test() {
120
+ greet(1, 2, 3);
121
+ }
122
+ `);
123
+ expect(errors.length).toBeGreaterThan(0);
124
+ expect(errors[0].message).toContain("expects 0 arguments, got 3");
125
+ });
126
+ it('rejects a required parameter after a default parameter', () => {
127
+ const errors = typeCheck(`
128
+ fn bad(a: int = 1, b: int) {}
129
+ `);
130
+ expect(errors.length).toBeGreaterThan(0);
131
+ expect(errors[0].message).toContain("cannot follow a default parameter");
132
+ });
133
+ it('rejects non-single selector tp destinations', () => {
134
+ const errors = typeCheck(`
135
+ fn test() {
136
+ tp(@s, @a);
137
+ }
138
+ `);
139
+ expect(errors.length).toBeGreaterThan(0);
140
+ expect(errors[0].message).toContain('tp destination must be a single-entity selector');
141
+ });
142
+ it('allows single-selector and BlockPos tp destinations', () => {
143
+ const singleErrors = typeCheck(`
144
+ fn test() {
145
+ tp(@s, @p);
146
+ tp(@s, @e[limit=1, tag=target]);
147
+ }
148
+ `);
149
+ expect(singleErrors).toHaveLength(0);
150
+ const posErrors = typeCheck(`
151
+ fn test() {
152
+ tp(@a, (1, 64, 1));
153
+ tp(@s, (~0, ~10, ~0));
154
+ }
155
+ `);
156
+ expect(posErrors).toHaveLength(0);
157
+ });
158
+ it('treats bossbar_get_value() as int', () => {
159
+ const errors = typeCheck(`
160
+ fn test() {
161
+ let current: int = bossbar_get_value("ns:health");
162
+ }
163
+ `);
164
+ expect(errors).toHaveLength(0);
165
+ });
166
+ it('allows lambda variables to be called via function types', () => {
167
+ const errors = typeCheck(`
168
+ fn test() {
169
+ let double: (int) -> int = (x: int) => x * 2;
170
+ let result: int = double(5);
171
+ }
172
+ `);
173
+ expect(errors).toHaveLength(0);
174
+ });
175
+ it('allows lambdas as callback arguments', () => {
176
+ const errors = typeCheck(`
177
+ fn apply(val: int, cb: (int) -> int) -> int {
178
+ return cb(val);
179
+ }
180
+
181
+ fn test() {
182
+ let result: int = apply(5, (x: int) => x * 3);
183
+ }
184
+ `);
185
+ expect(errors).toHaveLength(0);
186
+ });
187
+ it('infers single-parameter lambdas from the expected function type', () => {
188
+ const errors = typeCheck(`
189
+ fn test() {
190
+ let double: (int) -> int = x => x * 2;
191
+ let result: int = double(5);
192
+ }
193
+ `);
194
+ expect(errors).toHaveLength(0);
195
+ });
196
+ });
197
+ describe('return type checking', () => {
198
+ it('allows matching return type', () => {
199
+ const errors = typeCheck(`
200
+ fn get_five() -> int {
201
+ return 5;
202
+ }
203
+ `);
204
+ expect(errors).toHaveLength(0);
205
+ });
206
+ it('detects return type mismatch', () => {
207
+ const errors = typeCheck(`
208
+ fn get_bool() -> bool {
209
+ return 5;
210
+ }
211
+ `);
212
+ expect(errors.length).toBeGreaterThan(0);
213
+ expect(errors[0].message).toContain("Return type mismatch");
214
+ });
215
+ it('detects missing return value', () => {
216
+ const errors = typeCheck(`
217
+ fn get_int() -> int {
218
+ return;
219
+ }
220
+ `);
221
+ expect(errors.length).toBeGreaterThan(0);
222
+ expect(errors[0].message).toContain("Missing return value");
223
+ });
224
+ it('allows void return with no value', () => {
225
+ const errors = typeCheck(`
226
+ fn do_nothing() {
227
+ return;
228
+ }
229
+ `);
230
+ expect(errors).toHaveLength(0);
231
+ });
232
+ });
233
+ describe('member access', () => {
234
+ it('allows struct field access', () => {
235
+ const errors = typeCheck(`
236
+ struct Point { x: int, y: int }
237
+
238
+ fn test() {
239
+ let p: Point = { x: 10, y: 20 };
240
+ let val: int = p.x;
241
+ }
242
+ `);
243
+ expect(errors).toHaveLength(0);
244
+ });
245
+ it('detects invalid struct field', () => {
246
+ const errors = typeCheck(`
247
+ struct Point { x: int, y: int }
248
+
249
+ fn test() {
250
+ let p: Point = { x: 10, y: 20 };
251
+ let val: int = p.z;
252
+ }
253
+ `);
254
+ expect(errors.length).toBeGreaterThan(0);
255
+ expect(errors[0].message).toContain("has no field 'z'");
256
+ expect(errors[0].location.line).toBe(6);
257
+ });
258
+ it('allows array.len access', () => {
259
+ const errors = typeCheck(`
260
+ fn test() {
261
+ let arr: int[] = [1, 2, 3];
262
+ let len: int = arr.len;
263
+ }
264
+ `);
265
+ expect(errors).toHaveLength(0);
266
+ });
267
+ it('detects member access on primitive', () => {
268
+ const errors = typeCheck(`
269
+ fn test() {
270
+ let x: int = 5;
271
+ let y: int = x.value;
272
+ }
273
+ `);
274
+ expect(errors.length).toBeGreaterThan(0);
275
+ expect(errors[0].message).toContain("Cannot access member");
276
+ });
277
+ it('allows enum variants and enum-typed variables', () => {
278
+ const errors = typeCheck(`
279
+ enum Direction { North, South, East, West }
280
+
281
+ fn test() {
282
+ let dir: Direction = Direction.North;
283
+ if (dir == Direction.South) {
284
+ say("south");
285
+ }
286
+ match (dir) {
287
+ Direction.East => { say("east"); }
288
+ _ => { say("other"); }
289
+ }
290
+ }
291
+ `);
292
+ expect(errors).toHaveLength(0);
293
+ });
294
+ });
295
+ describe('control flow', () => {
296
+ it('checks conditions in if statements', () => {
297
+ const errors = typeCheck(`
298
+ fn test() {
299
+ if (undeclared > 0) {
300
+ say("yes");
301
+ }
302
+ }
303
+ `);
304
+ expect(errors.length).toBeGreaterThan(0);
305
+ expect(errors[0].message).toContain("'undeclared' used before declaration");
306
+ });
307
+ it('checks conditions in while loops', () => {
308
+ const errors = typeCheck(`
309
+ fn test() {
310
+ while (missing) {
311
+ say("loop");
312
+ }
313
+ }
314
+ `);
315
+ expect(errors.length).toBeGreaterThan(0);
316
+ expect(errors[0].message).toContain("'missing' used before declaration");
317
+ });
318
+ it('checks for loop parts', () => {
319
+ const errors = typeCheck(`
320
+ fn test() {
321
+ for (let i: int = 0; i < count; i = i + 1) {
322
+ say("loop");
323
+ }
324
+ }
325
+ `);
326
+ expect(errors.length).toBeGreaterThan(0);
327
+ expect(errors[0].message).toContain("'count' used before declaration");
328
+ });
329
+ });
330
+ describe('complex programs', () => {
331
+ it('handles valid complex program', () => {
332
+ const errors = typeCheck(`
333
+ struct Stats { health: int, mana: int }
334
+
335
+ fn heal(amount: int) -> int {
336
+ let bonus: int = amount * 2;
337
+ return bonus;
338
+ }
339
+
340
+ @tick
341
+ fn game_loop() {
342
+ let stats: Stats = { health: 100, mana: 50 };
343
+ let healed: int = heal(10);
344
+ stats.health = stats.health + healed;
345
+ }
346
+ `);
347
+ expect(errors).toHaveLength(0);
348
+ });
349
+ it('collects multiple errors', () => {
350
+ const errors = typeCheck(`
351
+ fn broken() -> int {
352
+ let x: int = undefined_var;
353
+ let y: int = another_undefined;
354
+ missing_func();
355
+ return false;
356
+ }
357
+ `);
358
+ // Should have multiple errors: 2 undefined vars, return type mismatch
359
+ // (missing_func is not checked since it's not defined as a user function)
360
+ expect(errors.length).toBeGreaterThanOrEqual(3);
361
+ });
362
+ });
363
+ });
364
+ //# sourceMappingURL=typechecker.test.js.map
@@ -0,0 +1,357 @@
1
+ /**
2
+ * RedScript AST Types
3
+ *
4
+ * This module defines the Abstract Syntax Tree structure for RedScript.
5
+ * The AST is produced by the parser and consumed by the lowering pass.
6
+ */
7
+ import type { BinOp, CmpOp } from '../ir/types';
8
+ export interface Span {
9
+ line: number;
10
+ col: number;
11
+ endLine?: number;
12
+ endCol?: number;
13
+ }
14
+ export type PrimitiveType = 'int' | 'bool' | 'float' | 'string' | 'void' | 'BlockPos' | 'byte' | 'short' | 'long' | 'double';
15
+ export type TypeNode = {
16
+ kind: 'named';
17
+ name: PrimitiveType;
18
+ } | {
19
+ kind: 'array';
20
+ elem: TypeNode;
21
+ } | {
22
+ kind: 'struct';
23
+ name: string;
24
+ } | {
25
+ kind: 'enum';
26
+ name: string;
27
+ } | {
28
+ kind: 'function_type';
29
+ params: TypeNode[];
30
+ return: TypeNode;
31
+ };
32
+ export interface LambdaParam {
33
+ name: string;
34
+ type?: TypeNode;
35
+ }
36
+ export interface LambdaExpr {
37
+ kind: 'lambda';
38
+ params: LambdaParam[];
39
+ returnType?: TypeNode;
40
+ body: Expr | Block;
41
+ }
42
+ export interface RangeExpr {
43
+ min?: number;
44
+ max?: number;
45
+ }
46
+ export type SelectorKind = '@a' | '@e' | '@s' | '@p' | '@r' | '@n';
47
+ export interface SelectorFilter {
48
+ type?: string;
49
+ distance?: RangeExpr;
50
+ tag?: string[];
51
+ notTag?: string[];
52
+ scores?: Record<string, RangeExpr>;
53
+ limit?: number;
54
+ sort?: 'nearest' | 'furthest' | 'random' | 'arbitrary';
55
+ nbt?: string;
56
+ gamemode?: string;
57
+ }
58
+ export interface EntitySelector {
59
+ kind: SelectorKind;
60
+ filters?: SelectorFilter;
61
+ }
62
+ export type CoordComponent = {
63
+ kind: 'absolute';
64
+ value: number;
65
+ } | {
66
+ kind: 'relative';
67
+ offset: number;
68
+ } | {
69
+ kind: 'local';
70
+ offset: number;
71
+ };
72
+ export interface BlockPosExpr {
73
+ kind: 'blockpos';
74
+ x: CoordComponent;
75
+ y: CoordComponent;
76
+ z: CoordComponent;
77
+ }
78
+ export type AssignOp = '=' | '+=' | '-=' | '*=' | '/=' | '%=';
79
+ export type Expr = {
80
+ kind: 'int_lit';
81
+ value: number;
82
+ span?: Span;
83
+ } | {
84
+ kind: 'float_lit';
85
+ value: number;
86
+ span?: Span;
87
+ } | {
88
+ kind: 'byte_lit';
89
+ value: number;
90
+ span?: Span;
91
+ } | {
92
+ kind: 'short_lit';
93
+ value: number;
94
+ span?: Span;
95
+ } | {
96
+ kind: 'long_lit';
97
+ value: number;
98
+ span?: Span;
99
+ } | {
100
+ kind: 'double_lit';
101
+ value: number;
102
+ span?: Span;
103
+ } | {
104
+ kind: 'bool_lit';
105
+ value: boolean;
106
+ span?: Span;
107
+ } | {
108
+ kind: 'str_lit';
109
+ value: string;
110
+ span?: Span;
111
+ } | {
112
+ kind: 'mc_name';
113
+ value: string;
114
+ span?: Span;
115
+ } | {
116
+ kind: 'str_interp';
117
+ parts: Array<string | Expr>;
118
+ span?: Span;
119
+ } | {
120
+ kind: 'range_lit';
121
+ range: RangeExpr;
122
+ span?: Span;
123
+ } | (BlockPosExpr & {
124
+ span?: Span;
125
+ }) | {
126
+ kind: 'ident';
127
+ name: string;
128
+ span?: Span;
129
+ } | {
130
+ kind: 'selector';
131
+ raw: string;
132
+ isSingle: boolean;
133
+ sel: EntitySelector;
134
+ span?: Span;
135
+ } | {
136
+ kind: 'binary';
137
+ op: BinOp | CmpOp | '&&' | '||';
138
+ left: Expr;
139
+ right: Expr;
140
+ span?: Span;
141
+ } | {
142
+ kind: 'unary';
143
+ op: '!' | '-';
144
+ operand: Expr;
145
+ span?: Span;
146
+ } | {
147
+ kind: 'assign';
148
+ target: string;
149
+ op: AssignOp;
150
+ value: Expr;
151
+ span?: Span;
152
+ } | {
153
+ kind: 'call';
154
+ fn: string;
155
+ args: Expr[];
156
+ span?: Span;
157
+ } | {
158
+ kind: 'invoke';
159
+ callee: Expr;
160
+ args: Expr[];
161
+ span?: Span;
162
+ } | {
163
+ kind: 'member';
164
+ obj: Expr;
165
+ field: string;
166
+ span?: Span;
167
+ } | {
168
+ kind: 'struct_lit';
169
+ fields: {
170
+ name: string;
171
+ value: Expr;
172
+ }[];
173
+ span?: Span;
174
+ } | {
175
+ kind: 'member_assign';
176
+ obj: Expr;
177
+ field: string;
178
+ op: AssignOp;
179
+ value: Expr;
180
+ span?: Span;
181
+ } | {
182
+ kind: 'index';
183
+ obj: Expr;
184
+ index: Expr;
185
+ span?: Span;
186
+ } | {
187
+ kind: 'array_lit';
188
+ elements: Expr[];
189
+ span?: Span;
190
+ } | {
191
+ kind: 'static_call';
192
+ type: string;
193
+ method: string;
194
+ args: Expr[];
195
+ span?: Span;
196
+ } | (LambdaExpr & {
197
+ span?: Span;
198
+ });
199
+ export type LiteralExpr = Extract<Expr, {
200
+ kind: 'int_lit';
201
+ }> | Extract<Expr, {
202
+ kind: 'float_lit';
203
+ }> | Extract<Expr, {
204
+ kind: 'bool_lit';
205
+ }> | Extract<Expr, {
206
+ kind: 'str_lit';
207
+ }>;
208
+ export type ExecuteSubcommand = {
209
+ kind: 'as';
210
+ selector: EntitySelector;
211
+ } | {
212
+ kind: 'at';
213
+ selector: EntitySelector;
214
+ } | {
215
+ kind: 'if_entity';
216
+ selector: EntitySelector;
217
+ } | {
218
+ kind: 'unless_entity';
219
+ selector: EntitySelector;
220
+ } | {
221
+ kind: 'in';
222
+ dimension: string;
223
+ };
224
+ export type Stmt = {
225
+ kind: 'let';
226
+ name: string;
227
+ type?: TypeNode;
228
+ init: Expr;
229
+ span?: Span;
230
+ } | {
231
+ kind: 'expr';
232
+ expr: Expr;
233
+ span?: Span;
234
+ } | {
235
+ kind: 'return';
236
+ value?: Expr;
237
+ span?: Span;
238
+ } | {
239
+ kind: 'if';
240
+ cond: Expr;
241
+ then: Block;
242
+ else_?: Block;
243
+ span?: Span;
244
+ } | {
245
+ kind: 'while';
246
+ cond: Expr;
247
+ body: Block;
248
+ span?: Span;
249
+ } | {
250
+ kind: 'for';
251
+ init?: Stmt;
252
+ cond: Expr;
253
+ step: Expr;
254
+ body: Block;
255
+ span?: Span;
256
+ } | {
257
+ kind: 'foreach';
258
+ binding: string;
259
+ iterable: Expr;
260
+ body: Block;
261
+ span?: Span;
262
+ } | {
263
+ kind: 'for_range';
264
+ varName: string;
265
+ start: Expr;
266
+ end: Expr;
267
+ body: Block;
268
+ span?: Span;
269
+ } | {
270
+ kind: 'match';
271
+ expr: Expr;
272
+ arms: {
273
+ pattern: Expr | null;
274
+ body: Block;
275
+ }[];
276
+ span?: Span;
277
+ } | {
278
+ kind: 'as_block';
279
+ selector: EntitySelector;
280
+ body: Block;
281
+ span?: Span;
282
+ } | {
283
+ kind: 'at_block';
284
+ selector: EntitySelector;
285
+ body: Block;
286
+ span?: Span;
287
+ } | {
288
+ kind: 'as_at';
289
+ as_sel: EntitySelector;
290
+ at_sel: EntitySelector;
291
+ body: Block;
292
+ span?: Span;
293
+ } | {
294
+ kind: 'execute';
295
+ subcommands: ExecuteSubcommand[];
296
+ body: Block;
297
+ span?: Span;
298
+ } | {
299
+ kind: 'raw';
300
+ cmd: string;
301
+ span?: Span;
302
+ };
303
+ export type Block = Stmt[];
304
+ export interface Decorator {
305
+ name: 'tick' | 'on_trigger' | 'on_advancement' | 'on_craft' | 'on_death' | 'on_login' | 'on_join_team';
306
+ args?: {
307
+ rate?: number;
308
+ trigger?: string;
309
+ advancement?: string;
310
+ item?: string;
311
+ team?: string;
312
+ };
313
+ }
314
+ export interface Param {
315
+ name: string;
316
+ type: TypeNode;
317
+ default?: Expr;
318
+ }
319
+ export interface FnDecl {
320
+ name: string;
321
+ params: Param[];
322
+ returnType: TypeNode;
323
+ decorators: Decorator[];
324
+ body: Block;
325
+ span?: Span;
326
+ }
327
+ export interface StructField {
328
+ name: string;
329
+ type: TypeNode;
330
+ }
331
+ export interface StructDecl {
332
+ name: string;
333
+ fields: StructField[];
334
+ span?: Span;
335
+ }
336
+ export interface EnumVariant {
337
+ name: string;
338
+ value?: number;
339
+ }
340
+ export interface EnumDecl {
341
+ name: string;
342
+ variants: EnumVariant[];
343
+ span?: Span;
344
+ }
345
+ export interface ConstDecl {
346
+ name: string;
347
+ type: TypeNode;
348
+ value: LiteralExpr;
349
+ span?: Span;
350
+ }
351
+ export interface Program {
352
+ namespace: string;
353
+ declarations: FnDecl[];
354
+ structs: StructDecl[];
355
+ enums: EnumDecl[];
356
+ consts: ConstDecl[];
357
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * RedScript AST Types
4
+ *
5
+ * This module defines the Abstract Syntax Tree structure for RedScript.
6
+ * The AST is produced by the parser and consumed by the lowering pass.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ //# sourceMappingURL=types.js.map