redscript-mc 1.1.0 → 1.2.1
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/CHANGELOG.md +59 -0
- package/README.md +53 -10
- package/README.zh.md +53 -10
- package/dist/__tests__/cli.test.js +138 -0
- package/dist/__tests__/codegen.test.js +25 -0
- package/dist/__tests__/dce.test.d.ts +1 -0
- package/dist/__tests__/dce.test.js +137 -0
- package/dist/__tests__/e2e.test.js +190 -12
- package/dist/__tests__/lexer.test.js +31 -4
- package/dist/__tests__/lowering.test.js +172 -9
- package/dist/__tests__/mc-integration.test.js +145 -51
- package/dist/__tests__/mc-syntax.test.js +12 -0
- package/dist/__tests__/optimizer-advanced.test.js +3 -3
- package/dist/__tests__/parser.test.js +90 -0
- package/dist/__tests__/runtime.test.js +21 -8
- package/dist/__tests__/typechecker.test.js +188 -0
- package/dist/ast/types.d.ts +42 -3
- package/dist/cli.js +15 -10
- package/dist/codegen/mcfunction/index.js +30 -1
- package/dist/codegen/structure/index.d.ts +4 -1
- package/dist/codegen/structure/index.js +29 -2
- package/dist/compile.d.ts +11 -0
- package/dist/compile.js +40 -6
- package/dist/events/types.d.ts +35 -0
- package/dist/events/types.js +59 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -3
- package/dist/ir/types.d.ts +4 -0
- package/dist/lexer/index.d.ts +2 -1
- package/dist/lexer/index.js +91 -1
- package/dist/lowering/index.d.ts +32 -1
- package/dist/lowering/index.js +476 -16
- package/dist/optimizer/dce.d.ts +23 -0
- package/dist/optimizer/dce.js +591 -0
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.js +160 -26
- package/dist/typechecker/index.d.ts +19 -0
- package/dist/typechecker/index.js +392 -17
- package/docs/ARCHITECTURE.zh.md +1088 -0
- package/docs/ENTITY_TYPE_SYSTEM.md +242 -0
- package/editors/vscode/.vscodeignore +3 -0
- package/editors/vscode/CHANGELOG.md +9 -0
- package/editors/vscode/icon.png +0 -0
- package/editors/vscode/out/extension.js +1144 -72
- package/editors/vscode/package-lock.json +2 -2
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +6 -2
- package/examples/spiral.mcrs +79 -0
- package/logo.png +0 -0
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +166 -0
- package/src/__tests__/codegen.test.ts +27 -0
- package/src/__tests__/dce.test.ts +129 -0
- package/src/__tests__/e2e.test.ts +201 -12
- 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 +35 -4
- package/src/__tests__/lowering.test.ts +187 -9
- package/src/__tests__/mc-integration.test.ts +166 -51
- package/src/__tests__/mc-syntax.test.ts +14 -0
- package/src/__tests__/optimizer-advanced.test.ts +3 -3
- package/src/__tests__/parser.test.ts +102 -5
- package/src/__tests__/runtime.test.ts +24 -8
- package/src/__tests__/typechecker.test.ts +204 -0
- package/src/ast/types.ts +39 -2
- package/src/cli.ts +24 -10
- package/src/codegen/mcfunction/index.ts +31 -1
- package/src/codegen/structure/index.ts +40 -2
- package/src/compile.ts +59 -7
- package/src/events/types.ts +69 -0
- package/src/index.ts +9 -4
- package/src/ir/types.ts +4 -0
- package/src/lexer/index.ts +105 -2
- package/src/lowering/index.ts +566 -18
- package/src/optimizer/dce.ts +618 -0
- package/src/parser/index.ts +187 -29
- package/src/stdlib/README.md +34 -4
- package/src/stdlib/tags.mcrs +951 -0
- package/src/stdlib/timer.mcrs +54 -33
- package/src/typechecker/index.ts +469 -18
|
@@ -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;
|
|
@@ -1227,6 +1301,15 @@ var require_parser = __commonJS({
|
|
|
1227
1301
|
}
|
|
1228
1302
|
parsePrimaryExpr() {
|
|
1229
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
|
+
}
|
|
1230
1313
|
if (token.kind === "ident" && this.peek(1).kind === "=>") {
|
|
1231
1314
|
return this.parseSingleParamLambda();
|
|
1232
1315
|
}
|
|
@@ -1592,6 +1675,34 @@ var require_parser = __commonJS({
|
|
|
1592
1675
|
const token = this.expect("selector");
|
|
1593
1676
|
return this.parseSelectorValue(token.value);
|
|
1594
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
|
+
}
|
|
1595
1706
|
parseSelectorValue(value) {
|
|
1596
1707
|
const bracketIndex = value.indexOf("[");
|
|
1597
1708
|
if (bracketIndex === -1) {
|
|
@@ -1642,6 +1753,21 @@ var require_parser = __commonJS({
|
|
|
1642
1753
|
case "scores":
|
|
1643
1754
|
filters.scores = this.parseScoresFilter(val);
|
|
1644
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;
|
|
1645
1771
|
}
|
|
1646
1772
|
}
|
|
1647
1773
|
return filters;
|
|
@@ -1700,6 +1826,70 @@ var require_parser = __commonJS({
|
|
|
1700
1826
|
}
|
|
1701
1827
|
});
|
|
1702
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
|
+
|
|
1703
1893
|
// ../../dist/typechecker/index.js
|
|
1704
1894
|
var require_typechecker = __commonJS({
|
|
1705
1895
|
"../../dist/typechecker/index.js"(exports2) {
|
|
@@ -1707,15 +1897,82 @@ var require_typechecker = __commonJS({
|
|
|
1707
1897
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1708
1898
|
exports2.TypeChecker = void 0;
|
|
1709
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
|
+
};
|
|
1710
1965
|
var TypeChecker = class {
|
|
1711
1966
|
constructor(source, filePath) {
|
|
1712
1967
|
this.functions = /* @__PURE__ */ new Map();
|
|
1968
|
+
this.implMethods = /* @__PURE__ */ new Map();
|
|
1713
1969
|
this.structs = /* @__PURE__ */ new Map();
|
|
1714
1970
|
this.enums = /* @__PURE__ */ new Map();
|
|
1715
1971
|
this.consts = /* @__PURE__ */ new Map();
|
|
1716
1972
|
this.currentFn = null;
|
|
1717
1973
|
this.currentReturnType = null;
|
|
1718
1974
|
this.scope = /* @__PURE__ */ new Map();
|
|
1975
|
+
this.selfTypeStack = ["entity"];
|
|
1719
1976
|
this.collector = new diagnostics_1.DiagnosticCollector(source, filePath);
|
|
1720
1977
|
}
|
|
1721
1978
|
getNodeLocation(node) {
|
|
@@ -1736,6 +1993,26 @@ var require_typechecker = __commonJS({
|
|
|
1736
1993
|
for (const fn of program.declarations) {
|
|
1737
1994
|
this.functions.set(fn.name, fn);
|
|
1738
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
|
+
}
|
|
1739
2016
|
for (const struct of program.structs ?? []) {
|
|
1740
2017
|
const fields = /* @__PURE__ */ new Map();
|
|
1741
2018
|
for (const field of struct.fields) {
|
|
@@ -1761,6 +2038,11 @@ var require_typechecker = __commonJS({
|
|
|
1761
2038
|
for (const fn of program.declarations) {
|
|
1762
2039
|
this.checkFunction(fn);
|
|
1763
2040
|
}
|
|
2041
|
+
for (const implBlock of program.implBlocks ?? []) {
|
|
2042
|
+
for (const method of implBlock.methods) {
|
|
2043
|
+
this.checkFunction(method);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
1764
2046
|
return this.collector.getErrors();
|
|
1765
2047
|
}
|
|
1766
2048
|
checkFunction(fn) {
|
|
@@ -1768,6 +2050,7 @@ var require_typechecker = __commonJS({
|
|
|
1768
2050
|
this.currentReturnType = this.normalizeType(fn.returnType);
|
|
1769
2051
|
this.scope = /* @__PURE__ */ new Map();
|
|
1770
2052
|
let seenDefault = false;
|
|
2053
|
+
this.checkFunctionDecorators(fn);
|
|
1771
2054
|
for (const [name, type] of this.consts.entries()) {
|
|
1772
2055
|
this.scope.set(name, { type, mutable: false });
|
|
1773
2056
|
}
|
|
@@ -1789,6 +2072,37 @@ var require_typechecker = __commonJS({
|
|
|
1789
2072
|
this.currentFn = null;
|
|
1790
2073
|
this.currentReturnType = null;
|
|
1791
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
|
+
}
|
|
1792
2106
|
checkBlock(stmts) {
|
|
1793
2107
|
for (const stmt of stmts) {
|
|
1794
2108
|
this.checkStmt(stmt);
|
|
@@ -1804,9 +2118,7 @@ var require_typechecker = __commonJS({
|
|
|
1804
2118
|
break;
|
|
1805
2119
|
case "if":
|
|
1806
2120
|
this.checkExpr(stmt.cond);
|
|
1807
|
-
this.
|
|
1808
|
-
if (stmt.else_)
|
|
1809
|
-
this.checkBlock(stmt.else_);
|
|
2121
|
+
this.checkIfBranches(stmt);
|
|
1810
2122
|
break;
|
|
1811
2123
|
case "while":
|
|
1812
2124
|
this.checkExpr(stmt.cond);
|
|
@@ -1822,7 +2134,15 @@ var require_typechecker = __commonJS({
|
|
|
1822
2134
|
case "foreach":
|
|
1823
2135
|
this.checkExpr(stmt.iterable);
|
|
1824
2136
|
if (stmt.iterable.kind === "selector") {
|
|
1825
|
-
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();
|
|
1826
2146
|
} else {
|
|
1827
2147
|
const iterableType = this.inferType(stmt.iterable);
|
|
1828
2148
|
if (iterableType.kind === "array") {
|
|
@@ -1830,8 +2150,8 @@ var require_typechecker = __commonJS({
|
|
|
1830
2150
|
} else {
|
|
1831
2151
|
this.scope.set(stmt.binding, { type: { kind: "named", name: "void" }, mutable: true });
|
|
1832
2152
|
}
|
|
2153
|
+
this.checkBlock(stmt.body);
|
|
1833
2154
|
}
|
|
1834
|
-
this.checkBlock(stmt.body);
|
|
1835
2155
|
break;
|
|
1836
2156
|
case "match":
|
|
1837
2157
|
this.checkExpr(stmt.expr);
|
|
@@ -1845,15 +2165,36 @@ var require_typechecker = __commonJS({
|
|
|
1845
2165
|
this.checkBlock(arm.body);
|
|
1846
2166
|
}
|
|
1847
2167
|
break;
|
|
1848
|
-
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
|
+
}
|
|
1849
2175
|
case "at_block":
|
|
1850
2176
|
this.checkBlock(stmt.body);
|
|
1851
2177
|
break;
|
|
1852
|
-
case "as_at":
|
|
2178
|
+
case "as_at": {
|
|
2179
|
+
const entityType = this.inferEntityTypeFromSelector(stmt.as_sel);
|
|
2180
|
+
this.pushSelfType(entityType);
|
|
1853
2181
|
this.checkBlock(stmt.body);
|
|
2182
|
+
this.popSelfType();
|
|
1854
2183
|
break;
|
|
2184
|
+
}
|
|
1855
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
|
+
}
|
|
1856
2192
|
this.checkBlock(stmt.body);
|
|
2193
|
+
for (const sub of stmt.subcommands) {
|
|
2194
|
+
if (sub.kind === "as") {
|
|
2195
|
+
this.popSelfType();
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
1857
2198
|
break;
|
|
1858
2199
|
case "expr":
|
|
1859
2200
|
this.checkExpr(stmt.expr);
|
|
@@ -1904,10 +2245,21 @@ var require_typechecker = __commonJS({
|
|
|
1904
2245
|
case "member":
|
|
1905
2246
|
this.checkMemberExpr(expr);
|
|
1906
2247
|
break;
|
|
2248
|
+
case "static_call":
|
|
2249
|
+
this.checkStaticCallExpr(expr);
|
|
2250
|
+
break;
|
|
1907
2251
|
case "binary":
|
|
1908
2252
|
this.checkExpr(expr.left);
|
|
1909
2253
|
this.checkExpr(expr.right);
|
|
1910
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
|
+
}
|
|
1911
2263
|
case "unary":
|
|
1912
2264
|
this.checkExpr(expr.operand);
|
|
1913
2265
|
break;
|
|
@@ -1953,11 +2305,6 @@ var require_typechecker = __commonJS({
|
|
|
1953
2305
|
break;
|
|
1954
2306
|
case "blockpos":
|
|
1955
2307
|
break;
|
|
1956
|
-
case "static_call":
|
|
1957
|
-
for (const arg of expr.args) {
|
|
1958
|
-
this.checkExpr(arg);
|
|
1959
|
-
}
|
|
1960
|
-
break;
|
|
1961
2308
|
// Literals don't need checking
|
|
1962
2309
|
case "int_lit":
|
|
1963
2310
|
case "float_lit":
|
|
@@ -1977,6 +2324,11 @@ var require_typechecker = __commonJS({
|
|
|
1977
2324
|
if (expr.fn === "tp" || expr.fn === "tp_to") {
|
|
1978
2325
|
this.checkTpCall(expr);
|
|
1979
2326
|
}
|
|
2327
|
+
const builtin = BUILTIN_SIGNATURES[expr.fn];
|
|
2328
|
+
if (builtin) {
|
|
2329
|
+
this.checkFunctionCallArgs(expr.args, builtin.params, expr.fn, expr);
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
1980
2332
|
const fn = this.functions.get(expr.fn);
|
|
1981
2333
|
if (fn) {
|
|
1982
2334
|
const requiredParams = fn.params.filter((param) => !param.default).length;
|
|
@@ -2001,6 +2353,11 @@ var require_typechecker = __commonJS({
|
|
|
2001
2353
|
this.checkFunctionCallArgs(expr.args, varType.params, expr.fn, expr);
|
|
2002
2354
|
return;
|
|
2003
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
|
+
}
|
|
2004
2361
|
for (const arg of expr.args) {
|
|
2005
2362
|
this.checkExpr(arg);
|
|
2006
2363
|
}
|
|
@@ -2081,6 +2438,21 @@ var require_typechecker = __commonJS({
|
|
|
2081
2438
|
}
|
|
2082
2439
|
}
|
|
2083
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
|
+
}
|
|
2084
2456
|
checkLambdaExpr(expr, expectedType) {
|
|
2085
2457
|
const normalizedExpected = expectedType ? this.normalizeType(expectedType) : void 0;
|
|
2086
2458
|
const expectedFnType = normalizedExpected?.kind === "function_type" ? normalizedExpected : void 0;
|
|
@@ -2113,6 +2485,36 @@ var require_typechecker = __commonJS({
|
|
|
2113
2485
|
this.scope = outerScope;
|
|
2114
2486
|
this.currentReturnType = outerReturnType;
|
|
2115
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
|
+
}
|
|
2116
2518
|
inferType(expr, expectedType) {
|
|
2117
2519
|
switch (expr.kind) {
|
|
2118
2520
|
case "int_lit":
|
|
@@ -2144,8 +2546,12 @@ var require_typechecker = __commonJS({
|
|
|
2144
2546
|
case "ident":
|
|
2145
2547
|
return this.scope.get(expr.name)?.type ?? { kind: "named", name: "void" };
|
|
2146
2548
|
case "call": {
|
|
2549
|
+
const builtin = BUILTIN_SIGNATURES[expr.fn];
|
|
2550
|
+
if (builtin) {
|
|
2551
|
+
return builtin.return;
|
|
2552
|
+
}
|
|
2147
2553
|
if (expr.fn === "__array_push") {
|
|
2148
|
-
return
|
|
2554
|
+
return VOID_TYPE;
|
|
2149
2555
|
}
|
|
2150
2556
|
if (expr.fn === "__array_pop") {
|
|
2151
2557
|
const target = expr.args[0];
|
|
@@ -2154,20 +2560,28 @@ var require_typechecker = __commonJS({
|
|
|
2154
2560
|
if (targetType?.kind === "array")
|
|
2155
2561
|
return targetType.elem;
|
|
2156
2562
|
}
|
|
2157
|
-
return
|
|
2563
|
+
return INT_TYPE;
|
|
2158
2564
|
}
|
|
2159
2565
|
if (expr.fn === "bossbar_get_value") {
|
|
2160
|
-
return
|
|
2566
|
+
return INT_TYPE;
|
|
2161
2567
|
}
|
|
2162
2568
|
if (expr.fn === "random_sequence") {
|
|
2163
|
-
return
|
|
2569
|
+
return VOID_TYPE;
|
|
2164
2570
|
}
|
|
2165
2571
|
const varType = this.scope.get(expr.fn)?.type;
|
|
2166
2572
|
if (varType?.kind === "function_type") {
|
|
2167
2573
|
return varType.return;
|
|
2168
2574
|
}
|
|
2575
|
+
const implMethod = this.resolveInstanceMethod(expr);
|
|
2576
|
+
if (implMethod) {
|
|
2577
|
+
return this.normalizeType(implMethod.returnType);
|
|
2578
|
+
}
|
|
2169
2579
|
const fn = this.functions.get(expr.fn);
|
|
2170
|
-
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" };
|
|
2171
2585
|
}
|
|
2172
2586
|
case "invoke": {
|
|
2173
2587
|
const calleeType = this.inferType(expr.callee);
|
|
@@ -2198,6 +2612,8 @@ var require_typechecker = __commonJS({
|
|
|
2198
2612
|
return { kind: "named", name: "bool" };
|
|
2199
2613
|
}
|
|
2200
2614
|
return this.inferType(expr.left);
|
|
2615
|
+
case "is_check":
|
|
2616
|
+
return { kind: "named", name: "bool" };
|
|
2201
2617
|
case "unary":
|
|
2202
2618
|
if (expr.op === "!")
|
|
2203
2619
|
return { kind: "named", name: "bool" };
|
|
@@ -2207,6 +2623,14 @@ var require_typechecker = __commonJS({
|
|
|
2207
2623
|
return { kind: "array", elem: this.inferType(expr.elements[0]) };
|
|
2208
2624
|
}
|
|
2209
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" };
|
|
2210
2634
|
case "lambda":
|
|
2211
2635
|
return this.inferLambdaType(expr, expectedType && this.normalizeType(expectedType).kind === "function_type" ? this.normalizeType(expectedType) : void 0);
|
|
2212
2636
|
default:
|
|
@@ -2231,6 +2655,64 @@ var require_typechecker = __commonJS({
|
|
|
2231
2655
|
}
|
|
2232
2656
|
return { kind: "function_type", params, return: returnType };
|
|
2233
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
|
+
}
|
|
2234
2716
|
typesMatch(expected, actual) {
|
|
2235
2717
|
if (expected.kind !== actual.kind)
|
|
2236
2718
|
return false;
|
|
@@ -2251,6 +2733,12 @@ var require_typechecker = __commonJS({
|
|
|
2251
2733
|
if (expected.kind === "function_type" && actual.kind === "function_type") {
|
|
2252
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);
|
|
2253
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
|
+
}
|
|
2254
2742
|
return false;
|
|
2255
2743
|
}
|
|
2256
2744
|
typeToString(type) {
|
|
@@ -2265,6 +2753,12 @@ var require_typechecker = __commonJS({
|
|
|
2265
2753
|
return type.name;
|
|
2266
2754
|
case "function_type":
|
|
2267
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";
|
|
2268
2762
|
}
|
|
2269
2763
|
}
|
|
2270
2764
|
normalizeType(type) {
|
|
@@ -2281,6 +2775,12 @@ var require_typechecker = __commonJS({
|
|
|
2281
2775
|
if ((type.kind === "struct" || type.kind === "enum") && this.enums.has(type.name)) {
|
|
2282
2776
|
return { kind: "enum", name: type.name };
|
|
2283
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
|
+
}
|
|
2284
2784
|
return type;
|
|
2285
2785
|
}
|
|
2286
2786
|
};
|
|
@@ -2392,10 +2892,49 @@ var require_builder = __commonJS({
|
|
|
2392
2892
|
var require_lowering = __commonJS({
|
|
2393
2893
|
"../../dist/lowering/index.js"(exports2) {
|
|
2394
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
|
+
})();
|
|
2395
2932
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2396
2933
|
exports2.Lowering = void 0;
|
|
2397
2934
|
var builder_1 = require_builder();
|
|
2398
2935
|
var diagnostics_1 = require_diagnostics();
|
|
2936
|
+
var path = __importStar(require("path"));
|
|
2937
|
+
var types_1 = require_types();
|
|
2399
2938
|
var BUILTINS2 = {
|
|
2400
2939
|
say: ([msg]) => `say ${msg}`,
|
|
2401
2940
|
tell: ([sel, msg]) => `tellraw ${sel} {"text":"${msg}"}`,
|
|
@@ -2407,6 +2946,7 @@ var require_lowering = __commonJS({
|
|
|
2407
2946
|
give: ([sel, item, count, nbt]) => nbt ? `give ${sel} ${item}${nbt} ${count ?? "1"}` : `give ${sel} ${item} ${count ?? "1"}`,
|
|
2408
2947
|
kill: ([sel]) => `kill ${sel ?? "@s"}`,
|
|
2409
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}`,
|
|
2410
2950
|
summon: ([type, x, y, z, nbt]) => {
|
|
2411
2951
|
const pos = [x ?? "~", y ?? "~", z ?? "~"].join(" ");
|
|
2412
2952
|
return nbt ? `summon ${type} ${pos} ${nbt}` : `summon ${type} ${pos}`;
|
|
@@ -2484,6 +3024,8 @@ var require_lowering = __commonJS({
|
|
|
2484
3024
|
// Special handling
|
|
2485
3025
|
data_get: () => null,
|
|
2486
3026
|
// Special handling (returns value from NBT)
|
|
3027
|
+
data_merge: () => null,
|
|
3028
|
+
// Special handling (merge NBT)
|
|
2487
3029
|
set_new: () => null,
|
|
2488
3030
|
// Special handling (returns set ID)
|
|
2489
3031
|
set_add: () => null,
|
|
@@ -2492,7 +3034,13 @@ var require_lowering = __commonJS({
|
|
|
2492
3034
|
// Special handling (returns 1/0)
|
|
2493
3035
|
set_remove: () => null,
|
|
2494
3036
|
// Special handling
|
|
2495
|
-
set_clear: () => null
|
|
3037
|
+
set_clear: () => null,
|
|
3038
|
+
// Special handling
|
|
3039
|
+
setTimeout: () => null,
|
|
3040
|
+
// Special handling
|
|
3041
|
+
setInterval: () => null,
|
|
3042
|
+
// Special handling
|
|
3043
|
+
clearInterval: () => null
|
|
2496
3044
|
// Special handling
|
|
2497
3045
|
};
|
|
2498
3046
|
function getSpan(node) {
|
|
@@ -2500,6 +3048,22 @@ var require_lowering = __commonJS({
|
|
|
2500
3048
|
}
|
|
2501
3049
|
var NAMESPACED_ENTITY_TYPE_RE = /^[a-z0-9_.-]+:[a-z0-9_./-]+$/;
|
|
2502
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
|
+
};
|
|
2503
3067
|
function normalizeSelector(selector, warnings) {
|
|
2504
3068
|
return selector.replace(/type=([^,\]]+)/g, (match, entityType) => {
|
|
2505
3069
|
const trimmed = entityType.trim();
|
|
@@ -2533,17 +3097,23 @@ var require_lowering = __commonJS({
|
|
|
2533
3097
|
return `${emitCoord(pos.x)} ${emitCoord(pos.y)} ${emitCoord(pos.z)}`;
|
|
2534
3098
|
}
|
|
2535
3099
|
var Lowering = class {
|
|
2536
|
-
constructor(namespace) {
|
|
3100
|
+
constructor(namespace, sourceRanges = []) {
|
|
2537
3101
|
this.functions = [];
|
|
2538
3102
|
this.globals = [];
|
|
3103
|
+
this.globalNames = /* @__PURE__ */ new Map();
|
|
2539
3104
|
this.fnDecls = /* @__PURE__ */ new Map();
|
|
3105
|
+
this.implMethods = /* @__PURE__ */ new Map();
|
|
2540
3106
|
this.specializedFunctions = /* @__PURE__ */ new Map();
|
|
2541
3107
|
this.currentFn = "";
|
|
2542
3108
|
this.foreachCounter = 0;
|
|
2543
3109
|
this.lambdaCounter = 0;
|
|
3110
|
+
this.timeoutCounter = 0;
|
|
3111
|
+
this.intervalCounter = 0;
|
|
2544
3112
|
this.warnings = [];
|
|
2545
3113
|
this.varMap = /* @__PURE__ */ new Map();
|
|
2546
3114
|
this.lambdaBindings = /* @__PURE__ */ new Map();
|
|
3115
|
+
this.intervalBindings = /* @__PURE__ */ new Map();
|
|
3116
|
+
this.intervalFunctions = /* @__PURE__ */ new Map();
|
|
2547
3117
|
this.currentCallbackBindings = /* @__PURE__ */ new Map();
|
|
2548
3118
|
this.currentContext = {};
|
|
2549
3119
|
this.blockPosVars = /* @__PURE__ */ new Map();
|
|
@@ -2556,6 +3126,8 @@ var require_lowering = __commonJS({
|
|
|
2556
3126
|
this.floatVars = /* @__PURE__ */ new Set();
|
|
2557
3127
|
this.worldObjCounter = 0;
|
|
2558
3128
|
this.namespace = namespace;
|
|
3129
|
+
this.sourceRanges = sourceRanges;
|
|
3130
|
+
LoweringBuilder.resetTempCounter();
|
|
2559
3131
|
}
|
|
2560
3132
|
lower(program) {
|
|
2561
3133
|
this.namespace = program.namespace;
|
|
@@ -2577,13 +3149,37 @@ var require_lowering = __commonJS({
|
|
|
2577
3149
|
this.constValues.set(constDecl.name, constDecl.value);
|
|
2578
3150
|
this.varTypes.set(constDecl.name, this.normalizeType(constDecl.type));
|
|
2579
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
|
+
}
|
|
2580
3158
|
for (const fn of program.declarations) {
|
|
2581
3159
|
this.fnDecls.set(fn.name, fn);
|
|
2582
3160
|
this.functionDefaults.set(fn.name, fn.params.map((param) => param.default));
|
|
2583
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
|
+
}
|
|
2584
3175
|
for (const fn of program.declarations) {
|
|
2585
3176
|
this.lowerFn(fn);
|
|
2586
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
|
+
}
|
|
2587
3183
|
return (0, builder_1.buildModule)(this.namespace, this.functions, this.globals);
|
|
2588
3184
|
}
|
|
2589
3185
|
// -------------------------------------------------------------------------
|
|
@@ -2592,20 +3188,44 @@ var require_lowering = __commonJS({
|
|
|
2592
3188
|
lowerFn(fn, options = {}) {
|
|
2593
3189
|
const loweredName = options.name ?? fn.name;
|
|
2594
3190
|
const callbackBindings = options.callbackBindings ?? /* @__PURE__ */ new Map();
|
|
2595
|
-
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));
|
|
2596
3196
|
this.currentFn = loweredName;
|
|
3197
|
+
this.currentStdlibCallSite = stdlibCallSite;
|
|
2597
3198
|
this.foreachCounter = 0;
|
|
2598
3199
|
this.varMap = /* @__PURE__ */ new Map();
|
|
2599
3200
|
this.lambdaBindings = /* @__PURE__ */ new Map();
|
|
3201
|
+
this.intervalBindings = /* @__PURE__ */ new Map();
|
|
2600
3202
|
this.currentCallbackBindings = new Map(callbackBindings);
|
|
2601
3203
|
this.currentContext = {};
|
|
2602
3204
|
this.blockPosVars = /* @__PURE__ */ new Map();
|
|
2603
3205
|
this.stringValues = /* @__PURE__ */ new Map();
|
|
2604
3206
|
this.builder = new LoweringBuilder();
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
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
|
+
}
|
|
2609
3229
|
}
|
|
2610
3230
|
for (const param of fn.params) {
|
|
2611
3231
|
if (callbackBindings.has(param.name)) {
|
|
@@ -2618,6 +3238,15 @@ var require_lowering = __commonJS({
|
|
|
2618
3238
|
const varName = `$${paramName}`;
|
|
2619
3239
|
this.builder.emitAssign(varName, { kind: "var", name: `$p${i}` });
|
|
2620
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
|
+
}
|
|
2621
3250
|
this.lowerBlock(fn.body);
|
|
2622
3251
|
if (!this.builder.isBlockSealed()) {
|
|
2623
3252
|
this.builder.emitReturn();
|
|
@@ -2652,6 +3281,15 @@ var require_lowering = __commonJS({
|
|
|
2652
3281
|
break;
|
|
2653
3282
|
}
|
|
2654
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
|
+
}
|
|
2655
3293
|
if (tickRate && tickRate > 1) {
|
|
2656
3294
|
this.wrapWithTickRate(irFn, tickRate);
|
|
2657
3295
|
}
|
|
@@ -2663,7 +3301,7 @@ var require_lowering = __commonJS({
|
|
|
2663
3301
|
}
|
|
2664
3302
|
wrapWithTickRate(fn, rate) {
|
|
2665
3303
|
const counterVar = `$__tick_${fn.name}`;
|
|
2666
|
-
this.globals.push(counterVar);
|
|
3304
|
+
this.globals.push({ name: counterVar, init: 0 });
|
|
2667
3305
|
const entry = fn.blocks[0];
|
|
2668
3306
|
const originalInstrs = [...entry.instrs];
|
|
2669
3307
|
const originalTerm = entry.term;
|
|
@@ -2751,6 +3389,9 @@ var require_lowering = __commonJS({
|
|
|
2751
3389
|
}
|
|
2752
3390
|
}
|
|
2753
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
|
+
}
|
|
2754
3395
|
const varName = `$${stmt.name}`;
|
|
2755
3396
|
this.varMap.set(stmt.name, varName);
|
|
2756
3397
|
const declaredType = stmt.type ? this.normalizeType(stmt.type) : this.inferExprType(stmt.init);
|
|
@@ -2765,15 +3406,24 @@ var require_lowering = __commonJS({
|
|
|
2765
3406
|
this.lambdaBindings.set(stmt.name, lambdaName);
|
|
2766
3407
|
return;
|
|
2767
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
|
+
}
|
|
2768
3418
|
if (stmt.init.kind === "struct_lit" && stmt.type?.kind === "struct") {
|
|
2769
3419
|
const structName = stmt.type.name.toLowerCase();
|
|
2770
3420
|
for (const field of stmt.init.fields) {
|
|
2771
|
-
const
|
|
3421
|
+
const path2 = `rs:heap ${structName}_${stmt.name}.${field.name}`;
|
|
2772
3422
|
const fieldValue = this.lowerExpr(field.value);
|
|
2773
3423
|
if (fieldValue.kind === "const") {
|
|
2774
|
-
this.builder.emitRaw(`data modify storage ${
|
|
3424
|
+
this.builder.emitRaw(`data modify storage ${path2} set value ${fieldValue.value}`);
|
|
2775
3425
|
} else if (fieldValue.kind === "var") {
|
|
2776
|
-
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`);
|
|
2777
3427
|
}
|
|
2778
3428
|
}
|
|
2779
3429
|
return;
|
|
@@ -2826,6 +3476,10 @@ var require_lowering = __commonJS({
|
|
|
2826
3476
|
}
|
|
2827
3477
|
}
|
|
2828
3478
|
lowerIfStmt(stmt) {
|
|
3479
|
+
if (stmt.cond.kind === "is_check") {
|
|
3480
|
+
this.lowerIsCheckIfStmt(stmt);
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
2829
3483
|
const condVar = this.lowerExpr(stmt.cond);
|
|
2830
3484
|
const condName = this.operandToVar(condVar);
|
|
2831
3485
|
const thenLabel = this.builder.freshLabel("then");
|
|
@@ -2846,6 +3500,40 @@ var require_lowering = __commonJS({
|
|
|
2846
3500
|
}
|
|
2847
3501
|
this.builder.startBlock(mergeLabel);
|
|
2848
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
|
+
}
|
|
2849
3537
|
lowerWhileStmt(stmt) {
|
|
2850
3538
|
const checkLabel = this.builder.freshLabel("loop_check");
|
|
2851
3539
|
const bodyLabel = this.builder.freshLabel("loop_body");
|
|
@@ -3116,10 +3804,20 @@ var require_lowering = __commonJS({
|
|
|
3116
3804
|
parts.push(`at ${this.selectorToString(sub.selector)}`);
|
|
3117
3805
|
break;
|
|
3118
3806
|
case "if_entity":
|
|
3119
|
-
|
|
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
|
+
}
|
|
3120
3813
|
break;
|
|
3121
3814
|
case "unless_entity":
|
|
3122
|
-
|
|
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
|
+
}
|
|
3123
3821
|
break;
|
|
3124
3822
|
case "in":
|
|
3125
3823
|
parts.push(`in ${sub.dimension}`);
|
|
@@ -3204,12 +3902,16 @@ var require_lowering = __commonJS({
|
|
|
3204
3902
|
return { kind: "var", name: this.selectorToString(expr.sel) };
|
|
3205
3903
|
case "binary":
|
|
3206
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 });
|
|
3207
3907
|
case "unary":
|
|
3208
3908
|
return this.lowerUnaryExpr(expr);
|
|
3209
3909
|
case "assign":
|
|
3210
3910
|
return this.lowerAssignExpr(expr);
|
|
3211
3911
|
case "call":
|
|
3212
3912
|
return this.lowerCallExpr(expr);
|
|
3913
|
+
case "static_call":
|
|
3914
|
+
return this.lowerStaticCallExpr(expr);
|
|
3213
3915
|
case "invoke":
|
|
3214
3916
|
return this.lowerInvokeExpr(expr);
|
|
3215
3917
|
case "member_assign":
|
|
@@ -3236,9 +3938,9 @@ var require_lowering = __commonJS({
|
|
|
3236
3938
|
}
|
|
3237
3939
|
if (varType?.kind === "struct") {
|
|
3238
3940
|
const structName = varType.name.toLowerCase();
|
|
3239
|
-
const
|
|
3941
|
+
const path2 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
|
|
3240
3942
|
const dst = this.builder.freshTemp();
|
|
3241
|
-
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}`);
|
|
3242
3944
|
return { kind: "var", name: dst };
|
|
3243
3945
|
}
|
|
3244
3946
|
if (varType?.kind === "array" && expr.field === "len") {
|
|
@@ -3276,20 +3978,20 @@ var require_lowering = __commonJS({
|
|
|
3276
3978
|
}
|
|
3277
3979
|
if (varType?.kind === "struct") {
|
|
3278
3980
|
const structName = varType.name.toLowerCase();
|
|
3279
|
-
const
|
|
3981
|
+
const path2 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
|
|
3280
3982
|
const value2 = this.lowerExpr(expr.value);
|
|
3281
3983
|
if (expr.op === "=") {
|
|
3282
3984
|
if (value2.kind === "const") {
|
|
3283
|
-
this.builder.emitRaw(`data modify storage ${
|
|
3985
|
+
this.builder.emitRaw(`data modify storage ${path2} set value ${value2.value}`);
|
|
3284
3986
|
} else if (value2.kind === "var") {
|
|
3285
|
-
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`);
|
|
3286
3988
|
}
|
|
3287
3989
|
} else {
|
|
3288
3990
|
const dst = this.builder.freshTemp();
|
|
3289
|
-
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}`);
|
|
3290
3992
|
const binOp = expr.op.slice(0, -1);
|
|
3291
3993
|
this.builder.emitBinop(dst, { kind: "var", name: dst }, binOp, value2);
|
|
3292
|
-
this.builder.emitRaw(`execute store result storage ${
|
|
3994
|
+
this.builder.emitRaw(`execute store result storage ${path2} int 1 run scoreboard players get ${dst} rs`);
|
|
3293
3995
|
}
|
|
3294
3996
|
return { kind: "const", value: 0 };
|
|
3295
3997
|
}
|
|
@@ -3368,6 +4070,13 @@ var require_lowering = __commonJS({
|
|
|
3368
4070
|
return { kind: "var", name: dst };
|
|
3369
4071
|
}
|
|
3370
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
|
+
}
|
|
3371
4080
|
const blockPosValue = this.resolveBlockPosExpr(expr.value);
|
|
3372
4081
|
if (blockPosValue) {
|
|
3373
4082
|
this.blockPosVars.set(expr.target, blockPosValue);
|
|
@@ -3475,6 +4184,10 @@ var require_lowering = __commonJS({
|
|
|
3475
4184
|
if (callbackTarget) {
|
|
3476
4185
|
return this.emitDirectFunctionCall(callbackTarget, expr.args);
|
|
3477
4186
|
}
|
|
4187
|
+
const implMethod = this.resolveInstanceMethod(expr);
|
|
4188
|
+
if (implMethod) {
|
|
4189
|
+
return this.emitMethodCall(implMethod.loweredName, implMethod.fn, expr.args);
|
|
4190
|
+
}
|
|
3478
4191
|
const fnDecl = this.fnDecls.get(expr.fn);
|
|
3479
4192
|
const defaultArgs = this.functionDefaults.get(expr.fn) ?? [];
|
|
3480
4193
|
const fullArgs = [...expr.args];
|
|
@@ -3500,11 +4213,17 @@ var require_lowering = __commonJS({
|
|
|
3500
4213
|
}
|
|
3501
4214
|
runtimeArgs.push(fullArgs[i]);
|
|
3502
4215
|
}
|
|
3503
|
-
const
|
|
4216
|
+
const stdlibCallSite = this.getStdlibCallSiteContext(fnDecl, getSpan(expr));
|
|
4217
|
+
const targetFn = callbackBindings.size > 0 || stdlibCallSite ? this.ensureSpecializedFunctionWithContext(fnDecl, callbackBindings, stdlibCallSite) : expr.fn;
|
|
3504
4218
|
return this.emitDirectFunctionCall(targetFn, runtimeArgs);
|
|
3505
4219
|
}
|
|
3506
4220
|
return this.emitDirectFunctionCall(expr.fn, fullArgs);
|
|
3507
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
|
+
}
|
|
3508
4227
|
lowerInvokeExpr(expr) {
|
|
3509
4228
|
if (expr.callee.kind === "lambda") {
|
|
3510
4229
|
if (!Array.isArray(expr.callee.body)) {
|
|
@@ -3549,6 +4268,18 @@ var require_lowering = __commonJS({
|
|
|
3549
4268
|
this.builder.emitCall(fn, loweredArgs, dst);
|
|
3550
4269
|
return { kind: "var", name: dst };
|
|
3551
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
|
+
}
|
|
3552
4283
|
resolveFunctionRefExpr(expr) {
|
|
3553
4284
|
if (expr.kind === "lambda") {
|
|
3554
4285
|
return this.lowerLambdaExpr(expr);
|
|
@@ -3562,7 +4293,14 @@ var require_lowering = __commonJS({
|
|
|
3562
4293
|
return this.lambdaBindings.get(name) ?? this.currentCallbackBindings.get(name) ?? null;
|
|
3563
4294
|
}
|
|
3564
4295
|
ensureSpecializedFunction(fn, callbackBindings) {
|
|
4296
|
+
return this.ensureSpecializedFunctionWithContext(fn, callbackBindings);
|
|
4297
|
+
}
|
|
4298
|
+
ensureSpecializedFunctionWithContext(fn, callbackBindings, stdlibCallSite) {
|
|
3565
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
|
+
}
|
|
3566
4304
|
const key = `${fn.name}::${parts.join("::")}`;
|
|
3567
4305
|
const cached = this.specializedFunctions.get(key);
|
|
3568
4306
|
if (cached) {
|
|
@@ -3571,7 +4309,7 @@ var require_lowering = __commonJS({
|
|
|
3571
4309
|
const specializedName = `${fn.name}__${parts.join("__")}`;
|
|
3572
4310
|
this.specializedFunctions.set(key, specializedName);
|
|
3573
4311
|
this.withSavedFunctionState(() => {
|
|
3574
|
-
this.lowerFn(fn, { name: specializedName, callbackBindings });
|
|
4312
|
+
this.lowerFn(fn, { name: specializedName, callbackBindings, stdlibCallSite });
|
|
3575
4313
|
});
|
|
3576
4314
|
return specializedName;
|
|
3577
4315
|
}
|
|
@@ -3594,10 +4332,12 @@ var require_lowering = __commonJS({
|
|
|
3594
4332
|
}
|
|
3595
4333
|
withSavedFunctionState(callback) {
|
|
3596
4334
|
const savedCurrentFn = this.currentFn;
|
|
4335
|
+
const savedStdlibCallSite = this.currentStdlibCallSite;
|
|
3597
4336
|
const savedForeachCounter = this.foreachCounter;
|
|
3598
4337
|
const savedBuilder = this.builder;
|
|
3599
4338
|
const savedVarMap = new Map(this.varMap);
|
|
3600
4339
|
const savedLambdaBindings = new Map(this.lambdaBindings);
|
|
4340
|
+
const savedIntervalBindings = new Map(this.intervalBindings);
|
|
3601
4341
|
const savedCallbackBindings = new Map(this.currentCallbackBindings);
|
|
3602
4342
|
const savedContext = this.currentContext;
|
|
3603
4343
|
const savedBlockPosVars = new Map(this.blockPosVars);
|
|
@@ -3607,10 +4347,12 @@ var require_lowering = __commonJS({
|
|
|
3607
4347
|
return callback();
|
|
3608
4348
|
} finally {
|
|
3609
4349
|
this.currentFn = savedCurrentFn;
|
|
4350
|
+
this.currentStdlibCallSite = savedStdlibCallSite;
|
|
3610
4351
|
this.foreachCounter = savedForeachCounter;
|
|
3611
4352
|
this.builder = savedBuilder;
|
|
3612
4353
|
this.varMap = savedVarMap;
|
|
3613
4354
|
this.lambdaBindings = savedLambdaBindings;
|
|
4355
|
+
this.intervalBindings = savedIntervalBindings;
|
|
3614
4356
|
this.currentCallbackBindings = savedCallbackBindings;
|
|
3615
4357
|
this.currentContext = savedContext;
|
|
3616
4358
|
this.blockPosVars = savedBlockPosVars;
|
|
@@ -3624,6 +4366,15 @@ var require_lowering = __commonJS({
|
|
|
3624
4366
|
this.builder.emitRaw(richTextCommand);
|
|
3625
4367
|
return { kind: "const", value: 0 };
|
|
3626
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
|
+
}
|
|
3627
4378
|
if (name === "random") {
|
|
3628
4379
|
const dst = this.builder.freshTemp();
|
|
3629
4380
|
const min = args[0] ? this.exprToLiteral(args[0]) : "0";
|
|
@@ -3647,13 +4398,13 @@ var require_lowering = __commonJS({
|
|
|
3647
4398
|
if (name === "scoreboard_get" || name === "score") {
|
|
3648
4399
|
const dst = this.builder.freshTemp();
|
|
3649
4400
|
const player = this.exprToTargetString(args[0]);
|
|
3650
|
-
const objective = this.
|
|
4401
|
+
const objective = this.resolveScoreboardObjective(args[0], args[1], callSpan);
|
|
3651
4402
|
this.builder.emitRaw(`execute store result score ${dst} rs run scoreboard players get ${player} ${objective}`);
|
|
3652
4403
|
return { kind: "var", name: dst };
|
|
3653
4404
|
}
|
|
3654
4405
|
if (name === "scoreboard_set") {
|
|
3655
4406
|
const player = this.exprToTargetString(args[0]);
|
|
3656
|
-
const objective = this.
|
|
4407
|
+
const objective = this.resolveScoreboardObjective(args[0], args[1], callSpan);
|
|
3657
4408
|
const value = this.lowerExpr(args[2]);
|
|
3658
4409
|
if (value.kind === "const") {
|
|
3659
4410
|
this.builder.emitRaw(`scoreboard players set ${player} ${objective} ${value.value}`);
|
|
@@ -3664,7 +4415,7 @@ var require_lowering = __commonJS({
|
|
|
3664
4415
|
}
|
|
3665
4416
|
if (name === "scoreboard_display") {
|
|
3666
4417
|
const slot = this.exprToString(args[0]);
|
|
3667
|
-
const objective = this.
|
|
4418
|
+
const objective = this.resolveScoreboardObjective(void 0, args[1], callSpan);
|
|
3668
4419
|
this.builder.emitRaw(`scoreboard objectives setdisplay ${slot} ${objective}`);
|
|
3669
4420
|
return { kind: "const", value: 0 };
|
|
3670
4421
|
}
|
|
@@ -3674,14 +4425,14 @@ var require_lowering = __commonJS({
|
|
|
3674
4425
|
return { kind: "const", value: 0 };
|
|
3675
4426
|
}
|
|
3676
4427
|
if (name === "scoreboard_add_objective") {
|
|
3677
|
-
const objective = this.
|
|
4428
|
+
const objective = this.resolveScoreboardObjective(void 0, args[0], callSpan);
|
|
3678
4429
|
const criteria = this.exprToString(args[1]);
|
|
3679
4430
|
const displayName = args[2] ? ` ${this.exprToQuotedString(args[2])}` : "";
|
|
3680
4431
|
this.builder.emitRaw(`scoreboard objectives add ${objective} ${criteria}${displayName}`);
|
|
3681
4432
|
return { kind: "const", value: 0 };
|
|
3682
4433
|
}
|
|
3683
4434
|
if (name === "scoreboard_remove_objective") {
|
|
3684
|
-
const objective = this.
|
|
4435
|
+
const objective = this.resolveScoreboardObjective(void 0, args[0], callSpan);
|
|
3685
4436
|
this.builder.emitRaw(`scoreboard objectives remove ${objective}`);
|
|
3686
4437
|
return { kind: "const", value: 0 };
|
|
3687
4438
|
}
|
|
@@ -3753,11 +4504,28 @@ var require_lowering = __commonJS({
|
|
|
3753
4504
|
const dst = this.builder.freshTemp();
|
|
3754
4505
|
const targetType = this.exprToString(args[0]);
|
|
3755
4506
|
const target = targetType === "entity" ? this.exprToTargetString(args[1]) : this.exprToString(args[1]);
|
|
3756
|
-
const
|
|
4507
|
+
const path2 = this.exprToString(args[2]);
|
|
3757
4508
|
const scale = args[3] ? this.exprToString(args[3]) : "1";
|
|
3758
|
-
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}`);
|
|
3759
4510
|
return { kind: "var", name: dst };
|
|
3760
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
|
+
}
|
|
3761
4529
|
if (name === "set_new") {
|
|
3762
4530
|
const setId = `__set_${this.foreachCounter++}`;
|
|
3763
4531
|
this.builder.emitRaw(`data modify storage rs:sets ${setId} set value []`);
|
|
@@ -3818,6 +4586,90 @@ var require_lowering = __commonJS({
|
|
|
3818
4586
|
}
|
|
3819
4587
|
return { kind: "const", value: 0 };
|
|
3820
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
|
+
}
|
|
3821
4673
|
lowerRichTextBuiltin(name, args) {
|
|
3822
4674
|
const messageArgIndex = this.getRichTextArgIndex(name);
|
|
3823
4675
|
if (messageArgIndex === null) {
|
|
@@ -3960,11 +4812,42 @@ var require_lowering = __commonJS({
|
|
|
3960
4812
|
}
|
|
3961
4813
|
case "selector":
|
|
3962
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);
|
|
3963
4824
|
default:
|
|
3964
4825
|
const op = this.lowerExpr(expr);
|
|
3965
4826
|
return this.operandToVar(op);
|
|
3966
4827
|
}
|
|
3967
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
|
+
}
|
|
3968
4851
|
exprToSnbt(expr) {
|
|
3969
4852
|
switch (expr.kind) {
|
|
3970
4853
|
case "struct_lit": {
|
|
@@ -4032,6 +4915,92 @@ var require_lowering = __commonJS({
|
|
|
4032
4915
|
isTeamTextOption(option) {
|
|
4033
4916
|
return option === "displayName" || option === "prefix" || option === "suffix";
|
|
4034
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
|
+
}
|
|
4035
5004
|
lowerCoordinateBuiltin(name, args) {
|
|
4036
5005
|
const pos0 = args[0] ? this.resolveBlockPosExpr(args[0]) : null;
|
|
4037
5006
|
const pos1 = args[1] ? this.resolveBlockPosExpr(args[1]) : null;
|
|
@@ -4054,6 +5023,13 @@ var require_lowering = __commonJS({
|
|
|
4054
5023
|
}
|
|
4055
5024
|
return null;
|
|
4056
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
|
+
}
|
|
4057
5033
|
return null;
|
|
4058
5034
|
}
|
|
4059
5035
|
lowerTpCommand(args) {
|
|
@@ -4132,7 +5108,11 @@ var require_lowering = __commonJS({
|
|
|
4132
5108
|
};
|
|
4133
5109
|
}
|
|
4134
5110
|
if (expr.kind === "call") {
|
|
4135
|
-
|
|
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;
|
|
4136
5116
|
}
|
|
4137
5117
|
if (expr.kind === "invoke") {
|
|
4138
5118
|
const calleeType = this.inferExprType(expr.callee);
|
|
@@ -4160,6 +5140,21 @@ var require_lowering = __commonJS({
|
|
|
4160
5140
|
}
|
|
4161
5141
|
return void 0;
|
|
4162
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
|
+
}
|
|
4163
5158
|
normalizeType(type) {
|
|
4164
5159
|
if (type.kind === "array") {
|
|
4165
5160
|
return { kind: "array", elem: this.normalizeType(type.elem) };
|
|
@@ -4281,6 +5276,16 @@ var require_lowering = __commonJS({
|
|
|
4281
5276
|
parts.push(`nbt=${filters.nbt}`);
|
|
4282
5277
|
if (filters.gamemode)
|
|
4283
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)}`);
|
|
4284
5289
|
return this.finalizeSelector(parts.length ? `${kind}[${parts.join(",")}]` : kind);
|
|
4285
5290
|
}
|
|
4286
5291
|
finalizeSelector(selector) {
|
|
@@ -4300,16 +5305,19 @@ var require_lowering = __commonJS({
|
|
|
4300
5305
|
}
|
|
4301
5306
|
};
|
|
4302
5307
|
exports2.Lowering = Lowering;
|
|
4303
|
-
var LoweringBuilder = class {
|
|
5308
|
+
var LoweringBuilder = class _LoweringBuilder {
|
|
4304
5309
|
constructor() {
|
|
4305
|
-
this.tempCount = 0;
|
|
4306
5310
|
this.labelCount = 0;
|
|
4307
5311
|
this.blocks = [];
|
|
4308
5312
|
this.currentBlock = null;
|
|
4309
5313
|
this.locals = /* @__PURE__ */ new Set();
|
|
4310
5314
|
}
|
|
5315
|
+
/** Reset the global temp counter (call between compilations). */
|
|
5316
|
+
static resetTempCounter() {
|
|
5317
|
+
_LoweringBuilder.globalTempId = 0;
|
|
5318
|
+
}
|
|
4311
5319
|
freshTemp() {
|
|
4312
|
-
const name = `$
|
|
5320
|
+
const name = `$_${_LoweringBuilder.globalTempId++}`;
|
|
4313
5321
|
this.locals.add(name);
|
|
4314
5322
|
return name;
|
|
4315
5323
|
}
|
|
@@ -4374,6 +5382,7 @@ var require_lowering = __commonJS({
|
|
|
4374
5382
|
};
|
|
4375
5383
|
}
|
|
4376
5384
|
};
|
|
5385
|
+
LoweringBuilder.globalTempId = 0;
|
|
4377
5386
|
}
|
|
4378
5387
|
});
|
|
4379
5388
|
|
|
@@ -4941,6 +5950,7 @@ var require_mcfunction = __commonJS({
|
|
|
4941
5950
|
exports2.generateDatapackWithStats = generateDatapackWithStats;
|
|
4942
5951
|
exports2.generateDatapack = generateDatapack;
|
|
4943
5952
|
var commands_1 = require_commands();
|
|
5953
|
+
var types_1 = require_types();
|
|
4944
5954
|
var OBJ = "rs";
|
|
4945
5955
|
function varRef(name) {
|
|
4946
5956
|
return name.startsWith("$") ? name : `$${name}`;
|
|
@@ -5132,6 +6142,8 @@ var require_mcfunction = __commonJS({
|
|
|
5132
6142
|
const ns = module3.namespace;
|
|
5133
6143
|
const triggerHandlers = module3.functions.filter((fn) => fn.isTriggerHandler && fn.triggerName);
|
|
5134
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));
|
|
5135
6147
|
const tickFunctionNames = [];
|
|
5136
6148
|
for (const fn of module3.functions) {
|
|
5137
6149
|
if (fn.isTickLoop) {
|
|
@@ -5149,12 +6161,24 @@ var require_mcfunction = __commonJS({
|
|
|
5149
6161
|
`scoreboard objectives add ${OBJ} dummy`
|
|
5150
6162
|
];
|
|
5151
6163
|
for (const g of module3.globals) {
|
|
5152
|
-
loadLines.push(`scoreboard players set ${varRef(g)} ${OBJ}
|
|
6164
|
+
loadLines.push(`scoreboard players set ${varRef(g.name)} ${OBJ} ${g.init}`);
|
|
5153
6165
|
}
|
|
5154
6166
|
for (const triggerName of triggerNames) {
|
|
5155
6167
|
loadLines.push(`scoreboard objectives add ${triggerName} trigger`);
|
|
5156
6168
|
loadLines.push(`scoreboard players enable @a ${triggerName}`);
|
|
5157
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
|
+
}
|
|
5158
6182
|
for (const triggerName of triggerNames) {
|
|
5159
6183
|
const handlers = triggerHandlers.filter((fn) => fn.triggerName === triggerName);
|
|
5160
6184
|
const dispatchLines = [
|
|
@@ -5191,6 +6215,11 @@ var require_mcfunction = __commonJS({
|
|
|
5191
6215
|
files.push({ path: filePath, content: lines.join("\n") });
|
|
5192
6216
|
}
|
|
5193
6217
|
}
|
|
6218
|
+
for (const fn of module3.functions) {
|
|
6219
|
+
if (fn.isLoadInit) {
|
|
6220
|
+
loadLines.push(`function ${ns}:${fn.name}`);
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
5194
6223
|
files.push({
|
|
5195
6224
|
path: `data/${ns}/function/__load.mcfunction`,
|
|
5196
6225
|
content: loadLines.join("\n")
|
|
@@ -5209,7 +6238,18 @@ var require_mcfunction = __commonJS({
|
|
|
5209
6238
|
tickLines.push(`execute as @a[scores={${triggerName}=1..}] run function ${ns}:__trigger_${triggerName}_dispatch`);
|
|
5210
6239
|
}
|
|
5211
6240
|
}
|
|
5212
|
-
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) {
|
|
5213
6253
|
files.push({
|
|
5214
6254
|
path: `data/${ns}/function/__tick.mcfunction`,
|
|
5215
6255
|
content: tickLines.join("\n")
|
|
@@ -5329,6 +6369,7 @@ var require_compile = __commonJS({
|
|
|
5329
6369
|
};
|
|
5330
6370
|
})();
|
|
5331
6371
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
6372
|
+
exports2.preprocessSourceWithMetadata = preprocessSourceWithMetadata;
|
|
5332
6373
|
exports2.preprocessSource = preprocessSource;
|
|
5333
6374
|
exports2.compile = compile;
|
|
5334
6375
|
exports2.formatCompileError = formatCompileError;
|
|
@@ -5341,7 +6382,17 @@ var require_compile = __commonJS({
|
|
|
5341
6382
|
var mcfunction_1 = require_mcfunction();
|
|
5342
6383
|
var diagnostics_1 = require_diagnostics();
|
|
5343
6384
|
var IMPORT_RE = /^\s*import\s+"([^"]+)"\s*;?\s*$/;
|
|
5344
|
-
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 = {}) {
|
|
5345
6396
|
const { filePath } = options;
|
|
5346
6397
|
const seen = options.seen ?? /* @__PURE__ */ new Set();
|
|
5347
6398
|
if (filePath) {
|
|
@@ -5368,7 +6419,7 @@ var require_compile = __commonJS({
|
|
|
5368
6419
|
} catch {
|
|
5369
6420
|
throw new diagnostics_1.DiagnosticError("ParseError", `Cannot import '${match[1]}'`, { file: filePath, line: i + 1, col: 1 }, lines);
|
|
5370
6421
|
}
|
|
5371
|
-
imports.push(
|
|
6422
|
+
imports.push(preprocessSourceWithMetadata(importedSource, { filePath: importPath, seen }));
|
|
5372
6423
|
}
|
|
5373
6424
|
continue;
|
|
5374
6425
|
}
|
|
@@ -5379,17 +6430,37 @@ var require_compile = __commonJS({
|
|
|
5379
6430
|
parsingHeader = false;
|
|
5380
6431
|
bodyLines.push(line);
|
|
5381
6432
|
}
|
|
5382
|
-
|
|
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;
|
|
5383
6453
|
}
|
|
5384
6454
|
function compile(source, options = {}) {
|
|
5385
6455
|
const { namespace = "redscript", filePath, optimize: shouldOptimize = true } = options;
|
|
5386
6456
|
let sourceLines = source.split("\n");
|
|
5387
6457
|
try {
|
|
5388
|
-
const
|
|
6458
|
+
const preprocessed = preprocessSourceWithMetadata(source, { filePath });
|
|
6459
|
+
const preprocessedSource = preprocessed.source;
|
|
5389
6460
|
sourceLines = preprocessedSource.split("\n");
|
|
5390
6461
|
const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
|
|
5391
6462
|
const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
|
|
5392
|
-
const ir = new lowering_1.Lowering(namespace).lower(ast);
|
|
6463
|
+
const ir = new lowering_1.Lowering(namespace, preprocessed.ranges).lower(ast);
|
|
5393
6464
|
const optimized = shouldOptimize ? { ...ir, functions: ir.functions.map((fn) => (0, passes_1.optimize)(fn)) } : ir;
|
|
5394
6465
|
const generated = (0, mcfunction_1.generateDatapackWithStats)(optimized);
|
|
5395
6466
|
return {
|
|
@@ -5773,7 +6844,8 @@ var require_dist = __commonJS({
|
|
|
5773
6844
|
const shouldOptimize = options.optimize ?? true;
|
|
5774
6845
|
const shouldTypeCheck = options.typeCheck ?? true;
|
|
5775
6846
|
const filePath = options.filePath;
|
|
5776
|
-
const
|
|
6847
|
+
const preprocessed = (0, compile_1.preprocessSourceWithMetadata)(source, { filePath });
|
|
6848
|
+
const preprocessedSource = preprocessed.source;
|
|
5777
6849
|
const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
|
|
5778
6850
|
const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
|
|
5779
6851
|
let typeErrors;
|
|
@@ -5781,7 +6853,7 @@ var require_dist = __commonJS({
|
|
|
5781
6853
|
const checker = new typechecker_1.TypeChecker(preprocessedSource, filePath);
|
|
5782
6854
|
typeErrors = checker.check(ast);
|
|
5783
6855
|
}
|
|
5784
|
-
const lowering = new lowering_1.Lowering(namespace);
|
|
6856
|
+
const lowering = new lowering_1.Lowering(namespace, preprocessed.ranges);
|
|
5785
6857
|
const ir = lowering.lower(ast);
|
|
5786
6858
|
let optimizedIR = ir;
|
|
5787
6859
|
let generated = (0, mcfunction_1.generateDatapackWithStats)(ir, { optimizeCommands: shouldOptimize });
|