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,117 @@
1
+ /**
2
+ * RedScript IR — Three-Address Code (TAC)
3
+ *
4
+ * Compilation pipeline:
5
+ * Source → AST → IR → (optimize) → CodeGen → mcfunction / cmdblock
6
+ *
7
+ * Variable storage in MC Java Edition:
8
+ * - Integer vars → scoreboard fake player ($name on objective "rs_vars")
9
+ * - Complex data → NBT storage (redscript:stack / redscript:heap)
10
+ * - Return value → fake player $ret
11
+ * - Temporaries → $t0, $t1, ...
12
+ */
13
+ export type Operand = {
14
+ kind: 'var';
15
+ name: string;
16
+ } | {
17
+ kind: 'const';
18
+ value: number;
19
+ } | {
20
+ kind: 'storage';
21
+ path: string;
22
+ };
23
+ export type BinOp = '+' | '-' | '*' | '/' | '%';
24
+ export type CmpOp = '==' | '!=' | '<' | '<=' | '>' | '>=';
25
+ export type IRInstr = {
26
+ op: 'assign';
27
+ dst: string;
28
+ src: Operand;
29
+ } | {
30
+ op: 'binop';
31
+ dst: string;
32
+ lhs: Operand;
33
+ bop: BinOp;
34
+ rhs: Operand;
35
+ } | {
36
+ op: 'cmp';
37
+ dst: string;
38
+ lhs: Operand;
39
+ cop: CmpOp;
40
+ rhs: Operand;
41
+ } | {
42
+ op: 'jump';
43
+ target: string;
44
+ } | {
45
+ op: 'jump_if';
46
+ cond: string;
47
+ target: string;
48
+ } | {
49
+ op: 'jump_unless';
50
+ cond: string;
51
+ target: string;
52
+ } | {
53
+ op: 'call';
54
+ fn: string;
55
+ args: Operand[];
56
+ dst?: string;
57
+ } | {
58
+ op: 'return';
59
+ value?: Operand;
60
+ } | {
61
+ op: 'label';
62
+ id: string;
63
+ } | {
64
+ op: 'raw';
65
+ cmd: string;
66
+ } | {
67
+ op: 'tick_yield';
68
+ };
69
+ export type Terminator = {
70
+ op: 'jump';
71
+ target: string;
72
+ } | {
73
+ op: 'jump_if';
74
+ cond: string;
75
+ then: string;
76
+ else_: string;
77
+ } | {
78
+ op: 'jump_unless';
79
+ cond: string;
80
+ then: string;
81
+ else_: string;
82
+ } | {
83
+ op: 'return';
84
+ value?: Operand;
85
+ } | {
86
+ op: 'tick_yield';
87
+ continuation: string;
88
+ };
89
+ export interface IRBlock {
90
+ label: string;
91
+ instrs: IRInstr[];
92
+ term: Terminator;
93
+ }
94
+ export interface IRCommand {
95
+ cmd: string;
96
+ conditional?: boolean;
97
+ label?: string;
98
+ }
99
+ export interface IRFunction {
100
+ name: string;
101
+ params: string[];
102
+ locals: string[];
103
+ blocks: IRBlock[];
104
+ commands?: IRCommand[];
105
+ isTickLoop?: boolean;
106
+ isTriggerHandler?: boolean;
107
+ triggerName?: string;
108
+ eventTrigger?: {
109
+ kind: 'advancement' | 'craft' | 'death' | 'login' | 'join_team';
110
+ value?: string;
111
+ };
112
+ }
113
+ export interface IRModule {
114
+ namespace: string;
115
+ functions: IRFunction[];
116
+ globals: string[];
117
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * RedScript IR — Three-Address Code (TAC)
4
+ *
5
+ * Compilation pipeline:
6
+ * Source → AST → IR → (optimize) → CodeGen → mcfunction / cmdblock
7
+ *
8
+ * Variable storage in MC Java Edition:
9
+ * - Integer vars → scoreboard fake player ($name on objective "rs_vars")
10
+ * - Complex data → NBT storage (redscript:stack / redscript:heap)
11
+ * - Return value → fake player $ret
12
+ * - Temporaries → $t0, $t1, ...
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * RedScript Lexer
3
+ *
4
+ * Tokenizes RedScript source code into a stream of tokens.
5
+ * Handles special cases like entity selectors vs decorators,
6
+ * range literals, and raw commands.
7
+ */
8
+ export type TokenKind = 'fn' | 'let' | 'const' | 'if' | 'else' | 'while' | 'for' | 'foreach' | 'match' | 'return' | 'as' | 'at' | 'in' | 'struct' | 'enum' | 'trigger' | 'namespace' | 'execute' | 'run' | 'unless' | 'int' | 'bool' | 'float' | 'string' | 'void' | 'BlockPos' | 'true' | 'false' | 'selector' | 'decorator' | 'int_lit' | 'float_lit' | 'byte_lit' | 'short_lit' | 'long_lit' | 'double_lit' | 'string_lit' | 'range_lit' | '+' | '-' | '*' | '/' | '%' | '~' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | '&&' | '||' | '!' | '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '{' | '}' | '(' | ')' | '[' | ']' | ',' | ';' | ':' | '::' | '->' | '=>' | '.' | 'ident' | 'mc_name' | 'raw_cmd' | 'eof';
9
+ export interface Token {
10
+ kind: TokenKind;
11
+ value: string;
12
+ line: number;
13
+ col: number;
14
+ }
15
+ export declare class Lexer {
16
+ private source;
17
+ private sourceLines;
18
+ private pos;
19
+ private line;
20
+ private col;
21
+ private tokens;
22
+ private filePath?;
23
+ constructor(source: string, filePath?: string);
24
+ private error;
25
+ tokenize(): Token[];
26
+ private isAtEnd;
27
+ private peek;
28
+ private advance;
29
+ private addToken;
30
+ private scanToken;
31
+ private scanAtToken;
32
+ private scanSelectorParams;
33
+ private scanString;
34
+ private scanNumber;
35
+ private scanIdentifier;
36
+ }
@@ -0,0 +1,458 @@
1
+ "use strict";
2
+ /**
3
+ * RedScript Lexer
4
+ *
5
+ * Tokenizes RedScript source code into a stream of tokens.
6
+ * Handles special cases like entity selectors vs decorators,
7
+ * range literals, and raw commands.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.Lexer = void 0;
11
+ const diagnostics_1 = require("../diagnostics");
12
+ // ---------------------------------------------------------------------------
13
+ // Keywords Map
14
+ // ---------------------------------------------------------------------------
15
+ const KEYWORDS = {
16
+ fn: 'fn',
17
+ let: 'let',
18
+ const: 'const',
19
+ if: 'if',
20
+ else: 'else',
21
+ while: 'while',
22
+ for: 'for',
23
+ foreach: 'foreach',
24
+ match: 'match',
25
+ return: 'return',
26
+ as: 'as',
27
+ at: 'at',
28
+ in: 'in',
29
+ struct: 'struct',
30
+ enum: 'enum',
31
+ trigger: 'trigger',
32
+ namespace: 'namespace',
33
+ execute: 'execute',
34
+ run: 'run',
35
+ unless: 'unless',
36
+ int: 'int',
37
+ bool: 'bool',
38
+ float: 'float',
39
+ string: 'string',
40
+ void: 'void',
41
+ BlockPos: 'BlockPos',
42
+ true: 'true',
43
+ false: 'false',
44
+ };
45
+ // Entity selector base characters
46
+ const SELECTOR_CHARS = new Set(['a', 'e', 's', 'p', 'r', 'n']);
47
+ // ---------------------------------------------------------------------------
48
+ // Lexer Class
49
+ // ---------------------------------------------------------------------------
50
+ class Lexer {
51
+ constructor(source, filePath) {
52
+ this.pos = 0;
53
+ this.line = 1;
54
+ this.col = 1;
55
+ this.tokens = [];
56
+ this.source = source;
57
+ this.sourceLines = source.split('\n');
58
+ this.filePath = filePath;
59
+ }
60
+ error(message, line, col) {
61
+ throw new diagnostics_1.DiagnosticError('LexError', message, { file: this.filePath, line: line ?? this.line, col: col ?? this.col }, this.sourceLines);
62
+ }
63
+ tokenize() {
64
+ while (!this.isAtEnd()) {
65
+ this.scanToken();
66
+ }
67
+ this.tokens.push({ kind: 'eof', value: '', line: this.line, col: this.col });
68
+ return this.tokens;
69
+ }
70
+ isAtEnd() {
71
+ return this.pos >= this.source.length;
72
+ }
73
+ peek(offset = 0) {
74
+ const idx = this.pos + offset;
75
+ if (idx >= this.source.length)
76
+ return '\0';
77
+ return this.source[idx];
78
+ }
79
+ advance() {
80
+ const char = this.source[this.pos++];
81
+ if (char === '\n') {
82
+ this.line++;
83
+ this.col = 1;
84
+ }
85
+ else {
86
+ this.col++;
87
+ }
88
+ return char;
89
+ }
90
+ addToken(kind, value, line, col) {
91
+ this.tokens.push({ kind, value, line, col });
92
+ }
93
+ scanToken() {
94
+ const startLine = this.line;
95
+ const startCol = this.col;
96
+ const char = this.advance();
97
+ // Whitespace
98
+ if (/\s/.test(char))
99
+ return;
100
+ // Comments
101
+ if (char === '/' && this.peek() === '/') {
102
+ // Skip to end of line
103
+ while (!this.isAtEnd() && this.peek() !== '\n') {
104
+ this.advance();
105
+ }
106
+ return;
107
+ }
108
+ // Block comments: /* ... */ and /** ... */
109
+ if (char === '/' && this.peek() === '*') {
110
+ this.advance(); // consume '*'
111
+ while (!this.isAtEnd()) {
112
+ if (this.peek() === '*' && this.peek(1) === '/') {
113
+ this.advance(); // consume '*'
114
+ this.advance(); // consume '/'
115
+ break;
116
+ }
117
+ this.advance();
118
+ }
119
+ return;
120
+ }
121
+ // Two-character operators
122
+ if (char === '-' && this.peek() === '>') {
123
+ this.advance();
124
+ this.addToken('->', '->', startLine, startCol);
125
+ return;
126
+ }
127
+ if (char === '=' && this.peek() === '>') {
128
+ this.advance();
129
+ this.addToken('=>', '=>', startLine, startCol);
130
+ return;
131
+ }
132
+ if (char === '=' && this.peek() === '=') {
133
+ this.advance();
134
+ this.addToken('==', '==', startLine, startCol);
135
+ return;
136
+ }
137
+ if (char === '!' && this.peek() === '=') {
138
+ this.advance();
139
+ this.addToken('!=', '!=', startLine, startCol);
140
+ return;
141
+ }
142
+ if (char === '<' && this.peek() === '=') {
143
+ this.advance();
144
+ this.addToken('<=', '<=', startLine, startCol);
145
+ return;
146
+ }
147
+ if (char === '>' && this.peek() === '=') {
148
+ this.advance();
149
+ this.addToken('>=', '>=', startLine, startCol);
150
+ return;
151
+ }
152
+ if (char === '&' && this.peek() === '&') {
153
+ this.advance();
154
+ this.addToken('&&', '&&', startLine, startCol);
155
+ return;
156
+ }
157
+ if (char === '|' && this.peek() === '|') {
158
+ this.advance();
159
+ this.addToken('||', '||', startLine, startCol);
160
+ return;
161
+ }
162
+ if (char === '+' && this.peek() === '=') {
163
+ this.advance();
164
+ this.addToken('+=', '+=', startLine, startCol);
165
+ return;
166
+ }
167
+ if (char === '-' && this.peek() === '=') {
168
+ this.advance();
169
+ this.addToken('-=', '-=', startLine, startCol);
170
+ return;
171
+ }
172
+ if (char === '*' && this.peek() === '=') {
173
+ this.advance();
174
+ this.addToken('*=', '*=', startLine, startCol);
175
+ return;
176
+ }
177
+ if (char === '/' && this.peek() === '=') {
178
+ this.advance();
179
+ this.addToken('/=', '/=', startLine, startCol);
180
+ return;
181
+ }
182
+ if (char === '%' && this.peek() === '=') {
183
+ this.advance();
184
+ this.addToken('%=', '%=', startLine, startCol);
185
+ return;
186
+ }
187
+ // Double colon ::
188
+ if (char === ':' && this.peek() === ':') {
189
+ this.advance();
190
+ this.addToken('::', '::', startLine, startCol);
191
+ return;
192
+ }
193
+ // Range literal starting with ..
194
+ if (char === '.' && this.peek() === '.') {
195
+ this.advance(); // consume second .
196
+ let value = '..';
197
+ while (/[0-9]/.test(this.peek())) {
198
+ value += this.advance();
199
+ }
200
+ this.addToken('range_lit', value, startLine, startCol);
201
+ return;
202
+ }
203
+ // Single-character operators and delimiters
204
+ const singleChar = ['+', '-', '*', '/', '%', '~', '^', '<', '>', '!', '=',
205
+ '{', '}', '(', ')', '[', ']', ',', ';', ':', '.'];
206
+ if (singleChar.includes(char)) {
207
+ this.addToken(char, char, startLine, startCol);
208
+ return;
209
+ }
210
+ // @ - selector or decorator
211
+ if (char === '@') {
212
+ this.scanAtToken(startLine, startCol);
213
+ return;
214
+ }
215
+ // String literal
216
+ if (char === '"') {
217
+ this.scanString(startLine, startCol);
218
+ return;
219
+ }
220
+ // MC name literal: #ident (e.g. #health, #red, #hasKey)
221
+ if (char === '#') {
222
+ const nextChar = this.peek();
223
+ if (/[a-zA-Z_]/.test(nextChar)) {
224
+ let name = '#';
225
+ while (/[a-zA-Z0-9_]/.test(this.peek())) {
226
+ name += this.advance();
227
+ }
228
+ this.addToken('mc_name', name, startLine, startCol);
229
+ return;
230
+ }
231
+ // Lone # (not followed by ident) — treat as unknown char error
232
+ this.error(`Unexpected character '#'`, startLine, startCol);
233
+ return;
234
+ }
235
+ // Number (int or float) or range literal starting with number
236
+ if (/[0-9]/.test(char)) {
237
+ this.scanNumber(char, startLine, startCol);
238
+ return;
239
+ }
240
+ // Identifier or keyword
241
+ if (/[a-zA-Z_]/.test(char)) {
242
+ this.scanIdentifier(char, startLine, startCol);
243
+ return;
244
+ }
245
+ this.error(`Unexpected character '${char}'`, startLine, startCol);
246
+ }
247
+ scanAtToken(startLine, startCol) {
248
+ // Check if it's a selector (@a, @e, @s, @p, @r, @n)
249
+ const nextChar = this.peek();
250
+ const afterNext = this.peek(1);
251
+ // Selector: @a/@e/@s/@p/@r/@n followed by non-letter (or end, or [)
252
+ if (SELECTOR_CHARS.has(nextChar) && !/[a-zA-Z_0-9]/.test(afterNext)) {
253
+ const selectorChar = this.advance(); // consume a/e/s/p/r/n
254
+ let value = '@' + selectorChar;
255
+ // Check for [...] parameters
256
+ if (this.peek() === '[') {
257
+ value += this.scanSelectorParams();
258
+ }
259
+ this.addToken('selector', value, startLine, startCol);
260
+ return;
261
+ }
262
+ // Otherwise it's a decorator (@tick, @on_trigger, etc.)
263
+ let value = '@';
264
+ while (/[a-zA-Z_0-9]/.test(this.peek())) {
265
+ value += this.advance();
266
+ }
267
+ // Check for decorator arguments (rate=N)
268
+ if (this.peek() === '(') {
269
+ value += this.advance(); // (
270
+ let parenDepth = 1;
271
+ while (!this.isAtEnd() && parenDepth > 0) {
272
+ const c = this.advance();
273
+ value += c;
274
+ if (c === '(')
275
+ parenDepth++;
276
+ if (c === ')')
277
+ parenDepth--;
278
+ }
279
+ }
280
+ this.addToken('decorator', value, startLine, startCol);
281
+ }
282
+ scanSelectorParams() {
283
+ let result = this.advance(); // consume [
284
+ let depth = 1;
285
+ let braceDepth = 0;
286
+ while (!this.isAtEnd() && depth > 0) {
287
+ const c = this.advance();
288
+ result += c;
289
+ if (c === '{')
290
+ braceDepth++;
291
+ else if (c === '}')
292
+ braceDepth--;
293
+ else if (c === '[' && braceDepth === 0)
294
+ depth++;
295
+ else if (c === ']' && braceDepth === 0)
296
+ depth--;
297
+ }
298
+ return result;
299
+ }
300
+ scanString(startLine, startCol) {
301
+ let value = '';
302
+ let interpolationDepth = 0;
303
+ let interpolationString = false;
304
+ while (!this.isAtEnd()) {
305
+ if (interpolationDepth === 0 && this.peek() === '"') {
306
+ break;
307
+ }
308
+ if (this.peek() === '\\' && this.peek(1) === '"') {
309
+ this.advance(); // skip backslash
310
+ value += this.advance(); // add escaped quote
311
+ continue;
312
+ }
313
+ if (interpolationDepth === 0 && this.peek() === '$' && this.peek(1) === '{') {
314
+ value += this.advance();
315
+ value += this.advance();
316
+ interpolationDepth = 1;
317
+ interpolationString = false;
318
+ continue;
319
+ }
320
+ const char = this.advance();
321
+ value += char;
322
+ if (interpolationDepth === 0)
323
+ continue;
324
+ if (char === '"') {
325
+ interpolationString = !interpolationString;
326
+ continue;
327
+ }
328
+ if (interpolationString)
329
+ continue;
330
+ if (char === '{')
331
+ interpolationDepth++;
332
+ if (char === '}')
333
+ interpolationDepth--;
334
+ }
335
+ if (this.isAtEnd()) {
336
+ this.error(`Unterminated string`, startLine, startCol);
337
+ }
338
+ this.advance(); // closing quote
339
+ this.addToken('string_lit', value, startLine, startCol);
340
+ }
341
+ scanNumber(firstChar, startLine, startCol) {
342
+ let value = firstChar;
343
+ // Consume integer part
344
+ while (/[0-9]/.test(this.peek())) {
345
+ value += this.advance();
346
+ }
347
+ // Check for range literal (e.g., 1.., 1..10)
348
+ if (this.peek() === '.' && this.peek(1) === '.') {
349
+ value += this.advance(); // first .
350
+ value += this.advance(); // second .
351
+ // Optional max value
352
+ while (/[0-9]/.test(this.peek())) {
353
+ value += this.advance();
354
+ }
355
+ this.addToken('range_lit', value, startLine, startCol);
356
+ return;
357
+ }
358
+ // Check for float
359
+ if (this.peek() === '.' && /[0-9]/.test(this.peek(1))) {
360
+ value += this.advance(); // .
361
+ while (/[0-9]/.test(this.peek())) {
362
+ value += this.advance();
363
+ }
364
+ // Check for NBT float/double suffix
365
+ const floatSuffix = this.peek().toLowerCase();
366
+ if (floatSuffix === 'f') {
367
+ value += this.advance();
368
+ this.addToken('float_lit', value, startLine, startCol);
369
+ return;
370
+ }
371
+ if (floatSuffix === 'd') {
372
+ value += this.advance();
373
+ this.addToken('double_lit', value, startLine, startCol);
374
+ return;
375
+ }
376
+ this.addToken('float_lit', value, startLine, startCol);
377
+ return;
378
+ }
379
+ // Check for NBT integer suffix (b, s, L/l, f, d)
380
+ const intSuffix = this.peek().toLowerCase();
381
+ if (intSuffix === 'b' && !/[a-zA-Z_0-9]/.test(this.peek(1))) {
382
+ value += this.advance();
383
+ this.addToken('byte_lit', value, startLine, startCol);
384
+ return;
385
+ }
386
+ if (intSuffix === 's' && !/[a-zA-Z_0-9]/.test(this.peek(1))) {
387
+ value += this.advance();
388
+ this.addToken('short_lit', value, startLine, startCol);
389
+ return;
390
+ }
391
+ if (intSuffix === 'l' && !/[a-zA-Z_0-9]/.test(this.peek(1))) {
392
+ value += this.advance();
393
+ this.addToken('long_lit', value, startLine, startCol);
394
+ return;
395
+ }
396
+ if (intSuffix === 'f' && !/[a-zA-Z_0-9]/.test(this.peek(1))) {
397
+ value += this.advance();
398
+ this.addToken('float_lit', value, startLine, startCol);
399
+ return;
400
+ }
401
+ if (intSuffix === 'd' && !/[a-zA-Z_0-9]/.test(this.peek(1))) {
402
+ value += this.advance();
403
+ this.addToken('double_lit', value, startLine, startCol);
404
+ return;
405
+ }
406
+ this.addToken('int_lit', value, startLine, startCol);
407
+ }
408
+ scanIdentifier(firstChar, startLine, startCol) {
409
+ let value = firstChar;
410
+ while (/[a-zA-Z_0-9]/.test(this.peek())) {
411
+ value += this.advance();
412
+ }
413
+ // Check for raw command
414
+ if (value === 'raw' && this.peek() === '(') {
415
+ this.advance(); // consume (
416
+ // Skip whitespace
417
+ while (/\s/.test(this.peek())) {
418
+ this.advance();
419
+ }
420
+ // Expect string
421
+ if (this.peek() === '"') {
422
+ this.advance(); // consume opening quote
423
+ let rawContent = '';
424
+ while (!this.isAtEnd() && this.peek() !== '"') {
425
+ if (this.peek() === '\\' && this.peek(1) === '"') {
426
+ this.advance();
427
+ rawContent += this.advance();
428
+ }
429
+ else {
430
+ rawContent += this.advance();
431
+ }
432
+ }
433
+ if (this.peek() === '"') {
434
+ this.advance(); // closing quote
435
+ }
436
+ // Skip whitespace and closing paren
437
+ while (/\s/.test(this.peek())) {
438
+ this.advance();
439
+ }
440
+ if (this.peek() === ')') {
441
+ this.advance(); // closing paren
442
+ }
443
+ this.addToken('raw_cmd', rawContent, startLine, startCol);
444
+ return;
445
+ }
446
+ }
447
+ // Check for keyword
448
+ const keyword = KEYWORDS[value];
449
+ if (keyword) {
450
+ this.addToken(keyword, value, startLine, startCol);
451
+ }
452
+ else {
453
+ this.addToken('ident', value, startLine, startCol);
454
+ }
455
+ }
456
+ }
457
+ exports.Lexer = Lexer;
458
+ //# sourceMappingURL=index.js.map