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
|
@@ -175,7 +175,9 @@ var require_lexer = __commonJS({
|
|
|
175
175
|
as: "as",
|
|
176
176
|
at: "at",
|
|
177
177
|
in: "in",
|
|
178
|
+
is: "is",
|
|
178
179
|
struct: "struct",
|
|
180
|
+
impl: "impl",
|
|
179
181
|
enum: "enum",
|
|
180
182
|
trigger: "trigger",
|
|
181
183
|
namespace: "namespace",
|
|
@@ -608,13 +610,34 @@ var require_parser = __commonJS({
|
|
|
608
610
|
"<=": 4,
|
|
609
611
|
">": 4,
|
|
610
612
|
">=": 4,
|
|
613
|
+
"is": 4,
|
|
611
614
|
"+": 5,
|
|
612
615
|
"-": 5,
|
|
613
616
|
"*": 6,
|
|
614
617
|
"/": 6,
|
|
615
618
|
"%": 6
|
|
616
619
|
};
|
|
617
|
-
var BINARY_OPS = /* @__PURE__ */ new Set(["||", "&&", "==", "!=", "<", "<=", ">", ">=", "+", "-", "*", "/", "%"]);
|
|
620
|
+
var BINARY_OPS = /* @__PURE__ */ new Set(["||", "&&", "==", "!=", "<", "<=", ">", ">=", "is", "+", "-", "*", "/", "%"]);
|
|
621
|
+
var ENTITY_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
622
|
+
"entity",
|
|
623
|
+
"Player",
|
|
624
|
+
"Mob",
|
|
625
|
+
"HostileMob",
|
|
626
|
+
"PassiveMob",
|
|
627
|
+
"Zombie",
|
|
628
|
+
"Skeleton",
|
|
629
|
+
"Creeper",
|
|
630
|
+
"Spider",
|
|
631
|
+
"Enderman",
|
|
632
|
+
"Pig",
|
|
633
|
+
"Cow",
|
|
634
|
+
"Sheep",
|
|
635
|
+
"Chicken",
|
|
636
|
+
"Villager",
|
|
637
|
+
"ArmorStand",
|
|
638
|
+
"Item",
|
|
639
|
+
"Arrow"
|
|
640
|
+
]);
|
|
618
641
|
function computeIsSingle(raw) {
|
|
619
642
|
if (/^@[spr](\[|$)/.test(raw))
|
|
620
643
|
return true;
|
|
@@ -690,8 +713,10 @@ var require_parser = __commonJS({
|
|
|
690
713
|
// -------------------------------------------------------------------------
|
|
691
714
|
parse(defaultNamespace = "redscript") {
|
|
692
715
|
let namespace = defaultNamespace;
|
|
716
|
+
const globals = [];
|
|
693
717
|
const declarations = [];
|
|
694
718
|
const structs = [];
|
|
719
|
+
const implBlocks = [];
|
|
695
720
|
const enums = [];
|
|
696
721
|
const consts = [];
|
|
697
722
|
if (this.check("namespace")) {
|
|
@@ -701,8 +726,12 @@ var require_parser = __commonJS({
|
|
|
701
726
|
this.expect(";");
|
|
702
727
|
}
|
|
703
728
|
while (!this.check("eof")) {
|
|
704
|
-
if (this.check("
|
|
729
|
+
if (this.check("let")) {
|
|
730
|
+
globals.push(this.parseGlobalDecl(true));
|
|
731
|
+
} else if (this.check("struct")) {
|
|
705
732
|
structs.push(this.parseStructDecl());
|
|
733
|
+
} else if (this.check("impl")) {
|
|
734
|
+
implBlocks.push(this.parseImplBlock());
|
|
706
735
|
} else if (this.check("enum")) {
|
|
707
736
|
enums.push(this.parseEnumDecl());
|
|
708
737
|
} else if (this.check("const")) {
|
|
@@ -711,7 +740,7 @@ var require_parser = __commonJS({
|
|
|
711
740
|
declarations.push(this.parseFnDecl());
|
|
712
741
|
}
|
|
713
742
|
}
|
|
714
|
-
return { namespace, declarations, structs, enums, consts };
|
|
743
|
+
return { namespace, globals, declarations, structs, implBlocks, enums, consts };
|
|
715
744
|
}
|
|
716
745
|
// -------------------------------------------------------------------------
|
|
717
746
|
// Struct Declaration
|
|
@@ -755,6 +784,17 @@ var require_parser = __commonJS({
|
|
|
755
784
|
this.expect("}");
|
|
756
785
|
return this.withLoc({ name, variants }, enumToken);
|
|
757
786
|
}
|
|
787
|
+
parseImplBlock() {
|
|
788
|
+
const implToken = this.expect("impl");
|
|
789
|
+
const typeName = this.expect("ident").value;
|
|
790
|
+
this.expect("{");
|
|
791
|
+
const methods = [];
|
|
792
|
+
while (!this.check("}") && !this.check("eof")) {
|
|
793
|
+
methods.push(this.parseFnDecl(typeName));
|
|
794
|
+
}
|
|
795
|
+
this.expect("}");
|
|
796
|
+
return this.withLoc({ kind: "impl_block", typeName, methods }, implToken);
|
|
797
|
+
}
|
|
758
798
|
parseConstDecl() {
|
|
759
799
|
const constToken = this.expect("const");
|
|
760
800
|
const name = this.expect("ident").value;
|
|
@@ -765,18 +805,28 @@ var require_parser = __commonJS({
|
|
|
765
805
|
this.match(";");
|
|
766
806
|
return this.withLoc({ name, type, value }, constToken);
|
|
767
807
|
}
|
|
808
|
+
parseGlobalDecl(mutable) {
|
|
809
|
+
const token = this.advance();
|
|
810
|
+
const name = this.expect("ident").value;
|
|
811
|
+
this.expect(":");
|
|
812
|
+
const type = this.parseType();
|
|
813
|
+
this.expect("=");
|
|
814
|
+
const init = this.parseExpr();
|
|
815
|
+
this.expect(";");
|
|
816
|
+
return this.withLoc({ kind: "global", name, type, init, mutable }, token);
|
|
817
|
+
}
|
|
768
818
|
// -------------------------------------------------------------------------
|
|
769
819
|
// Function Declaration
|
|
770
820
|
// -------------------------------------------------------------------------
|
|
771
|
-
parseFnDecl() {
|
|
821
|
+
parseFnDecl(implTypeName) {
|
|
772
822
|
const decorators = this.parseDecorators();
|
|
773
823
|
const fnToken = this.expect("fn");
|
|
774
824
|
const name = this.expect("ident").value;
|
|
775
825
|
this.expect("(");
|
|
776
|
-
const params = this.parseParams();
|
|
826
|
+
const params = this.parseParams(implTypeName);
|
|
777
827
|
this.expect(")");
|
|
778
828
|
let returnType = { kind: "named", name: "void" };
|
|
779
|
-
if (this.match("->")) {
|
|
829
|
+
if (this.match("->") || this.match(":")) {
|
|
780
830
|
returnType = this.parseType();
|
|
781
831
|
}
|
|
782
832
|
const body = this.parseBlock();
|
|
@@ -802,6 +852,13 @@ var require_parser = __commonJS({
|
|
|
802
852
|
return { name };
|
|
803
853
|
}
|
|
804
854
|
const args = {};
|
|
855
|
+
if (name === "on") {
|
|
856
|
+
const eventTypeMatch = argsStr.match(/^([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
857
|
+
if (eventTypeMatch) {
|
|
858
|
+
args.eventType = eventTypeMatch[1];
|
|
859
|
+
return { name, args };
|
|
860
|
+
}
|
|
861
|
+
}
|
|
805
862
|
if (name === "on_trigger" || name === "on_advancement" || name === "on_craft" || name === "on_join_team") {
|
|
806
863
|
const strMatch = argsStr.match(/^"([^"]*)"$/);
|
|
807
864
|
if (strMatch) {
|
|
@@ -833,14 +890,19 @@ var require_parser = __commonJS({
|
|
|
833
890
|
}
|
|
834
891
|
return { name, args };
|
|
835
892
|
}
|
|
836
|
-
parseParams() {
|
|
893
|
+
parseParams(implTypeName) {
|
|
837
894
|
const params = [];
|
|
838
895
|
if (!this.check(")")) {
|
|
839
896
|
do {
|
|
840
897
|
const paramToken = this.expect("ident");
|
|
841
898
|
const name = paramToken.value;
|
|
842
|
-
|
|
843
|
-
|
|
899
|
+
let type;
|
|
900
|
+
if (implTypeName && params.length === 0 && name === "self" && !this.check(":")) {
|
|
901
|
+
type = { kind: "struct", name: implTypeName };
|
|
902
|
+
} else {
|
|
903
|
+
this.expect(":");
|
|
904
|
+
type = this.parseType();
|
|
905
|
+
}
|
|
844
906
|
let defaultValue;
|
|
845
907
|
if (this.match("=")) {
|
|
846
908
|
defaultValue = this.parseExpr();
|
|
@@ -1080,14 +1142,14 @@ var require_parser = __commonJS({
|
|
|
1080
1142
|
if (this.peek().kind === "ident" && this.peek().value === "entity") {
|
|
1081
1143
|
this.advance();
|
|
1082
1144
|
}
|
|
1083
|
-
const
|
|
1084
|
-
subcommands.push({ kind: "if_entity",
|
|
1145
|
+
const selectorOrVar = this.parseSelectorOrVarSelector();
|
|
1146
|
+
subcommands.push({ kind: "if_entity", ...selectorOrVar });
|
|
1085
1147
|
} else if (this.match("unless")) {
|
|
1086
1148
|
if (this.peek().kind === "ident" && this.peek().value === "entity") {
|
|
1087
1149
|
this.advance();
|
|
1088
1150
|
}
|
|
1089
|
-
const
|
|
1090
|
-
subcommands.push({ kind: "unless_entity",
|
|
1151
|
+
const selectorOrVar = this.parseSelectorOrVarSelector();
|
|
1152
|
+
subcommands.push({ kind: "unless_entity", ...selectorOrVar });
|
|
1091
1153
|
} else if (this.match("in")) {
|
|
1092
1154
|
const dim = this.expect("ident").value;
|
|
1093
1155
|
subcommands.push({ kind: "in", dimension: dim });
|
|
@@ -1137,6 +1199,11 @@ var require_parser = __commonJS({
|
|
|
1137
1199
|
if (prec < minPrec)
|
|
1138
1200
|
break;
|
|
1139
1201
|
const opToken = this.advance();
|
|
1202
|
+
if (op === "is") {
|
|
1203
|
+
const entityType = this.parseEntityTypeName();
|
|
1204
|
+
left = this.withLoc({ kind: "is_check", expr: left, entityType }, this.getLocToken(left) ?? opToken);
|
|
1205
|
+
continue;
|
|
1206
|
+
}
|
|
1140
1207
|
const right = this.parseBinaryExpr(prec + 1);
|
|
1141
1208
|
left = this.withLoc({ kind: "binary", op, left, right }, this.getLocToken(left) ?? opToken);
|
|
1142
1209
|
}
|
|
@@ -1155,6 +1222,13 @@ var require_parser = __commonJS({
|
|
|
1155
1222
|
}
|
|
1156
1223
|
return this.parsePostfixExpr();
|
|
1157
1224
|
}
|
|
1225
|
+
parseEntityTypeName() {
|
|
1226
|
+
const token = this.expect("ident");
|
|
1227
|
+
if (ENTITY_TYPE_NAMES.has(token.value)) {
|
|
1228
|
+
return token.value;
|
|
1229
|
+
}
|
|
1230
|
+
this.error(`Unknown entity type '${token.value}'`);
|
|
1231
|
+
}
|
|
1158
1232
|
isSubtraction() {
|
|
1159
1233
|
if (this.pos === 0)
|
|
1160
1234
|
return false;
|
|
@@ -1178,16 +1252,23 @@ var require_parser = __commonJS({
|
|
|
1178
1252
|
"untag": "__entity_untag",
|
|
1179
1253
|
"has_tag": "__entity_has_tag",
|
|
1180
1254
|
"push": "__array_push",
|
|
1181
|
-
"pop": "__array_pop"
|
|
1255
|
+
"pop": "__array_pop",
|
|
1256
|
+
"add": "set_add",
|
|
1257
|
+
"contains": "set_contains",
|
|
1258
|
+
"remove": "set_remove",
|
|
1259
|
+
"clear": "set_clear"
|
|
1182
1260
|
};
|
|
1183
1261
|
const internalFn = methodMap[expr.field];
|
|
1184
1262
|
if (internalFn) {
|
|
1185
|
-
const
|
|
1263
|
+
const args3 = this.parseArgs();
|
|
1186
1264
|
this.expect(")");
|
|
1187
|
-
expr = this.withLoc({ kind: "call", fn: internalFn, args: [expr.obj, ...
|
|
1265
|
+
expr = this.withLoc({ kind: "call", fn: internalFn, args: [expr.obj, ...args3] }, this.getLocToken(expr) ?? openParenToken);
|
|
1188
1266
|
continue;
|
|
1189
1267
|
}
|
|
1190
|
-
this.
|
|
1268
|
+
const args2 = this.parseArgs();
|
|
1269
|
+
this.expect(")");
|
|
1270
|
+
expr = this.withLoc({ kind: "call", fn: expr.field, args: [expr.obj, ...args2] }, this.getLocToken(expr) ?? openParenToken);
|
|
1271
|
+
continue;
|
|
1191
1272
|
}
|
|
1192
1273
|
const args = this.parseArgs();
|
|
1193
1274
|
this.expect(")");
|
|
@@ -1220,6 +1301,15 @@ var require_parser = __commonJS({
|
|
|
1220
1301
|
}
|
|
1221
1302
|
parsePrimaryExpr() {
|
|
1222
1303
|
const token = this.peek();
|
|
1304
|
+
if (token.kind === "ident" && this.peek(1).kind === "::") {
|
|
1305
|
+
const typeToken = this.advance();
|
|
1306
|
+
this.expect("::");
|
|
1307
|
+
const methodToken = this.expect("ident");
|
|
1308
|
+
this.expect("(");
|
|
1309
|
+
const args = this.parseArgs();
|
|
1310
|
+
this.expect(")");
|
|
1311
|
+
return this.withLoc({ kind: "static_call", type: typeToken.value, method: methodToken.value, args }, typeToken);
|
|
1312
|
+
}
|
|
1223
1313
|
if (token.kind === "ident" && this.peek(1).kind === "=>") {
|
|
1224
1314
|
return this.parseSingleParamLambda();
|
|
1225
1315
|
}
|
|
@@ -1585,6 +1675,34 @@ var require_parser = __commonJS({
|
|
|
1585
1675
|
const token = this.expect("selector");
|
|
1586
1676
|
return this.parseSelectorValue(token.value);
|
|
1587
1677
|
}
|
|
1678
|
+
// Parse either a selector (@a[...]) or a variable with filters (p[...])
|
|
1679
|
+
// Returns { selector } for selectors or { varName, filters } for variables
|
|
1680
|
+
parseSelectorOrVarSelector() {
|
|
1681
|
+
if (this.check("selector")) {
|
|
1682
|
+
return { selector: this.parseSelector() };
|
|
1683
|
+
}
|
|
1684
|
+
const varToken = this.expect("ident");
|
|
1685
|
+
const varName = varToken.value;
|
|
1686
|
+
if (this.check("[")) {
|
|
1687
|
+
this.advance();
|
|
1688
|
+
let filterStr = "";
|
|
1689
|
+
let depth = 1;
|
|
1690
|
+
while (depth > 0 && !this.check("eof")) {
|
|
1691
|
+
if (this.check("["))
|
|
1692
|
+
depth++;
|
|
1693
|
+
else if (this.check("]"))
|
|
1694
|
+
depth--;
|
|
1695
|
+
if (depth > 0) {
|
|
1696
|
+
filterStr += this.peek().value ?? this.peek().kind;
|
|
1697
|
+
this.advance();
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
this.expect("]");
|
|
1701
|
+
const filters = this.parseSelectorFilters(filterStr);
|
|
1702
|
+
return { varName, filters };
|
|
1703
|
+
}
|
|
1704
|
+
return { varName };
|
|
1705
|
+
}
|
|
1588
1706
|
parseSelectorValue(value) {
|
|
1589
1707
|
const bracketIndex = value.indexOf("[");
|
|
1590
1708
|
if (bracketIndex === -1) {
|
|
@@ -1635,6 +1753,21 @@ var require_parser = __commonJS({
|
|
|
1635
1753
|
case "scores":
|
|
1636
1754
|
filters.scores = this.parseScoresFilter(val);
|
|
1637
1755
|
break;
|
|
1756
|
+
case "x":
|
|
1757
|
+
filters.x = this.parseRangeValue(val);
|
|
1758
|
+
break;
|
|
1759
|
+
case "y":
|
|
1760
|
+
filters.y = this.parseRangeValue(val);
|
|
1761
|
+
break;
|
|
1762
|
+
case "z":
|
|
1763
|
+
filters.z = this.parseRangeValue(val);
|
|
1764
|
+
break;
|
|
1765
|
+
case "x_rotation":
|
|
1766
|
+
filters.x_rotation = this.parseRangeValue(val);
|
|
1767
|
+
break;
|
|
1768
|
+
case "y_rotation":
|
|
1769
|
+
filters.y_rotation = this.parseRangeValue(val);
|
|
1770
|
+
break;
|
|
1638
1771
|
}
|
|
1639
1772
|
}
|
|
1640
1773
|
return filters;
|
|
@@ -1693,6 +1826,70 @@ var require_parser = __commonJS({
|
|
|
1693
1826
|
}
|
|
1694
1827
|
});
|
|
1695
1828
|
|
|
1829
|
+
// ../../dist/events/types.js
|
|
1830
|
+
var require_types = __commonJS({
|
|
1831
|
+
"../../dist/events/types.js"(exports2) {
|
|
1832
|
+
"use strict";
|
|
1833
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1834
|
+
exports2.EVENT_TYPES = void 0;
|
|
1835
|
+
exports2.isEventTypeName = isEventTypeName;
|
|
1836
|
+
exports2.getEventParamSpecs = getEventParamSpecs;
|
|
1837
|
+
exports2.EVENT_TYPES = {
|
|
1838
|
+
PlayerDeath: {
|
|
1839
|
+
tag: "rs.just_died",
|
|
1840
|
+
params: ["player: Player"],
|
|
1841
|
+
detection: "scoreboard"
|
|
1842
|
+
},
|
|
1843
|
+
PlayerJoin: {
|
|
1844
|
+
tag: "rs.just_joined",
|
|
1845
|
+
params: ["player: Player"],
|
|
1846
|
+
detection: "tag"
|
|
1847
|
+
},
|
|
1848
|
+
BlockBreak: {
|
|
1849
|
+
tag: "rs.just_broke_block",
|
|
1850
|
+
params: ["player: Player", "block: string"],
|
|
1851
|
+
detection: "advancement"
|
|
1852
|
+
},
|
|
1853
|
+
EntityKill: {
|
|
1854
|
+
tag: "rs.just_killed",
|
|
1855
|
+
params: ["player: Player"],
|
|
1856
|
+
detection: "scoreboard"
|
|
1857
|
+
},
|
|
1858
|
+
ItemUse: {
|
|
1859
|
+
tag: "rs.just_used_item",
|
|
1860
|
+
params: ["player: Player"],
|
|
1861
|
+
detection: "scoreboard"
|
|
1862
|
+
}
|
|
1863
|
+
};
|
|
1864
|
+
function isEventTypeName(value) {
|
|
1865
|
+
return value in exports2.EVENT_TYPES;
|
|
1866
|
+
}
|
|
1867
|
+
function getEventParamSpecs(eventType) {
|
|
1868
|
+
return exports2.EVENT_TYPES[eventType].params.map(parseEventParam);
|
|
1869
|
+
}
|
|
1870
|
+
function parseEventParam(spec) {
|
|
1871
|
+
const match = spec.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
1872
|
+
if (!match) {
|
|
1873
|
+
throw new Error(`Invalid event parameter spec: ${spec}`);
|
|
1874
|
+
}
|
|
1875
|
+
const [, name, typeName] = match;
|
|
1876
|
+
return {
|
|
1877
|
+
name,
|
|
1878
|
+
type: toTypeNode(typeName)
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
function toTypeNode(typeName) {
|
|
1882
|
+
if (typeName === "Player") {
|
|
1883
|
+
return { kind: "entity", entityType: "Player" };
|
|
1884
|
+
}
|
|
1885
|
+
if (typeName === "string" || typeName === "int" || typeName === "bool" || typeName === "float" || typeName === "void" || typeName === "BlockPos" || typeName === "byte" || typeName === "short" || typeName === "long" || typeName === "double") {
|
|
1886
|
+
return { kind: "named", name: typeName };
|
|
1887
|
+
}
|
|
1888
|
+
return { kind: "struct", name: typeName };
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
});
|
|
1892
|
+
|
|
1696
1893
|
// ../../dist/typechecker/index.js
|
|
1697
1894
|
var require_typechecker = __commonJS({
|
|
1698
1895
|
"../../dist/typechecker/index.js"(exports2) {
|
|
@@ -1700,15 +1897,82 @@ var require_typechecker = __commonJS({
|
|
|
1700
1897
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1701
1898
|
exports2.TypeChecker = void 0;
|
|
1702
1899
|
var diagnostics_1 = require_diagnostics();
|
|
1900
|
+
var types_1 = require_types();
|
|
1901
|
+
var ENTITY_HIERARCHY = {
|
|
1902
|
+
"entity": null,
|
|
1903
|
+
"Player": "entity",
|
|
1904
|
+
"Mob": "entity",
|
|
1905
|
+
"HostileMob": "Mob",
|
|
1906
|
+
"PassiveMob": "Mob",
|
|
1907
|
+
"Zombie": "HostileMob",
|
|
1908
|
+
"Skeleton": "HostileMob",
|
|
1909
|
+
"Creeper": "HostileMob",
|
|
1910
|
+
"Spider": "HostileMob",
|
|
1911
|
+
"Enderman": "HostileMob",
|
|
1912
|
+
"Pig": "PassiveMob",
|
|
1913
|
+
"Cow": "PassiveMob",
|
|
1914
|
+
"Sheep": "PassiveMob",
|
|
1915
|
+
"Chicken": "PassiveMob",
|
|
1916
|
+
"Villager": "PassiveMob",
|
|
1917
|
+
"ArmorStand": "entity",
|
|
1918
|
+
"Item": "entity",
|
|
1919
|
+
"Arrow": "entity"
|
|
1920
|
+
};
|
|
1921
|
+
var MC_TYPE_TO_ENTITY = {
|
|
1922
|
+
"zombie": "Zombie",
|
|
1923
|
+
"minecraft:zombie": "Zombie",
|
|
1924
|
+
"skeleton": "Skeleton",
|
|
1925
|
+
"minecraft:skeleton": "Skeleton",
|
|
1926
|
+
"creeper": "Creeper",
|
|
1927
|
+
"minecraft:creeper": "Creeper",
|
|
1928
|
+
"spider": "Spider",
|
|
1929
|
+
"minecraft:spider": "Spider",
|
|
1930
|
+
"enderman": "Enderman",
|
|
1931
|
+
"minecraft:enderman": "Enderman",
|
|
1932
|
+
"pig": "Pig",
|
|
1933
|
+
"minecraft:pig": "Pig",
|
|
1934
|
+
"cow": "Cow",
|
|
1935
|
+
"minecraft:cow": "Cow",
|
|
1936
|
+
"sheep": "Sheep",
|
|
1937
|
+
"minecraft:sheep": "Sheep",
|
|
1938
|
+
"chicken": "Chicken",
|
|
1939
|
+
"minecraft:chicken": "Chicken",
|
|
1940
|
+
"villager": "Villager",
|
|
1941
|
+
"minecraft:villager": "Villager",
|
|
1942
|
+
"armor_stand": "ArmorStand",
|
|
1943
|
+
"minecraft:armor_stand": "ArmorStand",
|
|
1944
|
+
"item": "Item",
|
|
1945
|
+
"minecraft:item": "Item",
|
|
1946
|
+
"arrow": "Arrow",
|
|
1947
|
+
"minecraft:arrow": "Arrow"
|
|
1948
|
+
};
|
|
1949
|
+
var VOID_TYPE = { kind: "named", name: "void" };
|
|
1950
|
+
var INT_TYPE = { kind: "named", name: "int" };
|
|
1951
|
+
var BUILTIN_SIGNATURES = {
|
|
1952
|
+
setTimeout: {
|
|
1953
|
+
params: [INT_TYPE, { kind: "function_type", params: [], return: VOID_TYPE }],
|
|
1954
|
+
return: VOID_TYPE
|
|
1955
|
+
},
|
|
1956
|
+
setInterval: {
|
|
1957
|
+
params: [INT_TYPE, { kind: "function_type", params: [], return: VOID_TYPE }],
|
|
1958
|
+
return: INT_TYPE
|
|
1959
|
+
},
|
|
1960
|
+
clearInterval: {
|
|
1961
|
+
params: [INT_TYPE],
|
|
1962
|
+
return: VOID_TYPE
|
|
1963
|
+
}
|
|
1964
|
+
};
|
|
1703
1965
|
var TypeChecker = class {
|
|
1704
1966
|
constructor(source, filePath) {
|
|
1705
1967
|
this.functions = /* @__PURE__ */ new Map();
|
|
1968
|
+
this.implMethods = /* @__PURE__ */ new Map();
|
|
1706
1969
|
this.structs = /* @__PURE__ */ new Map();
|
|
1707
1970
|
this.enums = /* @__PURE__ */ new Map();
|
|
1708
1971
|
this.consts = /* @__PURE__ */ new Map();
|
|
1709
1972
|
this.currentFn = null;
|
|
1710
1973
|
this.currentReturnType = null;
|
|
1711
1974
|
this.scope = /* @__PURE__ */ new Map();
|
|
1975
|
+
this.selfTypeStack = ["entity"];
|
|
1712
1976
|
this.collector = new diagnostics_1.DiagnosticCollector(source, filePath);
|
|
1713
1977
|
}
|
|
1714
1978
|
getNodeLocation(node) {
|
|
@@ -1729,6 +1993,26 @@ var require_typechecker = __commonJS({
|
|
|
1729
1993
|
for (const fn of program.declarations) {
|
|
1730
1994
|
this.functions.set(fn.name, fn);
|
|
1731
1995
|
}
|
|
1996
|
+
for (const implBlock of program.implBlocks ?? []) {
|
|
1997
|
+
let methods = this.implMethods.get(implBlock.typeName);
|
|
1998
|
+
if (!methods) {
|
|
1999
|
+
methods = /* @__PURE__ */ new Map();
|
|
2000
|
+
this.implMethods.set(implBlock.typeName, methods);
|
|
2001
|
+
}
|
|
2002
|
+
for (const method of implBlock.methods) {
|
|
2003
|
+
const selfIndex = method.params.findIndex((param) => param.name === "self");
|
|
2004
|
+
if (selfIndex > 0) {
|
|
2005
|
+
this.report(`Method '${method.name}' must declare 'self' as the first parameter`, method.params[selfIndex]);
|
|
2006
|
+
}
|
|
2007
|
+
if (selfIndex === 0) {
|
|
2008
|
+
const selfType = this.normalizeType(method.params[0].type);
|
|
2009
|
+
if (selfType.kind !== "struct" || selfType.name !== implBlock.typeName) {
|
|
2010
|
+
this.report(`Method '${method.name}' has invalid 'self' type`, method.params[0]);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
methods.set(method.name, method);
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
1732
2016
|
for (const struct of program.structs ?? []) {
|
|
1733
2017
|
const fields = /* @__PURE__ */ new Map();
|
|
1734
2018
|
for (const field of struct.fields) {
|
|
@@ -1754,6 +2038,11 @@ var require_typechecker = __commonJS({
|
|
|
1754
2038
|
for (const fn of program.declarations) {
|
|
1755
2039
|
this.checkFunction(fn);
|
|
1756
2040
|
}
|
|
2041
|
+
for (const implBlock of program.implBlocks ?? []) {
|
|
2042
|
+
for (const method of implBlock.methods) {
|
|
2043
|
+
this.checkFunction(method);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
1757
2046
|
return this.collector.getErrors();
|
|
1758
2047
|
}
|
|
1759
2048
|
checkFunction(fn) {
|
|
@@ -1761,6 +2050,7 @@ var require_typechecker = __commonJS({
|
|
|
1761
2050
|
this.currentReturnType = this.normalizeType(fn.returnType);
|
|
1762
2051
|
this.scope = /* @__PURE__ */ new Map();
|
|
1763
2052
|
let seenDefault = false;
|
|
2053
|
+
this.checkFunctionDecorators(fn);
|
|
1764
2054
|
for (const [name, type] of this.consts.entries()) {
|
|
1765
2055
|
this.scope.set(name, { type, mutable: false });
|
|
1766
2056
|
}
|
|
@@ -1782,6 +2072,37 @@ var require_typechecker = __commonJS({
|
|
|
1782
2072
|
this.currentFn = null;
|
|
1783
2073
|
this.currentReturnType = null;
|
|
1784
2074
|
}
|
|
2075
|
+
checkFunctionDecorators(fn) {
|
|
2076
|
+
const eventDecorators = fn.decorators.filter((decorator) => decorator.name === "on");
|
|
2077
|
+
if (eventDecorators.length === 0) {
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
if (eventDecorators.length > 1) {
|
|
2081
|
+
this.report(`Function '${fn.name}' cannot have multiple @on decorators`, fn);
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
const eventType = eventDecorators[0].args?.eventType;
|
|
2085
|
+
if (!eventType) {
|
|
2086
|
+
this.report(`Function '${fn.name}' is missing an event type in @on(...)`, fn);
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
if (!(0, types_1.isEventTypeName)(eventType)) {
|
|
2090
|
+
this.report(`Unknown event type '${eventType}'`, fn);
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
const expectedParams = (0, types_1.getEventParamSpecs)(eventType);
|
|
2094
|
+
if (fn.params.length !== expectedParams.length) {
|
|
2095
|
+
this.report(`Event handler '${fn.name}' for ${eventType} must declare ${expectedParams.length} parameter(s), got ${fn.params.length}`, fn);
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
for (let i = 0; i < expectedParams.length; i++) {
|
|
2099
|
+
const actual = this.normalizeType(fn.params[i].type);
|
|
2100
|
+
const expected = this.normalizeType(expectedParams[i].type);
|
|
2101
|
+
if (!this.typesMatch(expected, actual)) {
|
|
2102
|
+
this.report(`Event handler '${fn.name}' parameter ${i + 1} must be ${this.typeToString(expected)}, got ${this.typeToString(actual)}`, fn.params[i]);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
1785
2106
|
checkBlock(stmts) {
|
|
1786
2107
|
for (const stmt of stmts) {
|
|
1787
2108
|
this.checkStmt(stmt);
|
|
@@ -1797,9 +2118,7 @@ var require_typechecker = __commonJS({
|
|
|
1797
2118
|
break;
|
|
1798
2119
|
case "if":
|
|
1799
2120
|
this.checkExpr(stmt.cond);
|
|
1800
|
-
this.
|
|
1801
|
-
if (stmt.else_)
|
|
1802
|
-
this.checkBlock(stmt.else_);
|
|
2121
|
+
this.checkIfBranches(stmt);
|
|
1803
2122
|
break;
|
|
1804
2123
|
case "while":
|
|
1805
2124
|
this.checkExpr(stmt.cond);
|
|
@@ -1815,7 +2134,15 @@ var require_typechecker = __commonJS({
|
|
|
1815
2134
|
case "foreach":
|
|
1816
2135
|
this.checkExpr(stmt.iterable);
|
|
1817
2136
|
if (stmt.iterable.kind === "selector") {
|
|
1818
|
-
this.
|
|
2137
|
+
const entityType = this.inferEntityTypeFromSelector(stmt.iterable.sel);
|
|
2138
|
+
this.scope.set(stmt.binding, {
|
|
2139
|
+
type: { kind: "entity", entityType },
|
|
2140
|
+
mutable: false
|
|
2141
|
+
// Entity bindings are not reassignable
|
|
2142
|
+
});
|
|
2143
|
+
this.pushSelfType(entityType);
|
|
2144
|
+
this.checkBlock(stmt.body);
|
|
2145
|
+
this.popSelfType();
|
|
1819
2146
|
} else {
|
|
1820
2147
|
const iterableType = this.inferType(stmt.iterable);
|
|
1821
2148
|
if (iterableType.kind === "array") {
|
|
@@ -1823,8 +2150,8 @@ var require_typechecker = __commonJS({
|
|
|
1823
2150
|
} else {
|
|
1824
2151
|
this.scope.set(stmt.binding, { type: { kind: "named", name: "void" }, mutable: true });
|
|
1825
2152
|
}
|
|
2153
|
+
this.checkBlock(stmt.body);
|
|
1826
2154
|
}
|
|
1827
|
-
this.checkBlock(stmt.body);
|
|
1828
2155
|
break;
|
|
1829
2156
|
case "match":
|
|
1830
2157
|
this.checkExpr(stmt.expr);
|
|
@@ -1838,15 +2165,36 @@ var require_typechecker = __commonJS({
|
|
|
1838
2165
|
this.checkBlock(arm.body);
|
|
1839
2166
|
}
|
|
1840
2167
|
break;
|
|
1841
|
-
case "as_block":
|
|
2168
|
+
case "as_block": {
|
|
2169
|
+
const entityType = this.inferEntityTypeFromSelector(stmt.selector);
|
|
2170
|
+
this.pushSelfType(entityType);
|
|
2171
|
+
this.checkBlock(stmt.body);
|
|
2172
|
+
this.popSelfType();
|
|
2173
|
+
break;
|
|
2174
|
+
}
|
|
1842
2175
|
case "at_block":
|
|
1843
2176
|
this.checkBlock(stmt.body);
|
|
1844
2177
|
break;
|
|
1845
|
-
case "as_at":
|
|
2178
|
+
case "as_at": {
|
|
2179
|
+
const entityType = this.inferEntityTypeFromSelector(stmt.as_sel);
|
|
2180
|
+
this.pushSelfType(entityType);
|
|
1846
2181
|
this.checkBlock(stmt.body);
|
|
2182
|
+
this.popSelfType();
|
|
1847
2183
|
break;
|
|
2184
|
+
}
|
|
1848
2185
|
case "execute":
|
|
2186
|
+
for (const sub of stmt.subcommands) {
|
|
2187
|
+
if (sub.kind === "as" && sub.selector) {
|
|
2188
|
+
const entityType = this.inferEntityTypeFromSelector(sub.selector);
|
|
2189
|
+
this.pushSelfType(entityType);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
1849
2192
|
this.checkBlock(stmt.body);
|
|
2193
|
+
for (const sub of stmt.subcommands) {
|
|
2194
|
+
if (sub.kind === "as") {
|
|
2195
|
+
this.popSelfType();
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
1850
2198
|
break;
|
|
1851
2199
|
case "expr":
|
|
1852
2200
|
this.checkExpr(stmt.expr);
|
|
@@ -1897,10 +2245,21 @@ var require_typechecker = __commonJS({
|
|
|
1897
2245
|
case "member":
|
|
1898
2246
|
this.checkMemberExpr(expr);
|
|
1899
2247
|
break;
|
|
2248
|
+
case "static_call":
|
|
2249
|
+
this.checkStaticCallExpr(expr);
|
|
2250
|
+
break;
|
|
1900
2251
|
case "binary":
|
|
1901
2252
|
this.checkExpr(expr.left);
|
|
1902
2253
|
this.checkExpr(expr.right);
|
|
1903
2254
|
break;
|
|
2255
|
+
case "is_check": {
|
|
2256
|
+
this.checkExpr(expr.expr);
|
|
2257
|
+
const checkedType = this.inferType(expr.expr);
|
|
2258
|
+
if (checkedType.kind !== "entity") {
|
|
2259
|
+
this.report(`'is' checks require an entity expression, got ${this.typeToString(checkedType)}`, expr.expr);
|
|
2260
|
+
}
|
|
2261
|
+
break;
|
|
2262
|
+
}
|
|
1904
2263
|
case "unary":
|
|
1905
2264
|
this.checkExpr(expr.operand);
|
|
1906
2265
|
break;
|
|
@@ -1946,11 +2305,6 @@ var require_typechecker = __commonJS({
|
|
|
1946
2305
|
break;
|
|
1947
2306
|
case "blockpos":
|
|
1948
2307
|
break;
|
|
1949
|
-
case "static_call":
|
|
1950
|
-
for (const arg of expr.args) {
|
|
1951
|
-
this.checkExpr(arg);
|
|
1952
|
-
}
|
|
1953
|
-
break;
|
|
1954
2308
|
// Literals don't need checking
|
|
1955
2309
|
case "int_lit":
|
|
1956
2310
|
case "float_lit":
|
|
@@ -1970,6 +2324,11 @@ var require_typechecker = __commonJS({
|
|
|
1970
2324
|
if (expr.fn === "tp" || expr.fn === "tp_to") {
|
|
1971
2325
|
this.checkTpCall(expr);
|
|
1972
2326
|
}
|
|
2327
|
+
const builtin = BUILTIN_SIGNATURES[expr.fn];
|
|
2328
|
+
if (builtin) {
|
|
2329
|
+
this.checkFunctionCallArgs(expr.args, builtin.params, expr.fn, expr);
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
1973
2332
|
const fn = this.functions.get(expr.fn);
|
|
1974
2333
|
if (fn) {
|
|
1975
2334
|
const requiredParams = fn.params.filter((param) => !param.default).length;
|
|
@@ -1994,6 +2353,11 @@ var require_typechecker = __commonJS({
|
|
|
1994
2353
|
this.checkFunctionCallArgs(expr.args, varType.params, expr.fn, expr);
|
|
1995
2354
|
return;
|
|
1996
2355
|
}
|
|
2356
|
+
const implMethod = this.resolveInstanceMethod(expr);
|
|
2357
|
+
if (implMethod) {
|
|
2358
|
+
this.checkFunctionCallArgs(expr.args, implMethod.params.map((param) => this.normalizeType(param.type)), implMethod.name, expr);
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
1997
2361
|
for (const arg of expr.args) {
|
|
1998
2362
|
this.checkExpr(arg);
|
|
1999
2363
|
}
|
|
@@ -2074,6 +2438,21 @@ var require_typechecker = __commonJS({
|
|
|
2074
2438
|
}
|
|
2075
2439
|
}
|
|
2076
2440
|
}
|
|
2441
|
+
checkStaticCallExpr(expr) {
|
|
2442
|
+
const method = this.implMethods.get(expr.type)?.get(expr.method);
|
|
2443
|
+
if (!method) {
|
|
2444
|
+
this.report(`Type '${expr.type}' has no static method '${expr.method}'`, expr);
|
|
2445
|
+
for (const arg of expr.args) {
|
|
2446
|
+
this.checkExpr(arg);
|
|
2447
|
+
}
|
|
2448
|
+
return;
|
|
2449
|
+
}
|
|
2450
|
+
if (method.params[0]?.name === "self") {
|
|
2451
|
+
this.report(`Method '${expr.type}::${expr.method}' is an instance method`, expr);
|
|
2452
|
+
return;
|
|
2453
|
+
}
|
|
2454
|
+
this.checkFunctionCallArgs(expr.args, method.params.map((param) => this.normalizeType(param.type)), `${expr.type}::${expr.method}`, expr);
|
|
2455
|
+
}
|
|
2077
2456
|
checkLambdaExpr(expr, expectedType) {
|
|
2078
2457
|
const normalizedExpected = expectedType ? this.normalizeType(expectedType) : void 0;
|
|
2079
2458
|
const expectedFnType = normalizedExpected?.kind === "function_type" ? normalizedExpected : void 0;
|
|
@@ -2106,6 +2485,36 @@ var require_typechecker = __commonJS({
|
|
|
2106
2485
|
this.scope = outerScope;
|
|
2107
2486
|
this.currentReturnType = outerReturnType;
|
|
2108
2487
|
}
|
|
2488
|
+
checkIfBranches(stmt) {
|
|
2489
|
+
const narrowed = this.getThenBranchNarrowing(stmt.cond);
|
|
2490
|
+
if (narrowed) {
|
|
2491
|
+
const thenScope = new Map(this.scope);
|
|
2492
|
+
thenScope.set(narrowed.name, { type: narrowed.type, mutable: narrowed.mutable });
|
|
2493
|
+
const outerScope = this.scope;
|
|
2494
|
+
this.scope = thenScope;
|
|
2495
|
+
this.checkBlock(stmt.then);
|
|
2496
|
+
this.scope = outerScope;
|
|
2497
|
+
} else {
|
|
2498
|
+
this.checkBlock(stmt.then);
|
|
2499
|
+
}
|
|
2500
|
+
if (stmt.else_) {
|
|
2501
|
+
this.checkBlock(stmt.else_);
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
getThenBranchNarrowing(cond) {
|
|
2505
|
+
if (cond.kind !== "is_check" || cond.expr.kind !== "ident") {
|
|
2506
|
+
return null;
|
|
2507
|
+
}
|
|
2508
|
+
const symbol = this.scope.get(cond.expr.name);
|
|
2509
|
+
if (!symbol || symbol.type.kind !== "entity") {
|
|
2510
|
+
return null;
|
|
2511
|
+
}
|
|
2512
|
+
return {
|
|
2513
|
+
name: cond.expr.name,
|
|
2514
|
+
type: { kind: "entity", entityType: cond.entityType },
|
|
2515
|
+
mutable: symbol.mutable
|
|
2516
|
+
};
|
|
2517
|
+
}
|
|
2109
2518
|
inferType(expr, expectedType) {
|
|
2110
2519
|
switch (expr.kind) {
|
|
2111
2520
|
case "int_lit":
|
|
@@ -2137,8 +2546,12 @@ var require_typechecker = __commonJS({
|
|
|
2137
2546
|
case "ident":
|
|
2138
2547
|
return this.scope.get(expr.name)?.type ?? { kind: "named", name: "void" };
|
|
2139
2548
|
case "call": {
|
|
2549
|
+
const builtin = BUILTIN_SIGNATURES[expr.fn];
|
|
2550
|
+
if (builtin) {
|
|
2551
|
+
return builtin.return;
|
|
2552
|
+
}
|
|
2140
2553
|
if (expr.fn === "__array_push") {
|
|
2141
|
-
return
|
|
2554
|
+
return VOID_TYPE;
|
|
2142
2555
|
}
|
|
2143
2556
|
if (expr.fn === "__array_pop") {
|
|
2144
2557
|
const target = expr.args[0];
|
|
@@ -2147,20 +2560,28 @@ var require_typechecker = __commonJS({
|
|
|
2147
2560
|
if (targetType?.kind === "array")
|
|
2148
2561
|
return targetType.elem;
|
|
2149
2562
|
}
|
|
2150
|
-
return
|
|
2563
|
+
return INT_TYPE;
|
|
2151
2564
|
}
|
|
2152
2565
|
if (expr.fn === "bossbar_get_value") {
|
|
2153
|
-
return
|
|
2566
|
+
return INT_TYPE;
|
|
2154
2567
|
}
|
|
2155
2568
|
if (expr.fn === "random_sequence") {
|
|
2156
|
-
return
|
|
2569
|
+
return VOID_TYPE;
|
|
2157
2570
|
}
|
|
2158
2571
|
const varType = this.scope.get(expr.fn)?.type;
|
|
2159
2572
|
if (varType?.kind === "function_type") {
|
|
2160
2573
|
return varType.return;
|
|
2161
2574
|
}
|
|
2575
|
+
const implMethod = this.resolveInstanceMethod(expr);
|
|
2576
|
+
if (implMethod) {
|
|
2577
|
+
return this.normalizeType(implMethod.returnType);
|
|
2578
|
+
}
|
|
2162
2579
|
const fn = this.functions.get(expr.fn);
|
|
2163
|
-
return fn?.returnType ??
|
|
2580
|
+
return fn?.returnType ?? INT_TYPE;
|
|
2581
|
+
}
|
|
2582
|
+
case "static_call": {
|
|
2583
|
+
const method = this.implMethods.get(expr.type)?.get(expr.method);
|
|
2584
|
+
return method ? this.normalizeType(method.returnType) : { kind: "named", name: "void" };
|
|
2164
2585
|
}
|
|
2165
2586
|
case "invoke": {
|
|
2166
2587
|
const calleeType = this.inferType(expr.callee);
|
|
@@ -2191,6 +2612,8 @@ var require_typechecker = __commonJS({
|
|
|
2191
2612
|
return { kind: "named", name: "bool" };
|
|
2192
2613
|
}
|
|
2193
2614
|
return this.inferType(expr.left);
|
|
2615
|
+
case "is_check":
|
|
2616
|
+
return { kind: "named", name: "bool" };
|
|
2194
2617
|
case "unary":
|
|
2195
2618
|
if (expr.op === "!")
|
|
2196
2619
|
return { kind: "named", name: "bool" };
|
|
@@ -2200,6 +2623,14 @@ var require_typechecker = __commonJS({
|
|
|
2200
2623
|
return { kind: "array", elem: this.inferType(expr.elements[0]) };
|
|
2201
2624
|
}
|
|
2202
2625
|
return { kind: "array", elem: { kind: "named", name: "int" } };
|
|
2626
|
+
case "struct_lit":
|
|
2627
|
+
if (expectedType) {
|
|
2628
|
+
const normalized = this.normalizeType(expectedType);
|
|
2629
|
+
if (normalized.kind === "struct") {
|
|
2630
|
+
return normalized;
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
return { kind: "named", name: "void" };
|
|
2203
2634
|
case "lambda":
|
|
2204
2635
|
return this.inferLambdaType(expr, expectedType && this.normalizeType(expectedType).kind === "function_type" ? this.normalizeType(expectedType) : void 0);
|
|
2205
2636
|
default:
|
|
@@ -2224,6 +2655,64 @@ var require_typechecker = __commonJS({
|
|
|
2224
2655
|
}
|
|
2225
2656
|
return { kind: "function_type", params, return: returnType };
|
|
2226
2657
|
}
|
|
2658
|
+
// ---------------------------------------------------------------------------
|
|
2659
|
+
// Entity Type Helpers
|
|
2660
|
+
// ---------------------------------------------------------------------------
|
|
2661
|
+
/** Infer entity type from a selector */
|
|
2662
|
+
inferEntityTypeFromSelector(selector) {
|
|
2663
|
+
if (selector.kind === "@a" || selector.kind === "@p" || selector.kind === "@r") {
|
|
2664
|
+
return "Player";
|
|
2665
|
+
}
|
|
2666
|
+
if (selector.filters?.type) {
|
|
2667
|
+
const mcType = selector.filters.type.toLowerCase();
|
|
2668
|
+
return MC_TYPE_TO_ENTITY[mcType] ?? "entity";
|
|
2669
|
+
}
|
|
2670
|
+
if (selector.kind === "@s") {
|
|
2671
|
+
return this.selfTypeStack[this.selfTypeStack.length - 1];
|
|
2672
|
+
}
|
|
2673
|
+
return "entity";
|
|
2674
|
+
}
|
|
2675
|
+
resolveInstanceMethod(expr) {
|
|
2676
|
+
const receiver = expr.args[0];
|
|
2677
|
+
if (!receiver) {
|
|
2678
|
+
return null;
|
|
2679
|
+
}
|
|
2680
|
+
const receiverType = this.inferType(receiver);
|
|
2681
|
+
if (receiverType.kind !== "struct") {
|
|
2682
|
+
return null;
|
|
2683
|
+
}
|
|
2684
|
+
const method = this.implMethods.get(receiverType.name)?.get(expr.fn);
|
|
2685
|
+
if (!method || method.params[0]?.name !== "self") {
|
|
2686
|
+
return null;
|
|
2687
|
+
}
|
|
2688
|
+
return method;
|
|
2689
|
+
}
|
|
2690
|
+
/** Check if childType is a subtype of parentType */
|
|
2691
|
+
isEntitySubtype(childType, parentType) {
|
|
2692
|
+
if (childType === parentType)
|
|
2693
|
+
return true;
|
|
2694
|
+
let current = childType;
|
|
2695
|
+
while (current !== null) {
|
|
2696
|
+
if (current === parentType)
|
|
2697
|
+
return true;
|
|
2698
|
+
current = ENTITY_HIERARCHY[current];
|
|
2699
|
+
}
|
|
2700
|
+
return false;
|
|
2701
|
+
}
|
|
2702
|
+
/** Push a new self type context */
|
|
2703
|
+
pushSelfType(entityType) {
|
|
2704
|
+
this.selfTypeStack.push(entityType);
|
|
2705
|
+
}
|
|
2706
|
+
/** Pop self type context */
|
|
2707
|
+
popSelfType() {
|
|
2708
|
+
if (this.selfTypeStack.length > 1) {
|
|
2709
|
+
this.selfTypeStack.pop();
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
/** Get current @s type */
|
|
2713
|
+
getCurrentSelfType() {
|
|
2714
|
+
return this.selfTypeStack[this.selfTypeStack.length - 1];
|
|
2715
|
+
}
|
|
2227
2716
|
typesMatch(expected, actual) {
|
|
2228
2717
|
if (expected.kind !== actual.kind)
|
|
2229
2718
|
return false;
|
|
@@ -2244,6 +2733,12 @@ var require_typechecker = __commonJS({
|
|
|
2244
2733
|
if (expected.kind === "function_type" && actual.kind === "function_type") {
|
|
2245
2734
|
return expected.params.length === actual.params.length && expected.params.every((param, index) => this.typesMatch(param, actual.params[index])) && this.typesMatch(expected.return, actual.return);
|
|
2246
2735
|
}
|
|
2736
|
+
if (expected.kind === "entity" && actual.kind === "entity") {
|
|
2737
|
+
return this.isEntitySubtype(actual.entityType, expected.entityType);
|
|
2738
|
+
}
|
|
2739
|
+
if (expected.kind === "selector" && actual.kind === "entity") {
|
|
2740
|
+
return true;
|
|
2741
|
+
}
|
|
2247
2742
|
return false;
|
|
2248
2743
|
}
|
|
2249
2744
|
typeToString(type) {
|
|
@@ -2258,6 +2753,12 @@ var require_typechecker = __commonJS({
|
|
|
2258
2753
|
return type.name;
|
|
2259
2754
|
case "function_type":
|
|
2260
2755
|
return `(${type.params.map((param) => this.typeToString(param)).join(", ")}) -> ${this.typeToString(type.return)}`;
|
|
2756
|
+
case "entity":
|
|
2757
|
+
return type.entityType;
|
|
2758
|
+
case "selector":
|
|
2759
|
+
return "selector";
|
|
2760
|
+
default:
|
|
2761
|
+
return "unknown";
|
|
2261
2762
|
}
|
|
2262
2763
|
}
|
|
2263
2764
|
normalizeType(type) {
|
|
@@ -2274,6 +2775,12 @@ var require_typechecker = __commonJS({
|
|
|
2274
2775
|
if ((type.kind === "struct" || type.kind === "enum") && this.enums.has(type.name)) {
|
|
2275
2776
|
return { kind: "enum", name: type.name };
|
|
2276
2777
|
}
|
|
2778
|
+
if (type.kind === "struct" && type.name in ENTITY_HIERARCHY) {
|
|
2779
|
+
return { kind: "entity", entityType: type.name };
|
|
2780
|
+
}
|
|
2781
|
+
if (type.kind === "named" && type.name in ENTITY_HIERARCHY) {
|
|
2782
|
+
return { kind: "entity", entityType: type.name };
|
|
2783
|
+
}
|
|
2277
2784
|
return type;
|
|
2278
2785
|
}
|
|
2279
2786
|
};
|
|
@@ -2385,10 +2892,49 @@ var require_builder = __commonJS({
|
|
|
2385
2892
|
var require_lowering = __commonJS({
|
|
2386
2893
|
"../../dist/lowering/index.js"(exports2) {
|
|
2387
2894
|
"use strict";
|
|
2895
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
2896
|
+
if (k2 === void 0) k2 = k;
|
|
2897
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
2898
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
2899
|
+
desc = { enumerable: true, get: function() {
|
|
2900
|
+
return m[k];
|
|
2901
|
+
} };
|
|
2902
|
+
}
|
|
2903
|
+
Object.defineProperty(o, k2, desc);
|
|
2904
|
+
}) : (function(o, m, k, k2) {
|
|
2905
|
+
if (k2 === void 0) k2 = k;
|
|
2906
|
+
o[k2] = m[k];
|
|
2907
|
+
}));
|
|
2908
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
2909
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
2910
|
+
}) : function(o, v) {
|
|
2911
|
+
o["default"] = v;
|
|
2912
|
+
});
|
|
2913
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
|
|
2914
|
+
var ownKeys = function(o) {
|
|
2915
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
2916
|
+
var ar = [];
|
|
2917
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
2918
|
+
return ar;
|
|
2919
|
+
};
|
|
2920
|
+
return ownKeys(o);
|
|
2921
|
+
};
|
|
2922
|
+
return function(mod) {
|
|
2923
|
+
if (mod && mod.__esModule) return mod;
|
|
2924
|
+
var result = {};
|
|
2925
|
+
if (mod != null) {
|
|
2926
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
2927
|
+
}
|
|
2928
|
+
__setModuleDefault(result, mod);
|
|
2929
|
+
return result;
|
|
2930
|
+
};
|
|
2931
|
+
})();
|
|
2388
2932
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2389
2933
|
exports2.Lowering = void 0;
|
|
2390
2934
|
var builder_1 = require_builder();
|
|
2391
2935
|
var diagnostics_1 = require_diagnostics();
|
|
2936
|
+
var path = __importStar(require("path"));
|
|
2937
|
+
var types_1 = require_types();
|
|
2392
2938
|
var BUILTINS2 = {
|
|
2393
2939
|
say: ([msg]) => `say ${msg}`,
|
|
2394
2940
|
tell: ([sel, msg]) => `tellraw ${sel} {"text":"${msg}"}`,
|
|
@@ -2397,9 +2943,10 @@ var require_lowering = __commonJS({
|
|
|
2397
2943
|
subtitle: ([sel, msg]) => `title ${sel} subtitle {"text":"${msg}"}`,
|
|
2398
2944
|
title_times: ([sel, fadeIn, stay, fadeOut]) => `title ${sel} times ${fadeIn} ${stay} ${fadeOut}`,
|
|
2399
2945
|
announce: ([msg]) => `tellraw @a {"text":"${msg}"}`,
|
|
2400
|
-
give: ([sel, item, count]) => `give ${sel} ${item} ${count ?? "1"}`,
|
|
2946
|
+
give: ([sel, item, count, nbt]) => nbt ? `give ${sel} ${item}${nbt} ${count ?? "1"}` : `give ${sel} ${item} ${count ?? "1"}`,
|
|
2401
2947
|
kill: ([sel]) => `kill ${sel ?? "@s"}`,
|
|
2402
2948
|
effect: ([sel, eff, dur, amp]) => `effect give ${sel} ${eff} ${dur ?? "30"} ${amp ?? "0"}`,
|
|
2949
|
+
effect_clear: ([sel, eff]) => eff ? `effect clear ${sel} ${eff}` : `effect clear ${sel}`,
|
|
2403
2950
|
summon: ([type, x, y, z, nbt]) => {
|
|
2404
2951
|
const pos = [x ?? "~", y ?? "~", z ?? "~"].join(" ");
|
|
2405
2952
|
return nbt ? `summon ${type} ${pos} ${nbt}` : `summon ${type} ${pos}`;
|
|
@@ -2475,14 +3022,48 @@ var require_lowering = __commonJS({
|
|
|
2475
3022
|
// Special handling
|
|
2476
3023
|
team_option: () => null,
|
|
2477
3024
|
// Special handling
|
|
2478
|
-
data_get: () => null
|
|
3025
|
+
data_get: () => null,
|
|
2479
3026
|
// Special handling (returns value from NBT)
|
|
3027
|
+
data_merge: () => null,
|
|
3028
|
+
// Special handling (merge NBT)
|
|
3029
|
+
set_new: () => null,
|
|
3030
|
+
// Special handling (returns set ID)
|
|
3031
|
+
set_add: () => null,
|
|
3032
|
+
// Special handling
|
|
3033
|
+
set_contains: () => null,
|
|
3034
|
+
// Special handling (returns 1/0)
|
|
3035
|
+
set_remove: () => null,
|
|
3036
|
+
// Special handling
|
|
3037
|
+
set_clear: () => null,
|
|
3038
|
+
// Special handling
|
|
3039
|
+
setTimeout: () => null,
|
|
3040
|
+
// Special handling
|
|
3041
|
+
setInterval: () => null,
|
|
3042
|
+
// Special handling
|
|
3043
|
+
clearInterval: () => null
|
|
3044
|
+
// Special handling
|
|
2480
3045
|
};
|
|
2481
3046
|
function getSpan(node) {
|
|
2482
3047
|
return node?.span;
|
|
2483
3048
|
}
|
|
2484
3049
|
var NAMESPACED_ENTITY_TYPE_RE = /^[a-z0-9_.-]+:[a-z0-9_./-]+$/;
|
|
2485
3050
|
var BARE_ENTITY_TYPE_RE = /^[a-z0-9_./-]+$/;
|
|
3051
|
+
var ENTITY_TO_MC_TYPE = {
|
|
3052
|
+
Player: "player",
|
|
3053
|
+
Zombie: "zombie",
|
|
3054
|
+
Skeleton: "skeleton",
|
|
3055
|
+
Creeper: "creeper",
|
|
3056
|
+
Spider: "spider",
|
|
3057
|
+
Enderman: "enderman",
|
|
3058
|
+
Pig: "pig",
|
|
3059
|
+
Cow: "cow",
|
|
3060
|
+
Sheep: "sheep",
|
|
3061
|
+
Chicken: "chicken",
|
|
3062
|
+
Villager: "villager",
|
|
3063
|
+
ArmorStand: "armor_stand",
|
|
3064
|
+
Item: "item",
|
|
3065
|
+
Arrow: "arrow"
|
|
3066
|
+
};
|
|
2486
3067
|
function normalizeSelector(selector, warnings) {
|
|
2487
3068
|
return selector.replace(/type=([^,\]]+)/g, (match, entityType) => {
|
|
2488
3069
|
const trimmed = entityType.trim();
|
|
@@ -2516,17 +3097,23 @@ var require_lowering = __commonJS({
|
|
|
2516
3097
|
return `${emitCoord(pos.x)} ${emitCoord(pos.y)} ${emitCoord(pos.z)}`;
|
|
2517
3098
|
}
|
|
2518
3099
|
var Lowering = class {
|
|
2519
|
-
constructor(namespace) {
|
|
3100
|
+
constructor(namespace, sourceRanges = []) {
|
|
2520
3101
|
this.functions = [];
|
|
2521
3102
|
this.globals = [];
|
|
3103
|
+
this.globalNames = /* @__PURE__ */ new Map();
|
|
2522
3104
|
this.fnDecls = /* @__PURE__ */ new Map();
|
|
3105
|
+
this.implMethods = /* @__PURE__ */ new Map();
|
|
2523
3106
|
this.specializedFunctions = /* @__PURE__ */ new Map();
|
|
2524
3107
|
this.currentFn = "";
|
|
2525
3108
|
this.foreachCounter = 0;
|
|
2526
3109
|
this.lambdaCounter = 0;
|
|
3110
|
+
this.timeoutCounter = 0;
|
|
3111
|
+
this.intervalCounter = 0;
|
|
2527
3112
|
this.warnings = [];
|
|
2528
3113
|
this.varMap = /* @__PURE__ */ new Map();
|
|
2529
3114
|
this.lambdaBindings = /* @__PURE__ */ new Map();
|
|
3115
|
+
this.intervalBindings = /* @__PURE__ */ new Map();
|
|
3116
|
+
this.intervalFunctions = /* @__PURE__ */ new Map();
|
|
2530
3117
|
this.currentCallbackBindings = /* @__PURE__ */ new Map();
|
|
2531
3118
|
this.currentContext = {};
|
|
2532
3119
|
this.blockPosVars = /* @__PURE__ */ new Map();
|
|
@@ -2539,6 +3126,8 @@ var require_lowering = __commonJS({
|
|
|
2539
3126
|
this.floatVars = /* @__PURE__ */ new Set();
|
|
2540
3127
|
this.worldObjCounter = 0;
|
|
2541
3128
|
this.namespace = namespace;
|
|
3129
|
+
this.sourceRanges = sourceRanges;
|
|
3130
|
+
LoweringBuilder.resetTempCounter();
|
|
2542
3131
|
}
|
|
2543
3132
|
lower(program) {
|
|
2544
3133
|
this.namespace = program.namespace;
|
|
@@ -2560,13 +3149,37 @@ var require_lowering = __commonJS({
|
|
|
2560
3149
|
this.constValues.set(constDecl.name, constDecl.value);
|
|
2561
3150
|
this.varTypes.set(constDecl.name, this.normalizeType(constDecl.type));
|
|
2562
3151
|
}
|
|
3152
|
+
for (const g of program.globals ?? []) {
|
|
3153
|
+
this.globalNames.set(g.name, { mutable: g.mutable });
|
|
3154
|
+
this.varTypes.set(g.name, this.normalizeType(g.type));
|
|
3155
|
+
const initValue = g.init.kind === "int_lit" ? g.init.value : 0;
|
|
3156
|
+
this.globals.push({ name: `$${g.name}`, init: initValue });
|
|
3157
|
+
}
|
|
2563
3158
|
for (const fn of program.declarations) {
|
|
2564
3159
|
this.fnDecls.set(fn.name, fn);
|
|
2565
3160
|
this.functionDefaults.set(fn.name, fn.params.map((param) => param.default));
|
|
2566
3161
|
}
|
|
3162
|
+
for (const implBlock of program.implBlocks ?? []) {
|
|
3163
|
+
let methods = this.implMethods.get(implBlock.typeName);
|
|
3164
|
+
if (!methods) {
|
|
3165
|
+
methods = /* @__PURE__ */ new Map();
|
|
3166
|
+
this.implMethods.set(implBlock.typeName, methods);
|
|
3167
|
+
}
|
|
3168
|
+
for (const method of implBlock.methods) {
|
|
3169
|
+
const loweredName = `${implBlock.typeName}_${method.name}`;
|
|
3170
|
+
methods.set(method.name, { fn: method, loweredName });
|
|
3171
|
+
this.fnDecls.set(loweredName, method);
|
|
3172
|
+
this.functionDefaults.set(loweredName, method.params.map((param) => param.default));
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
2567
3175
|
for (const fn of program.declarations) {
|
|
2568
3176
|
this.lowerFn(fn);
|
|
2569
3177
|
}
|
|
3178
|
+
for (const implBlock of program.implBlocks ?? []) {
|
|
3179
|
+
for (const method of implBlock.methods) {
|
|
3180
|
+
this.lowerFn(method, { name: `${implBlock.typeName}_${method.name}` });
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
2570
3183
|
return (0, builder_1.buildModule)(this.namespace, this.functions, this.globals);
|
|
2571
3184
|
}
|
|
2572
3185
|
// -------------------------------------------------------------------------
|
|
@@ -2575,20 +3188,44 @@ var require_lowering = __commonJS({
|
|
|
2575
3188
|
lowerFn(fn, options = {}) {
|
|
2576
3189
|
const loweredName = options.name ?? fn.name;
|
|
2577
3190
|
const callbackBindings = options.callbackBindings ?? /* @__PURE__ */ new Map();
|
|
2578
|
-
const
|
|
3191
|
+
const stdlibCallSite = options.stdlibCallSite;
|
|
3192
|
+
const staticEventDec = fn.decorators.find((d) => d.name === "on");
|
|
3193
|
+
const eventType = staticEventDec?.args?.eventType;
|
|
3194
|
+
const eventParamSpecs = eventType && (0, types_1.isEventTypeName)(eventType) ? (0, types_1.getEventParamSpecs)(eventType) : [];
|
|
3195
|
+
const runtimeParams = staticEventDec ? [] : fn.params.filter((param) => !callbackBindings.has(param.name));
|
|
2579
3196
|
this.currentFn = loweredName;
|
|
3197
|
+
this.currentStdlibCallSite = stdlibCallSite;
|
|
2580
3198
|
this.foreachCounter = 0;
|
|
2581
3199
|
this.varMap = /* @__PURE__ */ new Map();
|
|
2582
3200
|
this.lambdaBindings = /* @__PURE__ */ new Map();
|
|
3201
|
+
this.intervalBindings = /* @__PURE__ */ new Map();
|
|
2583
3202
|
this.currentCallbackBindings = new Map(callbackBindings);
|
|
2584
3203
|
this.currentContext = {};
|
|
2585
3204
|
this.blockPosVars = /* @__PURE__ */ new Map();
|
|
2586
3205
|
this.stringValues = /* @__PURE__ */ new Map();
|
|
2587
3206
|
this.builder = new LoweringBuilder();
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
3207
|
+
if (staticEventDec) {
|
|
3208
|
+
for (let i = 0; i < fn.params.length; i++) {
|
|
3209
|
+
const param = fn.params[i];
|
|
3210
|
+
const expected = eventParamSpecs[i];
|
|
3211
|
+
const normalizedType = this.normalizeType(param.type);
|
|
3212
|
+
this.varTypes.set(param.name, normalizedType);
|
|
3213
|
+
if (expected?.type.kind === "entity") {
|
|
3214
|
+
this.varMap.set(param.name, "@s");
|
|
3215
|
+
continue;
|
|
3216
|
+
}
|
|
3217
|
+
if (expected?.type.kind === "named" && expected.type.name === "string") {
|
|
3218
|
+
this.stringValues.set(param.name, "");
|
|
3219
|
+
continue;
|
|
3220
|
+
}
|
|
3221
|
+
this.varMap.set(param.name, `$${param.name}`);
|
|
3222
|
+
}
|
|
3223
|
+
} else {
|
|
3224
|
+
for (const param of runtimeParams) {
|
|
3225
|
+
const paramName = param.name;
|
|
3226
|
+
this.varMap.set(paramName, `$${paramName}`);
|
|
3227
|
+
this.varTypes.set(paramName, this.normalizeType(param.type));
|
|
3228
|
+
}
|
|
2592
3229
|
}
|
|
2593
3230
|
for (const param of fn.params) {
|
|
2594
3231
|
if (callbackBindings.has(param.name)) {
|
|
@@ -2601,6 +3238,15 @@ var require_lowering = __commonJS({
|
|
|
2601
3238
|
const varName = `$${paramName}`;
|
|
2602
3239
|
this.builder.emitAssign(varName, { kind: "var", name: `$p${i}` });
|
|
2603
3240
|
}
|
|
3241
|
+
if (staticEventDec) {
|
|
3242
|
+
for (let i = 0; i < fn.params.length; i++) {
|
|
3243
|
+
const param = fn.params[i];
|
|
3244
|
+
const expected = eventParamSpecs[i];
|
|
3245
|
+
if (expected?.type.kind === "named" && expected.type.name !== "string") {
|
|
3246
|
+
this.builder.emitAssign(`$${param.name}`, { kind: "const", value: 0 });
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
2604
3250
|
this.lowerBlock(fn.body);
|
|
2605
3251
|
if (!this.builder.isBlockSealed()) {
|
|
2606
3252
|
this.builder.emitReturn();
|
|
@@ -2635,6 +3281,15 @@ var require_lowering = __commonJS({
|
|
|
2635
3281
|
break;
|
|
2636
3282
|
}
|
|
2637
3283
|
}
|
|
3284
|
+
if (eventType && (0, types_1.isEventTypeName)(eventType)) {
|
|
3285
|
+
irFn.eventHandler = {
|
|
3286
|
+
eventType,
|
|
3287
|
+
tag: types_1.EVENT_TYPES[eventType].tag
|
|
3288
|
+
};
|
|
3289
|
+
}
|
|
3290
|
+
if (fn.decorators.some((d) => d.name === "load")) {
|
|
3291
|
+
irFn.isLoadInit = true;
|
|
3292
|
+
}
|
|
2638
3293
|
if (tickRate && tickRate > 1) {
|
|
2639
3294
|
this.wrapWithTickRate(irFn, tickRate);
|
|
2640
3295
|
}
|
|
@@ -2646,7 +3301,7 @@ var require_lowering = __commonJS({
|
|
|
2646
3301
|
}
|
|
2647
3302
|
wrapWithTickRate(fn, rate) {
|
|
2648
3303
|
const counterVar = `$__tick_${fn.name}`;
|
|
2649
|
-
this.globals.push(counterVar);
|
|
3304
|
+
this.globals.push({ name: counterVar, init: 0 });
|
|
2650
3305
|
const entry = fn.blocks[0];
|
|
2651
3306
|
const originalInstrs = [...entry.instrs];
|
|
2652
3307
|
const originalTerm = entry.term;
|
|
@@ -2734,6 +3389,9 @@ var require_lowering = __commonJS({
|
|
|
2734
3389
|
}
|
|
2735
3390
|
}
|
|
2736
3391
|
lowerLetStmt(stmt) {
|
|
3392
|
+
if (this.currentContext.binding === stmt.name) {
|
|
3393
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", `Cannot redeclare foreach binding '${stmt.name}'`, stmt.span ?? { line: 0, col: 0 });
|
|
3394
|
+
}
|
|
2737
3395
|
const varName = `$${stmt.name}`;
|
|
2738
3396
|
this.varMap.set(stmt.name, varName);
|
|
2739
3397
|
const declaredType = stmt.type ? this.normalizeType(stmt.type) : this.inferExprType(stmt.init);
|
|
@@ -2748,15 +3406,24 @@ var require_lowering = __commonJS({
|
|
|
2748
3406
|
this.lambdaBindings.set(stmt.name, lambdaName);
|
|
2749
3407
|
return;
|
|
2750
3408
|
}
|
|
3409
|
+
if (stmt.init.kind === "call" && stmt.init.fn === "setInterval") {
|
|
3410
|
+
const value2 = this.lowerExpr(stmt.init);
|
|
3411
|
+
const intervalFn = this.intervalFunctions.get(value2.kind === "const" ? value2.value : NaN);
|
|
3412
|
+
if (intervalFn) {
|
|
3413
|
+
this.intervalBindings.set(stmt.name, intervalFn);
|
|
3414
|
+
}
|
|
3415
|
+
this.builder.emitAssign(varName, value2);
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
2751
3418
|
if (stmt.init.kind === "struct_lit" && stmt.type?.kind === "struct") {
|
|
2752
3419
|
const structName = stmt.type.name.toLowerCase();
|
|
2753
3420
|
for (const field of stmt.init.fields) {
|
|
2754
|
-
const
|
|
3421
|
+
const path2 = `rs:heap ${structName}_${stmt.name}.${field.name}`;
|
|
2755
3422
|
const fieldValue = this.lowerExpr(field.value);
|
|
2756
3423
|
if (fieldValue.kind === "const") {
|
|
2757
|
-
this.builder.emitRaw(`data modify storage ${
|
|
3424
|
+
this.builder.emitRaw(`data modify storage ${path2} set value ${fieldValue.value}`);
|
|
2758
3425
|
} else if (fieldValue.kind === "var") {
|
|
2759
|
-
this.builder.emitRaw(`execute store result storage ${
|
|
3426
|
+
this.builder.emitRaw(`execute store result storage ${path2} int 1 run scoreboard players get ${fieldValue.name} rs`);
|
|
2760
3427
|
}
|
|
2761
3428
|
}
|
|
2762
3429
|
return;
|
|
@@ -2774,6 +3441,12 @@ var require_lowering = __commonJS({
|
|
|
2774
3441
|
}
|
|
2775
3442
|
return;
|
|
2776
3443
|
}
|
|
3444
|
+
if (stmt.init.kind === "call" && stmt.init.fn === "set_new") {
|
|
3445
|
+
const setId = `__set_${this.foreachCounter++}`;
|
|
3446
|
+
this.builder.emitRaw(`data modify storage rs:sets ${setId} set value []`);
|
|
3447
|
+
this.stringValues.set(stmt.name, setId);
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
2777
3450
|
if (stmt.init.kind === "call" && stmt.init.fn === "spawn_object") {
|
|
2778
3451
|
const value2 = this.lowerExpr(stmt.init);
|
|
2779
3452
|
if (value2.kind === "var" && value2.name.startsWith("@e[tag=__rs_obj_")) {
|
|
@@ -2803,6 +3476,10 @@ var require_lowering = __commonJS({
|
|
|
2803
3476
|
}
|
|
2804
3477
|
}
|
|
2805
3478
|
lowerIfStmt(stmt) {
|
|
3479
|
+
if (stmt.cond.kind === "is_check") {
|
|
3480
|
+
this.lowerIsCheckIfStmt(stmt);
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
2806
3483
|
const condVar = this.lowerExpr(stmt.cond);
|
|
2807
3484
|
const condName = this.operandToVar(condVar);
|
|
2808
3485
|
const thenLabel = this.builder.freshLabel("then");
|
|
@@ -2823,6 +3500,40 @@ var require_lowering = __commonJS({
|
|
|
2823
3500
|
}
|
|
2824
3501
|
this.builder.startBlock(mergeLabel);
|
|
2825
3502
|
}
|
|
3503
|
+
lowerIsCheckIfStmt(stmt) {
|
|
3504
|
+
const cond = stmt.cond;
|
|
3505
|
+
if (cond.kind !== "is_check") {
|
|
3506
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", "Internal error: expected 'is' check condition", stmt.span ?? { line: 0, col: 0 });
|
|
3507
|
+
}
|
|
3508
|
+
if (stmt.else_) {
|
|
3509
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", "'is' checks with else branches are not yet supported", cond.span ?? stmt.span ?? { line: 0, col: 0 });
|
|
3510
|
+
}
|
|
3511
|
+
const selector = this.exprToEntitySelector(cond.expr);
|
|
3512
|
+
if (!selector) {
|
|
3513
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", "'is' checks require an entity selector or entity binding", cond.span ?? stmt.span ?? { line: 0, col: 0 });
|
|
3514
|
+
}
|
|
3515
|
+
const mcType = ENTITY_TO_MC_TYPE[cond.entityType];
|
|
3516
|
+
if (!mcType) {
|
|
3517
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", `Cannot lower entity type check for '${cond.entityType}'`, cond.span ?? stmt.span ?? { line: 0, col: 0 });
|
|
3518
|
+
}
|
|
3519
|
+
const thenFnName = `${this.currentFn}/then_${this.foreachCounter++}`;
|
|
3520
|
+
this.builder.emitRaw(`execute if entity ${this.appendTypeFilter(selector, mcType)} run function ${this.namespace}:${thenFnName}`);
|
|
3521
|
+
const savedBuilder = this.builder;
|
|
3522
|
+
const savedVarMap = new Map(this.varMap);
|
|
3523
|
+
const savedBlockPosVars = new Map(this.blockPosVars);
|
|
3524
|
+
this.builder = new LoweringBuilder();
|
|
3525
|
+
this.varMap = new Map(savedVarMap);
|
|
3526
|
+
this.blockPosVars = new Map(savedBlockPosVars);
|
|
3527
|
+
this.builder.startBlock("entry");
|
|
3528
|
+
this.lowerBlock(stmt.then);
|
|
3529
|
+
if (!this.builder.isBlockSealed()) {
|
|
3530
|
+
this.builder.emitReturn();
|
|
3531
|
+
}
|
|
3532
|
+
this.functions.push(this.builder.build(thenFnName, [], false));
|
|
3533
|
+
this.builder = savedBuilder;
|
|
3534
|
+
this.varMap = savedVarMap;
|
|
3535
|
+
this.blockPosVars = savedBlockPosVars;
|
|
3536
|
+
}
|
|
2826
3537
|
lowerWhileStmt(stmt) {
|
|
2827
3538
|
const checkLabel = this.builder.freshLabel("loop_check");
|
|
2828
3539
|
const bodyLabel = this.builder.freshLabel("loop_body");
|
|
@@ -3093,10 +3804,20 @@ var require_lowering = __commonJS({
|
|
|
3093
3804
|
parts.push(`at ${this.selectorToString(sub.selector)}`);
|
|
3094
3805
|
break;
|
|
3095
3806
|
case "if_entity":
|
|
3096
|
-
|
|
3807
|
+
if (sub.selector) {
|
|
3808
|
+
parts.push(`if entity ${this.selectorToString(sub.selector)}`);
|
|
3809
|
+
} else if (sub.varName) {
|
|
3810
|
+
const sel = { kind: "@s", filters: sub.filters };
|
|
3811
|
+
parts.push(`if entity ${this.selectorToString(sel)}`);
|
|
3812
|
+
}
|
|
3097
3813
|
break;
|
|
3098
3814
|
case "unless_entity":
|
|
3099
|
-
|
|
3815
|
+
if (sub.selector) {
|
|
3816
|
+
parts.push(`unless entity ${this.selectorToString(sub.selector)}`);
|
|
3817
|
+
} else if (sub.varName) {
|
|
3818
|
+
const sel = { kind: "@s", filters: sub.filters };
|
|
3819
|
+
parts.push(`unless entity ${this.selectorToString(sel)}`);
|
|
3820
|
+
}
|
|
3100
3821
|
break;
|
|
3101
3822
|
case "in":
|
|
3102
3823
|
parts.push(`in ${sub.dimension}`);
|
|
@@ -3181,12 +3902,16 @@ var require_lowering = __commonJS({
|
|
|
3181
3902
|
return { kind: "var", name: this.selectorToString(expr.sel) };
|
|
3182
3903
|
case "binary":
|
|
3183
3904
|
return this.lowerBinaryExpr(expr);
|
|
3905
|
+
case "is_check":
|
|
3906
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", "'is' checks are only supported as if conditions", expr.span ?? { line: 0, col: 0 });
|
|
3184
3907
|
case "unary":
|
|
3185
3908
|
return this.lowerUnaryExpr(expr);
|
|
3186
3909
|
case "assign":
|
|
3187
3910
|
return this.lowerAssignExpr(expr);
|
|
3188
3911
|
case "call":
|
|
3189
3912
|
return this.lowerCallExpr(expr);
|
|
3913
|
+
case "static_call":
|
|
3914
|
+
return this.lowerStaticCallExpr(expr);
|
|
3190
3915
|
case "invoke":
|
|
3191
3916
|
return this.lowerInvokeExpr(expr);
|
|
3192
3917
|
case "member_assign":
|
|
@@ -3213,9 +3938,9 @@ var require_lowering = __commonJS({
|
|
|
3213
3938
|
}
|
|
3214
3939
|
if (varType?.kind === "struct") {
|
|
3215
3940
|
const structName = varType.name.toLowerCase();
|
|
3216
|
-
const
|
|
3941
|
+
const path2 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
|
|
3217
3942
|
const dst = this.builder.freshTemp();
|
|
3218
|
-
this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${
|
|
3943
|
+
this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path2}`);
|
|
3219
3944
|
return { kind: "var", name: dst };
|
|
3220
3945
|
}
|
|
3221
3946
|
if (varType?.kind === "array" && expr.field === "len") {
|
|
@@ -3253,20 +3978,20 @@ var require_lowering = __commonJS({
|
|
|
3253
3978
|
}
|
|
3254
3979
|
if (varType?.kind === "struct") {
|
|
3255
3980
|
const structName = varType.name.toLowerCase();
|
|
3256
|
-
const
|
|
3981
|
+
const path2 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
|
|
3257
3982
|
const value2 = this.lowerExpr(expr.value);
|
|
3258
3983
|
if (expr.op === "=") {
|
|
3259
3984
|
if (value2.kind === "const") {
|
|
3260
|
-
this.builder.emitRaw(`data modify storage ${
|
|
3985
|
+
this.builder.emitRaw(`data modify storage ${path2} set value ${value2.value}`);
|
|
3261
3986
|
} else if (value2.kind === "var") {
|
|
3262
|
-
this.builder.emitRaw(`execute store result storage ${
|
|
3987
|
+
this.builder.emitRaw(`execute store result storage ${path2} int 1 run scoreboard players get ${value2.name} rs`);
|
|
3263
3988
|
}
|
|
3264
3989
|
} else {
|
|
3265
3990
|
const dst = this.builder.freshTemp();
|
|
3266
|
-
this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${
|
|
3991
|
+
this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path2}`);
|
|
3267
3992
|
const binOp = expr.op.slice(0, -1);
|
|
3268
3993
|
this.builder.emitBinop(dst, { kind: "var", name: dst }, binOp, value2);
|
|
3269
|
-
this.builder.emitRaw(`execute store result storage ${
|
|
3994
|
+
this.builder.emitRaw(`execute store result storage ${path2} int 1 run scoreboard players get ${dst} rs`);
|
|
3270
3995
|
}
|
|
3271
3996
|
return { kind: "const", value: 0 };
|
|
3272
3997
|
}
|
|
@@ -3345,6 +4070,13 @@ var require_lowering = __commonJS({
|
|
|
3345
4070
|
return { kind: "var", name: dst };
|
|
3346
4071
|
}
|
|
3347
4072
|
lowerAssignExpr(expr) {
|
|
4073
|
+
if (this.constValues.has(expr.target)) {
|
|
4074
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", `Cannot assign to constant '${expr.target}'`, getSpan(expr) ?? { line: 1, col: 1 });
|
|
4075
|
+
}
|
|
4076
|
+
const globalInfo = this.globalNames.get(expr.target);
|
|
4077
|
+
if (globalInfo && !globalInfo.mutable) {
|
|
4078
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", `Cannot assign to constant '${expr.target}'`, getSpan(expr) ?? { line: 1, col: 1 });
|
|
4079
|
+
}
|
|
3348
4080
|
const blockPosValue = this.resolveBlockPosExpr(expr.value);
|
|
3349
4081
|
if (blockPosValue) {
|
|
3350
4082
|
this.blockPosVars.set(expr.target, blockPosValue);
|
|
@@ -3452,6 +4184,10 @@ var require_lowering = __commonJS({
|
|
|
3452
4184
|
if (callbackTarget) {
|
|
3453
4185
|
return this.emitDirectFunctionCall(callbackTarget, expr.args);
|
|
3454
4186
|
}
|
|
4187
|
+
const implMethod = this.resolveInstanceMethod(expr);
|
|
4188
|
+
if (implMethod) {
|
|
4189
|
+
return this.emitMethodCall(implMethod.loweredName, implMethod.fn, expr.args);
|
|
4190
|
+
}
|
|
3455
4191
|
const fnDecl = this.fnDecls.get(expr.fn);
|
|
3456
4192
|
const defaultArgs = this.functionDefaults.get(expr.fn) ?? [];
|
|
3457
4193
|
const fullArgs = [...expr.args];
|
|
@@ -3477,11 +4213,17 @@ var require_lowering = __commonJS({
|
|
|
3477
4213
|
}
|
|
3478
4214
|
runtimeArgs.push(fullArgs[i]);
|
|
3479
4215
|
}
|
|
3480
|
-
const
|
|
4216
|
+
const stdlibCallSite = this.getStdlibCallSiteContext(fnDecl, getSpan(expr));
|
|
4217
|
+
const targetFn = callbackBindings.size > 0 || stdlibCallSite ? this.ensureSpecializedFunctionWithContext(fnDecl, callbackBindings, stdlibCallSite) : expr.fn;
|
|
3481
4218
|
return this.emitDirectFunctionCall(targetFn, runtimeArgs);
|
|
3482
4219
|
}
|
|
3483
4220
|
return this.emitDirectFunctionCall(expr.fn, fullArgs);
|
|
3484
4221
|
}
|
|
4222
|
+
lowerStaticCallExpr(expr) {
|
|
4223
|
+
const method = this.implMethods.get(expr.type)?.get(expr.method);
|
|
4224
|
+
const targetFn = method?.loweredName ?? `${expr.type}_${expr.method}`;
|
|
4225
|
+
return this.emitMethodCall(targetFn, method?.fn, expr.args);
|
|
4226
|
+
}
|
|
3485
4227
|
lowerInvokeExpr(expr) {
|
|
3486
4228
|
if (expr.callee.kind === "lambda") {
|
|
3487
4229
|
if (!Array.isArray(expr.callee.body)) {
|
|
@@ -3526,6 +4268,18 @@ var require_lowering = __commonJS({
|
|
|
3526
4268
|
this.builder.emitCall(fn, loweredArgs, dst);
|
|
3527
4269
|
return { kind: "var", name: dst };
|
|
3528
4270
|
}
|
|
4271
|
+
emitMethodCall(fn, fnDecl, args) {
|
|
4272
|
+
const defaultArgs = this.functionDefaults.get(fn) ?? fnDecl?.params.map((param) => param.default) ?? [];
|
|
4273
|
+
const fullArgs = [...args];
|
|
4274
|
+
for (let i = fullArgs.length; i < defaultArgs.length; i++) {
|
|
4275
|
+
const defaultExpr = defaultArgs[i];
|
|
4276
|
+
if (!defaultExpr) {
|
|
4277
|
+
break;
|
|
4278
|
+
}
|
|
4279
|
+
fullArgs.push(defaultExpr);
|
|
4280
|
+
}
|
|
4281
|
+
return this.emitDirectFunctionCall(fn, fullArgs);
|
|
4282
|
+
}
|
|
3529
4283
|
resolveFunctionRefExpr(expr) {
|
|
3530
4284
|
if (expr.kind === "lambda") {
|
|
3531
4285
|
return this.lowerLambdaExpr(expr);
|
|
@@ -3539,7 +4293,14 @@ var require_lowering = __commonJS({
|
|
|
3539
4293
|
return this.lambdaBindings.get(name) ?? this.currentCallbackBindings.get(name) ?? null;
|
|
3540
4294
|
}
|
|
3541
4295
|
ensureSpecializedFunction(fn, callbackBindings) {
|
|
4296
|
+
return this.ensureSpecializedFunctionWithContext(fn, callbackBindings);
|
|
4297
|
+
}
|
|
4298
|
+
ensureSpecializedFunctionWithContext(fn, callbackBindings, stdlibCallSite) {
|
|
3542
4299
|
const parts = [...callbackBindings.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([param, target]) => `${param}_${target.replace(/[^a-zA-Z0-9_]/g, "_")}`);
|
|
4300
|
+
const callSiteHash = stdlibCallSite ? this.shortHash(this.serializeCallSite(stdlibCallSite)) : null;
|
|
4301
|
+
if (callSiteHash) {
|
|
4302
|
+
parts.push(`callsite_${callSiteHash}`);
|
|
4303
|
+
}
|
|
3543
4304
|
const key = `${fn.name}::${parts.join("::")}`;
|
|
3544
4305
|
const cached = this.specializedFunctions.get(key);
|
|
3545
4306
|
if (cached) {
|
|
@@ -3548,7 +4309,7 @@ var require_lowering = __commonJS({
|
|
|
3548
4309
|
const specializedName = `${fn.name}__${parts.join("__")}`;
|
|
3549
4310
|
this.specializedFunctions.set(key, specializedName);
|
|
3550
4311
|
this.withSavedFunctionState(() => {
|
|
3551
|
-
this.lowerFn(fn, { name: specializedName, callbackBindings });
|
|
4312
|
+
this.lowerFn(fn, { name: specializedName, callbackBindings, stdlibCallSite });
|
|
3552
4313
|
});
|
|
3553
4314
|
return specializedName;
|
|
3554
4315
|
}
|
|
@@ -3571,10 +4332,12 @@ var require_lowering = __commonJS({
|
|
|
3571
4332
|
}
|
|
3572
4333
|
withSavedFunctionState(callback) {
|
|
3573
4334
|
const savedCurrentFn = this.currentFn;
|
|
4335
|
+
const savedStdlibCallSite = this.currentStdlibCallSite;
|
|
3574
4336
|
const savedForeachCounter = this.foreachCounter;
|
|
3575
4337
|
const savedBuilder = this.builder;
|
|
3576
4338
|
const savedVarMap = new Map(this.varMap);
|
|
3577
4339
|
const savedLambdaBindings = new Map(this.lambdaBindings);
|
|
4340
|
+
const savedIntervalBindings = new Map(this.intervalBindings);
|
|
3578
4341
|
const savedCallbackBindings = new Map(this.currentCallbackBindings);
|
|
3579
4342
|
const savedContext = this.currentContext;
|
|
3580
4343
|
const savedBlockPosVars = new Map(this.blockPosVars);
|
|
@@ -3584,10 +4347,12 @@ var require_lowering = __commonJS({
|
|
|
3584
4347
|
return callback();
|
|
3585
4348
|
} finally {
|
|
3586
4349
|
this.currentFn = savedCurrentFn;
|
|
4350
|
+
this.currentStdlibCallSite = savedStdlibCallSite;
|
|
3587
4351
|
this.foreachCounter = savedForeachCounter;
|
|
3588
4352
|
this.builder = savedBuilder;
|
|
3589
4353
|
this.varMap = savedVarMap;
|
|
3590
4354
|
this.lambdaBindings = savedLambdaBindings;
|
|
4355
|
+
this.intervalBindings = savedIntervalBindings;
|
|
3591
4356
|
this.currentCallbackBindings = savedCallbackBindings;
|
|
3592
4357
|
this.currentContext = savedContext;
|
|
3593
4358
|
this.blockPosVars = savedBlockPosVars;
|
|
@@ -3601,6 +4366,15 @@ var require_lowering = __commonJS({
|
|
|
3601
4366
|
this.builder.emitRaw(richTextCommand);
|
|
3602
4367
|
return { kind: "const", value: 0 };
|
|
3603
4368
|
}
|
|
4369
|
+
if (name === "setTimeout") {
|
|
4370
|
+
return this.lowerSetTimeout(args);
|
|
4371
|
+
}
|
|
4372
|
+
if (name === "setInterval") {
|
|
4373
|
+
return this.lowerSetInterval(args);
|
|
4374
|
+
}
|
|
4375
|
+
if (name === "clearInterval") {
|
|
4376
|
+
return this.lowerClearInterval(args, callSpan);
|
|
4377
|
+
}
|
|
3604
4378
|
if (name === "random") {
|
|
3605
4379
|
const dst = this.builder.freshTemp();
|
|
3606
4380
|
const min = args[0] ? this.exprToLiteral(args[0]) : "0";
|
|
@@ -3624,13 +4398,13 @@ var require_lowering = __commonJS({
|
|
|
3624
4398
|
if (name === "scoreboard_get" || name === "score") {
|
|
3625
4399
|
const dst = this.builder.freshTemp();
|
|
3626
4400
|
const player = this.exprToTargetString(args[0]);
|
|
3627
|
-
const objective = this.
|
|
4401
|
+
const objective = this.resolveScoreboardObjective(args[0], args[1], callSpan);
|
|
3628
4402
|
this.builder.emitRaw(`execute store result score ${dst} rs run scoreboard players get ${player} ${objective}`);
|
|
3629
4403
|
return { kind: "var", name: dst };
|
|
3630
4404
|
}
|
|
3631
4405
|
if (name === "scoreboard_set") {
|
|
3632
4406
|
const player = this.exprToTargetString(args[0]);
|
|
3633
|
-
const objective = this.
|
|
4407
|
+
const objective = this.resolveScoreboardObjective(args[0], args[1], callSpan);
|
|
3634
4408
|
const value = this.lowerExpr(args[2]);
|
|
3635
4409
|
if (value.kind === "const") {
|
|
3636
4410
|
this.builder.emitRaw(`scoreboard players set ${player} ${objective} ${value.value}`);
|
|
@@ -3641,7 +4415,7 @@ var require_lowering = __commonJS({
|
|
|
3641
4415
|
}
|
|
3642
4416
|
if (name === "scoreboard_display") {
|
|
3643
4417
|
const slot = this.exprToString(args[0]);
|
|
3644
|
-
const objective = this.
|
|
4418
|
+
const objective = this.resolveScoreboardObjective(void 0, args[1], callSpan);
|
|
3645
4419
|
this.builder.emitRaw(`scoreboard objectives setdisplay ${slot} ${objective}`);
|
|
3646
4420
|
return { kind: "const", value: 0 };
|
|
3647
4421
|
}
|
|
@@ -3651,14 +4425,14 @@ var require_lowering = __commonJS({
|
|
|
3651
4425
|
return { kind: "const", value: 0 };
|
|
3652
4426
|
}
|
|
3653
4427
|
if (name === "scoreboard_add_objective") {
|
|
3654
|
-
const objective = this.
|
|
4428
|
+
const objective = this.resolveScoreboardObjective(void 0, args[0], callSpan);
|
|
3655
4429
|
const criteria = this.exprToString(args[1]);
|
|
3656
4430
|
const displayName = args[2] ? ` ${this.exprToQuotedString(args[2])}` : "";
|
|
3657
4431
|
this.builder.emitRaw(`scoreboard objectives add ${objective} ${criteria}${displayName}`);
|
|
3658
4432
|
return { kind: "const", value: 0 };
|
|
3659
4433
|
}
|
|
3660
4434
|
if (name === "scoreboard_remove_objective") {
|
|
3661
|
-
const objective = this.
|
|
4435
|
+
const objective = this.resolveScoreboardObjective(void 0, args[0], callSpan);
|
|
3662
4436
|
this.builder.emitRaw(`scoreboard objectives remove ${objective}`);
|
|
3663
4437
|
return { kind: "const", value: 0 };
|
|
3664
4438
|
}
|
|
@@ -3730,11 +4504,57 @@ var require_lowering = __commonJS({
|
|
|
3730
4504
|
const dst = this.builder.freshTemp();
|
|
3731
4505
|
const targetType = this.exprToString(args[0]);
|
|
3732
4506
|
const target = targetType === "entity" ? this.exprToTargetString(args[1]) : this.exprToString(args[1]);
|
|
3733
|
-
const
|
|
4507
|
+
const path2 = this.exprToString(args[2]);
|
|
3734
4508
|
const scale = args[3] ? this.exprToString(args[3]) : "1";
|
|
3735
|
-
this.builder.emitRaw(`execute store result score ${dst} rs run data get ${targetType} ${target} ${
|
|
4509
|
+
this.builder.emitRaw(`execute store result score ${dst} rs run data get ${targetType} ${target} ${path2} ${scale}`);
|
|
4510
|
+
return { kind: "var", name: dst };
|
|
4511
|
+
}
|
|
4512
|
+
if (name === "data_merge") {
|
|
4513
|
+
const target = args[0];
|
|
4514
|
+
const nbt = args[1];
|
|
4515
|
+
const nbtStr = this.exprToSnbt ? this.exprToSnbt(nbt) : this.exprToString(nbt);
|
|
4516
|
+
if (target.kind === "selector") {
|
|
4517
|
+
const sel = this.exprToTargetString(target);
|
|
4518
|
+
this.builder.emitRaw(`data merge entity ${sel} ${nbtStr}`);
|
|
4519
|
+
} else {
|
|
4520
|
+
const targetStr = this.exprToString(target);
|
|
4521
|
+
if (targetStr.match(/^~|^\d|^\^/)) {
|
|
4522
|
+
this.builder.emitRaw(`data merge block ${targetStr} ${nbtStr}`);
|
|
4523
|
+
} else {
|
|
4524
|
+
this.builder.emitRaw(`data merge storage ${targetStr} ${nbtStr}`);
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
return { kind: "const", value: 0 };
|
|
4528
|
+
}
|
|
4529
|
+
if (name === "set_new") {
|
|
4530
|
+
const setId = `__set_${this.foreachCounter++}`;
|
|
4531
|
+
this.builder.emitRaw(`data modify storage rs:sets ${setId} set value []`);
|
|
4532
|
+
return { kind: "const", value: 0 };
|
|
4533
|
+
}
|
|
4534
|
+
if (name === "set_add") {
|
|
4535
|
+
const setId = this.exprToString(args[0]);
|
|
4536
|
+
const value = this.exprToString(args[1]);
|
|
4537
|
+
this.builder.emitRaw(`execute unless data storage rs:sets ${setId}[{value:${value}}] run data modify storage rs:sets ${setId} append value {value:${value}}`);
|
|
4538
|
+
return { kind: "const", value: 0 };
|
|
4539
|
+
}
|
|
4540
|
+
if (name === "set_contains") {
|
|
4541
|
+
const dst = this.builder.freshTemp();
|
|
4542
|
+
const setId = this.exprToString(args[0]);
|
|
4543
|
+
const value = this.exprToString(args[1]);
|
|
4544
|
+
this.builder.emitRaw(`execute store result score ${dst} rs if data storage rs:sets ${setId}[{value:${value}}]`);
|
|
3736
4545
|
return { kind: "var", name: dst };
|
|
3737
4546
|
}
|
|
4547
|
+
if (name === "set_remove") {
|
|
4548
|
+
const setId = this.exprToString(args[0]);
|
|
4549
|
+
const value = this.exprToString(args[1]);
|
|
4550
|
+
this.builder.emitRaw(`data remove storage rs:sets ${setId}[{value:${value}}]`);
|
|
4551
|
+
return { kind: "const", value: 0 };
|
|
4552
|
+
}
|
|
4553
|
+
if (name === "set_clear") {
|
|
4554
|
+
const setId = this.exprToString(args[0]);
|
|
4555
|
+
this.builder.emitRaw(`data modify storage rs:sets ${setId} set value []`);
|
|
4556
|
+
return { kind: "const", value: 0 };
|
|
4557
|
+
}
|
|
3738
4558
|
const coordCommand = this.lowerCoordinateBuiltin(name, args);
|
|
3739
4559
|
if (coordCommand) {
|
|
3740
4560
|
this.builder.emitRaw(coordCommand);
|
|
@@ -3759,13 +4579,97 @@ var require_lowering = __commonJS({
|
|
|
3759
4579
|
}
|
|
3760
4580
|
return { kind: "const", value: 0 };
|
|
3761
4581
|
}
|
|
3762
|
-
const strArgs = args.map((arg) => this.exprToString(arg));
|
|
4582
|
+
const strArgs = args.map((arg) => arg.kind === "struct_lit" || arg.kind === "array_lit" ? this.exprToSnbt(arg) : this.exprToString(arg));
|
|
3763
4583
|
const cmd = BUILTINS2[name](strArgs);
|
|
3764
4584
|
if (cmd) {
|
|
3765
4585
|
this.builder.emitRaw(cmd);
|
|
3766
4586
|
}
|
|
3767
4587
|
return { kind: "const", value: 0 };
|
|
3768
4588
|
}
|
|
4589
|
+
lowerSetTimeout(args) {
|
|
4590
|
+
const delay = this.exprToLiteral(args[0]);
|
|
4591
|
+
const callback = args[1];
|
|
4592
|
+
if (!callback || callback.kind !== "lambda") {
|
|
4593
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", "setTimeout requires a lambda callback", getSpan(callback) ?? { line: 1, col: 1 });
|
|
4594
|
+
}
|
|
4595
|
+
const fnName = `__timeout_${this.timeoutCounter++}`;
|
|
4596
|
+
this.lowerNamedLambdaFunction(fnName, callback);
|
|
4597
|
+
this.builder.emitRaw(`schedule function ${this.namespace}:${fnName} ${delay}t`);
|
|
4598
|
+
return { kind: "const", value: 0 };
|
|
4599
|
+
}
|
|
4600
|
+
lowerSetInterval(args) {
|
|
4601
|
+
const delay = this.exprToLiteral(args[0]);
|
|
4602
|
+
const callback = args[1];
|
|
4603
|
+
if (!callback || callback.kind !== "lambda") {
|
|
4604
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", "setInterval requires a lambda callback", getSpan(callback) ?? { line: 1, col: 1 });
|
|
4605
|
+
}
|
|
4606
|
+
const id = this.intervalCounter++;
|
|
4607
|
+
const bodyName = `__interval_body_${id}`;
|
|
4608
|
+
const fnName = `__interval_${id}`;
|
|
4609
|
+
this.lowerNamedLambdaFunction(bodyName, callback);
|
|
4610
|
+
this.lowerIntervalWrapperFunction(fnName, bodyName, delay);
|
|
4611
|
+
this.intervalFunctions.set(id, fnName);
|
|
4612
|
+
this.builder.emitRaw(`schedule function ${this.namespace}:${fnName} ${delay}t`);
|
|
4613
|
+
return { kind: "const", value: id };
|
|
4614
|
+
}
|
|
4615
|
+
lowerClearInterval(args, callSpan) {
|
|
4616
|
+
const fnName = this.resolveIntervalFunctionName(args[0]);
|
|
4617
|
+
if (!fnName) {
|
|
4618
|
+
throw new diagnostics_1.DiagnosticError("LoweringError", "clearInterval requires an interval ID returned from setInterval", callSpan ?? getSpan(args[0]) ?? { line: 1, col: 1 });
|
|
4619
|
+
}
|
|
4620
|
+
this.builder.emitRaw(`schedule clear ${this.namespace}:${fnName}`);
|
|
4621
|
+
return { kind: "const", value: 0 };
|
|
4622
|
+
}
|
|
4623
|
+
lowerNamedLambdaFunction(name, expr) {
|
|
4624
|
+
const lambdaFn = {
|
|
4625
|
+
name,
|
|
4626
|
+
params: expr.params.map((param) => ({
|
|
4627
|
+
name: param.name,
|
|
4628
|
+
type: param.type ?? { kind: "named", name: "int" }
|
|
4629
|
+
})),
|
|
4630
|
+
returnType: expr.returnType ?? this.inferLambdaReturnType(expr),
|
|
4631
|
+
decorators: [],
|
|
4632
|
+
body: Array.isArray(expr.body) ? expr.body : [{ kind: "return", value: expr.body }]
|
|
4633
|
+
};
|
|
4634
|
+
this.withSavedFunctionState(() => {
|
|
4635
|
+
this.lowerFn(lambdaFn);
|
|
4636
|
+
});
|
|
4637
|
+
}
|
|
4638
|
+
lowerIntervalWrapperFunction(name, bodyName, delay) {
|
|
4639
|
+
const intervalFn = {
|
|
4640
|
+
name,
|
|
4641
|
+
params: [],
|
|
4642
|
+
returnType: { kind: "named", name: "void" },
|
|
4643
|
+
decorators: [],
|
|
4644
|
+
body: [
|
|
4645
|
+
{ kind: "raw", cmd: `function ${this.namespace}:${bodyName}` },
|
|
4646
|
+
{ kind: "raw", cmd: `schedule function ${this.namespace}:${name} ${delay}t` }
|
|
4647
|
+
]
|
|
4648
|
+
};
|
|
4649
|
+
this.withSavedFunctionState(() => {
|
|
4650
|
+
this.lowerFn(intervalFn);
|
|
4651
|
+
});
|
|
4652
|
+
}
|
|
4653
|
+
resolveIntervalFunctionName(expr) {
|
|
4654
|
+
if (!expr) {
|
|
4655
|
+
return null;
|
|
4656
|
+
}
|
|
4657
|
+
if (expr.kind === "ident") {
|
|
4658
|
+
const boundInterval = this.intervalBindings.get(expr.name);
|
|
4659
|
+
if (boundInterval) {
|
|
4660
|
+
return boundInterval;
|
|
4661
|
+
}
|
|
4662
|
+
const constValue = this.constValues.get(expr.name);
|
|
4663
|
+
if (constValue?.kind === "int_lit") {
|
|
4664
|
+
return this.intervalFunctions.get(constValue.value) ?? null;
|
|
4665
|
+
}
|
|
4666
|
+
return null;
|
|
4667
|
+
}
|
|
4668
|
+
if (expr.kind === "int_lit") {
|
|
4669
|
+
return this.intervalFunctions.get(expr.value) ?? null;
|
|
4670
|
+
}
|
|
4671
|
+
return null;
|
|
4672
|
+
}
|
|
3769
4673
|
lowerRichTextBuiltin(name, args) {
|
|
3770
4674
|
const messageArgIndex = this.getRichTextArgIndex(name);
|
|
3771
4675
|
if (messageArgIndex === null) {
|
|
@@ -3908,11 +4812,72 @@ var require_lowering = __commonJS({
|
|
|
3908
4812
|
}
|
|
3909
4813
|
case "selector":
|
|
3910
4814
|
return this.selectorToString(expr.sel);
|
|
4815
|
+
case "unary":
|
|
4816
|
+
if (expr.op === "-" && expr.operand.kind === "int_lit") {
|
|
4817
|
+
return (-expr.operand.value).toString();
|
|
4818
|
+
}
|
|
4819
|
+
if (expr.op === "-" && expr.operand.kind === "float_lit") {
|
|
4820
|
+
return Math.trunc(-expr.operand.value).toString();
|
|
4821
|
+
}
|
|
4822
|
+
const unaryOp = this.lowerExpr(expr);
|
|
4823
|
+
return this.operandToVar(unaryOp);
|
|
3911
4824
|
default:
|
|
3912
4825
|
const op = this.lowerExpr(expr);
|
|
3913
4826
|
return this.operandToVar(op);
|
|
3914
4827
|
}
|
|
3915
4828
|
}
|
|
4829
|
+
exprToEntitySelector(expr) {
|
|
4830
|
+
if (expr.kind === "selector") {
|
|
4831
|
+
return this.selectorToString(expr.sel);
|
|
4832
|
+
}
|
|
4833
|
+
if (expr.kind === "ident") {
|
|
4834
|
+
const constValue = this.constValues.get(expr.name);
|
|
4835
|
+
if (constValue) {
|
|
4836
|
+
return this.exprToEntitySelector(constValue);
|
|
4837
|
+
}
|
|
4838
|
+
const mapped = this.varMap.get(expr.name);
|
|
4839
|
+
if (mapped?.startsWith("@")) {
|
|
4840
|
+
return mapped;
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
return null;
|
|
4844
|
+
}
|
|
4845
|
+
appendTypeFilter(selector, mcType) {
|
|
4846
|
+
if (selector.endsWith("]")) {
|
|
4847
|
+
return `${selector.slice(0, -1)},type=${mcType}]`;
|
|
4848
|
+
}
|
|
4849
|
+
return `${selector}[type=${mcType}]`;
|
|
4850
|
+
}
|
|
4851
|
+
exprToSnbt(expr) {
|
|
4852
|
+
switch (expr.kind) {
|
|
4853
|
+
case "struct_lit": {
|
|
4854
|
+
const entries = expr.fields.map((f) => `${f.name}:${this.exprToSnbt(f.value)}`);
|
|
4855
|
+
return `{${entries.join(",")}}`;
|
|
4856
|
+
}
|
|
4857
|
+
case "array_lit": {
|
|
4858
|
+
const items = expr.elements.map((e) => this.exprToSnbt(e));
|
|
4859
|
+
return `[${items.join(",")}]`;
|
|
4860
|
+
}
|
|
4861
|
+
case "str_lit":
|
|
4862
|
+
return `"${expr.value}"`;
|
|
4863
|
+
case "int_lit":
|
|
4864
|
+
return String(expr.value);
|
|
4865
|
+
case "float_lit":
|
|
4866
|
+
return String(expr.value);
|
|
4867
|
+
case "byte_lit":
|
|
4868
|
+
return `${expr.value}b`;
|
|
4869
|
+
case "short_lit":
|
|
4870
|
+
return `${expr.value}s`;
|
|
4871
|
+
case "long_lit":
|
|
4872
|
+
return `${expr.value}L`;
|
|
4873
|
+
case "double_lit":
|
|
4874
|
+
return `${expr.value}d`;
|
|
4875
|
+
case "bool_lit":
|
|
4876
|
+
return expr.value ? "1b" : "0b";
|
|
4877
|
+
default:
|
|
4878
|
+
return this.exprToString(expr);
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
3916
4881
|
exprToTargetString(expr) {
|
|
3917
4882
|
if (expr.kind === "selector") {
|
|
3918
4883
|
return this.selectorToString(expr.sel);
|
|
@@ -3950,6 +4915,92 @@ var require_lowering = __commonJS({
|
|
|
3950
4915
|
isTeamTextOption(option) {
|
|
3951
4916
|
return option === "displayName" || option === "prefix" || option === "suffix";
|
|
3952
4917
|
}
|
|
4918
|
+
exprToScoreboardObjective(expr, span) {
|
|
4919
|
+
if (expr.kind === "mc_name") {
|
|
4920
|
+
return expr.value;
|
|
4921
|
+
}
|
|
4922
|
+
const objective = this.exprToString(expr);
|
|
4923
|
+
if (objective.startsWith("#") || objective.includes(".")) {
|
|
4924
|
+
return objective.startsWith("#") ? objective.slice(1) : objective;
|
|
4925
|
+
}
|
|
4926
|
+
return `${this.getObjectiveNamespace(span)}.${objective}`;
|
|
4927
|
+
}
|
|
4928
|
+
resolveScoreboardObjective(playerExpr, objectiveExpr, span) {
|
|
4929
|
+
const stdlibInternalObjective = this.tryGetStdlibInternalObjective(playerExpr, objectiveExpr, span);
|
|
4930
|
+
if (stdlibInternalObjective) {
|
|
4931
|
+
return stdlibInternalObjective;
|
|
4932
|
+
}
|
|
4933
|
+
return this.exprToScoreboardObjective(objectiveExpr, span);
|
|
4934
|
+
}
|
|
4935
|
+
getObjectiveNamespace(span) {
|
|
4936
|
+
const filePath = this.filePathForSpan(span);
|
|
4937
|
+
if (!filePath) {
|
|
4938
|
+
return this.namespace;
|
|
4939
|
+
}
|
|
4940
|
+
return this.isStdlibFile(filePath) ? "rs" : this.namespace;
|
|
4941
|
+
}
|
|
4942
|
+
tryGetStdlibInternalObjective(playerExpr, objectiveExpr, span) {
|
|
4943
|
+
if (!span || !this.currentStdlibCallSite || objectiveExpr.kind !== "mc_name" || objectiveExpr.value !== "rs") {
|
|
4944
|
+
return null;
|
|
4945
|
+
}
|
|
4946
|
+
const filePath = this.filePathForSpan(span);
|
|
4947
|
+
if (!filePath || !this.isStdlibFile(filePath)) {
|
|
4948
|
+
return null;
|
|
4949
|
+
}
|
|
4950
|
+
const resourceBase = this.getStdlibInternalResourceBase(playerExpr);
|
|
4951
|
+
if (!resourceBase) {
|
|
4952
|
+
return null;
|
|
4953
|
+
}
|
|
4954
|
+
const hash = this.shortHash(this.serializeCallSite(this.currentStdlibCallSite));
|
|
4955
|
+
return `rs._${resourceBase}_${hash}`;
|
|
4956
|
+
}
|
|
4957
|
+
getStdlibInternalResourceBase(playerExpr) {
|
|
4958
|
+
if (!playerExpr || playerExpr.kind !== "str_lit") {
|
|
4959
|
+
return null;
|
|
4960
|
+
}
|
|
4961
|
+
const match = playerExpr.value.match(/^([a-z0-9]+)_/);
|
|
4962
|
+
return match?.[1] ?? null;
|
|
4963
|
+
}
|
|
4964
|
+
getStdlibCallSiteContext(fn, exprSpan) {
|
|
4965
|
+
const fnFilePath = this.filePathForSpan(getSpan(fn));
|
|
4966
|
+
if (!fnFilePath || !this.isStdlibFile(fnFilePath)) {
|
|
4967
|
+
return void 0;
|
|
4968
|
+
}
|
|
4969
|
+
if (this.currentStdlibCallSite) {
|
|
4970
|
+
return this.currentStdlibCallSite;
|
|
4971
|
+
}
|
|
4972
|
+
if (!exprSpan) {
|
|
4973
|
+
return void 0;
|
|
4974
|
+
}
|
|
4975
|
+
return {
|
|
4976
|
+
filePath: this.filePathForSpan(exprSpan),
|
|
4977
|
+
line: exprSpan.line,
|
|
4978
|
+
col: exprSpan.col
|
|
4979
|
+
};
|
|
4980
|
+
}
|
|
4981
|
+
serializeCallSite(callSite) {
|
|
4982
|
+
return `${callSite.filePath ?? "<memory>"}:${callSite.line}:${callSite.col}`;
|
|
4983
|
+
}
|
|
4984
|
+
shortHash(input) {
|
|
4985
|
+
let hash = 2166136261;
|
|
4986
|
+
for (let i = 0; i < input.length; i++) {
|
|
4987
|
+
hash ^= input.charCodeAt(i);
|
|
4988
|
+
hash = Math.imul(hash, 16777619);
|
|
4989
|
+
}
|
|
4990
|
+
return (hash >>> 0).toString(16).padStart(8, "0").slice(0, 4);
|
|
4991
|
+
}
|
|
4992
|
+
isStdlibFile(filePath) {
|
|
4993
|
+
const normalized = path.normalize(filePath);
|
|
4994
|
+
const stdlibSegment = `${path.sep}src${path.sep}stdlib${path.sep}`;
|
|
4995
|
+
return normalized.includes(stdlibSegment);
|
|
4996
|
+
}
|
|
4997
|
+
filePathForSpan(span) {
|
|
4998
|
+
if (!span) {
|
|
4999
|
+
return void 0;
|
|
5000
|
+
}
|
|
5001
|
+
const line = span.line;
|
|
5002
|
+
return this.sourceRanges.find((range) => line >= range.startLine && line <= range.endLine)?.filePath;
|
|
5003
|
+
}
|
|
3953
5004
|
lowerCoordinateBuiltin(name, args) {
|
|
3954
5005
|
const pos0 = args[0] ? this.resolveBlockPosExpr(args[0]) : null;
|
|
3955
5006
|
const pos1 = args[1] ? this.resolveBlockPosExpr(args[1]) : null;
|
|
@@ -3972,6 +5023,13 @@ var require_lowering = __commonJS({
|
|
|
3972
5023
|
}
|
|
3973
5024
|
return null;
|
|
3974
5025
|
}
|
|
5026
|
+
if (name === "summon") {
|
|
5027
|
+
if (args.length >= 2 && pos1) {
|
|
5028
|
+
const nbt = args[2] ? ` ${this.exprToString(args[2])}` : "";
|
|
5029
|
+
return `summon ${this.exprToString(args[0])} ${emitBlockPos(pos1)}${nbt}`;
|
|
5030
|
+
}
|
|
5031
|
+
return null;
|
|
5032
|
+
}
|
|
3975
5033
|
return null;
|
|
3976
5034
|
}
|
|
3977
5035
|
lowerTpCommand(args) {
|
|
@@ -4050,7 +5108,11 @@ var require_lowering = __commonJS({
|
|
|
4050
5108
|
};
|
|
4051
5109
|
}
|
|
4052
5110
|
if (expr.kind === "call") {
|
|
4053
|
-
|
|
5111
|
+
const resolved = this.resolveFunctionRefByName(expr.fn) ?? this.resolveInstanceMethod(expr)?.loweredName ?? expr.fn;
|
|
5112
|
+
return this.fnDecls.get(resolved)?.returnType;
|
|
5113
|
+
}
|
|
5114
|
+
if (expr.kind === "static_call") {
|
|
5115
|
+
return this.implMethods.get(expr.type)?.get(expr.method)?.fn.returnType;
|
|
4054
5116
|
}
|
|
4055
5117
|
if (expr.kind === "invoke") {
|
|
4056
5118
|
const calleeType = this.inferExprType(expr.callee);
|
|
@@ -4078,6 +5140,21 @@ var require_lowering = __commonJS({
|
|
|
4078
5140
|
}
|
|
4079
5141
|
return void 0;
|
|
4080
5142
|
}
|
|
5143
|
+
resolveInstanceMethod(expr) {
|
|
5144
|
+
const receiver = expr.args[0];
|
|
5145
|
+
if (!receiver) {
|
|
5146
|
+
return null;
|
|
5147
|
+
}
|
|
5148
|
+
const receiverType = this.inferExprType(receiver);
|
|
5149
|
+
if (receiverType?.kind !== "struct") {
|
|
5150
|
+
return null;
|
|
5151
|
+
}
|
|
5152
|
+
const method = this.implMethods.get(receiverType.name)?.get(expr.fn);
|
|
5153
|
+
if (!method || method.fn.params[0]?.name !== "self") {
|
|
5154
|
+
return null;
|
|
5155
|
+
}
|
|
5156
|
+
return method;
|
|
5157
|
+
}
|
|
4081
5158
|
normalizeType(type) {
|
|
4082
5159
|
if (type.kind === "array") {
|
|
4083
5160
|
return { kind: "array", elem: this.normalizeType(type.elem) };
|
|
@@ -4199,6 +5276,16 @@ var require_lowering = __commonJS({
|
|
|
4199
5276
|
parts.push(`nbt=${filters.nbt}`);
|
|
4200
5277
|
if (filters.gamemode)
|
|
4201
5278
|
parts.push(`gamemode=${filters.gamemode}`);
|
|
5279
|
+
if (filters.x)
|
|
5280
|
+
parts.push(`x=${this.rangeToString(filters.x)}`);
|
|
5281
|
+
if (filters.y)
|
|
5282
|
+
parts.push(`y=${this.rangeToString(filters.y)}`);
|
|
5283
|
+
if (filters.z)
|
|
5284
|
+
parts.push(`z=${this.rangeToString(filters.z)}`);
|
|
5285
|
+
if (filters.x_rotation)
|
|
5286
|
+
parts.push(`x_rotation=${this.rangeToString(filters.x_rotation)}`);
|
|
5287
|
+
if (filters.y_rotation)
|
|
5288
|
+
parts.push(`y_rotation=${this.rangeToString(filters.y_rotation)}`);
|
|
4202
5289
|
return this.finalizeSelector(parts.length ? `${kind}[${parts.join(",")}]` : kind);
|
|
4203
5290
|
}
|
|
4204
5291
|
finalizeSelector(selector) {
|
|
@@ -4218,16 +5305,19 @@ var require_lowering = __commonJS({
|
|
|
4218
5305
|
}
|
|
4219
5306
|
};
|
|
4220
5307
|
exports2.Lowering = Lowering;
|
|
4221
|
-
var LoweringBuilder = class {
|
|
5308
|
+
var LoweringBuilder = class _LoweringBuilder {
|
|
4222
5309
|
constructor() {
|
|
4223
|
-
this.tempCount = 0;
|
|
4224
5310
|
this.labelCount = 0;
|
|
4225
5311
|
this.blocks = [];
|
|
4226
5312
|
this.currentBlock = null;
|
|
4227
5313
|
this.locals = /* @__PURE__ */ new Set();
|
|
4228
5314
|
}
|
|
5315
|
+
/** Reset the global temp counter (call between compilations). */
|
|
5316
|
+
static resetTempCounter() {
|
|
5317
|
+
_LoweringBuilder.globalTempId = 0;
|
|
5318
|
+
}
|
|
4229
5319
|
freshTemp() {
|
|
4230
|
-
const name = `$
|
|
5320
|
+
const name = `$_${_LoweringBuilder.globalTempId++}`;
|
|
4231
5321
|
this.locals.add(name);
|
|
4232
5322
|
return name;
|
|
4233
5323
|
}
|
|
@@ -4292,6 +5382,7 @@ var require_lowering = __commonJS({
|
|
|
4292
5382
|
};
|
|
4293
5383
|
}
|
|
4294
5384
|
};
|
|
5385
|
+
LoweringBuilder.globalTempId = 0;
|
|
4295
5386
|
}
|
|
4296
5387
|
});
|
|
4297
5388
|
|
|
@@ -4859,6 +5950,7 @@ var require_mcfunction = __commonJS({
|
|
|
4859
5950
|
exports2.generateDatapackWithStats = generateDatapackWithStats;
|
|
4860
5951
|
exports2.generateDatapack = generateDatapack;
|
|
4861
5952
|
var commands_1 = require_commands();
|
|
5953
|
+
var types_1 = require_types();
|
|
4862
5954
|
var OBJ = "rs";
|
|
4863
5955
|
function varRef(name) {
|
|
4864
5956
|
return name.startsWith("$") ? name : `$${name}`;
|
|
@@ -5050,6 +6142,8 @@ var require_mcfunction = __commonJS({
|
|
|
5050
6142
|
const ns = module3.namespace;
|
|
5051
6143
|
const triggerHandlers = module3.functions.filter((fn) => fn.isTriggerHandler && fn.triggerName);
|
|
5052
6144
|
const triggerNames = new Set(triggerHandlers.map((fn) => fn.triggerName));
|
|
6145
|
+
const eventHandlers = module3.functions.filter((fn) => !!fn.eventHandler && (0, types_1.isEventTypeName)(fn.eventHandler.eventType));
|
|
6146
|
+
const eventTypes = new Set(eventHandlers.map((fn) => fn.eventHandler.eventType));
|
|
5053
6147
|
const tickFunctionNames = [];
|
|
5054
6148
|
for (const fn of module3.functions) {
|
|
5055
6149
|
if (fn.isTickLoop) {
|
|
@@ -5067,12 +6161,24 @@ var require_mcfunction = __commonJS({
|
|
|
5067
6161
|
`scoreboard objectives add ${OBJ} dummy`
|
|
5068
6162
|
];
|
|
5069
6163
|
for (const g of module3.globals) {
|
|
5070
|
-
loadLines.push(`scoreboard players set ${varRef(g)} ${OBJ}
|
|
6164
|
+
loadLines.push(`scoreboard players set ${varRef(g.name)} ${OBJ} ${g.init}`);
|
|
5071
6165
|
}
|
|
5072
6166
|
for (const triggerName of triggerNames) {
|
|
5073
6167
|
loadLines.push(`scoreboard objectives add ${triggerName} trigger`);
|
|
5074
6168
|
loadLines.push(`scoreboard players enable @a ${triggerName}`);
|
|
5075
6169
|
}
|
|
6170
|
+
for (const eventType of eventTypes) {
|
|
6171
|
+
const detection = types_1.EVENT_TYPES[eventType].detection;
|
|
6172
|
+
if (eventType === "PlayerDeath") {
|
|
6173
|
+
loadLines.push("scoreboard objectives add rs.deaths deathCount");
|
|
6174
|
+
} else if (eventType === "EntityKill") {
|
|
6175
|
+
loadLines.push("scoreboard objectives add rs.kills totalKillCount");
|
|
6176
|
+
} else if (eventType === "ItemUse") {
|
|
6177
|
+
loadLines.push("# ItemUse detection requires a project-specific objective/tag setup");
|
|
6178
|
+
} else if (detection === "tag" || detection === "advancement") {
|
|
6179
|
+
loadLines.push(`# ${eventType} detection expects tag ${types_1.EVENT_TYPES[eventType].tag} to be set externally`);
|
|
6180
|
+
}
|
|
6181
|
+
}
|
|
5076
6182
|
for (const triggerName of triggerNames) {
|
|
5077
6183
|
const handlers = triggerHandlers.filter((fn) => fn.triggerName === triggerName);
|
|
5078
6184
|
const dispatchLines = [
|
|
@@ -5109,6 +6215,11 @@ var require_mcfunction = __commonJS({
|
|
|
5109
6215
|
files.push({ path: filePath, content: lines.join("\n") });
|
|
5110
6216
|
}
|
|
5111
6217
|
}
|
|
6218
|
+
for (const fn of module3.functions) {
|
|
6219
|
+
if (fn.isLoadInit) {
|
|
6220
|
+
loadLines.push(`function ${ns}:${fn.name}`);
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
5112
6223
|
files.push({
|
|
5113
6224
|
path: `data/${ns}/function/__load.mcfunction`,
|
|
5114
6225
|
content: loadLines.join("\n")
|
|
@@ -5127,7 +6238,18 @@ var require_mcfunction = __commonJS({
|
|
|
5127
6238
|
tickLines.push(`execute as @a[scores={${triggerName}=1..}] run function ${ns}:__trigger_${triggerName}_dispatch`);
|
|
5128
6239
|
}
|
|
5129
6240
|
}
|
|
5130
|
-
if (
|
|
6241
|
+
if (eventHandlers.length > 0) {
|
|
6242
|
+
tickLines.push("# Event checks");
|
|
6243
|
+
for (const eventType of eventTypes) {
|
|
6244
|
+
const tag = types_1.EVENT_TYPES[eventType].tag;
|
|
6245
|
+
const handlers = eventHandlers.filter((fn) => fn.eventHandler?.eventType === eventType);
|
|
6246
|
+
for (const handler of handlers) {
|
|
6247
|
+
tickLines.push(`execute as @a[tag=${tag}] run function ${ns}:${handler.name}`);
|
|
6248
|
+
}
|
|
6249
|
+
tickLines.push(`tag @a[tag=${tag}] remove ${tag}`);
|
|
6250
|
+
}
|
|
6251
|
+
}
|
|
6252
|
+
if (tickFunctionNames.length > 0 || triggerNames.size > 0 || eventHandlers.length > 0) {
|
|
5131
6253
|
files.push({
|
|
5132
6254
|
path: `data/${ns}/function/__tick.mcfunction`,
|
|
5133
6255
|
content: tickLines.join("\n")
|
|
@@ -5247,6 +6369,7 @@ var require_compile = __commonJS({
|
|
|
5247
6369
|
};
|
|
5248
6370
|
})();
|
|
5249
6371
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
6372
|
+
exports2.preprocessSourceWithMetadata = preprocessSourceWithMetadata;
|
|
5250
6373
|
exports2.preprocessSource = preprocessSource;
|
|
5251
6374
|
exports2.compile = compile;
|
|
5252
6375
|
exports2.formatCompileError = formatCompileError;
|
|
@@ -5259,7 +6382,17 @@ var require_compile = __commonJS({
|
|
|
5259
6382
|
var mcfunction_1 = require_mcfunction();
|
|
5260
6383
|
var diagnostics_1 = require_diagnostics();
|
|
5261
6384
|
var IMPORT_RE = /^\s*import\s+"([^"]+)"\s*;?\s*$/;
|
|
5262
|
-
function
|
|
6385
|
+
function countLines(source) {
|
|
6386
|
+
return source === "" ? 0 : source.split("\n").length;
|
|
6387
|
+
}
|
|
6388
|
+
function offsetRanges(ranges, lineOffset) {
|
|
6389
|
+
return ranges.map((range) => ({
|
|
6390
|
+
startLine: range.startLine + lineOffset,
|
|
6391
|
+
endLine: range.endLine + lineOffset,
|
|
6392
|
+
filePath: range.filePath
|
|
6393
|
+
}));
|
|
6394
|
+
}
|
|
6395
|
+
function preprocessSourceWithMetadata(source, options = {}) {
|
|
5263
6396
|
const { filePath } = options;
|
|
5264
6397
|
const seen = options.seen ?? /* @__PURE__ */ new Set();
|
|
5265
6398
|
if (filePath) {
|
|
@@ -5286,7 +6419,7 @@ var require_compile = __commonJS({
|
|
|
5286
6419
|
} catch {
|
|
5287
6420
|
throw new diagnostics_1.DiagnosticError("ParseError", `Cannot import '${match[1]}'`, { file: filePath, line: i + 1, col: 1 }, lines);
|
|
5288
6421
|
}
|
|
5289
|
-
imports.push(
|
|
6422
|
+
imports.push(preprocessSourceWithMetadata(importedSource, { filePath: importPath, seen }));
|
|
5290
6423
|
}
|
|
5291
6424
|
continue;
|
|
5292
6425
|
}
|
|
@@ -5297,17 +6430,37 @@ var require_compile = __commonJS({
|
|
|
5297
6430
|
parsingHeader = false;
|
|
5298
6431
|
bodyLines.push(line);
|
|
5299
6432
|
}
|
|
5300
|
-
|
|
6433
|
+
const body = bodyLines.join("\n");
|
|
6434
|
+
const parts = [...imports.map((entry) => entry.source), body].filter(Boolean);
|
|
6435
|
+
const combined = parts.join("\n");
|
|
6436
|
+
const ranges = [];
|
|
6437
|
+
let lineOffset = 0;
|
|
6438
|
+
for (const entry of imports) {
|
|
6439
|
+
ranges.push(...offsetRanges(entry.ranges, lineOffset));
|
|
6440
|
+
lineOffset += countLines(entry.source);
|
|
6441
|
+
}
|
|
6442
|
+
if (filePath && body) {
|
|
6443
|
+
ranges.push({
|
|
6444
|
+
startLine: lineOffset + 1,
|
|
6445
|
+
endLine: lineOffset + countLines(body),
|
|
6446
|
+
filePath: path.resolve(filePath)
|
|
6447
|
+
});
|
|
6448
|
+
}
|
|
6449
|
+
return { source: combined, ranges };
|
|
6450
|
+
}
|
|
6451
|
+
function preprocessSource(source, options = {}) {
|
|
6452
|
+
return preprocessSourceWithMetadata(source, options).source;
|
|
5301
6453
|
}
|
|
5302
6454
|
function compile(source, options = {}) {
|
|
5303
6455
|
const { namespace = "redscript", filePath, optimize: shouldOptimize = true } = options;
|
|
5304
6456
|
let sourceLines = source.split("\n");
|
|
5305
6457
|
try {
|
|
5306
|
-
const
|
|
6458
|
+
const preprocessed = preprocessSourceWithMetadata(source, { filePath });
|
|
6459
|
+
const preprocessedSource = preprocessed.source;
|
|
5307
6460
|
sourceLines = preprocessedSource.split("\n");
|
|
5308
6461
|
const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
|
|
5309
6462
|
const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
|
|
5310
|
-
const ir = new lowering_1.Lowering(namespace).lower(ast);
|
|
6463
|
+
const ir = new lowering_1.Lowering(namespace, preprocessed.ranges).lower(ast);
|
|
5311
6464
|
const optimized = shouldOptimize ? { ...ir, functions: ir.functions.map((fn) => (0, passes_1.optimize)(fn)) } : ir;
|
|
5312
6465
|
const generated = (0, mcfunction_1.generateDatapackWithStats)(optimized);
|
|
5313
6466
|
return {
|
|
@@ -5691,7 +6844,8 @@ var require_dist = __commonJS({
|
|
|
5691
6844
|
const shouldOptimize = options.optimize ?? true;
|
|
5692
6845
|
const shouldTypeCheck = options.typeCheck ?? true;
|
|
5693
6846
|
const filePath = options.filePath;
|
|
5694
|
-
const
|
|
6847
|
+
const preprocessed = (0, compile_1.preprocessSourceWithMetadata)(source, { filePath });
|
|
6848
|
+
const preprocessedSource = preprocessed.source;
|
|
5695
6849
|
const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
|
|
5696
6850
|
const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
|
|
5697
6851
|
let typeErrors;
|
|
@@ -5699,7 +6853,7 @@ var require_dist = __commonJS({
|
|
|
5699
6853
|
const checker = new typechecker_1.TypeChecker(preprocessedSource, filePath);
|
|
5700
6854
|
typeErrors = checker.check(ast);
|
|
5701
6855
|
}
|
|
5702
|
-
const lowering = new lowering_1.Lowering(namespace);
|
|
6856
|
+
const lowering = new lowering_1.Lowering(namespace, preprocessed.ranges);
|
|
5703
6857
|
const ir = lowering.lower(ast);
|
|
5704
6858
|
let optimizedIR = ir;
|
|
5705
6859
|
let generated = (0, mcfunction_1.generateDatapackWithStats)(ir, { optimizeCommands: shouldOptimize });
|
|
@@ -6495,16 +7649,52 @@ function findFnDeclLine(document, name) {
|
|
|
6495
7649
|
}
|
|
6496
7650
|
function findFnSignature(document, name) {
|
|
6497
7651
|
const text = document.getText();
|
|
6498
|
-
const re = new RegExp(`\\bfn\\s+${escapeRe(name)}\\s*\\(([^)]*)\\)(?:\\s*->\\s*([A-Za-z_][A-Za-z0-9_\\[\\]]*))
|
|
7652
|
+
const re = new RegExp(`\\bfn\\s+${escapeRe(name)}\\s*\\(([^)]*)\\)(?:\\s*->\\s*([A-Za-z_][A-Za-z0-9_\\[\\]]*))?\\s*\\{`, "m");
|
|
6499
7653
|
const match = re.exec(text);
|
|
6500
7654
|
if (!match) return null;
|
|
6501
7655
|
const params = match[1].trim();
|
|
6502
|
-
|
|
7656
|
+
let returnType = match[2];
|
|
7657
|
+
if (!returnType) {
|
|
7658
|
+
returnType = inferReturnType(text, match.index + match[0].length);
|
|
7659
|
+
}
|
|
6503
7660
|
if (returnType) {
|
|
6504
7661
|
return `fn ${name}(${params}) -> ${returnType}`;
|
|
6505
7662
|
}
|
|
6506
7663
|
return `fn ${name}(${params})`;
|
|
6507
7664
|
}
|
|
7665
|
+
function inferReturnType(text, bodyStart) {
|
|
7666
|
+
let braceCount = 1;
|
|
7667
|
+
let pos = bodyStart;
|
|
7668
|
+
while (pos < text.length && braceCount > 0) {
|
|
7669
|
+
if (text[pos] === "{") braceCount++;
|
|
7670
|
+
else if (text[pos] === "}") braceCount--;
|
|
7671
|
+
pos++;
|
|
7672
|
+
}
|
|
7673
|
+
const body = text.slice(bodyStart, pos - 1);
|
|
7674
|
+
const returnMatch = body.match(/\breturn\s+(.+?);/);
|
|
7675
|
+
if (!returnMatch) return null;
|
|
7676
|
+
const returnExpr = returnMatch[1].trim();
|
|
7677
|
+
if (/^\d+$/.test(returnExpr)) return "int";
|
|
7678
|
+
if (/^\d+\.\d+$/.test(returnExpr)) return "float";
|
|
7679
|
+
if (/^\d+[bB]$/.test(returnExpr)) return "byte";
|
|
7680
|
+
if (/^\d+[sS]$/.test(returnExpr)) return "short";
|
|
7681
|
+
if (/^\d+[lL]$/.test(returnExpr)) return "long";
|
|
7682
|
+
if (/^\d+(\.\d+)?[dD]$/.test(returnExpr)) return "double";
|
|
7683
|
+
if (/^".*"$/.test(returnExpr)) return "string";
|
|
7684
|
+
if (/^(true|false)$/.test(returnExpr)) return "bool";
|
|
7685
|
+
if (/^@[aeprs]/.test(returnExpr)) return "selector";
|
|
7686
|
+
if (/^\{/.test(returnExpr)) return "struct";
|
|
7687
|
+
if (/^\[/.test(returnExpr)) return "array";
|
|
7688
|
+
const callMatch = returnExpr.match(/^(\w+)\s*\(/);
|
|
7689
|
+
if (callMatch) {
|
|
7690
|
+
const fnName = callMatch[1];
|
|
7691
|
+
if (["scoreboard_get", "score", "random", "random_native", "str_len", "len", "data_get", "bossbar_get_value", "set_contains"].includes(fnName)) {
|
|
7692
|
+
return "int";
|
|
7693
|
+
}
|
|
7694
|
+
if (fnName === "set_new") return "string";
|
|
7695
|
+
}
|
|
7696
|
+
return null;
|
|
7697
|
+
}
|
|
6508
7698
|
function escapeRe(s) {
|
|
6509
7699
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6510
7700
|
}
|
|
@@ -6978,6 +8168,23 @@ function isStructLiteralField(doc, position, word) {
|
|
|
6978
8168
|
if (fnMatch) return fnMatch[1];
|
|
6979
8169
|
return null;
|
|
6980
8170
|
}
|
|
8171
|
+
function isMemberAccessField(doc, position, word) {
|
|
8172
|
+
const line = doc.lineAt(position.line).text;
|
|
8173
|
+
const wordStart = position.character;
|
|
8174
|
+
const beforeWord = line.slice(0, wordStart);
|
|
8175
|
+
if (!beforeWord.endsWith(".")) return null;
|
|
8176
|
+
const varMatch = beforeWord.match(/(\w+)\s*\.$/);
|
|
8177
|
+
if (!varMatch) return null;
|
|
8178
|
+
const varName = varMatch[1];
|
|
8179
|
+
const text = doc.getText();
|
|
8180
|
+
const typeRe = new RegExp(`\\b(?:let|const)\\s+${varName}\\s*:\\s*(\\w+)`, "m");
|
|
8181
|
+
const typeMatch = text.match(typeRe);
|
|
8182
|
+
if (typeMatch) return typeMatch[1];
|
|
8183
|
+
const paramRe = new RegExp(`\\((?:[^)]*,\\s*)?${varName}\\s*:\\s*(\\w+)`, "m");
|
|
8184
|
+
const paramMatch = text.match(paramRe);
|
|
8185
|
+
if (paramMatch) return paramMatch[1];
|
|
8186
|
+
return null;
|
|
8187
|
+
}
|
|
6981
8188
|
function findAllOccurrences(doc, word) {
|
|
6982
8189
|
const text = doc.getText();
|
|
6983
8190
|
const re = new RegExp(`\\b${escapeRegex(word)}\\b`, "g");
|
|
@@ -7010,6 +8217,14 @@ function registerSymbolProviders(context) {
|
|
|
7010
8217
|
return new vscode4.Location(doc.uri, field.fieldRange);
|
|
7011
8218
|
}
|
|
7012
8219
|
}
|
|
8220
|
+
const memberAccess = isMemberAccessField(doc, position, word);
|
|
8221
|
+
if (memberAccess) {
|
|
8222
|
+
const structFields = findStructFields(doc);
|
|
8223
|
+
const field = structFields.find((f) => f.structName === memberAccess && f.fieldName === word);
|
|
8224
|
+
if (field) {
|
|
8225
|
+
return new vscode4.Location(doc.uri, field.fieldRange);
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
7013
8228
|
const decls = findDeclarations(doc);
|
|
7014
8229
|
const decl = decls.find((d) => d.name === word);
|
|
7015
8230
|
if (!decl) return null;
|