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
package/dist/cli.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * RedScript CLI
4
+ *
5
+ * Usage:
6
+ * redscript compile <file> [-o <out>] [--output-nbt <file>] [--namespace <ns>]
7
+ * redscript check <file>
8
+ * redscript repl
9
+ * redscript version
10
+ */
11
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,407 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * RedScript CLI
5
+ *
6
+ * Usage:
7
+ * redscript compile <file> [-o <out>] [--output-nbt <file>] [--namespace <ns>]
8
+ * redscript check <file>
9
+ * redscript repl
10
+ * redscript version
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ const index_1 = require("./index");
47
+ const cmdblock_1 = require("./codegen/cmdblock");
48
+ const structure_1 = require("./codegen/structure");
49
+ const diagnostics_1 = require("./diagnostics");
50
+ const repl_1 = require("./repl");
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ // Parse command line arguments
54
+ const args = process.argv.slice(2);
55
+ function printUsage() {
56
+ console.log(`
57
+ RedScript Compiler
58
+
59
+ Usage:
60
+ redscript compile <file> [-o <out>] [--output-nbt <file>] [--namespace <ns>] [--target <target>]
61
+ redscript watch <dir> [-o <outdir>] [--namespace <ns>] [--hot-reload <url>]
62
+ redscript check <file>
63
+ redscript repl
64
+ redscript version
65
+
66
+ Commands:
67
+ compile Compile a RedScript file to a Minecraft datapack
68
+ watch Watch a directory for .rs file changes, recompile, and hot reload
69
+ check Check a RedScript file for errors without generating output
70
+ repl Start an interactive RedScript REPL
71
+ version Print the RedScript version
72
+
73
+ Options:
74
+ -o, --output <path> Output directory or file path, depending on target
75
+ --output-nbt <file> Output .nbt file path for structure target
76
+ --namespace <ns> Datapack namespace (default: derived from filename)
77
+ --target <target> Output target: datapack (default), cmdblock, or structure
78
+ --stats Print optimizer statistics
79
+ --hot-reload <url> After each successful compile, POST to <url>/reload
80
+ (use with redscript-testharness; e.g. http://localhost:25561)
81
+ -h, --help Show this help message
82
+
83
+ Targets:
84
+ datapack Generate a full Minecraft datapack (default)
85
+ cmdblock Generate JSON structure for command block placement
86
+ structure Generate a Minecraft structure .nbt file with command blocks
87
+ `);
88
+ }
89
+ function printVersion() {
90
+ const packagePath = path.join(__dirname, '..', 'package.json');
91
+ try {
92
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
93
+ console.log(`RedScript v${pkg.version}`);
94
+ }
95
+ catch {
96
+ console.log('RedScript v0.1.0');
97
+ }
98
+ }
99
+ function parseArgs(args) {
100
+ const result = {};
101
+ let i = 0;
102
+ while (i < args.length) {
103
+ const arg = args[i];
104
+ if (arg === '-h' || arg === '--help') {
105
+ result.help = true;
106
+ i++;
107
+ }
108
+ else if (arg === '-o' || arg === '--output') {
109
+ result.output = args[++i];
110
+ i++;
111
+ }
112
+ else if (arg === '--output-nbt') {
113
+ result.outputNbt = args[++i];
114
+ i++;
115
+ }
116
+ else if (arg === '--namespace') {
117
+ result.namespace = args[++i];
118
+ i++;
119
+ }
120
+ else if (arg === '--target') {
121
+ result.target = args[++i];
122
+ i++;
123
+ }
124
+ else if (arg === '--stats') {
125
+ result.stats = true;
126
+ i++;
127
+ }
128
+ else if (arg === '--hot-reload') {
129
+ result.hotReload = args[++i];
130
+ i++;
131
+ }
132
+ else if (!result.command) {
133
+ result.command = arg;
134
+ i++;
135
+ }
136
+ else if (!result.file) {
137
+ result.file = arg;
138
+ i++;
139
+ }
140
+ else {
141
+ i++;
142
+ }
143
+ }
144
+ return result;
145
+ }
146
+ function deriveNamespace(filePath) {
147
+ const basename = path.basename(filePath, path.extname(filePath));
148
+ // Convert to valid identifier: lowercase, replace non-alphanumeric with underscore
149
+ return basename.toLowerCase().replace(/[^a-z0-9]/g, '_');
150
+ }
151
+ function printWarnings(warnings) {
152
+ if (!warnings || warnings.length === 0) {
153
+ return;
154
+ }
155
+ for (const warning of warnings) {
156
+ console.error(`Warning [${warning.code}]: ${warning.message}`);
157
+ }
158
+ }
159
+ function formatReduction(before, after) {
160
+ if (before === 0)
161
+ return '0%';
162
+ return `${Math.round(((before - after) / before) * 100)}%`;
163
+ }
164
+ function printOptimizationStats(stats) {
165
+ if (!stats)
166
+ return;
167
+ console.log('Optimizations applied:');
168
+ console.log(` LICM: ${stats.licmHoists} reads hoisted from ${stats.licmLoopBodies} loop bodies`);
169
+ console.log(` CSE: ${stats.cseRedundantReads + stats.cseArithmetic} expressions eliminated`);
170
+ console.log(` setblock batching: ${stats.setblockMergedCommands} setblocks -> ${stats.setblockFillCommands} fills (saved ${stats.setblockSavedCommands} commands)`);
171
+ console.log(` dead code: ${stats.deadCodeRemoved} commands removed`);
172
+ console.log(` constant folding: ${stats.constantFolds} constants folded`);
173
+ console.log(` Total mcfunction commands: ${stats.totalCommandsBefore} -> ${stats.totalCommandsAfter} (${formatReduction(stats.totalCommandsBefore, stats.totalCommandsAfter)} reduction)`);
174
+ }
175
+ function compileCommand(file, output, namespace, target = 'datapack', showStats = false) {
176
+ // Read source file
177
+ if (!fs.existsSync(file)) {
178
+ console.error(`Error: File not found: ${file}`);
179
+ process.exit(1);
180
+ }
181
+ const source = fs.readFileSync(file, 'utf-8');
182
+ try {
183
+ if (target === 'cmdblock') {
184
+ const result = (0, index_1.compile)(source, { namespace, filePath: file });
185
+ printWarnings(result.warnings);
186
+ // Generate command block JSON
187
+ const hasTick = result.files.some(f => f.path.includes('__tick.mcfunction'));
188
+ const hasLoad = result.files.some(f => f.path.includes('__load.mcfunction'));
189
+ const cmdBlocks = (0, cmdblock_1.generateCommandBlocks)(namespace, hasTick, hasLoad);
190
+ // Write command block JSON
191
+ fs.mkdirSync(output, { recursive: true });
192
+ const outputFile = path.join(output, `${namespace}_cmdblocks.json`);
193
+ fs.writeFileSync(outputFile, JSON.stringify(cmdBlocks, null, 2));
194
+ console.log(`✓ Generated command blocks for ${file}`);
195
+ console.log(` Output: ${outputFile}`);
196
+ console.log(` Blocks: ${cmdBlocks.blocks.length}`);
197
+ if (showStats) {
198
+ printOptimizationStats(result.stats);
199
+ }
200
+ }
201
+ else if (target === 'structure') {
202
+ const structure = (0, structure_1.compileToStructure)(source, namespace, file);
203
+ fs.mkdirSync(path.dirname(output), { recursive: true });
204
+ fs.writeFileSync(output, structure.buffer);
205
+ console.log(`✓ Generated structure for ${file}`);
206
+ console.log(` Output: ${output}`);
207
+ console.log(` Blocks: ${structure.blockCount}`);
208
+ if (showStats) {
209
+ printOptimizationStats(structure.stats);
210
+ }
211
+ }
212
+ else {
213
+ const result = (0, index_1.compile)(source, { namespace, filePath: file });
214
+ printWarnings(result.warnings);
215
+ // Default: generate datapack
216
+ // Create output directory
217
+ fs.mkdirSync(output, { recursive: true });
218
+ // Write all files
219
+ for (const dataFile of result.files) {
220
+ const filePath = path.join(output, dataFile.path);
221
+ const dir = path.dirname(filePath);
222
+ fs.mkdirSync(dir, { recursive: true });
223
+ fs.writeFileSync(filePath, dataFile.content);
224
+ }
225
+ console.log(`✓ Compiled ${file} to ${output}/`);
226
+ console.log(` Namespace: ${namespace}`);
227
+ console.log(` Functions: ${result.ir.functions.length}`);
228
+ console.log(` Files: ${result.files.length}`);
229
+ if (showStats) {
230
+ printOptimizationStats(result.stats);
231
+ }
232
+ }
233
+ }
234
+ catch (err) {
235
+ console.error((0, diagnostics_1.formatError)(err, source));
236
+ process.exit(1);
237
+ }
238
+ }
239
+ function checkCommand(file) {
240
+ // Read source file
241
+ if (!fs.existsSync(file)) {
242
+ console.error(`Error: File not found: ${file}`);
243
+ process.exit(1);
244
+ }
245
+ const source = fs.readFileSync(file, 'utf-8');
246
+ const error = (0, index_1.check)(source, 'redscript', file);
247
+ if (error) {
248
+ console.error((0, diagnostics_1.formatError)(error, source));
249
+ process.exit(1);
250
+ }
251
+ console.log(`✓ ${file} is valid`);
252
+ }
253
+ async function hotReload(url) {
254
+ try {
255
+ const res = await fetch(`${url}/reload`, { method: 'POST' });
256
+ if (res.ok) {
257
+ console.log(`🔄 Hot reload sent → ${url}`);
258
+ }
259
+ else {
260
+ console.warn(`⚠ Hot reload failed: HTTP ${res.status}`);
261
+ }
262
+ }
263
+ catch (e) {
264
+ console.warn(`⚠ Hot reload failed (is the server running?): ${e.message}`);
265
+ }
266
+ }
267
+ function watchCommand(dir, output, namespace, hotReloadUrl) {
268
+ // Check if directory exists
269
+ if (!fs.existsSync(dir)) {
270
+ console.error(`Error: Directory not found: ${dir}`);
271
+ process.exit(1);
272
+ }
273
+ const stat = fs.statSync(dir);
274
+ if (!stat.isDirectory()) {
275
+ console.error(`Error: ${dir} is not a directory`);
276
+ process.exit(1);
277
+ }
278
+ console.log(`👁 Watching ${dir} for .rs file changes...`);
279
+ console.log(` Output: ${output}`);
280
+ if (hotReloadUrl)
281
+ console.log(` Hot reload: ${hotReloadUrl}`);
282
+ console.log(` Press Ctrl+C to stop\n`);
283
+ // Debounce timer
284
+ let debounceTimer = null;
285
+ // Compile all .rs files in directory
286
+ async function compileAll() {
287
+ const files = findRsFiles(dir);
288
+ if (files.length === 0) {
289
+ console.log(`⚠ No .rs files found in ${dir}`);
290
+ return;
291
+ }
292
+ let hasErrors = false;
293
+ for (const file of files) {
294
+ let source = '';
295
+ try {
296
+ source = fs.readFileSync(file, 'utf-8');
297
+ const ns = namespace ?? deriveNamespace(file);
298
+ const result = (0, index_1.compile)(source, { namespace: ns, filePath: file });
299
+ printWarnings(result.warnings);
300
+ // Create output directory
301
+ fs.mkdirSync(output, { recursive: true });
302
+ // Write all files
303
+ for (const dataFile of result.files) {
304
+ const filePath = path.join(output, dataFile.path);
305
+ const fileDir = path.dirname(filePath);
306
+ fs.mkdirSync(fileDir, { recursive: true });
307
+ fs.writeFileSync(filePath, dataFile.content);
308
+ }
309
+ const timestamp = new Date().toLocaleTimeString();
310
+ console.log(`✓ [${timestamp}] Compiled ${file} (${result.files.length} files)`);
311
+ }
312
+ catch (err) {
313
+ hasErrors = true;
314
+ const timestamp = new Date().toLocaleTimeString();
315
+ console.error(`✗ [${timestamp}] ${(0, diagnostics_1.formatError)(err, source)}`);
316
+ }
317
+ }
318
+ if (!hasErrors) {
319
+ if (hotReloadUrl)
320
+ await hotReload(hotReloadUrl);
321
+ console.log('');
322
+ }
323
+ }
324
+ // Find all .rs files recursively
325
+ function findRsFiles(directory) {
326
+ const results = [];
327
+ const entries = fs.readdirSync(directory, { withFileTypes: true });
328
+ for (const entry of entries) {
329
+ const fullPath = path.join(directory, entry.name);
330
+ if (entry.isDirectory()) {
331
+ results.push(...findRsFiles(fullPath));
332
+ }
333
+ else if (entry.isFile() && entry.name.endsWith('.rs')) {
334
+ results.push(fullPath);
335
+ }
336
+ }
337
+ return results;
338
+ }
339
+ // Initial compile
340
+ void compileAll();
341
+ // Watch for changes
342
+ fs.watch(dir, { recursive: true }, (eventType, filename) => {
343
+ if (filename && filename.endsWith('.rs')) {
344
+ // Debounce rapid changes
345
+ if (debounceTimer) {
346
+ clearTimeout(debounceTimer);
347
+ }
348
+ debounceTimer = setTimeout(() => {
349
+ console.log(`📝 Change detected: ${filename}`);
350
+ void compileAll();
351
+ }, 100);
352
+ }
353
+ });
354
+ }
355
+ // Main
356
+ const parsed = parseArgs(args);
357
+ async function main() {
358
+ if (parsed.help || !parsed.command) {
359
+ printUsage();
360
+ process.exit(parsed.help ? 0 : 1);
361
+ }
362
+ switch (parsed.command) {
363
+ case 'compile':
364
+ if (!parsed.file) {
365
+ console.error('Error: No input file specified');
366
+ printUsage();
367
+ process.exit(1);
368
+ }
369
+ {
370
+ const namespace = parsed.namespace ?? deriveNamespace(parsed.file);
371
+ const target = parsed.target ?? 'datapack';
372
+ const output = target === 'structure'
373
+ ? (parsed.outputNbt ?? parsed.output ?? `./${namespace}.nbt`)
374
+ : (parsed.output ?? './dist');
375
+ compileCommand(parsed.file, output, namespace, target, parsed.stats);
376
+ }
377
+ break;
378
+ case 'watch':
379
+ if (!parsed.file) {
380
+ console.error('Error: No directory specified');
381
+ printUsage();
382
+ process.exit(1);
383
+ }
384
+ watchCommand(parsed.file, parsed.output ?? './dist', parsed.namespace, parsed.hotReload);
385
+ break;
386
+ case 'check':
387
+ if (!parsed.file) {
388
+ console.error('Error: No input file specified');
389
+ printUsage();
390
+ process.exit(1);
391
+ }
392
+ checkCommand(parsed.file);
393
+ break;
394
+ case 'repl':
395
+ await (0, repl_1.startRepl)(parsed.namespace ?? 'repl');
396
+ break;
397
+ case 'version':
398
+ printVersion();
399
+ break;
400
+ default:
401
+ console.error(`Error: Unknown command '${parsed.command}'`);
402
+ printUsage();
403
+ process.exit(1);
404
+ }
405
+ }
406
+ void main();
407
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Command Block Target
3
+ *
4
+ * Generates a JSON structure representing command blocks that can be
5
+ * placed in Minecraft to run the compiled datapack.
6
+ */
7
+ export interface CommandBlock {
8
+ type: 'repeat' | 'impulse' | 'chain';
9
+ command: string;
10
+ pos: [number, number, number];
11
+ auto?: boolean;
12
+ conditional?: boolean;
13
+ }
14
+ export interface CommandBlockStructure {
15
+ format: 'redscript-cmdblock-v1';
16
+ namespace: string;
17
+ blocks: CommandBlock[];
18
+ }
19
+ /**
20
+ * Generate a command block structure JSON for a given namespace.
21
+ *
22
+ * Creates:
23
+ * - 1 × Repeat block: function <namespace>:__tick
24
+ * - 1 × Impulse block (auto): function <namespace>:__load
25
+ */
26
+ export declare function generateCommandBlocks(namespace: string, hasTick: boolean, hasLoad: boolean): CommandBlockStructure;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /**
3
+ * Command Block Target
4
+ *
5
+ * Generates a JSON structure representing command blocks that can be
6
+ * placed in Minecraft to run the compiled datapack.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.generateCommandBlocks = generateCommandBlocks;
10
+ /**
11
+ * Generate a command block structure JSON for a given namespace.
12
+ *
13
+ * Creates:
14
+ * - 1 × Repeat block: function <namespace>:__tick
15
+ * - 1 × Impulse block (auto): function <namespace>:__load
16
+ */
17
+ function generateCommandBlocks(namespace, hasTick, hasLoad) {
18
+ const blocks = [];
19
+ let x = 0;
20
+ // Load block - impulse with auto (runs once when placed)
21
+ if (hasLoad) {
22
+ blocks.push({
23
+ type: 'impulse',
24
+ command: `function ${namespace}:__load`,
25
+ pos: [x, 0, 0],
26
+ auto: true,
27
+ });
28
+ x++;
29
+ }
30
+ // Tick block - repeat (runs every tick)
31
+ if (hasTick) {
32
+ blocks.push({
33
+ type: 'repeat',
34
+ command: `function ${namespace}:__tick`,
35
+ pos: [x, 0, 0],
36
+ });
37
+ x++;
38
+ }
39
+ return {
40
+ format: 'redscript-cmdblock-v1',
41
+ namespace,
42
+ blocks,
43
+ };
44
+ }
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Code generator: IR → mcfunction datapack
3
+ *
4
+ * Output structure:
5
+ * <namespace>/
6
+ * functions/
7
+ * <fn_name>.mcfunction
8
+ * <fn_name>/<block_label>.mcfunction (for control-flow continuations)
9
+ * load.mcfunction (objective setup)
10
+ *
11
+ * Variable mapping:
12
+ * scoreboard objective: "rs"
13
+ * fake player: "$<varname>"
14
+ * temporaries: "$t0", "$t1", ...
15
+ * return value: "$ret"
16
+ * parameters: "$p0", "$p1", ...
17
+ */
18
+ import type { IRModule } from '../../ir/types';
19
+ import { type OptimizationStats } from '../../optimizer/commands';
20
+ export interface DatapackFile {
21
+ path: string;
22
+ content: string;
23
+ }
24
+ export interface DatapackGenerationResult {
25
+ files: DatapackFile[];
26
+ advancements: DatapackFile[];
27
+ stats: OptimizationStats;
28
+ }
29
+ export interface DatapackGenerationOptions {
30
+ optimizeCommands?: boolean;
31
+ }
32
+ export declare function countMcfunctionCommands(files: DatapackFile[]): number;
33
+ export declare function generateDatapackWithStats(module: IRModule, options?: DatapackGenerationOptions): DatapackGenerationResult;
34
+ export declare function generateDatapack(module: IRModule): DatapackFile[];