redscript-mc 1.0.0 → 1.2.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 (136) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +72 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.yml +57 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +17 -25
  4. package/CHANGELOG.md +112 -0
  5. package/CONTRIBUTING.md +140 -0
  6. package/README.md +28 -19
  7. package/README.zh.md +28 -19
  8. package/dist/__tests__/cli.test.js +148 -10
  9. package/dist/__tests__/codegen.test.js +26 -1
  10. package/dist/__tests__/diagnostics.test.js +5 -5
  11. package/dist/__tests__/e2e.test.js +336 -17
  12. package/dist/__tests__/formatter.test.d.ts +1 -0
  13. package/dist/__tests__/formatter.test.js +40 -0
  14. package/dist/__tests__/lexer.test.js +12 -2
  15. package/dist/__tests__/lowering.test.js +200 -12
  16. package/dist/__tests__/mc-integration.test.js +370 -31
  17. package/dist/__tests__/mc-syntax.test.js +3 -3
  18. package/dist/__tests__/nbt.test.js +2 -2
  19. package/dist/__tests__/optimizer-advanced.test.js +5 -5
  20. package/dist/__tests__/parser.test.js +80 -0
  21. package/dist/__tests__/runtime.test.js +9 -9
  22. package/dist/__tests__/typechecker.test.js +158 -0
  23. package/dist/ast/types.d.ts +40 -3
  24. package/dist/cli.js +25 -7
  25. package/dist/codegen/mcfunction/index.d.ts +1 -1
  26. package/dist/codegen/mcfunction/index.js +38 -3
  27. package/dist/codegen/structure/index.js +32 -1
  28. package/dist/compile.d.ts +10 -0
  29. package/dist/compile.js +36 -5
  30. package/dist/events/types.d.ts +35 -0
  31. package/dist/events/types.js +59 -0
  32. package/dist/formatter/index.d.ts +1 -0
  33. package/dist/formatter/index.js +26 -0
  34. package/dist/index.js +3 -2
  35. package/dist/ir/builder.d.ts +2 -1
  36. package/dist/ir/types.d.ts +11 -2
  37. package/dist/ir/types.js +1 -1
  38. package/dist/lexer/index.d.ts +1 -1
  39. package/dist/lexer/index.js +2 -0
  40. package/dist/lowering/index.d.ts +34 -1
  41. package/dist/lowering/index.js +622 -23
  42. package/dist/mc-test/runner.d.ts +2 -2
  43. package/dist/mc-test/runner.js +3 -3
  44. package/dist/mc-test/setup.js +2 -2
  45. package/dist/parser/index.d.ts +4 -0
  46. package/dist/parser/index.js +153 -16
  47. package/dist/typechecker/index.d.ts +17 -0
  48. package/dist/typechecker/index.js +343 -17
  49. package/docs/COMPILATION_STATS.md +24 -24
  50. package/docs/ENTITY_TYPE_SYSTEM.md +242 -0
  51. package/docs/IMPLEMENTATION_GUIDE.md +1 -1
  52. package/docs/STRUCTURE_TARGET.md +1 -1
  53. package/editors/vscode/.vscodeignore +1 -0
  54. package/editors/vscode/CHANGELOG.md +9 -0
  55. package/editors/vscode/icons/mcrs.svg +7 -0
  56. package/editors/vscode/icons/redscript-icons.json +10 -0
  57. package/editors/vscode/out/extension.js +1295 -80
  58. package/editors/vscode/package-lock.json +2 -2
  59. package/editors/vscode/package.json +10 -3
  60. package/editors/vscode/src/hover.ts +55 -2
  61. package/editors/vscode/src/symbols.ts +42 -0
  62. package/package.json +1 -1
  63. package/src/__tests__/cli.test.ts +176 -10
  64. package/src/__tests__/codegen.test.ts +28 -1
  65. package/src/__tests__/diagnostics.test.ts +5 -5
  66. package/src/__tests__/e2e.test.ts +335 -17
  67. package/src/__tests__/fixtures/event-test.mcrs +13 -0
  68. package/src/__tests__/fixtures/impl-test.mcrs +46 -0
  69. package/src/__tests__/fixtures/interval-test.mcrs +11 -0
  70. package/src/__tests__/fixtures/is-check-test.mcrs +20 -0
  71. package/src/__tests__/fixtures/timeout-test.mcrs +7 -0
  72. package/src/__tests__/lexer.test.ts +14 -2
  73. package/src/__tests__/lowering.test.ts +226 -12
  74. package/src/__tests__/mc-integration.test.ts +421 -31
  75. package/src/__tests__/mc-syntax.test.ts +3 -3
  76. package/src/__tests__/nbt.test.ts +2 -2
  77. package/src/__tests__/optimizer-advanced.test.ts +5 -5
  78. package/src/__tests__/parser.test.ts +91 -5
  79. package/src/__tests__/runtime.test.ts +9 -9
  80. package/src/__tests__/typechecker.test.ts +171 -0
  81. package/src/ast/types.ts +44 -3
  82. package/src/cli.ts +10 -10
  83. package/src/codegen/mcfunction/index.ts +40 -3
  84. package/src/codegen/structure/index.ts +35 -1
  85. package/src/compile.ts +54 -6
  86. package/src/events/types.ts +69 -0
  87. package/src/examples/capture_the_flag.mcrs +208 -0
  88. package/src/examples/{counter.rs → counter.mcrs} +1 -1
  89. package/src/examples/hunger_games.mcrs +301 -0
  90. package/src/examples/new_features_demo.mcrs +193 -0
  91. package/src/examples/parkour_race.mcrs +233 -0
  92. package/src/examples/rpg.mcrs +13 -0
  93. package/src/examples/{shop.rs → shop.mcrs} +1 -1
  94. package/src/examples/{showcase_game.rs → showcase_game.mcrs} +3 -3
  95. package/src/examples/{turret.rs → turret.mcrs} +1 -1
  96. package/src/examples/zombie_survival.mcrs +314 -0
  97. package/src/index.ts +4 -3
  98. package/src/ir/builder.ts +3 -1
  99. package/src/ir/types.ts +12 -2
  100. package/src/lexer/index.ts +3 -1
  101. package/src/lowering/index.ts +684 -24
  102. package/src/mc-test/runner.ts +3 -3
  103. package/src/mc-test/setup.ts +2 -2
  104. package/src/parser/index.ts +170 -19
  105. package/src/stdlib/README.md +178 -140
  106. package/src/stdlib/bossbar.mcrs +68 -0
  107. package/src/stdlib/{cooldown.rs → cooldown.mcrs} +1 -1
  108. package/src/stdlib/effects.mcrs +64 -0
  109. package/src/stdlib/interactions.mcrs +195 -0
  110. package/src/stdlib/inventory.mcrs +38 -0
  111. package/src/stdlib/mobs.mcrs +99 -0
  112. package/src/stdlib/particles.mcrs +52 -0
  113. package/src/stdlib/sets.mcrs +20 -0
  114. package/src/stdlib/spawn.mcrs +41 -0
  115. package/src/stdlib/tags.mcrs +951 -0
  116. package/src/stdlib/teams.mcrs +68 -0
  117. package/src/stdlib/timer.mcrs +72 -0
  118. package/src/stdlib/world.mcrs +92 -0
  119. package/src/typechecker/index.ts +404 -18
  120. package/src/examples/rpg.rs +0 -13
  121. package/src/stdlib/mobs.rs +0 -99
  122. package/src/stdlib/timer.rs +0 -51
  123. /package/src/examples/{arena.rs → arena.mcrs} +0 -0
  124. /package/src/examples/{pvp_arena.rs → pvp_arena.mcrs} +0 -0
  125. /package/src/examples/{quiz.rs → quiz.mcrs} +0 -0
  126. /package/src/examples/{stdlib_demo.rs → stdlib_demo.mcrs} +0 -0
  127. /package/src/examples/{world_manager.rs → world_manager.mcrs} +0 -0
  128. /package/src/stdlib/{combat.rs → combat.mcrs} +0 -0
  129. /package/src/stdlib/{math.rs → math.mcrs} +0 -0
  130. /package/src/stdlib/{player.rs → player.mcrs} +0 -0
  131. /package/src/stdlib/{strings.rs → strings.mcrs} +0 -0
  132. /package/src/templates/{combat.rs → combat.mcrs} +0 -0
  133. /package/src/templates/{economy.rs → economy.mcrs} +0 -0
  134. /package/src/templates/{mini-game-framework.rs → mini-game-framework.mcrs} +0 -0
  135. /package/src/templates/{quest.rs → quest.mcrs} +0 -0
  136. /package/src/test_programs/{zombie_game.rs → zombie_game.mcrs} +0 -0
@@ -10,6 +10,7 @@ const commands_1 = require("../../optimizer/commands");
10
10
  const passes_1 = require("../../optimizer/passes");
11
11
  const structure_1 = require("../../optimizer/structure");
12
12
  const compile_1 = require("../../compile");
13
+ const types_1 = require("../../events/types");
13
14
  const DATA_VERSION = 3953;
14
15
  const MAX_WIDTH = 16;
15
16
  const OBJ = 'rs';
@@ -62,15 +63,31 @@ function collectCommandEntriesFromModule(module) {
62
63
  const entries = [];
63
64
  const triggerHandlers = module.functions.filter(fn => fn.isTriggerHandler && fn.triggerName);
64
65
  const triggerNames = new Set(triggerHandlers.map(fn => fn.triggerName));
66
+ const eventHandlers = module.functions.filter((fn) => !!fn.eventHandler && (0, types_1.isEventTypeName)(fn.eventHandler.eventType));
67
+ const eventTypes = new Set(eventHandlers.map(fn => fn.eventHandler.eventType));
65
68
  const loadCommands = [
66
69
  `scoreboard objectives add ${OBJ} dummy`,
67
- ...module.globals.map(globalName => `scoreboard players set ${varRef(globalName)} ${OBJ} 0`),
70
+ ...module.globals.map(g => `scoreboard players set ${varRef(g.name)} ${OBJ} ${g.init}`),
68
71
  ...Array.from(triggerNames).flatMap(triggerName => [
69
72
  `scoreboard objectives add ${triggerName} trigger`,
70
73
  `scoreboard players enable @a ${triggerName}`,
71
74
  ]),
72
75
  ...Array.from(new Set(module.functions.flatMap(fn => Array.from(collectConsts(fn))))).map(constSetup),
73
76
  ];
77
+ for (const eventType of eventTypes) {
78
+ if (eventType === 'PlayerDeath') {
79
+ loadCommands.push('scoreboard objectives add rs.deaths deathCount');
80
+ }
81
+ else if (eventType === 'EntityKill') {
82
+ loadCommands.push('scoreboard objectives add rs.kills totalKillCount');
83
+ }
84
+ }
85
+ // Call @load functions from __load
86
+ for (const fn of module.functions) {
87
+ if (fn.isLoadInit) {
88
+ loadCommands.push(`function ${module.namespace}:${fn.name}`);
89
+ }
90
+ }
74
91
  const sections = [];
75
92
  if (loadCommands.length > 0) {
76
93
  sections.push({
@@ -108,6 +125,20 @@ function collectCommandEntriesFromModule(module) {
108
125
  });
109
126
  }
110
127
  }
128
+ if (eventHandlers.length > 0) {
129
+ for (const eventType of eventTypes) {
130
+ const tag = types_1.EVENT_TYPES[eventType].tag;
131
+ const handlers = eventHandlers.filter(fn => fn.eventHandler?.eventType === eventType);
132
+ for (const handler of handlers) {
133
+ tickCommands.push({
134
+ cmd: `execute as @a[tag=${tag}] run function ${module.namespace}:${handler.name}`,
135
+ });
136
+ }
137
+ tickCommands.push({
138
+ cmd: `tag @a[tag=${tag}] remove ${tag}`,
139
+ });
140
+ }
141
+ }
111
142
  if (tickCommands.length > 0) {
112
143
  sections.push({
113
144
  name: '__tick',
package/dist/compile.d.ts CHANGED
@@ -20,10 +20,20 @@ export interface CompileResult {
20
20
  ir?: IRModule;
21
21
  error?: DiagnosticError;
22
22
  }
23
+ export interface SourceRange {
24
+ startLine: number;
25
+ endLine: number;
26
+ filePath: string;
27
+ }
28
+ export interface PreprocessedSource {
29
+ source: string;
30
+ ranges: SourceRange[];
31
+ }
23
32
  interface PreprocessOptions {
24
33
  filePath?: string;
25
34
  seen?: Set<string>;
26
35
  }
36
+ export declare function preprocessSourceWithMetadata(source: string, options?: PreprocessOptions): PreprocessedSource;
27
37
  export declare function preprocessSource(source: string, options?: PreprocessOptions): string;
28
38
  export declare function compile(source: string, options?: CompileOptions): CompileResult;
29
39
  export declare function formatCompileError(result: CompileResult): string;
package/dist/compile.js CHANGED
@@ -38,6 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
38
38
  };
39
39
  })();
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.preprocessSourceWithMetadata = preprocessSourceWithMetadata;
41
42
  exports.preprocessSource = preprocessSource;
42
43
  exports.compile = compile;
43
44
  exports.formatCompileError = formatCompileError;
@@ -50,7 +51,17 @@ const passes_1 = require("./optimizer/passes");
50
51
  const mcfunction_1 = require("./codegen/mcfunction");
51
52
  const diagnostics_1 = require("./diagnostics");
52
53
  const IMPORT_RE = /^\s*import\s+"([^"]+)"\s*;?\s*$/;
53
- function preprocessSource(source, options = {}) {
54
+ function countLines(source) {
55
+ return source === '' ? 0 : source.split('\n').length;
56
+ }
57
+ function offsetRanges(ranges, lineOffset) {
58
+ return ranges.map(range => ({
59
+ startLine: range.startLine + lineOffset,
60
+ endLine: range.endLine + lineOffset,
61
+ filePath: range.filePath,
62
+ }));
63
+ }
64
+ function preprocessSourceWithMetadata(source, options = {}) {
54
65
  const { filePath } = options;
55
66
  const seen = options.seen ?? new Set();
56
67
  if (filePath) {
@@ -78,7 +89,7 @@ function preprocessSource(source, options = {}) {
78
89
  catch {
79
90
  throw new diagnostics_1.DiagnosticError('ParseError', `Cannot import '${match[1]}'`, { file: filePath, line: i + 1, col: 1 }, lines);
80
91
  }
81
- imports.push(preprocessSource(importedSource, { filePath: importPath, seen }));
92
+ imports.push(preprocessSourceWithMetadata(importedSource, { filePath: importPath, seen }));
82
93
  }
83
94
  continue;
84
95
  }
@@ -89,7 +100,26 @@ function preprocessSource(source, options = {}) {
89
100
  parsingHeader = false;
90
101
  bodyLines.push(line);
91
102
  }
92
- return [...imports, bodyLines.join('\n')].filter(Boolean).join('\n');
103
+ const body = bodyLines.join('\n');
104
+ const parts = [...imports.map(entry => entry.source), body].filter(Boolean);
105
+ const combined = parts.join('\n');
106
+ const ranges = [];
107
+ let lineOffset = 0;
108
+ for (const entry of imports) {
109
+ ranges.push(...offsetRanges(entry.ranges, lineOffset));
110
+ lineOffset += countLines(entry.source);
111
+ }
112
+ if (filePath && body) {
113
+ ranges.push({
114
+ startLine: lineOffset + 1,
115
+ endLine: lineOffset + countLines(body),
116
+ filePath: path.resolve(filePath),
117
+ });
118
+ }
119
+ return { source: combined, ranges };
120
+ }
121
+ function preprocessSource(source, options = {}) {
122
+ return preprocessSourceWithMetadata(source, options).source;
93
123
  }
94
124
  // ---------------------------------------------------------------------------
95
125
  // Main Compile Function
@@ -98,14 +128,15 @@ function compile(source, options = {}) {
98
128
  const { namespace = 'redscript', filePath, optimize: shouldOptimize = true } = options;
99
129
  let sourceLines = source.split('\n');
100
130
  try {
101
- const preprocessedSource = preprocessSource(source, { filePath });
131
+ const preprocessed = preprocessSourceWithMetadata(source, { filePath });
132
+ const preprocessedSource = preprocessed.source;
102
133
  sourceLines = preprocessedSource.split('\n');
103
134
  // Lexing
104
135
  const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
105
136
  // Parsing
106
137
  const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
107
138
  // Lowering
108
- const ir = new lowering_1.Lowering(namespace).lower(ast);
139
+ const ir = new lowering_1.Lowering(namespace, preprocessed.ranges).lower(ast);
109
140
  // Optimization
110
141
  const optimized = shouldOptimize
111
142
  ? { ...ir, functions: ir.functions.map(fn => (0, passes_1.optimize)(fn)) }
@@ -0,0 +1,35 @@
1
+ import type { TypeNode } from '../ast/types';
2
+ export declare const EVENT_TYPES: {
3
+ readonly PlayerDeath: {
4
+ readonly tag: "rs.just_died";
5
+ readonly params: readonly ["player: Player"];
6
+ readonly detection: "scoreboard";
7
+ };
8
+ readonly PlayerJoin: {
9
+ readonly tag: "rs.just_joined";
10
+ readonly params: readonly ["player: Player"];
11
+ readonly detection: "tag";
12
+ };
13
+ readonly BlockBreak: {
14
+ readonly tag: "rs.just_broke_block";
15
+ readonly params: readonly ["player: Player", "block: string"];
16
+ readonly detection: "advancement";
17
+ };
18
+ readonly EntityKill: {
19
+ readonly tag: "rs.just_killed";
20
+ readonly params: readonly ["player: Player"];
21
+ readonly detection: "scoreboard";
22
+ };
23
+ readonly ItemUse: {
24
+ readonly tag: "rs.just_used_item";
25
+ readonly params: readonly ["player: Player"];
26
+ readonly detection: "scoreboard";
27
+ };
28
+ };
29
+ export type EventTypeName = keyof typeof EVENT_TYPES;
30
+ export interface EventParamSpec {
31
+ name: string;
32
+ type: TypeNode;
33
+ }
34
+ export declare function isEventTypeName(value: string): value is EventTypeName;
35
+ export declare function getEventParamSpecs(eventType: EventTypeName): EventParamSpec[];
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EVENT_TYPES = void 0;
4
+ exports.isEventTypeName = isEventTypeName;
5
+ exports.getEventParamSpecs = getEventParamSpecs;
6
+ exports.EVENT_TYPES = {
7
+ PlayerDeath: {
8
+ tag: 'rs.just_died',
9
+ params: ['player: Player'],
10
+ detection: 'scoreboard',
11
+ },
12
+ PlayerJoin: {
13
+ tag: 'rs.just_joined',
14
+ params: ['player: Player'],
15
+ detection: 'tag',
16
+ },
17
+ BlockBreak: {
18
+ tag: 'rs.just_broke_block',
19
+ params: ['player: Player', 'block: string'],
20
+ detection: 'advancement',
21
+ },
22
+ EntityKill: {
23
+ tag: 'rs.just_killed',
24
+ params: ['player: Player'],
25
+ detection: 'scoreboard',
26
+ },
27
+ ItemUse: {
28
+ tag: 'rs.just_used_item',
29
+ params: ['player: Player'],
30
+ detection: 'scoreboard',
31
+ },
32
+ };
33
+ function isEventTypeName(value) {
34
+ return value in exports.EVENT_TYPES;
35
+ }
36
+ function getEventParamSpecs(eventType) {
37
+ return exports.EVENT_TYPES[eventType].params.map(parseEventParam);
38
+ }
39
+ function parseEventParam(spec) {
40
+ const match = spec.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_]*)$/);
41
+ if (!match) {
42
+ throw new Error(`Invalid event parameter spec: ${spec}`);
43
+ }
44
+ const [, name, typeName] = match;
45
+ return {
46
+ name,
47
+ type: toTypeNode(typeName),
48
+ };
49
+ }
50
+ function toTypeNode(typeName) {
51
+ if (typeName === 'Player') {
52
+ return { kind: 'entity', entityType: 'Player' };
53
+ }
54
+ if (typeName === 'string' || typeName === 'int' || typeName === 'bool' || typeName === 'float' || typeName === 'void' || typeName === 'BlockPos' || typeName === 'byte' || typeName === 'short' || typeName === 'long' || typeName === 'double') {
55
+ return { kind: 'named', name: typeName };
56
+ }
57
+ return { kind: 'struct', name: typeName };
58
+ }
59
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ export declare function format(source: string): string;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.format = format;
4
+ function format(source) {
5
+ const lines = source.split("\n");
6
+ let indent = 0;
7
+ const result = [];
8
+ for (let line of lines) {
9
+ line = line.trim();
10
+ if (!line) {
11
+ result.push("");
12
+ continue;
13
+ }
14
+ // Decrease indent before }
15
+ if (line.startsWith("}"))
16
+ indent = Math.max(0, indent - 1);
17
+ // Add indentation
18
+ result.push(" ".repeat(indent) + line);
19
+ // Increase indent after {
20
+ if (line.endsWith("{"))
21
+ indent++;
22
+ }
23
+ // Ensure single newline at end
24
+ return result.join("\n").trimEnd() + "\n";
25
+ }
26
+ //# sourceMappingURL=index.js.map
package/dist/index.js CHANGED
@@ -28,7 +28,8 @@ function compile(source, options = {}) {
28
28
  const shouldOptimize = options.optimize ?? true;
29
29
  const shouldTypeCheck = options.typeCheck ?? true;
30
30
  const filePath = options.filePath;
31
- const preprocessedSource = (0, compile_1.preprocessSource)(source, { filePath });
31
+ const preprocessed = (0, compile_1.preprocessSourceWithMetadata)(source, { filePath });
32
+ const preprocessedSource = preprocessed.source;
32
33
  // Lexing
33
34
  const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
34
35
  // Parsing
@@ -40,7 +41,7 @@ function compile(source, options = {}) {
40
41
  typeErrors = checker.check(ast);
41
42
  }
42
43
  // Lowering to IR
43
- const lowering = new lowering_1.Lowering(namespace);
44
+ const lowering = new lowering_1.Lowering(namespace, preprocessed.ranges);
44
45
  const ir = lowering.lower(ast);
45
46
  let optimizedIR = ir;
46
47
  let generated = (0, mcfunction_1.generateDatapackWithStats)(ir, { optimizeCommands: shouldOptimize });
@@ -29,4 +29,5 @@ export declare class IRBuilder {
29
29
  emitTickYield(continuation: string): void;
30
30
  build(name: string, params: string[], isTickLoop?: boolean): IRFunction;
31
31
  }
32
- export declare function buildModule(namespace: string, fns: IRFunction[], globals?: string[]): IRModule;
32
+ import type { GlobalVar } from './types';
33
+ export declare function buildModule(namespace: string, fns: IRFunction[], globals?: GlobalVar[]): IRModule;
@@ -8,7 +8,7 @@
8
8
  * - Integer vars → scoreboard fake player ($name on objective "rs_vars")
9
9
  * - Complex data → NBT storage (redscript:stack / redscript:heap)
10
10
  * - Return value → fake player $ret
11
- * - Temporaries → $t0, $t1, ...
11
+ * - Temporaries → $_0, $_1, ...
12
12
  */
13
13
  export type Operand = {
14
14
  kind: 'var';
@@ -103,15 +103,24 @@ export interface IRFunction {
103
103
  blocks: IRBlock[];
104
104
  commands?: IRCommand[];
105
105
  isTickLoop?: boolean;
106
+ isLoadInit?: boolean;
106
107
  isTriggerHandler?: boolean;
107
108
  triggerName?: string;
108
109
  eventTrigger?: {
109
110
  kind: 'advancement' | 'craft' | 'death' | 'login' | 'join_team';
110
111
  value?: string;
111
112
  };
113
+ eventHandler?: {
114
+ eventType: string;
115
+ tag: string;
116
+ };
117
+ }
118
+ export interface GlobalVar {
119
+ name: string;
120
+ init: number;
112
121
  }
113
122
  export interface IRModule {
114
123
  namespace: string;
115
124
  functions: IRFunction[];
116
- globals: string[];
125
+ globals: GlobalVar[];
117
126
  }
package/dist/ir/types.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * - Integer vars → scoreboard fake player ($name on objective "rs_vars")
10
10
  * - Complex data → NBT storage (redscript:stack / redscript:heap)
11
11
  * - Return value → fake player $ret
12
- * - Temporaries → $t0, $t1, ...
12
+ * - Temporaries → $_0, $_1, ...
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  //# sourceMappingURL=types.js.map
@@ -5,7 +5,7 @@
5
5
  * Handles special cases like entity selectors vs decorators,
6
6
  * range literals, and raw commands.
7
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';
8
+ export type TokenKind = 'fn' | 'let' | 'const' | 'if' | 'else' | 'while' | 'for' | 'foreach' | 'match' | 'return' | 'as' | 'at' | 'in' | 'is' | 'struct' | 'impl' | '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
9
  export interface Token {
10
10
  kind: TokenKind;
11
11
  value: string;
@@ -26,7 +26,9 @@ const KEYWORDS = {
26
26
  as: 'as',
27
27
  at: 'at',
28
28
  in: 'in',
29
+ is: 'is',
29
30
  struct: 'struct',
31
+ impl: 'impl',
30
32
  enum: 'enum',
31
33
  trigger: 'trigger',
32
34
  namespace: 'namespace',
@@ -5,6 +5,7 @@
5
5
  * Handles control flow, function extraction for foreach, and builtin calls.
6
6
  */
7
7
  import type { IRModule } from '../ir/types';
8
+ import type { SourceRange } from '../compile';
8
9
  import type { Program } from '../ast/types';
9
10
  export interface Warning {
10
11
  message: string;
@@ -14,17 +15,25 @@ export interface Warning {
14
15
  }
15
16
  export declare class Lowering {
16
17
  private namespace;
18
+ private readonly sourceRanges;
17
19
  private functions;
18
20
  private globals;
21
+ private globalNames;
19
22
  private fnDecls;
23
+ private implMethods;
20
24
  private specializedFunctions;
21
25
  private currentFn;
26
+ private currentStdlibCallSite?;
22
27
  private foreachCounter;
23
28
  private lambdaCounter;
29
+ private timeoutCounter;
30
+ private intervalCounter;
24
31
  readonly warnings: Warning[];
25
32
  private builder;
26
33
  private varMap;
27
34
  private lambdaBindings;
35
+ private intervalBindings;
36
+ private intervalFunctions;
28
37
  private currentCallbackBindings;
29
38
  private currentContext;
30
39
  private blockPosVars;
@@ -36,7 +45,7 @@ export declare class Lowering {
36
45
  private varTypes;
37
46
  private floatVars;
38
47
  private worldObjCounter;
39
- constructor(namespace: string);
48
+ constructor(namespace: string, sourceRanges?: SourceRange[]);
40
49
  lower(program: Program): IRModule;
41
50
  private lowerFn;
42
51
  private getTickRate;
@@ -46,6 +55,7 @@ export declare class Lowering {
46
55
  private lowerLetStmt;
47
56
  private lowerReturnStmt;
48
57
  private lowerIfStmt;
58
+ private lowerIsCheckIfStmt;
49
59
  private lowerWhileStmt;
50
60
  private lowerForStmt;
51
61
  private lowerForRangeStmt;
@@ -66,32 +76,55 @@ export declare class Lowering {
66
76
  private lowerUnaryExpr;
67
77
  private lowerAssignExpr;
68
78
  private lowerCallExpr;
79
+ private lowerStaticCallExpr;
69
80
  private lowerInvokeExpr;
70
81
  private inlineLambdaInvoke;
71
82
  private emitDirectFunctionCall;
83
+ private emitMethodCall;
72
84
  private resolveFunctionRefExpr;
73
85
  private resolveFunctionRefByName;
74
86
  private ensureSpecializedFunction;
87
+ private ensureSpecializedFunctionWithContext;
75
88
  private lowerLambdaExpr;
76
89
  private withSavedFunctionState;
77
90
  private lowerBuiltinCall;
91
+ private lowerSetTimeout;
92
+ private lowerSetInterval;
93
+ private lowerClearInterval;
94
+ private lowerNamedLambdaFunction;
95
+ private lowerIntervalWrapperFunction;
96
+ private resolveIntervalFunctionName;
78
97
  private lowerRichTextBuiltin;
79
98
  private getRichTextArgIndex;
80
99
  private buildRichTextJson;
81
100
  private appendRichTextExpr;
82
101
  private exprToString;
102
+ private exprToEntitySelector;
103
+ private appendTypeFilter;
104
+ private exprToSnbt;
83
105
  private exprToTargetString;
84
106
  private exprToLiteral;
85
107
  private exprToQuotedString;
86
108
  private exprToTextComponent;
87
109
  private exprToBoolString;
88
110
  private isTeamTextOption;
111
+ private exprToScoreboardObjective;
112
+ private resolveScoreboardObjective;
113
+ private getObjectiveNamespace;
114
+ private tryGetStdlibInternalObjective;
115
+ private getStdlibInternalResourceBase;
116
+ private getStdlibCallSiteContext;
117
+ private serializeCallSite;
118
+ private shortHash;
119
+ private isStdlibFile;
120
+ private filePathForSpan;
89
121
  private lowerCoordinateBuiltin;
90
122
  private lowerTpCommand;
91
123
  private resolveBlockPosExpr;
92
124
  private getArrayStorageName;
93
125
  private inferLambdaReturnType;
94
126
  private inferExprType;
127
+ private resolveInstanceMethod;
95
128
  private normalizeType;
96
129
  private readArrayElement;
97
130
  private emitRawSubFunction;