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,42 @@
1
+ /**
2
+ * RedScript Type Checker
3
+ *
4
+ * Performs basic type checking between Parser and Lowering phases.
5
+ * Collects errors but doesn't block compilation (warn mode).
6
+ */
7
+ import type { Program } from '../ast/types';
8
+ import { DiagnosticError } from '../diagnostics';
9
+ export declare class TypeChecker {
10
+ private collector;
11
+ private functions;
12
+ private structs;
13
+ private enums;
14
+ private consts;
15
+ private currentFn;
16
+ private currentReturnType;
17
+ private scope;
18
+ constructor(source?: string, filePath?: string);
19
+ private getNodeLocation;
20
+ private report;
21
+ /**
22
+ * Type check a program. Returns collected errors.
23
+ */
24
+ check(program: Program): DiagnosticError[];
25
+ private checkFunction;
26
+ private checkBlock;
27
+ private checkStmt;
28
+ private checkLetStmt;
29
+ private checkReturnStmt;
30
+ private checkExpr;
31
+ private checkCallExpr;
32
+ private checkInvokeExpr;
33
+ private checkFunctionCallArgs;
34
+ private checkTpCall;
35
+ private checkMemberExpr;
36
+ private checkLambdaExpr;
37
+ private inferType;
38
+ private inferLambdaType;
39
+ private typesMatch;
40
+ private typeToString;
41
+ private normalizeType;
42
+ }
@@ -0,0 +1,629 @@
1
+ "use strict";
2
+ /**
3
+ * RedScript Type Checker
4
+ *
5
+ * Performs basic type checking between Parser and Lowering phases.
6
+ * Collects errors but doesn't block compilation (warn mode).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TypeChecker = void 0;
10
+ const diagnostics_1 = require("../diagnostics");
11
+ // ---------------------------------------------------------------------------
12
+ // Type Checker
13
+ // ---------------------------------------------------------------------------
14
+ class TypeChecker {
15
+ constructor(source, filePath) {
16
+ this.functions = new Map();
17
+ this.structs = new Map();
18
+ this.enums = new Map();
19
+ this.consts = new Map();
20
+ this.currentFn = null;
21
+ this.currentReturnType = null;
22
+ this.scope = new Map();
23
+ this.collector = new diagnostics_1.DiagnosticCollector(source, filePath);
24
+ }
25
+ getNodeLocation(node) {
26
+ const span = node?.span;
27
+ return {
28
+ line: span?.line ?? 1,
29
+ col: span?.col ?? 1,
30
+ };
31
+ }
32
+ report(message, node) {
33
+ const { line, col } = this.getNodeLocation(node);
34
+ this.collector.error('TypeError', message, line, col);
35
+ }
36
+ /**
37
+ * Type check a program. Returns collected errors.
38
+ */
39
+ check(program) {
40
+ // First pass: collect function and struct declarations
41
+ for (const fn of program.declarations) {
42
+ this.functions.set(fn.name, fn);
43
+ }
44
+ for (const struct of program.structs ?? []) {
45
+ const fields = new Map();
46
+ for (const field of struct.fields) {
47
+ fields.set(field.name, field.type);
48
+ }
49
+ this.structs.set(struct.name, fields);
50
+ }
51
+ for (const enumDecl of program.enums ?? []) {
52
+ const variants = new Map();
53
+ for (const variant of enumDecl.variants) {
54
+ variants.set(variant.name, variant.value ?? 0);
55
+ }
56
+ this.enums.set(enumDecl.name, variants);
57
+ }
58
+ for (const constDecl of program.consts ?? []) {
59
+ const constType = this.normalizeType(constDecl.type);
60
+ const actualType = this.inferType(constDecl.value);
61
+ if (!this.typesMatch(constType, actualType)) {
62
+ this.report(`Type mismatch: expected ${this.typeToString(constType)}, got ${this.typeToString(actualType)}`, constDecl.value);
63
+ }
64
+ this.consts.set(constDecl.name, constType);
65
+ }
66
+ // Second pass: type check function bodies
67
+ for (const fn of program.declarations) {
68
+ this.checkFunction(fn);
69
+ }
70
+ return this.collector.getErrors();
71
+ }
72
+ checkFunction(fn) {
73
+ this.currentFn = fn;
74
+ this.currentReturnType = this.normalizeType(fn.returnType);
75
+ this.scope = new Map();
76
+ let seenDefault = false;
77
+ for (const [name, type] of this.consts.entries()) {
78
+ this.scope.set(name, { type, mutable: false });
79
+ }
80
+ // Add parameters to scope
81
+ for (const param of fn.params) {
82
+ this.scope.set(param.name, { type: this.normalizeType(param.type), mutable: true });
83
+ if (param.default) {
84
+ seenDefault = true;
85
+ this.checkExpr(param.default);
86
+ const defaultType = this.inferType(param.default);
87
+ const paramType = this.normalizeType(param.type);
88
+ if (!this.typesMatch(paramType, defaultType)) {
89
+ this.report(`Default value for '${param.name}' must be ${this.typeToString(paramType)}, got ${this.typeToString(defaultType)}`, param.default);
90
+ }
91
+ }
92
+ else if (seenDefault) {
93
+ this.report(`Parameter '${param.name}' cannot follow a default parameter`, param);
94
+ }
95
+ }
96
+ // Check body
97
+ this.checkBlock(fn.body);
98
+ this.currentFn = null;
99
+ this.currentReturnType = null;
100
+ }
101
+ checkBlock(stmts) {
102
+ for (const stmt of stmts) {
103
+ this.checkStmt(stmt);
104
+ }
105
+ }
106
+ checkStmt(stmt) {
107
+ switch (stmt.kind) {
108
+ case 'let':
109
+ this.checkLetStmt(stmt);
110
+ break;
111
+ case 'return':
112
+ this.checkReturnStmt(stmt);
113
+ break;
114
+ case 'if':
115
+ this.checkExpr(stmt.cond);
116
+ this.checkBlock(stmt.then);
117
+ if (stmt.else_)
118
+ this.checkBlock(stmt.else_);
119
+ break;
120
+ case 'while':
121
+ this.checkExpr(stmt.cond);
122
+ this.checkBlock(stmt.body);
123
+ break;
124
+ case 'for':
125
+ if (stmt.init)
126
+ this.checkStmt(stmt.init);
127
+ this.checkExpr(stmt.cond);
128
+ this.checkExpr(stmt.step);
129
+ this.checkBlock(stmt.body);
130
+ break;
131
+ case 'foreach':
132
+ this.checkExpr(stmt.iterable);
133
+ if (stmt.iterable.kind === 'selector') {
134
+ this.scope.set(stmt.binding, { type: { kind: 'named', name: 'void' }, mutable: true }); // Entity marker
135
+ }
136
+ else {
137
+ const iterableType = this.inferType(stmt.iterable);
138
+ if (iterableType.kind === 'array') {
139
+ this.scope.set(stmt.binding, { type: iterableType.elem, mutable: true });
140
+ }
141
+ else {
142
+ this.scope.set(stmt.binding, { type: { kind: 'named', name: 'void' }, mutable: true });
143
+ }
144
+ }
145
+ this.checkBlock(stmt.body);
146
+ break;
147
+ case 'match':
148
+ this.checkExpr(stmt.expr);
149
+ for (const arm of stmt.arms) {
150
+ if (arm.pattern) {
151
+ this.checkExpr(arm.pattern);
152
+ if (!this.typesMatch(this.inferType(stmt.expr), this.inferType(arm.pattern))) {
153
+ this.report('Match arm pattern type must match subject type', arm.pattern);
154
+ }
155
+ }
156
+ this.checkBlock(arm.body);
157
+ }
158
+ break;
159
+ case 'as_block':
160
+ case 'at_block':
161
+ this.checkBlock(stmt.body);
162
+ break;
163
+ case 'as_at':
164
+ this.checkBlock(stmt.body);
165
+ break;
166
+ case 'execute':
167
+ this.checkBlock(stmt.body);
168
+ break;
169
+ case 'expr':
170
+ this.checkExpr(stmt.expr);
171
+ break;
172
+ case 'raw':
173
+ // Raw commands are not type checked
174
+ break;
175
+ }
176
+ }
177
+ checkLetStmt(stmt) {
178
+ // Check initializer
179
+ const expectedType = stmt.type ? this.normalizeType(stmt.type) : undefined;
180
+ this.checkExpr(stmt.init, expectedType);
181
+ // Add variable to scope
182
+ const type = expectedType ?? this.inferType(stmt.init);
183
+ this.scope.set(stmt.name, { type, mutable: true });
184
+ const actualType = this.inferType(stmt.init, expectedType);
185
+ if (expectedType &&
186
+ stmt.init.kind !== 'struct_lit' &&
187
+ stmt.init.kind !== 'array_lit' &&
188
+ !(actualType.kind === 'named' && actualType.name === 'void') &&
189
+ !this.typesMatch(expectedType, actualType)) {
190
+ this.report(`Type mismatch: expected ${this.typeToString(expectedType)}, got ${this.typeToString(actualType)}`, stmt);
191
+ }
192
+ }
193
+ checkReturnStmt(stmt) {
194
+ if (!this.currentReturnType)
195
+ return;
196
+ const expectedType = this.currentReturnType;
197
+ if (stmt.value) {
198
+ const actualType = this.inferType(stmt.value, expectedType);
199
+ this.checkExpr(stmt.value, expectedType);
200
+ if (!this.typesMatch(expectedType, actualType)) {
201
+ this.report(`Return type mismatch: expected ${this.typeToString(expectedType)}, got ${this.typeToString(actualType)}`, stmt);
202
+ }
203
+ }
204
+ else {
205
+ // No return value
206
+ if (expectedType.kind !== 'named' || expectedType.name !== 'void') {
207
+ this.report(`Missing return value: expected ${this.typeToString(expectedType)}`, stmt);
208
+ }
209
+ }
210
+ }
211
+ checkExpr(expr, expectedType) {
212
+ switch (expr.kind) {
213
+ case 'ident':
214
+ if (!this.scope.has(expr.name)) {
215
+ this.report(`Variable '${expr.name}' used before declaration`, expr);
216
+ }
217
+ break;
218
+ case 'call':
219
+ this.checkCallExpr(expr);
220
+ break;
221
+ case 'invoke':
222
+ this.checkInvokeExpr(expr);
223
+ break;
224
+ case 'member':
225
+ this.checkMemberExpr(expr);
226
+ break;
227
+ case 'binary':
228
+ this.checkExpr(expr.left);
229
+ this.checkExpr(expr.right);
230
+ break;
231
+ case 'unary':
232
+ this.checkExpr(expr.operand);
233
+ break;
234
+ case 'assign':
235
+ if (!this.scope.has(expr.target)) {
236
+ this.report(`Variable '${expr.target}' used before declaration`, expr);
237
+ }
238
+ else if (!this.scope.get(expr.target)?.mutable) {
239
+ this.report(`Cannot assign to const '${expr.target}'`, expr);
240
+ }
241
+ this.checkExpr(expr.value, this.scope.get(expr.target)?.type);
242
+ break;
243
+ case 'member_assign':
244
+ this.checkExpr(expr.obj);
245
+ this.checkExpr(expr.value);
246
+ break;
247
+ case 'index':
248
+ this.checkExpr(expr.obj);
249
+ this.checkExpr(expr.index);
250
+ const indexType = this.inferType(expr.index);
251
+ if (indexType.kind !== 'named' || indexType.name !== 'int') {
252
+ this.report('Array index must be int', expr.index);
253
+ }
254
+ break;
255
+ case 'struct_lit':
256
+ for (const field of expr.fields) {
257
+ this.checkExpr(field.value);
258
+ }
259
+ break;
260
+ case 'str_interp':
261
+ for (const part of expr.parts) {
262
+ if (typeof part !== 'string') {
263
+ this.checkExpr(part);
264
+ }
265
+ }
266
+ break;
267
+ case 'array_lit':
268
+ for (const elem of expr.elements) {
269
+ this.checkExpr(elem);
270
+ }
271
+ break;
272
+ case 'lambda':
273
+ this.checkLambdaExpr(expr, expectedType);
274
+ break;
275
+ case 'blockpos':
276
+ break;
277
+ case 'static_call':
278
+ for (const arg of expr.args) {
279
+ this.checkExpr(arg);
280
+ }
281
+ break;
282
+ // Literals don't need checking
283
+ case 'int_lit':
284
+ case 'float_lit':
285
+ case 'bool_lit':
286
+ case 'str_lit':
287
+ case 'mc_name':
288
+ case 'range_lit':
289
+ case 'selector':
290
+ case 'byte_lit':
291
+ case 'short_lit':
292
+ case 'long_lit':
293
+ case 'double_lit':
294
+ break;
295
+ }
296
+ }
297
+ checkCallExpr(expr) {
298
+ if (expr.fn === 'tp' || expr.fn === 'tp_to') {
299
+ this.checkTpCall(expr);
300
+ }
301
+ // Check if function exists and arg count matches
302
+ const fn = this.functions.get(expr.fn);
303
+ if (fn) {
304
+ const requiredParams = fn.params.filter(param => !param.default).length;
305
+ if (expr.args.length < requiredParams || expr.args.length > fn.params.length) {
306
+ const expectedRange = requiredParams === fn.params.length
307
+ ? `${fn.params.length}`
308
+ : `${requiredParams}-${fn.params.length}`;
309
+ this.report(`Function '${expr.fn}' expects ${expectedRange} arguments, got ${expr.args.length}`, expr);
310
+ }
311
+ for (let i = 0; i < expr.args.length; i++) {
312
+ const paramType = fn.params[i] ? this.normalizeType(fn.params[i].type) : undefined;
313
+ if (paramType) {
314
+ this.checkExpr(expr.args[i], paramType);
315
+ }
316
+ const argType = this.inferType(expr.args[i], paramType);
317
+ if (paramType && !this.typesMatch(paramType, argType)) {
318
+ this.report(`Argument ${i + 1} of '${expr.fn}' expects ${this.typeToString(paramType)}, got ${this.typeToString(argType)}`, expr.args[i]);
319
+ }
320
+ }
321
+ return;
322
+ }
323
+ const varType = this.scope.get(expr.fn)?.type;
324
+ if (varType?.kind === 'function_type') {
325
+ this.checkFunctionCallArgs(expr.args, varType.params, expr.fn, expr);
326
+ return;
327
+ }
328
+ for (const arg of expr.args) {
329
+ this.checkExpr(arg);
330
+ }
331
+ // Built-in functions are not checked for arg count
332
+ }
333
+ checkInvokeExpr(expr) {
334
+ this.checkExpr(expr.callee);
335
+ const calleeType = this.inferType(expr.callee);
336
+ if (calleeType.kind !== 'function_type') {
337
+ this.report('Attempted to call a non-function value', expr.callee);
338
+ for (const arg of expr.args) {
339
+ this.checkExpr(arg);
340
+ }
341
+ return;
342
+ }
343
+ this.checkFunctionCallArgs(expr.args, calleeType.params, 'lambda', expr);
344
+ }
345
+ checkFunctionCallArgs(args, params, calleeName, node) {
346
+ if (args.length !== params.length) {
347
+ this.report(`Function '${calleeName}' expects ${params.length} arguments, got ${args.length}`, node);
348
+ }
349
+ for (let i = 0; i < args.length; i++) {
350
+ const paramType = params[i];
351
+ if (!paramType) {
352
+ this.checkExpr(args[i]);
353
+ continue;
354
+ }
355
+ this.checkExpr(args[i], paramType);
356
+ const argType = this.inferType(args[i], paramType);
357
+ if (!this.typesMatch(paramType, argType)) {
358
+ this.report(`Argument ${i + 1} of '${calleeName}' expects ${this.typeToString(paramType)}, got ${this.typeToString(argType)}`, args[i]);
359
+ }
360
+ }
361
+ }
362
+ checkTpCall(expr) {
363
+ const dest = expr.args[1];
364
+ if (!dest) {
365
+ return;
366
+ }
367
+ const destType = this.inferType(dest);
368
+ if (destType.kind === 'named' && destType.name === 'BlockPos') {
369
+ return;
370
+ }
371
+ if (dest.kind === 'selector' && !dest.isSingle) {
372
+ this.report('tp destination must be a single-entity selector (@s, @p, @r, or limit=1)', dest);
373
+ }
374
+ }
375
+ checkMemberExpr(expr) {
376
+ if (!(expr.obj.kind === 'ident' && this.enums.has(expr.obj.name))) {
377
+ this.checkExpr(expr.obj);
378
+ }
379
+ // Check if accessing member on appropriate type
380
+ if (expr.obj.kind === 'ident') {
381
+ if (this.enums.has(expr.obj.name)) {
382
+ const enumVariants = this.enums.get(expr.obj.name);
383
+ if (!enumVariants.has(expr.field)) {
384
+ this.report(`Enum '${expr.obj.name}' has no variant '${expr.field}'`, expr);
385
+ }
386
+ return;
387
+ }
388
+ const varSymbol = this.scope.get(expr.obj.name);
389
+ const varType = varSymbol?.type;
390
+ if (varType) {
391
+ // Allow member access on struct types
392
+ if (varType.kind === 'struct') {
393
+ const structFields = this.structs.get(varType.name);
394
+ if (structFields && !structFields.has(expr.field)) {
395
+ this.report(`Struct '${varType.name}' has no field '${expr.field}'`, expr);
396
+ }
397
+ }
398
+ else if (varType.kind === 'array') {
399
+ if (expr.field !== 'len' && expr.field !== 'push' && expr.field !== 'pop') {
400
+ this.report(`Array has no field '${expr.field}'`, expr);
401
+ }
402
+ }
403
+ else if (varType.kind === 'named') {
404
+ // Entity marker (void) - allow all members
405
+ if (varType.name !== 'void') {
406
+ // Only warn for primitive types
407
+ if (['int', 'bool', 'float', 'string', 'byte', 'short', 'long', 'double'].includes(varType.name)) {
408
+ this.report(`Cannot access member '${expr.field}' on ${this.typeToString(varType)}`, expr);
409
+ }
410
+ }
411
+ }
412
+ }
413
+ }
414
+ }
415
+ checkLambdaExpr(expr, expectedType) {
416
+ const normalizedExpected = expectedType ? this.normalizeType(expectedType) : undefined;
417
+ const expectedFnType = normalizedExpected?.kind === 'function_type' ? normalizedExpected : undefined;
418
+ const lambdaType = this.inferLambdaType(expr, expectedFnType);
419
+ if (expectedFnType && !this.typesMatch(expectedFnType, lambdaType)) {
420
+ this.report(`Type mismatch: expected ${this.typeToString(expectedFnType)}, got ${this.typeToString(lambdaType)}`, expr);
421
+ return;
422
+ }
423
+ const outerScope = this.scope;
424
+ const outerReturnType = this.currentReturnType;
425
+ const lambdaScope = new Map(this.scope);
426
+ const paramTypes = expectedFnType?.params ?? lambdaType.params;
427
+ for (let i = 0; i < expr.params.length; i++) {
428
+ lambdaScope.set(expr.params[i].name, {
429
+ type: paramTypes[i] ?? { kind: 'named', name: 'void' },
430
+ mutable: true,
431
+ });
432
+ }
433
+ this.scope = lambdaScope;
434
+ this.currentReturnType = expr.returnType
435
+ ? this.normalizeType(expr.returnType)
436
+ : (expectedFnType?.return ?? lambdaType.return);
437
+ if (Array.isArray(expr.body)) {
438
+ this.checkBlock(expr.body);
439
+ }
440
+ else {
441
+ this.checkExpr(expr.body, this.currentReturnType);
442
+ const actualType = this.inferType(expr.body, this.currentReturnType);
443
+ if (!this.typesMatch(this.currentReturnType, actualType)) {
444
+ this.report(`Return type mismatch: expected ${this.typeToString(this.currentReturnType)}, got ${this.typeToString(actualType)}`, expr.body);
445
+ }
446
+ }
447
+ this.scope = outerScope;
448
+ this.currentReturnType = outerReturnType;
449
+ }
450
+ inferType(expr, expectedType) {
451
+ switch (expr.kind) {
452
+ case 'int_lit':
453
+ return { kind: 'named', name: 'int' };
454
+ case 'float_lit':
455
+ return { kind: 'named', name: 'float' };
456
+ case 'byte_lit':
457
+ return { kind: 'named', name: 'byte' };
458
+ case 'short_lit':
459
+ return { kind: 'named', name: 'short' };
460
+ case 'long_lit':
461
+ return { kind: 'named', name: 'long' };
462
+ case 'double_lit':
463
+ return { kind: 'named', name: 'double' };
464
+ case 'bool_lit':
465
+ return { kind: 'named', name: 'bool' };
466
+ case 'str_lit':
467
+ case 'mc_name':
468
+ return { kind: 'named', name: 'string' };
469
+ case 'str_interp':
470
+ for (const part of expr.parts) {
471
+ if (typeof part !== 'string') {
472
+ this.checkExpr(part);
473
+ }
474
+ }
475
+ return { kind: 'named', name: 'string' };
476
+ case 'blockpos':
477
+ return { kind: 'named', name: 'BlockPos' };
478
+ case 'ident':
479
+ return this.scope.get(expr.name)?.type ?? { kind: 'named', name: 'void' };
480
+ case 'call': {
481
+ if (expr.fn === '__array_push') {
482
+ return { kind: 'named', name: 'void' };
483
+ }
484
+ if (expr.fn === '__array_pop') {
485
+ const target = expr.args[0];
486
+ if (target && target.kind === 'ident') {
487
+ const targetType = this.scope.get(target.name)?.type;
488
+ if (targetType?.kind === 'array')
489
+ return targetType.elem;
490
+ }
491
+ return { kind: 'named', name: 'int' };
492
+ }
493
+ if (expr.fn === 'bossbar_get_value') {
494
+ return { kind: 'named', name: 'int' };
495
+ }
496
+ if (expr.fn === 'random_sequence') {
497
+ return { kind: 'named', name: 'void' };
498
+ }
499
+ const varType = this.scope.get(expr.fn)?.type;
500
+ if (varType?.kind === 'function_type') {
501
+ return varType.return;
502
+ }
503
+ const fn = this.functions.get(expr.fn);
504
+ return fn?.returnType ?? { kind: 'named', name: 'int' };
505
+ }
506
+ case 'invoke': {
507
+ const calleeType = this.inferType(expr.callee);
508
+ if (calleeType.kind === 'function_type') {
509
+ return calleeType.return;
510
+ }
511
+ return { kind: 'named', name: 'void' };
512
+ }
513
+ case 'member':
514
+ if (expr.obj.kind === 'ident' && this.enums.has(expr.obj.name)) {
515
+ return { kind: 'enum', name: expr.obj.name };
516
+ }
517
+ if (expr.obj.kind === 'ident') {
518
+ const objTypeNode = this.scope.get(expr.obj.name)?.type;
519
+ if (objTypeNode?.kind === 'array' && expr.field === 'len') {
520
+ return { kind: 'named', name: 'int' };
521
+ }
522
+ }
523
+ return { kind: 'named', name: 'void' };
524
+ case 'index': {
525
+ const objType = this.inferType(expr.obj);
526
+ if (objType.kind === 'array')
527
+ return objType.elem;
528
+ return { kind: 'named', name: 'void' };
529
+ }
530
+ case 'binary':
531
+ if (['==', '!=', '<', '<=', '>', '>=', '&&', '||'].includes(expr.op)) {
532
+ return { kind: 'named', name: 'bool' };
533
+ }
534
+ return this.inferType(expr.left);
535
+ case 'unary':
536
+ if (expr.op === '!')
537
+ return { kind: 'named', name: 'bool' };
538
+ return this.inferType(expr.operand);
539
+ case 'array_lit':
540
+ if (expr.elements.length > 0) {
541
+ return { kind: 'array', elem: this.inferType(expr.elements[0]) };
542
+ }
543
+ return { kind: 'array', elem: { kind: 'named', name: 'int' } };
544
+ case 'lambda':
545
+ return this.inferLambdaType(expr, expectedType && this.normalizeType(expectedType).kind === 'function_type'
546
+ ? this.normalizeType(expectedType)
547
+ : undefined);
548
+ default:
549
+ return { kind: 'named', name: 'void' };
550
+ }
551
+ }
552
+ inferLambdaType(expr, expectedType) {
553
+ const params = expr.params.map((param, index) => {
554
+ if (param.type) {
555
+ return this.normalizeType(param.type);
556
+ }
557
+ const inferred = expectedType?.params[index];
558
+ if (inferred) {
559
+ return inferred;
560
+ }
561
+ this.report(`Lambda parameter '${param.name}' requires a type annotation`, expr);
562
+ return { kind: 'named', name: 'void' };
563
+ });
564
+ let returnType = expr.returnType
565
+ ? this.normalizeType(expr.returnType)
566
+ : expectedType?.return;
567
+ if (!returnType) {
568
+ returnType = Array.isArray(expr.body) ? { kind: 'named', name: 'void' } : this.inferType(expr.body);
569
+ }
570
+ return { kind: 'function_type', params, return: returnType };
571
+ }
572
+ typesMatch(expected, actual) {
573
+ if (expected.kind !== actual.kind)
574
+ return false;
575
+ if (expected.kind === 'named' && actual.kind === 'named') {
576
+ // void matches anything (for inferred types)
577
+ if (actual.name === 'void')
578
+ return true;
579
+ return expected.name === actual.name;
580
+ }
581
+ if (expected.kind === 'array' && actual.kind === 'array') {
582
+ return this.typesMatch(expected.elem, actual.elem);
583
+ }
584
+ if (expected.kind === 'struct' && actual.kind === 'struct') {
585
+ return expected.name === actual.name;
586
+ }
587
+ if (expected.kind === 'enum' && actual.kind === 'enum') {
588
+ return expected.name === actual.name;
589
+ }
590
+ if (expected.kind === 'function_type' && actual.kind === 'function_type') {
591
+ return expected.params.length === actual.params.length &&
592
+ expected.params.every((param, index) => this.typesMatch(param, actual.params[index])) &&
593
+ this.typesMatch(expected.return, actual.return);
594
+ }
595
+ return false;
596
+ }
597
+ typeToString(type) {
598
+ switch (type.kind) {
599
+ case 'named':
600
+ return type.name;
601
+ case 'array':
602
+ return `${this.typeToString(type.elem)}[]`;
603
+ case 'struct':
604
+ return type.name;
605
+ case 'enum':
606
+ return type.name;
607
+ case 'function_type':
608
+ return `(${type.params.map(param => this.typeToString(param)).join(', ')}) -> ${this.typeToString(type.return)}`;
609
+ }
610
+ }
611
+ normalizeType(type) {
612
+ if (type.kind === 'array') {
613
+ return { kind: 'array', elem: this.normalizeType(type.elem) };
614
+ }
615
+ if (type.kind === 'function_type') {
616
+ return {
617
+ kind: 'function_type',
618
+ params: type.params.map(param => this.normalizeType(param)),
619
+ return: this.normalizeType(type.return),
620
+ };
621
+ }
622
+ if ((type.kind === 'struct' || type.kind === 'enum') && this.enums.has(type.name)) {
623
+ return { kind: 'enum', name: type.name };
624
+ }
625
+ return type;
626
+ }
627
+ }
628
+ exports.TypeChecker = TypeChecker;
629
+ //# sourceMappingURL=index.js.map