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.
- package/CHANGELOG.md +5 -0
- package/README.md +53 -10
- package/README.zh.md +53 -10
- package/dist/__tests__/dce.test.d.ts +1 -0
- package/dist/__tests__/dce.test.js +137 -0
- package/dist/__tests__/lexer.test.js +19 -2
- package/dist/__tests__/lowering.test.js +8 -0
- package/dist/__tests__/mc-syntax.test.js +12 -0
- package/dist/__tests__/parser.test.js +10 -0
- package/dist/__tests__/runtime.test.js +13 -0
- package/dist/__tests__/typechecker.test.js +30 -0
- package/dist/ast/types.d.ts +22 -2
- package/dist/cli.js +15 -10
- package/dist/codegen/structure/index.d.ts +4 -1
- package/dist/codegen/structure/index.js +4 -2
- package/dist/compile.d.ts +1 -0
- package/dist/compile.js +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/lexer/index.d.ts +2 -1
- package/dist/lexer/index.js +89 -1
- package/dist/lowering/index.js +37 -1
- package/dist/optimizer/dce.d.ts +23 -0
- package/dist/optimizer/dce.js +592 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +81 -16
- package/dist/typechecker/index.d.ts +2 -0
- package/dist/typechecker/index.js +49 -0
- package/docs/ARCHITECTURE.zh.md +1088 -0
- package/editors/vscode/.vscodeignore +3 -0
- package/editors/vscode/icon.png +0 -0
- package/editors/vscode/out/extension.js +834 -19
- package/editors/vscode/package-lock.json +2 -2
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +6 -2
- package/examples/spiral.mcrs +41 -0
- package/logo.png +0 -0
- package/package.json +1 -1
- package/src/__tests__/dce.test.ts +129 -0
- package/src/__tests__/lexer.test.ts +21 -2
- package/src/__tests__/lowering.test.ts +9 -0
- package/src/__tests__/mc-syntax.test.ts +14 -0
- package/src/__tests__/parser.test.ts +11 -0
- package/src/__tests__/runtime.test.ts +16 -0
- package/src/__tests__/typechecker.test.ts +33 -0
- package/src/ast/types.ts +14 -1
- package/src/cli.ts +24 -10
- package/src/codegen/structure/index.ts +13 -2
- package/src/compile.ts +5 -1
- package/src/index.ts +5 -1
- package/src/lexer/index.ts +102 -1
- package/src/lowering/index.ts +38 -2
- package/src/optimizer/dce.ts +619 -0
- package/src/parser/index.ts +97 -17
- 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
|
|
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 === "
|
|
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.
|
|
1654
|
-
return
|
|
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
|
|
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
|
|
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);
|