redscript-mc 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/__tests__/cli.test.js +138 -0
  3. package/dist/__tests__/codegen.test.js +25 -0
  4. package/dist/__tests__/e2e.test.js +190 -12
  5. package/dist/__tests__/lexer.test.js +12 -2
  6. package/dist/__tests__/lowering.test.js +164 -9
  7. package/dist/__tests__/mc-integration.test.js +145 -51
  8. package/dist/__tests__/optimizer-advanced.test.js +3 -3
  9. package/dist/__tests__/parser.test.js +80 -0
  10. package/dist/__tests__/runtime.test.js +8 -8
  11. package/dist/__tests__/typechecker.test.js +158 -0
  12. package/dist/ast/types.d.ts +20 -1
  13. package/dist/codegen/mcfunction/index.js +30 -1
  14. package/dist/codegen/structure/index.js +25 -0
  15. package/dist/compile.d.ts +10 -0
  16. package/dist/compile.js +36 -5
  17. package/dist/events/types.d.ts +35 -0
  18. package/dist/events/types.js +59 -0
  19. package/dist/index.js +3 -2
  20. package/dist/ir/types.d.ts +4 -0
  21. package/dist/lexer/index.d.ts +1 -1
  22. package/dist/lexer/index.js +2 -0
  23. package/dist/lowering/index.d.ts +32 -1
  24. package/dist/lowering/index.js +439 -15
  25. package/dist/parser/index.d.ts +2 -0
  26. package/dist/parser/index.js +79 -10
  27. package/dist/typechecker/index.d.ts +17 -0
  28. package/dist/typechecker/index.js +343 -17
  29. package/docs/ENTITY_TYPE_SYSTEM.md +242 -0
  30. package/editors/vscode/CHANGELOG.md +9 -0
  31. package/editors/vscode/out/extension.js +1144 -72
  32. package/editors/vscode/package-lock.json +2 -2
  33. package/editors/vscode/package.json +1 -1
  34. package/package.json +1 -1
  35. package/src/__tests__/cli.test.ts +166 -0
  36. package/src/__tests__/codegen.test.ts +27 -0
  37. package/src/__tests__/e2e.test.ts +201 -12
  38. package/src/__tests__/fixtures/event-test.mcrs +13 -0
  39. package/src/__tests__/fixtures/impl-test.mcrs +46 -0
  40. package/src/__tests__/fixtures/interval-test.mcrs +11 -0
  41. package/src/__tests__/fixtures/is-check-test.mcrs +20 -0
  42. package/src/__tests__/fixtures/timeout-test.mcrs +7 -0
  43. package/src/__tests__/lexer.test.ts +14 -2
  44. package/src/__tests__/lowering.test.ts +178 -9
  45. package/src/__tests__/mc-integration.test.ts +166 -51
  46. package/src/__tests__/optimizer-advanced.test.ts +3 -3
  47. package/src/__tests__/parser.test.ts +91 -5
  48. package/src/__tests__/runtime.test.ts +8 -8
  49. package/src/__tests__/typechecker.test.ts +171 -0
  50. package/src/ast/types.ts +25 -1
  51. package/src/codegen/mcfunction/index.ts +31 -1
  52. package/src/codegen/structure/index.ts +27 -0
  53. package/src/compile.ts +54 -6
  54. package/src/events/types.ts +69 -0
  55. package/src/index.ts +4 -3
  56. package/src/ir/types.ts +4 -0
  57. package/src/lexer/index.ts +3 -1
  58. package/src/lowering/index.ts +528 -16
  59. package/src/parser/index.ts +90 -12
  60. package/src/stdlib/README.md +34 -4
  61. package/src/stdlib/tags.mcrs +951 -0
  62. package/src/stdlib/timer.mcrs +54 -33
  63. package/src/typechecker/index.ts +404 -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("struct")) {
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
- this.expect(":");
843
- const type = this.parseType();
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 selector = this.parseSelector();
1084
- subcommands.push({ kind: "if_entity", selector });
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 selector = this.parseSelector();
1090
- subcommands.push({ kind: "unless_entity", selector });
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.checkBlock(stmt.then);
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.scope.set(stmt.binding, { type: { kind: "named", name: "void" }, mutable: true });
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 { kind: "named", name: "void" };
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 { kind: "named", name: "int" };
2563
+ return INT_TYPE;
2158
2564
  }
2159
2565
  if (expr.fn === "bossbar_get_value") {
2160
- return { kind: "named", name: "int" };
2566
+ return INT_TYPE;
2161
2567
  }
2162
2568
  if (expr.fn === "random_sequence") {
2163
- return { kind: "named", name: "void" };
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 ?? { kind: "named", name: "int" };
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 runtimeParams = fn.params.filter((param) => !callbackBindings.has(param.name));
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
- for (const param of runtimeParams) {
2606
- const paramName = param.name;
2607
- this.varMap.set(paramName, `$${paramName}`);
2608
- this.varTypes.set(paramName, this.normalizeType(param.type));
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 path = `rs:heap ${structName}_${stmt.name}.${field.name}`;
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 ${path} set value ${fieldValue.value}`);
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 ${path} int 1 run scoreboard players get ${fieldValue.name} rs`);
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
- parts.push(`if entity ${this.selectorToString(sub.selector)}`);
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
- parts.push(`unless entity ${this.selectorToString(sub.selector)}`);
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 path = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
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 ${path}`);
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 path = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
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 ${path} set value ${value2.value}`);
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 ${path} int 1 run scoreboard players get ${value2.name} rs`);
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 ${path}`);
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 ${path} int 1 run scoreboard players get ${dst} rs`);
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 targetFn = callbackBindings.size > 0 ? this.ensureSpecializedFunction(fnDecl, callbackBindings) : expr.fn;
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.exprToString(args[1]);
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.exprToString(args[1]);
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.exprToString(args[1]);
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.exprToString(args[0]);
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.exprToString(args[0]);
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 path = this.exprToString(args[2]);
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} ${path} ${scale}`);
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
- return this.fnDecls.get(this.resolveFunctionRefByName(expr.fn) ?? expr.fn)?.returnType;
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 = `$t${this.tempCount++}`;
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} 0`);
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 (tickFunctionNames.length > 0 || triggerNames.size > 0) {
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 preprocessSource(source, options = {}) {
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(preprocessSource(importedSource, { filePath: importPath, seen }));
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
- return [...imports, bodyLines.join("\n")].filter(Boolean).join("\n");
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 preprocessedSource = preprocessSource(source, { filePath });
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 preprocessedSource = (0, compile_1.preprocessSource)(source, { filePath });
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 });