redscript-mc 1.2.0 → 1.2.2

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 (55) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +53 -10
  3. package/README.zh.md +53 -10
  4. package/dist/__tests__/dce.test.d.ts +1 -0
  5. package/dist/__tests__/dce.test.js +137 -0
  6. package/dist/__tests__/lexer.test.js +19 -2
  7. package/dist/__tests__/lowering.test.js +8 -0
  8. package/dist/__tests__/mc-syntax.test.js +12 -0
  9. package/dist/__tests__/parser.test.js +10 -0
  10. package/dist/__tests__/runtime.test.js +13 -0
  11. package/dist/__tests__/typechecker.test.js +30 -0
  12. package/dist/ast/types.d.ts +22 -2
  13. package/dist/cli.js +15 -10
  14. package/dist/codegen/structure/index.d.ts +4 -1
  15. package/dist/codegen/structure/index.js +4 -2
  16. package/dist/compile.d.ts +1 -0
  17. package/dist/compile.js +4 -1
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +4 -1
  20. package/dist/lexer/index.d.ts +2 -1
  21. package/dist/lexer/index.js +89 -1
  22. package/dist/lowering/index.js +37 -1
  23. package/dist/optimizer/dce.d.ts +23 -0
  24. package/dist/optimizer/dce.js +592 -0
  25. package/dist/parser/index.d.ts +2 -0
  26. package/dist/parser/index.js +81 -16
  27. package/dist/typechecker/index.d.ts +2 -0
  28. package/dist/typechecker/index.js +49 -0
  29. package/docs/ARCHITECTURE.zh.md +1088 -0
  30. package/editors/vscode/.vscodeignore +3 -0
  31. package/editors/vscode/icon.png +0 -0
  32. package/editors/vscode/out/extension.js +834 -19
  33. package/editors/vscode/package-lock.json +2 -2
  34. package/editors/vscode/package.json +1 -1
  35. package/editors/vscode/syntaxes/redscript.tmLanguage.json +6 -2
  36. package/examples/spiral.mcrs +41 -0
  37. package/logo.png +0 -0
  38. package/package.json +1 -1
  39. package/src/__tests__/dce.test.ts +129 -0
  40. package/src/__tests__/lexer.test.ts +21 -2
  41. package/src/__tests__/lowering.test.ts +9 -0
  42. package/src/__tests__/mc-syntax.test.ts +14 -0
  43. package/src/__tests__/parser.test.ts +11 -0
  44. package/src/__tests__/runtime.test.ts +16 -0
  45. package/src/__tests__/typechecker.test.ts +33 -0
  46. package/src/ast/types.ts +14 -1
  47. package/src/cli.ts +24 -10
  48. package/src/codegen/structure/index.ts +13 -2
  49. package/src/compile.ts +5 -1
  50. package/src/index.ts +5 -1
  51. package/src/lexer/index.ts +102 -1
  52. package/src/lowering/index.ts +38 -2
  53. package/src/optimizer/dce.ts +619 -0
  54. package/src/parser/index.ts +97 -17
  55. package/src/typechecker/index.ts +65 -0
@@ -339,14 +339,46 @@ var require_lexer = __commonJS({
339
339
  this.addToken("range_lit", value, startLine, startCol);
340
340
  return;
341
341
  }
342
+ if (char === "~") {
343
+ let value = "~";
344
+ if (this.peek() === "-" || this.peek() === "+") {
345
+ value += this.advance();
346
+ }
347
+ while (/[0-9]/.test(this.peek())) {
348
+ value += this.advance();
349
+ }
350
+ if (this.peek() === "." && /[0-9]/.test(this.peek(1))) {
351
+ value += this.advance();
352
+ while (/[0-9]/.test(this.peek())) {
353
+ value += this.advance();
354
+ }
355
+ }
356
+ this.addToken("rel_coord", value, startLine, startCol);
357
+ return;
358
+ }
359
+ if (char === "^") {
360
+ let value = "^";
361
+ if (this.peek() === "-" || this.peek() === "+") {
362
+ value += this.advance();
363
+ }
364
+ while (/[0-9]/.test(this.peek())) {
365
+ value += this.advance();
366
+ }
367
+ if (this.peek() === "." && /[0-9]/.test(this.peek(1))) {
368
+ value += this.advance();
369
+ while (/[0-9]/.test(this.peek())) {
370
+ value += this.advance();
371
+ }
372
+ }
373
+ this.addToken("local_coord", value, startLine, startCol);
374
+ return;
375
+ }
342
376
  const singleChar = [
343
377
  "+",
344
378
  "-",
345
379
  "*",
346
380
  "/",
347
381
  "%",
348
- "~",
349
- "^",
350
382
  "<",
351
383
  ">",
352
384
  "!",
@@ -370,6 +402,11 @@ var require_lexer = __commonJS({
370
402
  this.scanAtToken(startLine, startCol);
371
403
  return;
372
404
  }
405
+ if (char === "f" && this.peek() === '"') {
406
+ this.advance();
407
+ this.scanFString(startLine, startCol);
408
+ return;
409
+ }
373
410
  if (char === '"') {
374
411
  this.scanString(startLine, startCol);
375
412
  return;
@@ -486,6 +523,46 @@ var require_lexer = __commonJS({
486
523
  this.advance();
487
524
  this.addToken("string_lit", value, startLine, startCol);
488
525
  }
526
+ scanFString(startLine, startCol) {
527
+ let value = "";
528
+ let interpolationDepth = 0;
529
+ let interpolationString = false;
530
+ while (!this.isAtEnd()) {
531
+ if (interpolationDepth === 0 && this.peek() === '"') {
532
+ break;
533
+ }
534
+ if (this.peek() === "\\" && this.peek(1) === '"') {
535
+ this.advance();
536
+ value += this.advance();
537
+ continue;
538
+ }
539
+ if (interpolationDepth === 0 && this.peek() === "{") {
540
+ value += this.advance();
541
+ interpolationDepth = 1;
542
+ interpolationString = false;
543
+ continue;
544
+ }
545
+ const char = this.advance();
546
+ value += char;
547
+ if (interpolationDepth === 0)
548
+ continue;
549
+ if (char === '"' && this.source[this.pos - 2] !== "\\") {
550
+ interpolationString = !interpolationString;
551
+ continue;
552
+ }
553
+ if (interpolationString)
554
+ continue;
555
+ if (char === "{")
556
+ interpolationDepth++;
557
+ if (char === "}")
558
+ interpolationDepth--;
559
+ }
560
+ if (this.isAtEnd()) {
561
+ this.error("Unterminated f-string", startLine, startCol);
562
+ }
563
+ this.advance();
564
+ this.addToken("f_string", value, startLine, startCol);
565
+ }
489
566
  scanNumber(firstChar, startLine, startCol) {
490
567
  let value = firstChar;
491
568
  while (/[0-9]/.test(this.peek())) {
@@ -1321,6 +1398,14 @@ var require_parser = __commonJS({
1321
1398
  this.advance();
1322
1399
  return this.withLoc({ kind: "float_lit", value: parseFloat(token.value) }, token);
1323
1400
  }
1401
+ if (token.kind === "rel_coord") {
1402
+ this.advance();
1403
+ return this.withLoc({ kind: "rel_coord", value: token.value }, token);
1404
+ }
1405
+ if (token.kind === "local_coord") {
1406
+ this.advance();
1407
+ return this.withLoc({ kind: "local_coord", value: token.value }, token);
1408
+ }
1324
1409
  if (token.kind === "byte_lit") {
1325
1410
  this.advance();
1326
1411
  return this.withLoc({ kind: "byte_lit", value: parseInt(token.value.slice(0, -1), 10) }, token);
@@ -1341,6 +1426,10 @@ var require_parser = __commonJS({
1341
1426
  this.advance();
1342
1427
  return this.parseStringExpr(token);
1343
1428
  }
1429
+ if (token.kind === "f_string") {
1430
+ this.advance();
1431
+ return this.parseFStringExpr(token);
1432
+ }
1344
1433
  if (token.kind === "mc_name") {
1345
1434
  this.advance();
1346
1435
  return this.withLoc({ kind: "mc_name", value: token.value.slice(1) }, token);
@@ -1480,6 +1569,55 @@ var require_parser = __commonJS({
1480
1569
  }
1481
1570
  return this.withLoc({ kind: "str_interp", parts }, token);
1482
1571
  }
1572
+ parseFStringExpr(token) {
1573
+ const parts = [];
1574
+ let current = "";
1575
+ let index = 0;
1576
+ while (index < token.value.length) {
1577
+ if (token.value[index] === "{") {
1578
+ if (current) {
1579
+ parts.push({ kind: "text", value: current });
1580
+ current = "";
1581
+ }
1582
+ index++;
1583
+ let depth = 1;
1584
+ let exprSource = "";
1585
+ let inString = false;
1586
+ while (index < token.value.length && depth > 0) {
1587
+ const char = token.value[index];
1588
+ if (char === '"' && token.value[index - 1] !== "\\") {
1589
+ inString = !inString;
1590
+ }
1591
+ if (!inString) {
1592
+ if (char === "{") {
1593
+ depth++;
1594
+ } else if (char === "}") {
1595
+ depth--;
1596
+ if (depth === 0) {
1597
+ index++;
1598
+ break;
1599
+ }
1600
+ }
1601
+ }
1602
+ if (depth > 0) {
1603
+ exprSource += char;
1604
+ }
1605
+ index++;
1606
+ }
1607
+ if (depth !== 0) {
1608
+ this.error("Unterminated f-string interpolation");
1609
+ }
1610
+ parts.push({ kind: "expr", expr: this.parseEmbeddedExpr(exprSource) });
1611
+ continue;
1612
+ }
1613
+ current += token.value[index];
1614
+ index++;
1615
+ }
1616
+ if (current) {
1617
+ parts.push({ kind: "text", value: current });
1618
+ }
1619
+ return this.withLoc({ kind: "f_string", parts }, token);
1620
+ }
1483
1621
  parseEmbeddedExpr(source) {
1484
1622
  const tokens = new lexer_1.Lexer(source, this.filePath).tokenize();
1485
1623
  const parser = new _Parser(tokens, source, this.filePath);
@@ -1621,19 +1759,9 @@ var require_parser = __commonJS({
1621
1759
  if (token.kind === "-") {
1622
1760
  return this.peek(offset + 1).kind === "int_lit" ? 2 : 0;
1623
1761
  }
1624
- if (token.kind !== "~" && token.kind !== "^") {
1625
- return 0;
1626
- }
1627
- const next = this.peek(offset + 1);
1628
- if (next.kind === "," || next.kind === ")") {
1762
+ if (token.kind === "rel_coord" || token.kind === "local_coord") {
1629
1763
  return 1;
1630
1764
  }
1631
- if (next.kind === "int_lit") {
1632
- return 2;
1633
- }
1634
- if (next.kind === "-" && this.peek(offset + 2).kind === "int_lit") {
1635
- return 3;
1636
- }
1637
1765
  return 0;
1638
1766
  }
1639
1767
  parseBlockPos() {
@@ -1648,13 +1776,23 @@ var require_parser = __commonJS({
1648
1776
  }
1649
1777
  parseCoordComponent() {
1650
1778
  const token = this.peek();
1651
- if (token.kind === "~" || token.kind === "^") {
1779
+ if (token.kind === "rel_coord") {
1780
+ this.advance();
1781
+ const offset = this.parseCoordOffsetFromValue(token.value.slice(1));
1782
+ return { kind: "relative", offset };
1783
+ }
1784
+ if (token.kind === "local_coord") {
1652
1785
  this.advance();
1653
- const offset = this.parseSignedCoordOffset();
1654
- return token.kind === "~" ? { kind: "relative", offset } : { kind: "local", offset };
1786
+ const offset = this.parseCoordOffsetFromValue(token.value.slice(1));
1787
+ return { kind: "local", offset };
1655
1788
  }
1656
1789
  return { kind: "absolute", value: this.parseSignedCoordOffset(true) };
1657
1790
  }
1791
+ parseCoordOffsetFromValue(value) {
1792
+ if (value === "" || value === void 0)
1793
+ return 0;
1794
+ return parseFloat(value);
1795
+ }
1658
1796
  parseSignedCoordOffset(requireValue = false) {
1659
1797
  let sign = 1;
1660
1798
  if (this.match("-")) {
@@ -1948,6 +2086,8 @@ var require_typechecker = __commonJS({
1948
2086
  };
1949
2087
  var VOID_TYPE = { kind: "named", name: "void" };
1950
2088
  var INT_TYPE = { kind: "named", name: "int" };
2089
+ var STRING_TYPE = { kind: "named", name: "string" };
2090
+ var FORMAT_STRING_TYPE = { kind: "named", name: "format_string" };
1951
2091
  var BUILTIN_SIGNATURES = {
1952
2092
  setTimeout: {
1953
2093
  params: [INT_TYPE, { kind: "function_type", params: [], return: VOID_TYPE }],
@@ -1973,6 +2113,15 @@ var require_typechecker = __commonJS({
1973
2113
  this.currentReturnType = null;
1974
2114
  this.scope = /* @__PURE__ */ new Map();
1975
2115
  this.selfTypeStack = ["entity"];
2116
+ this.richTextBuiltins = /* @__PURE__ */ new Map([
2117
+ ["say", { messageIndex: 0 }],
2118
+ ["announce", { messageIndex: 0 }],
2119
+ ["tell", { messageIndex: 1 }],
2120
+ ["tellraw", { messageIndex: 1 }],
2121
+ ["title", { messageIndex: 1 }],
2122
+ ["actionbar", { messageIndex: 1 }],
2123
+ ["subtitle", { messageIndex: 1 }]
2124
+ ]);
1976
2125
  this.collector = new diagnostics_1.DiagnosticCollector(source, filePath);
1977
2126
  }
1978
2127
  getNodeLocation(node) {
@@ -2295,6 +2444,18 @@ var require_typechecker = __commonJS({
2295
2444
  }
2296
2445
  }
2297
2446
  break;
2447
+ case "f_string":
2448
+ for (const part of expr.parts) {
2449
+ if (part.kind !== "expr") {
2450
+ continue;
2451
+ }
2452
+ this.checkExpr(part.expr);
2453
+ const partType = this.inferType(part.expr);
2454
+ if (!(partType.kind === "named" && (partType.name === "int" || partType.name === "string" || partType.name === "format_string"))) {
2455
+ this.report(`f-string placeholder must be int or string, got ${this.typeToString(partType)}`, part.expr);
2456
+ }
2457
+ }
2458
+ break;
2298
2459
  case "array_lit":
2299
2460
  for (const elem of expr.elements) {
2300
2461
  this.checkExpr(elem);
@@ -2324,6 +2485,11 @@ var require_typechecker = __commonJS({
2324
2485
  if (expr.fn === "tp" || expr.fn === "tp_to") {
2325
2486
  this.checkTpCall(expr);
2326
2487
  }
2488
+ const richTextBuiltin = this.richTextBuiltins.get(expr.fn);
2489
+ if (richTextBuiltin) {
2490
+ this.checkRichTextBuiltinCall(expr, richTextBuiltin.messageIndex);
2491
+ return;
2492
+ }
2327
2493
  const builtin = BUILTIN_SIGNATURES[expr.fn];
2328
2494
  if (builtin) {
2329
2495
  this.checkFunctionCallArgs(expr.args, builtin.params, expr.fn, expr);
@@ -2362,6 +2528,19 @@ var require_typechecker = __commonJS({
2362
2528
  this.checkExpr(arg);
2363
2529
  }
2364
2530
  }
2531
+ checkRichTextBuiltinCall(expr, messageIndex) {
2532
+ for (let i = 0; i < expr.args.length; i++) {
2533
+ this.checkExpr(expr.args[i], i === messageIndex ? void 0 : STRING_TYPE);
2534
+ }
2535
+ const message = expr.args[messageIndex];
2536
+ if (!message) {
2537
+ return;
2538
+ }
2539
+ const messageType = this.inferType(message);
2540
+ if (messageType.kind !== "named" || messageType.name !== "string" && messageType.name !== "format_string") {
2541
+ this.report(`Argument ${messageIndex + 1} of '${expr.fn}' expects string or format_string, got ${this.typeToString(messageType)}`, message);
2542
+ }
2543
+ }
2365
2544
  checkInvokeExpr(expr) {
2366
2545
  this.checkExpr(expr.callee);
2367
2546
  const calleeType = this.inferType(expr.callee);
@@ -2541,6 +2720,13 @@ var require_typechecker = __commonJS({
2541
2720
  }
2542
2721
  }
2543
2722
  return { kind: "named", name: "string" };
2723
+ case "f_string":
2724
+ for (const part of expr.parts) {
2725
+ if (part.kind === "expr") {
2726
+ this.checkExpr(part.expr);
2727
+ }
2728
+ }
2729
+ return FORMAT_STRING_TYPE;
2544
2730
  case "blockpos":
2545
2731
  return { kind: "named", name: "BlockPos" };
2546
2732
  case "ident":
@@ -2938,6 +3124,7 @@ var require_lowering = __commonJS({
2938
3124
  var BUILTINS2 = {
2939
3125
  say: ([msg]) => `say ${msg}`,
2940
3126
  tell: ([sel, msg]) => `tellraw ${sel} {"text":"${msg}"}`,
3127
+ tellraw: ([sel, msg]) => `tellraw ${sel} {"text":"${msg}"}`,
2941
3128
  title: ([sel, msg]) => `title ${sel} title {"text":"${msg}"}`,
2942
3129
  actionbar: ([sel, msg]) => `title ${sel} actionbar {"text":"${msg}"}`,
2943
3130
  subtitle: ([sel, msg]) => `title ${sel} subtitle {"text":"${msg}"}`,
@@ -3869,6 +4056,7 @@ var require_lowering = __commonJS({
3869
4056
  return { kind: "const", value: 0 };
3870
4057
  // Handled inline in exprToString
3871
4058
  case "str_interp":
4059
+ case "f_string":
3872
4060
  return { kind: "const", value: 0 };
3873
4061
  case "range_lit":
3874
4062
  return { kind: "const", value: 0 };
@@ -4676,7 +4864,7 @@ var require_lowering = __commonJS({
4676
4864
  return null;
4677
4865
  }
4678
4866
  const messageExpr = args[messageArgIndex];
4679
- if (!messageExpr || messageExpr.kind !== "str_interp") {
4867
+ if (!messageExpr || messageExpr.kind !== "str_interp" && messageExpr.kind !== "f_string") {
4680
4868
  return null;
4681
4869
  }
4682
4870
  const json = this.buildRichTextJson(messageExpr);
@@ -4685,6 +4873,7 @@ var require_lowering = __commonJS({
4685
4873
  case "announce":
4686
4874
  return `tellraw @a ${json}`;
4687
4875
  case "tell":
4876
+ case "tellraw":
4688
4877
  return `tellraw ${this.exprToString(args[0])} ${json}`;
4689
4878
  case "title":
4690
4879
  return `title ${this.exprToString(args[0])} title ${json}`;
@@ -4702,6 +4891,7 @@ var require_lowering = __commonJS({
4702
4891
  case "announce":
4703
4892
  return 0;
4704
4893
  case "tell":
4894
+ case "tellraw":
4705
4895
  case "title":
4706
4896
  case "actionbar":
4707
4897
  case "subtitle":
@@ -4712,6 +4902,18 @@ var require_lowering = __commonJS({
4712
4902
  }
4713
4903
  buildRichTextJson(expr) {
4714
4904
  const components = [""];
4905
+ if (expr.kind === "f_string") {
4906
+ for (const part of expr.parts) {
4907
+ if (part.kind === "text") {
4908
+ if (part.value.length > 0) {
4909
+ components.push({ text: part.value });
4910
+ }
4911
+ continue;
4912
+ }
4913
+ this.appendRichTextExpr(components, part.expr);
4914
+ }
4915
+ return JSON.stringify(components);
4916
+ }
4715
4917
  for (const part of expr.parts) {
4716
4918
  if (typeof part === "string") {
4717
4919
  if (part.length > 0) {
@@ -4754,6 +4956,18 @@ var require_lowering = __commonJS({
4754
4956
  }
4755
4957
  return;
4756
4958
  }
4959
+ if (expr.kind === "f_string") {
4960
+ for (const part of expr.parts) {
4961
+ if (part.kind === "text") {
4962
+ if (part.value.length > 0) {
4963
+ components.push({ text: part.value });
4964
+ }
4965
+ } else {
4966
+ this.appendRichTextExpr(components, part.expr);
4967
+ }
4968
+ }
4969
+ return;
4970
+ }
4757
4971
  if (expr.kind === "bool_lit") {
4758
4972
  components.push({ text: expr.value ? "true" : "false" });
4759
4973
  return;
@@ -4787,6 +5001,12 @@ var require_lowering = __commonJS({
4787
5001
  return `${expr.value}L`;
4788
5002
  case "double_lit":
4789
5003
  return `${expr.value}d`;
5004
+ case "rel_coord":
5005
+ return expr.value;
5006
+ // ~ or ~5 or ~-3 - output as-is for MC commands
5007
+ case "local_coord":
5008
+ return expr.value;
5009
+ // ^ or ^5 or ^-3 - output as-is for MC commands
4790
5010
  case "bool_lit":
4791
5011
  return expr.value ? "1" : "0";
4792
5012
  case "str_lit":
@@ -4795,6 +5015,7 @@ var require_lowering = __commonJS({
4795
5015
  return expr.value;
4796
5016
  // #health → "health" (no quotes, used as bare MC name)
4797
5017
  case "str_interp":
5018
+ case "f_string":
4798
5019
  return this.buildRichTextJson(expr);
4799
5020
  case "blockpos":
4800
5021
  return emitBlockPos(expr);
@@ -5082,6 +5303,8 @@ var require_lowering = __commonJS({
5082
5303
  return { kind: "named", name: "bool" };
5083
5304
  if (expr.kind === "str_lit" || expr.kind === "str_interp")
5084
5305
  return { kind: "named", name: "string" };
5306
+ if (expr.kind === "f_string")
5307
+ return { kind: "named", name: "format_string" };
5085
5308
  if (expr.kind === "blockpos")
5086
5309
  return { kind: "named", name: "BlockPos" };
5087
5310
  if (expr.kind === "ident") {
@@ -5941,6 +6164,592 @@ var require_passes = __commonJS({
5941
6164
  }
5942
6165
  });
5943
6166
 
6167
+ // ../../dist/optimizer/dce.js
6168
+ var require_dce = __commonJS({
6169
+ "../../dist/optimizer/dce.js"(exports2) {
6170
+ "use strict";
6171
+ Object.defineProperty(exports2, "__esModule", { value: true });
6172
+ exports2.DeadCodeEliminator = void 0;
6173
+ exports2.eliminateDeadCode = eliminateDeadCode;
6174
+ function copySpan(target, source) {
6175
+ const descriptor = Object.getOwnPropertyDescriptor(source, "span");
6176
+ if (descriptor) {
6177
+ Object.defineProperty(target, "span", descriptor);
6178
+ }
6179
+ return target;
6180
+ }
6181
+ function isConstantBoolean(expr) {
6182
+ if (expr.kind === "bool_lit") {
6183
+ return expr.value;
6184
+ }
6185
+ return null;
6186
+ }
6187
+ function isPureExpr(expr) {
6188
+ switch (expr.kind) {
6189
+ case "int_lit":
6190
+ case "float_lit":
6191
+ case "byte_lit":
6192
+ case "short_lit":
6193
+ case "long_lit":
6194
+ case "double_lit":
6195
+ case "rel_coord":
6196
+ case "local_coord":
6197
+ case "bool_lit":
6198
+ case "str_lit":
6199
+ case "mc_name":
6200
+ case "range_lit":
6201
+ case "selector":
6202
+ case "ident":
6203
+ case "blockpos":
6204
+ return true;
6205
+ case "str_interp":
6206
+ return expr.parts.every((part) => typeof part === "string" || isPureExpr(part));
6207
+ case "f_string":
6208
+ return expr.parts.every((part) => part.kind === "text" || isPureExpr(part.expr));
6209
+ case "binary":
6210
+ return isPureExpr(expr.left) && isPureExpr(expr.right);
6211
+ case "is_check":
6212
+ return isPureExpr(expr.expr);
6213
+ case "unary":
6214
+ return isPureExpr(expr.operand);
6215
+ case "member":
6216
+ return isPureExpr(expr.obj);
6217
+ case "index":
6218
+ return isPureExpr(expr.obj) && isPureExpr(expr.index);
6219
+ case "array_lit":
6220
+ return expr.elements.every(isPureExpr);
6221
+ case "struct_lit":
6222
+ return expr.fields.every((field) => isPureExpr(field.value));
6223
+ case "lambda":
6224
+ return true;
6225
+ case "assign":
6226
+ case "member_assign":
6227
+ case "call":
6228
+ case "invoke":
6229
+ case "static_call":
6230
+ return false;
6231
+ }
6232
+ }
6233
+ var DeadCodeEliminator = class {
6234
+ constructor() {
6235
+ this.functionMap = /* @__PURE__ */ new Map();
6236
+ this.reachableFunctions = /* @__PURE__ */ new Set();
6237
+ this.usedConstants = /* @__PURE__ */ new Set();
6238
+ this.localReads = /* @__PURE__ */ new Set();
6239
+ this.localDeclIds = /* @__PURE__ */ new WeakMap();
6240
+ this.localIdCounter = 0;
6241
+ }
6242
+ eliminate(program) {
6243
+ this.functionMap.clear();
6244
+ this.reachableFunctions.clear();
6245
+ this.usedConstants.clear();
6246
+ this.localReads.clear();
6247
+ this.localIdCounter = 0;
6248
+ for (const fn of program.declarations) {
6249
+ this.functionMap.set(fn.name, fn);
6250
+ }
6251
+ const entryPoints = this.findEntryPoints(program);
6252
+ if (entryPoints.length === 0) {
6253
+ for (const fn of program.declarations) {
6254
+ this.markReachable(fn.name);
6255
+ }
6256
+ } else {
6257
+ for (const fnName of entryPoints) {
6258
+ this.markReachable(fnName);
6259
+ }
6260
+ }
6261
+ for (const global of program.globals) {
6262
+ this.collectExprRefs(global.init, []);
6263
+ }
6264
+ for (const implBlock of program.implBlocks) {
6265
+ for (const method of implBlock.methods) {
6266
+ this.collectFunctionRefs(method);
6267
+ }
6268
+ }
6269
+ return {
6270
+ ...program,
6271
+ declarations: program.declarations.filter((fn) => this.reachableFunctions.has(fn.name)).map((fn) => this.transformFunction(fn)),
6272
+ consts: program.consts.filter((constDecl) => this.usedConstants.has(constDecl.name)),
6273
+ implBlocks: program.implBlocks.map((implBlock) => ({
6274
+ ...implBlock,
6275
+ methods: implBlock.methods.map((method) => this.transformFunction(method))
6276
+ }))
6277
+ };
6278
+ }
6279
+ findEntryPoints(program) {
6280
+ const entries = /* @__PURE__ */ new Set();
6281
+ for (const fn of program.declarations) {
6282
+ if (fn.name === "main") {
6283
+ entries.add(fn.name);
6284
+ }
6285
+ if (fn.decorators.some((decorator) => [
6286
+ "tick",
6287
+ "load",
6288
+ "on",
6289
+ "on_trigger",
6290
+ "on_advancement",
6291
+ "on_craft",
6292
+ "on_death",
6293
+ "on_login",
6294
+ "on_join_team"
6295
+ ].includes(decorator.name))) {
6296
+ entries.add(fn.name);
6297
+ }
6298
+ }
6299
+ return [...entries];
6300
+ }
6301
+ markReachable(fnName) {
6302
+ if (this.reachableFunctions.has(fnName)) {
6303
+ return;
6304
+ }
6305
+ const fn = this.functionMap.get(fnName);
6306
+ if (!fn) {
6307
+ return;
6308
+ }
6309
+ this.reachableFunctions.add(fnName);
6310
+ this.collectFunctionRefs(fn);
6311
+ }
6312
+ collectFunctionRefs(fn) {
6313
+ const scope = [fn.params.map((param) => ({ id: `param:${fn.name}:${param.name}`, name: param.name }))];
6314
+ for (const param of fn.params) {
6315
+ if (param.default) {
6316
+ this.collectExprRefs(param.default, scope);
6317
+ }
6318
+ }
6319
+ this.collectStmtRefs(fn.body, scope);
6320
+ }
6321
+ collectStmtRefs(block, scope) {
6322
+ scope.push([]);
6323
+ for (const stmt of block) {
6324
+ this.collectStmtRef(stmt, scope);
6325
+ }
6326
+ scope.pop();
6327
+ }
6328
+ collectStmtRef(stmt, scope) {
6329
+ switch (stmt.kind) {
6330
+ case "let": {
6331
+ this.collectExprRefs(stmt.init, scope);
6332
+ const id = `local:${stmt.name}:${this.localIdCounter++}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`;
6333
+ this.localDeclIds.set(stmt, id);
6334
+ scope[scope.length - 1].push({ id, name: stmt.name });
6335
+ break;
6336
+ }
6337
+ case "expr":
6338
+ this.collectExprRefs(stmt.expr, scope);
6339
+ break;
6340
+ case "return":
6341
+ if (stmt.value) {
6342
+ this.collectExprRefs(stmt.value, scope);
6343
+ }
6344
+ break;
6345
+ case "if": {
6346
+ this.collectExprRefs(stmt.cond, scope);
6347
+ const constant = isConstantBoolean(stmt.cond);
6348
+ if (constant === true) {
6349
+ this.collectStmtRefs(stmt.then, scope);
6350
+ } else if (constant === false) {
6351
+ if (stmt.else_) {
6352
+ this.collectStmtRefs(stmt.else_, scope);
6353
+ }
6354
+ } else {
6355
+ this.collectStmtRefs(stmt.then, scope);
6356
+ if (stmt.else_) {
6357
+ this.collectStmtRefs(stmt.else_, scope);
6358
+ }
6359
+ }
6360
+ break;
6361
+ }
6362
+ case "while":
6363
+ this.collectExprRefs(stmt.cond, scope);
6364
+ this.collectStmtRefs(stmt.body, scope);
6365
+ break;
6366
+ case "for":
6367
+ scope.push([]);
6368
+ if (stmt.init) {
6369
+ this.collectStmtRef(stmt.init, scope);
6370
+ }
6371
+ this.collectExprRefs(stmt.cond, scope);
6372
+ this.collectExprRefs(stmt.step, scope);
6373
+ this.collectStmtRefs(stmt.body, scope);
6374
+ scope.pop();
6375
+ break;
6376
+ case "foreach":
6377
+ this.collectExprRefs(stmt.iterable, scope);
6378
+ scope.push([{ id: `foreach:${stmt.binding}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.binding }]);
6379
+ this.collectStmtRefs(stmt.body, scope);
6380
+ scope.pop();
6381
+ break;
6382
+ case "for_range":
6383
+ this.collectExprRefs(stmt.start, scope);
6384
+ this.collectExprRefs(stmt.end, scope);
6385
+ scope.push([{ id: `range:${stmt.varName}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.varName }]);
6386
+ this.collectStmtRefs(stmt.body, scope);
6387
+ scope.pop();
6388
+ break;
6389
+ case "match":
6390
+ this.collectExprRefs(stmt.expr, scope);
6391
+ for (const arm of stmt.arms) {
6392
+ if (arm.pattern) {
6393
+ this.collectExprRefs(arm.pattern, scope);
6394
+ }
6395
+ this.collectStmtRefs(arm.body, scope);
6396
+ }
6397
+ break;
6398
+ case "as_block":
6399
+ case "at_block":
6400
+ case "as_at":
6401
+ case "execute":
6402
+ this.collectNestedStmtRefs(stmt, scope);
6403
+ break;
6404
+ case "raw":
6405
+ break;
6406
+ }
6407
+ }
6408
+ collectNestedStmtRefs(stmt, scope) {
6409
+ if (stmt.kind === "execute") {
6410
+ for (const sub of stmt.subcommands) {
6411
+ if ("varName" in sub && sub.varName) {
6412
+ const resolved = this.resolveLocal(sub.varName, scope);
6413
+ if (resolved) {
6414
+ this.localReads.add(resolved.id);
6415
+ }
6416
+ }
6417
+ }
6418
+ }
6419
+ this.collectStmtRefs(stmt.body, scope);
6420
+ }
6421
+ collectExprRefs(expr, scope) {
6422
+ switch (expr.kind) {
6423
+ case "ident": {
6424
+ const resolved = this.resolveLocal(expr.name, scope);
6425
+ if (resolved) {
6426
+ this.localReads.add(resolved.id);
6427
+ } else {
6428
+ this.usedConstants.add(expr.name);
6429
+ }
6430
+ break;
6431
+ }
6432
+ case "call":
6433
+ {
6434
+ const resolved = this.resolveLocal(expr.fn, scope);
6435
+ if (resolved) {
6436
+ this.localReads.add(resolved.id);
6437
+ } else if (this.functionMap.has(expr.fn)) {
6438
+ this.markReachable(expr.fn);
6439
+ }
6440
+ }
6441
+ for (const arg of expr.args) {
6442
+ this.collectExprRefs(arg, scope);
6443
+ }
6444
+ break;
6445
+ case "static_call":
6446
+ for (const arg of expr.args) {
6447
+ this.collectExprRefs(arg, scope);
6448
+ }
6449
+ break;
6450
+ case "invoke":
6451
+ this.collectExprRefs(expr.callee, scope);
6452
+ for (const arg of expr.args) {
6453
+ this.collectExprRefs(arg, scope);
6454
+ }
6455
+ break;
6456
+ case "member":
6457
+ this.collectExprRefs(expr.obj, scope);
6458
+ break;
6459
+ case "member_assign":
6460
+ this.collectExprRefs(expr.obj, scope);
6461
+ this.collectExprRefs(expr.value, scope);
6462
+ break;
6463
+ case "index":
6464
+ this.collectExprRefs(expr.obj, scope);
6465
+ this.collectExprRefs(expr.index, scope);
6466
+ break;
6467
+ case "array_lit":
6468
+ expr.elements.forEach((element) => this.collectExprRefs(element, scope));
6469
+ break;
6470
+ case "struct_lit":
6471
+ expr.fields.forEach((field) => this.collectExprRefs(field.value, scope));
6472
+ break;
6473
+ case "binary":
6474
+ this.collectExprRefs(expr.left, scope);
6475
+ this.collectExprRefs(expr.right, scope);
6476
+ break;
6477
+ case "is_check":
6478
+ this.collectExprRefs(expr.expr, scope);
6479
+ break;
6480
+ case "unary":
6481
+ this.collectExprRefs(expr.operand, scope);
6482
+ break;
6483
+ case "assign": {
6484
+ this.collectExprRefs(expr.value, scope);
6485
+ break;
6486
+ }
6487
+ case "str_interp":
6488
+ expr.parts.forEach((part) => {
6489
+ if (typeof part !== "string") {
6490
+ this.collectExprRefs(part, scope);
6491
+ }
6492
+ });
6493
+ break;
6494
+ case "f_string":
6495
+ expr.parts.forEach((part) => {
6496
+ if (part.kind === "expr") {
6497
+ this.collectExprRefs(part.expr, scope);
6498
+ }
6499
+ });
6500
+ break;
6501
+ case "lambda": {
6502
+ const lambdaScope = [
6503
+ ...scope.map((entries) => [...entries]),
6504
+ expr.params.map((param) => ({ id: `lambda:${param.name}:${expr.span?.line ?? 0}:${expr.span?.col ?? 0}`, name: param.name }))
6505
+ ];
6506
+ if (Array.isArray(expr.body)) {
6507
+ this.collectStmtRefs(expr.body, lambdaScope);
6508
+ } else {
6509
+ this.collectExprRefs(expr.body, lambdaScope);
6510
+ }
6511
+ break;
6512
+ }
6513
+ case "blockpos":
6514
+ case "bool_lit":
6515
+ case "byte_lit":
6516
+ case "double_lit":
6517
+ case "float_lit":
6518
+ case "int_lit":
6519
+ case "long_lit":
6520
+ case "mc_name":
6521
+ case "range_lit":
6522
+ case "selector":
6523
+ case "short_lit":
6524
+ case "str_lit":
6525
+ break;
6526
+ }
6527
+ }
6528
+ resolveLocal(name, scope) {
6529
+ for (let i = scope.length - 1; i >= 0; i--) {
6530
+ for (let j = scope[i].length - 1; j >= 0; j--) {
6531
+ if (scope[i][j].name === name) {
6532
+ return scope[i][j];
6533
+ }
6534
+ }
6535
+ }
6536
+ return null;
6537
+ }
6538
+ transformFunction(fn) {
6539
+ const scope = [fn.params.map((param) => ({ id: `param:${fn.name}:${param.name}`, name: param.name }))];
6540
+ const body = this.transformBlock(fn.body, scope);
6541
+ return body === fn.body ? fn : copySpan({ ...fn, body }, fn);
6542
+ }
6543
+ transformBlock(block, scope) {
6544
+ scope.push([]);
6545
+ const transformed = [];
6546
+ for (const stmt of block) {
6547
+ const next = this.transformStmt(stmt, scope);
6548
+ transformed.push(...next);
6549
+ }
6550
+ scope.pop();
6551
+ return transformed;
6552
+ }
6553
+ transformStmt(stmt, scope) {
6554
+ switch (stmt.kind) {
6555
+ case "let": {
6556
+ const init = this.transformExpr(stmt.init, scope);
6557
+ const id = this.localDeclIds.get(stmt) ?? `local:${stmt.name}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`;
6558
+ scope[scope.length - 1].push({ id, name: stmt.name });
6559
+ if (this.localReads.has(id)) {
6560
+ if (init === stmt.init) {
6561
+ return [stmt];
6562
+ }
6563
+ return [copySpan({ ...stmt, init }, stmt)];
6564
+ }
6565
+ if (isPureExpr(init)) {
6566
+ return [];
6567
+ }
6568
+ return [copySpan({ kind: "expr", expr: init }, stmt)];
6569
+ }
6570
+ case "expr": {
6571
+ const expr = this.transformExpr(stmt.expr, scope);
6572
+ if (expr.kind === "assign") {
6573
+ const resolved = this.resolveLocal(expr.target, scope);
6574
+ if (resolved && !this.localReads.has(resolved.id)) {
6575
+ if (isPureExpr(expr.value)) {
6576
+ return [];
6577
+ }
6578
+ return [copySpan({ kind: "expr", expr: expr.value }, stmt)];
6579
+ }
6580
+ }
6581
+ if (expr === stmt.expr) {
6582
+ return [stmt];
6583
+ }
6584
+ return [copySpan({ ...stmt, expr }, stmt)];
6585
+ }
6586
+ case "return": {
6587
+ if (!stmt.value) {
6588
+ return [stmt];
6589
+ }
6590
+ const value = this.transformExpr(stmt.value, scope);
6591
+ if (value === stmt.value) {
6592
+ return [stmt];
6593
+ }
6594
+ return [copySpan({ ...stmt, value }, stmt)];
6595
+ }
6596
+ case "if": {
6597
+ const cond = this.transformExpr(stmt.cond, scope);
6598
+ const constant = isConstantBoolean(cond);
6599
+ if (constant === true) {
6600
+ return this.transformBlock(stmt.then, scope);
6601
+ }
6602
+ if (constant === false) {
6603
+ return stmt.else_ ? this.transformBlock(stmt.else_, scope) : [];
6604
+ }
6605
+ const thenBlock = this.transformBlock(stmt.then, scope);
6606
+ const elseBlock = stmt.else_ ? this.transformBlock(stmt.else_, scope) : void 0;
6607
+ if (cond === stmt.cond && thenBlock === stmt.then && elseBlock === stmt.else_) {
6608
+ return [stmt];
6609
+ }
6610
+ return [copySpan({ ...stmt, cond, then: thenBlock, else_: elseBlock }, stmt)];
6611
+ }
6612
+ case "while": {
6613
+ const cond = this.transformExpr(stmt.cond, scope);
6614
+ if (isConstantBoolean(cond) === false) {
6615
+ return [];
6616
+ }
6617
+ const body = this.transformBlock(stmt.body, scope);
6618
+ return [copySpan({ ...stmt, cond, body }, stmt)];
6619
+ }
6620
+ case "for": {
6621
+ const forScope = [...scope, []];
6622
+ const init = stmt.init ? this.transformStmt(stmt.init, forScope)[0] : void 0;
6623
+ const cond = this.transformExpr(stmt.cond, forScope);
6624
+ if (isConstantBoolean(cond) === false) {
6625
+ return init ? [init] : [];
6626
+ }
6627
+ const step = this.transformExpr(stmt.step, forScope);
6628
+ const body = this.transformBlock(stmt.body, forScope);
6629
+ return [copySpan({ ...stmt, init, cond, step, body }, stmt)];
6630
+ }
6631
+ case "foreach": {
6632
+ const iterable = this.transformExpr(stmt.iterable, scope);
6633
+ const foreachScope = [...scope, [{ id: `foreach:${stmt.binding}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.binding }]];
6634
+ const body = this.transformBlock(stmt.body, foreachScope);
6635
+ return [copySpan({ ...stmt, iterable, body }, stmt)];
6636
+ }
6637
+ case "for_range": {
6638
+ const start = this.transformExpr(stmt.start, scope);
6639
+ const end = this.transformExpr(stmt.end, scope);
6640
+ const rangeScope = [...scope, [{ id: `range:${stmt.varName}:${stmt.span?.line ?? 0}:${stmt.span?.col ?? 0}`, name: stmt.varName }]];
6641
+ const body = this.transformBlock(stmt.body, rangeScope);
6642
+ return [copySpan({ ...stmt, start, end, body }, stmt)];
6643
+ }
6644
+ case "match": {
6645
+ const expr = this.transformExpr(stmt.expr, scope);
6646
+ const arms = stmt.arms.map((arm) => ({
6647
+ pattern: arm.pattern ? this.transformExpr(arm.pattern, scope) : null,
6648
+ body: this.transformBlock(arm.body, scope)
6649
+ }));
6650
+ return [copySpan({ ...stmt, expr, arms }, stmt)];
6651
+ }
6652
+ case "as_block":
6653
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
6654
+ case "at_block":
6655
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
6656
+ case "as_at":
6657
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
6658
+ case "execute":
6659
+ return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
6660
+ case "raw":
6661
+ return [stmt];
6662
+ }
6663
+ }
6664
+ transformExpr(expr, scope) {
6665
+ switch (expr.kind) {
6666
+ case "call":
6667
+ return copySpan({ ...expr, args: expr.args.map((arg) => this.transformExpr(arg, scope)) }, expr);
6668
+ case "static_call":
6669
+ return copySpan({ ...expr, args: expr.args.map((arg) => this.transformExpr(arg, scope)) }, expr);
6670
+ case "invoke":
6671
+ return copySpan({
6672
+ ...expr,
6673
+ callee: this.transformExpr(expr.callee, scope),
6674
+ args: expr.args.map((arg) => this.transformExpr(arg, scope))
6675
+ }, expr);
6676
+ case "binary":
6677
+ return copySpan({
6678
+ ...expr,
6679
+ left: this.transformExpr(expr.left, scope),
6680
+ right: this.transformExpr(expr.right, scope)
6681
+ }, expr);
6682
+ case "is_check":
6683
+ return copySpan({ ...expr, expr: this.transformExpr(expr.expr, scope) }, expr);
6684
+ case "unary":
6685
+ return copySpan({ ...expr, operand: this.transformExpr(expr.operand, scope) }, expr);
6686
+ case "assign":
6687
+ return copySpan({ ...expr, value: this.transformExpr(expr.value, scope) }, expr);
6688
+ case "member":
6689
+ return copySpan({ ...expr, obj: this.transformExpr(expr.obj, scope) }, expr);
6690
+ case "member_assign":
6691
+ return copySpan({
6692
+ ...expr,
6693
+ obj: this.transformExpr(expr.obj, scope),
6694
+ value: this.transformExpr(expr.value, scope)
6695
+ }, expr);
6696
+ case "index":
6697
+ return copySpan({
6698
+ ...expr,
6699
+ obj: this.transformExpr(expr.obj, scope),
6700
+ index: this.transformExpr(expr.index, scope)
6701
+ }, expr);
6702
+ case "array_lit":
6703
+ return copySpan({ ...expr, elements: expr.elements.map((element) => this.transformExpr(element, scope)) }, expr);
6704
+ case "struct_lit":
6705
+ return copySpan({
6706
+ ...expr,
6707
+ fields: expr.fields.map((field) => ({ ...field, value: this.transformExpr(field.value, scope) }))
6708
+ }, expr);
6709
+ case "str_interp":
6710
+ return copySpan({
6711
+ ...expr,
6712
+ parts: expr.parts.map((part) => typeof part === "string" ? part : this.transformExpr(part, scope))
6713
+ }, expr);
6714
+ case "f_string":
6715
+ return copySpan({
6716
+ ...expr,
6717
+ parts: expr.parts.map((part) => part.kind === "text" ? part : { kind: "expr", expr: this.transformExpr(part.expr, scope) })
6718
+ }, expr);
6719
+ case "lambda": {
6720
+ const lambdaScope = [
6721
+ ...scope.map((entries) => [...entries]),
6722
+ expr.params.map((param) => ({ id: `lambda:${param.name}:${expr.span?.line ?? 0}:${expr.span?.col ?? 0}`, name: param.name }))
6723
+ ];
6724
+ const body = Array.isArray(expr.body) ? this.transformBlock(expr.body, lambdaScope) : this.transformExpr(expr.body, lambdaScope);
6725
+ return copySpan({ ...expr, body }, expr);
6726
+ }
6727
+ case "blockpos":
6728
+ case "bool_lit":
6729
+ case "byte_lit":
6730
+ case "double_lit":
6731
+ case "float_lit":
6732
+ case "ident":
6733
+ case "int_lit":
6734
+ case "long_lit":
6735
+ case "mc_name":
6736
+ case "range_lit":
6737
+ case "rel_coord":
6738
+ case "local_coord":
6739
+ case "selector":
6740
+ case "short_lit":
6741
+ case "str_lit":
6742
+ return expr;
6743
+ }
6744
+ }
6745
+ };
6746
+ exports2.DeadCodeEliminator = DeadCodeEliminator;
6747
+ function eliminateDeadCode(program) {
6748
+ return new DeadCodeEliminator().eliminate(program);
6749
+ }
6750
+ }
6751
+ });
6752
+
5944
6753
  // ../../dist/codegen/mcfunction/index.js
5945
6754
  var require_mcfunction = __commonJS({
5946
6755
  "../../dist/codegen/mcfunction/index.js"(exports2) {
@@ -6379,6 +7188,7 @@ var require_compile = __commonJS({
6379
7188
  var parser_1 = require_parser();
6380
7189
  var lowering_1 = require_lowering();
6381
7190
  var passes_1 = require_passes();
7191
+ var dce_1 = require_dce();
6382
7192
  var mcfunction_1 = require_mcfunction();
6383
7193
  var diagnostics_1 = require_diagnostics();
6384
7194
  var IMPORT_RE = /^\s*import\s+"([^"]+)"\s*;?\s*$/;
@@ -6453,13 +7263,15 @@ var require_compile = __commonJS({
6453
7263
  }
6454
7264
  function compile(source, options = {}) {
6455
7265
  const { namespace = "redscript", filePath, optimize: shouldOptimize = true } = options;
7266
+ const shouldRunDce = options.dce ?? shouldOptimize;
6456
7267
  let sourceLines = source.split("\n");
6457
7268
  try {
6458
7269
  const preprocessed = preprocessSourceWithMetadata(source, { filePath });
6459
7270
  const preprocessedSource = preprocessed.source;
6460
7271
  sourceLines = preprocessedSource.split("\n");
6461
7272
  const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
6462
- const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
7273
+ const parsedAst = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
7274
+ const ast = shouldRunDce ? (0, dce_1.eliminateDeadCode)(parsedAst) : parsedAst;
6463
7275
  const ir = new lowering_1.Lowering(namespace, preprocessed.ranges).lower(ast);
6464
7276
  const optimized = shouldOptimize ? { ...ir, functions: ir.functions.map((fn) => (0, passes_1.optimize)(fn)) } : ir;
6465
7277
  const generated = (0, mcfunction_1.generateDatapackWithStats)(optimized);
@@ -6836,6 +7648,7 @@ var require_dist = __commonJS({
6836
7648
  var typechecker_1 = require_typechecker();
6837
7649
  var lowering_1 = require_lowering();
6838
7650
  var passes_1 = require_passes();
7651
+ var dce_1 = require_dce();
6839
7652
  var mcfunction_1 = require_mcfunction();
6840
7653
  var compile_1 = require_compile();
6841
7654
  var commands_1 = require_commands();
@@ -6843,11 +7656,13 @@ var require_dist = __commonJS({
6843
7656
  const namespace = options.namespace ?? "redscript";
6844
7657
  const shouldOptimize = options.optimize ?? true;
6845
7658
  const shouldTypeCheck = options.typeCheck ?? true;
7659
+ const shouldRunDce = options.dce ?? shouldOptimize;
6846
7660
  const filePath = options.filePath;
6847
7661
  const preprocessed = (0, compile_1.preprocessSourceWithMetadata)(source, { filePath });
6848
7662
  const preprocessedSource = preprocessed.source;
6849
7663
  const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
6850
- const ast = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
7664
+ const parsedAst = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
7665
+ const ast = shouldRunDce ? (0, dce_1.eliminateDeadCode)(parsedAst) : parsedAst;
6851
7666
  let typeErrors;
6852
7667
  if (shouldTypeCheck) {
6853
7668
  const checker = new typechecker_1.TypeChecker(preprocessedSource, filePath);