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.
- package/.github/ISSUE_TEMPLATE/bug_report.yml +72 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +57 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +17 -25
- package/CHANGELOG.md +112 -0
- package/CONTRIBUTING.md +140 -0
- package/README.md +28 -19
- package/README.zh.md +28 -19
- package/dist/__tests__/cli.test.js +148 -10
- package/dist/__tests__/codegen.test.js +26 -1
- package/dist/__tests__/diagnostics.test.js +5 -5
- package/dist/__tests__/e2e.test.js +336 -17
- package/dist/__tests__/formatter.test.d.ts +1 -0
- package/dist/__tests__/formatter.test.js +40 -0
- package/dist/__tests__/lexer.test.js +12 -2
- package/dist/__tests__/lowering.test.js +200 -12
- package/dist/__tests__/mc-integration.test.js +370 -31
- package/dist/__tests__/mc-syntax.test.js +3 -3
- package/dist/__tests__/nbt.test.js +2 -2
- package/dist/__tests__/optimizer-advanced.test.js +5 -5
- package/dist/__tests__/parser.test.js +80 -0
- package/dist/__tests__/runtime.test.js +9 -9
- package/dist/__tests__/typechecker.test.js +158 -0
- package/dist/ast/types.d.ts +40 -3
- package/dist/cli.js +25 -7
- package/dist/codegen/mcfunction/index.d.ts +1 -1
- package/dist/codegen/mcfunction/index.js +38 -3
- package/dist/codegen/structure/index.js +32 -1
- package/dist/compile.d.ts +10 -0
- package/dist/compile.js +36 -5
- package/dist/events/types.d.ts +35 -0
- package/dist/events/types.js +59 -0
- package/dist/formatter/index.d.ts +1 -0
- package/dist/formatter/index.js +26 -0
- package/dist/index.js +3 -2
- package/dist/ir/builder.d.ts +2 -1
- package/dist/ir/types.d.ts +11 -2
- package/dist/ir/types.js +1 -1
- package/dist/lexer/index.d.ts +1 -1
- package/dist/lexer/index.js +2 -0
- package/dist/lowering/index.d.ts +34 -1
- package/dist/lowering/index.js +622 -23
- package/dist/mc-test/runner.d.ts +2 -2
- package/dist/mc-test/runner.js +3 -3
- package/dist/mc-test/setup.js +2 -2
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.js +153 -16
- package/dist/typechecker/index.d.ts +17 -0
- package/dist/typechecker/index.js +343 -17
- package/docs/COMPILATION_STATS.md +24 -24
- package/docs/ENTITY_TYPE_SYSTEM.md +242 -0
- package/docs/IMPLEMENTATION_GUIDE.md +1 -1
- package/docs/STRUCTURE_TARGET.md +1 -1
- package/editors/vscode/.vscodeignore +1 -0
- package/editors/vscode/CHANGELOG.md +9 -0
- package/editors/vscode/icons/mcrs.svg +7 -0
- package/editors/vscode/icons/redscript-icons.json +10 -0
- package/editors/vscode/out/extension.js +1295 -80
- package/editors/vscode/package-lock.json +2 -2
- package/editors/vscode/package.json +10 -3
- package/editors/vscode/src/hover.ts +55 -2
- package/editors/vscode/src/symbols.ts +42 -0
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +176 -10
- package/src/__tests__/codegen.test.ts +28 -1
- package/src/__tests__/diagnostics.test.ts +5 -5
- package/src/__tests__/e2e.test.ts +335 -17
- package/src/__tests__/fixtures/event-test.mcrs +13 -0
- package/src/__tests__/fixtures/impl-test.mcrs +46 -0
- package/src/__tests__/fixtures/interval-test.mcrs +11 -0
- package/src/__tests__/fixtures/is-check-test.mcrs +20 -0
- package/src/__tests__/fixtures/timeout-test.mcrs +7 -0
- package/src/__tests__/lexer.test.ts +14 -2
- package/src/__tests__/lowering.test.ts +226 -12
- package/src/__tests__/mc-integration.test.ts +421 -31
- package/src/__tests__/mc-syntax.test.ts +3 -3
- package/src/__tests__/nbt.test.ts +2 -2
- package/src/__tests__/optimizer-advanced.test.ts +5 -5
- package/src/__tests__/parser.test.ts +91 -5
- package/src/__tests__/runtime.test.ts +9 -9
- package/src/__tests__/typechecker.test.ts +171 -0
- package/src/ast/types.ts +44 -3
- package/src/cli.ts +10 -10
- package/src/codegen/mcfunction/index.ts +40 -3
- package/src/codegen/structure/index.ts +35 -1
- package/src/compile.ts +54 -6
- package/src/events/types.ts +69 -0
- package/src/examples/capture_the_flag.mcrs +208 -0
- package/src/examples/{counter.rs → counter.mcrs} +1 -1
- package/src/examples/hunger_games.mcrs +301 -0
- package/src/examples/new_features_demo.mcrs +193 -0
- package/src/examples/parkour_race.mcrs +233 -0
- package/src/examples/rpg.mcrs +13 -0
- package/src/examples/{shop.rs → shop.mcrs} +1 -1
- package/src/examples/{showcase_game.rs → showcase_game.mcrs} +3 -3
- package/src/examples/{turret.rs → turret.mcrs} +1 -1
- package/src/examples/zombie_survival.mcrs +314 -0
- package/src/index.ts +4 -3
- package/src/ir/builder.ts +3 -1
- package/src/ir/types.ts +12 -2
- package/src/lexer/index.ts +3 -1
- package/src/lowering/index.ts +684 -24
- package/src/mc-test/runner.ts +3 -3
- package/src/mc-test/setup.ts +2 -2
- package/src/parser/index.ts +170 -19
- package/src/stdlib/README.md +178 -140
- package/src/stdlib/bossbar.mcrs +68 -0
- package/src/stdlib/{cooldown.rs → cooldown.mcrs} +1 -1
- package/src/stdlib/effects.mcrs +64 -0
- package/src/stdlib/interactions.mcrs +195 -0
- package/src/stdlib/inventory.mcrs +38 -0
- package/src/stdlib/mobs.mcrs +99 -0
- package/src/stdlib/particles.mcrs +52 -0
- package/src/stdlib/sets.mcrs +20 -0
- package/src/stdlib/spawn.mcrs +41 -0
- package/src/stdlib/tags.mcrs +951 -0
- package/src/stdlib/teams.mcrs +68 -0
- package/src/stdlib/timer.mcrs +72 -0
- package/src/stdlib/world.mcrs +92 -0
- package/src/typechecker/index.ts +404 -18
- package/src/examples/rpg.rs +0 -13
- package/src/stdlib/mobs.rs +0 -99
- package/src/stdlib/timer.rs +0 -51
- /package/src/examples/{arena.rs → arena.mcrs} +0 -0
- /package/src/examples/{pvp_arena.rs → pvp_arena.mcrs} +0 -0
- /package/src/examples/{quiz.rs → quiz.mcrs} +0 -0
- /package/src/examples/{stdlib_demo.rs → stdlib_demo.mcrs} +0 -0
- /package/src/examples/{world_manager.rs → world_manager.mcrs} +0 -0
- /package/src/stdlib/{combat.rs → combat.mcrs} +0 -0
- /package/src/stdlib/{math.rs → math.mcrs} +0 -0
- /package/src/stdlib/{player.rs → player.mcrs} +0 -0
- /package/src/stdlib/{strings.rs → strings.mcrs} +0 -0
- /package/src/templates/{combat.rs → combat.mcrs} +0 -0
- /package/src/templates/{economy.rs → economy.mcrs} +0 -0
- /package/src/templates/{mini-game-framework.rs → mini-game-framework.mcrs} +0 -0
- /package/src/templates/{quest.rs → quest.mcrs} +0 -0
- /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(
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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 });
|
package/dist/ir/builder.d.ts
CHANGED
|
@@ -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
|
-
|
|
32
|
+
import type { GlobalVar } from './types';
|
|
33
|
+
export declare function buildModule(namespace: string, fns: IRFunction[], globals?: GlobalVar[]): IRModule;
|
package/dist/ir/types.d.ts
CHANGED
|
@@ -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 → $
|
|
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:
|
|
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 → $
|
|
12
|
+
* - Temporaries → $_0, $_1, ...
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
//# sourceMappingURL=types.js.map
|
package/dist/lexer/index.d.ts
CHANGED
|
@@ -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;
|
package/dist/lexer/index.js
CHANGED
package/dist/lowering/index.d.ts
CHANGED
|
@@ -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;
|