redscript-mc 1.2.2 → 1.2.3
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/dist/__tests__/optimizer.test.js +7 -7
- package/dist/optimizer/passes.js +5 -1
- package/editors/vscode/out/extension.js +3 -1
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +2 -2
- package/package.json +1 -1
- package/src/__tests__/optimizer.test.ts +7 -7
- package/src/optimizer/passes.ts +5 -1
|
@@ -71,12 +71,12 @@ describe('copyPropagation', () => {
|
|
|
71
71
|
describe('deadCodeElimination', () => {
|
|
72
72
|
it('removes unused assignment', () => {
|
|
73
73
|
const fn = makeFn([
|
|
74
|
-
{ op: 'assign', dst: '$
|
|
75
|
-
{ op: 'assign', dst: '$
|
|
76
|
-
], { op: 'return', value: { kind: 'var', name: '$
|
|
74
|
+
{ op: 'assign', dst: '$t0', src: { kind: 'const', value: 99 } }, // unused temp
|
|
75
|
+
{ op: 'assign', dst: '$t1', src: { kind: 'const', value: 1 } }, // used temp
|
|
76
|
+
], { op: 'return', value: { kind: 'var', name: '$t1' } });
|
|
77
77
|
const opt = (0, passes_1.deadCodeElimination)(fn);
|
|
78
78
|
expect(opt.blocks[0].instrs).toHaveLength(1);
|
|
79
|
-
expect(opt.blocks[0].instrs[0].dst).toBe('$
|
|
79
|
+
expect(opt.blocks[0].instrs[0].dst).toBe('$t1');
|
|
80
80
|
});
|
|
81
81
|
it('keeps call even if return value unused (side effects)', () => {
|
|
82
82
|
const fn = makeFn([
|
|
@@ -104,12 +104,12 @@ describe('optimize pipeline', () => {
|
|
|
104
104
|
const fn = makeFn([
|
|
105
105
|
{ op: 'binop', dst: '$t0', lhs: { kind: 'const', value: 2 }, bop: '+', rhs: { kind: 'const', value: 3 } },
|
|
106
106
|
{ op: 'assign', dst: '$x', src: { kind: 'var', name: '$t0' } },
|
|
107
|
-
{ op: 'assign', dst: '$
|
|
107
|
+
{ op: 'assign', dst: '$t1', src: { kind: 'const', value: 0 } }, // unused temp, should be removed
|
|
108
108
|
], { op: 'return', value: { kind: 'var', name: '$x' } });
|
|
109
109
|
const opt = (0, passes_1.optimize)(fn);
|
|
110
110
|
const instrs = opt.blocks[0].instrs;
|
|
111
|
-
// $unused should be gone
|
|
112
|
-
expect(instrs.some((i) => i.dst === '$
|
|
111
|
+
// $t1 (unused temp) should be gone
|
|
112
|
+
expect(instrs.some((i) => i.dst === '$t1')).toBe(false);
|
|
113
113
|
// $x should be const 5 (after folding + propagation)
|
|
114
114
|
const xInstr = instrs.find((i) => i.dst === '$x');
|
|
115
115
|
expect(xInstr?.src).toEqual({ kind: 'const', value: 5 });
|
package/dist/optimizer/passes.js
CHANGED
|
@@ -184,7 +184,11 @@ function deadCodeEliminationWithStats(fn) {
|
|
|
184
184
|
instrs: block.instrs.filter(instr => {
|
|
185
185
|
// Only assignments/binops/cmps with an unused dst are candidates for removal
|
|
186
186
|
if (instr.op === 'assign' || instr.op === 'binop' || instr.op === 'cmp') {
|
|
187
|
-
|
|
187
|
+
// Always keep assignments to global variables (they may be read by other functions)
|
|
188
|
+
// Temps are $t0, $t1, ...; params are $p0, $p1, ...; locals are $_0, $_1, ...
|
|
189
|
+
// Everything else is a potential global
|
|
190
|
+
const isTemp = /^\$t\d+$/.test(instr.dst) || /^\$p\d+$/.test(instr.dst) || /^\$_\d+$/.test(instr.dst);
|
|
191
|
+
const keep = !isTemp || readVars.has(instr.dst);
|
|
188
192
|
if (!keep)
|
|
189
193
|
removed++;
|
|
190
194
|
return keep;
|
|
@@ -6291,7 +6291,9 @@ var require_dce = __commonJS({
|
|
|
6291
6291
|
"on_craft",
|
|
6292
6292
|
"on_death",
|
|
6293
6293
|
"on_login",
|
|
6294
|
-
"on_join_team"
|
|
6294
|
+
"on_join_team",
|
|
6295
|
+
"keep"
|
|
6296
|
+
// Prevent DCE from removing this function
|
|
6295
6297
|
].includes(decorator.name))) {
|
|
6296
6298
|
entries.add(fn.name);
|
|
6297
6299
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "redscript-vscode",
|
|
3
3
|
"displayName": "RedScript for Minecraft",
|
|
4
4
|
"description": "Syntax highlighting, error diagnostics, and language support for RedScript — a compiler targeting Minecraft Java Edition",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.5",
|
|
6
6
|
"publisher": "bkmashiro",
|
|
7
7
|
"icon": "icon.png",
|
|
8
8
|
"license": "MIT",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"patterns": [
|
|
62
62
|
{
|
|
63
63
|
"comment": "Decorator with arguments: @tick(rate=20)",
|
|
64
|
-
"begin": "(@(?:tick|on_advancement|on_craft|on_death|on_trigger|on_join_team|on_login))\\s*(\\()",
|
|
64
|
+
"begin": "(@(?:tick|load|keep|on|on_advancement|on_craft|on_death|on_trigger|on_join_team|on_login))\\s*(\\()",
|
|
65
65
|
"beginCaptures": {
|
|
66
66
|
"1": { "name": "entity.name.function.decorator.redscript" },
|
|
67
67
|
"2": { "name": "punctuation.definition.parameters.redscript" }
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
{
|
|
87
87
|
"comment": "Bare decorator: @on_death",
|
|
88
88
|
"name": "entity.name.function.decorator.redscript",
|
|
89
|
-
"match": "@(?:tick|on_advancement|on_craft|on_death|on_trigger|on_join_team|on_login)\\b"
|
|
89
|
+
"match": "@(?:tick|load|keep|on|on_advancement|on_craft|on_death|on_trigger|on_join_team|on_login)\\b"
|
|
90
90
|
}
|
|
91
91
|
]
|
|
92
92
|
},
|
package/package.json
CHANGED
|
@@ -79,12 +79,12 @@ describe('copyPropagation', () => {
|
|
|
79
79
|
describe('deadCodeElimination', () => {
|
|
80
80
|
it('removes unused assignment', () => {
|
|
81
81
|
const fn = makeFn([
|
|
82
|
-
{ op: 'assign', dst: '$
|
|
83
|
-
{ op: 'assign', dst: '$
|
|
84
|
-
], { op: 'return', value: { kind: 'var', name: '$
|
|
82
|
+
{ op: 'assign', dst: '$t0', src: { kind: 'const', value: 99 } }, // unused temp
|
|
83
|
+
{ op: 'assign', dst: '$t1', src: { kind: 'const', value: 1 } }, // used temp
|
|
84
|
+
], { op: 'return', value: { kind: 'var', name: '$t1' } })
|
|
85
85
|
const opt = deadCodeElimination(fn)
|
|
86
86
|
expect(opt.blocks[0].instrs).toHaveLength(1)
|
|
87
|
-
expect((opt.blocks[0].instrs[0] as any).dst).toBe('$
|
|
87
|
+
expect((opt.blocks[0].instrs[0] as any).dst).toBe('$t1')
|
|
88
88
|
})
|
|
89
89
|
|
|
90
90
|
it('keeps call even if return value unused (side effects)', () => {
|
|
@@ -115,13 +115,13 @@ describe('optimize pipeline', () => {
|
|
|
115
115
|
const fn = makeFn([
|
|
116
116
|
{ op: 'binop', dst: '$t0', lhs: { kind: 'const', value: 2 }, bop: '+', rhs: { kind: 'const', value: 3 } },
|
|
117
117
|
{ op: 'assign', dst: '$x', src: { kind: 'var', name: '$t0' } },
|
|
118
|
-
{ op: 'assign', dst: '$
|
|
118
|
+
{ op: 'assign', dst: '$t1', src: { kind: 'const', value: 0 } }, // unused temp, should be removed
|
|
119
119
|
], { op: 'return', value: { kind: 'var', name: '$x' } })
|
|
120
120
|
|
|
121
121
|
const opt = optimize(fn)
|
|
122
122
|
const instrs = opt.blocks[0].instrs
|
|
123
|
-
// $unused should be gone
|
|
124
|
-
expect(instrs.some((i: any) => i.dst === '$
|
|
123
|
+
// $t1 (unused temp) should be gone
|
|
124
|
+
expect(instrs.some((i: any) => i.dst === '$t1')).toBe(false)
|
|
125
125
|
// $x should be const 5 (after folding + propagation)
|
|
126
126
|
const xInstr = instrs.find((i: any) => i.dst === '$x') as any
|
|
127
127
|
expect(xInstr?.src).toEqual({ kind: 'const', value: 5 })
|
package/src/optimizer/passes.ts
CHANGED
|
@@ -177,7 +177,11 @@ export function deadCodeEliminationWithStats(fn: IRFunction): { fn: IRFunction;
|
|
|
177
177
|
instrs: block.instrs.filter(instr => {
|
|
178
178
|
// Only assignments/binops/cmps with an unused dst are candidates for removal
|
|
179
179
|
if (instr.op === 'assign' || instr.op === 'binop' || instr.op === 'cmp') {
|
|
180
|
-
|
|
180
|
+
// Always keep assignments to global variables (they may be read by other functions)
|
|
181
|
+
// Temps are $t0, $t1, ...; params are $p0, $p1, ...; locals are $_0, $_1, ...
|
|
182
|
+
// Everything else is a potential global
|
|
183
|
+
const isTemp = /^\$t\d+$/.test(instr.dst) || /^\$p\d+$/.test(instr.dst) || /^\$_\d+$/.test(instr.dst)
|
|
184
|
+
const keep = !isTemp || readVars.has(instr.dst)
|
|
181
185
|
if (!keep) removed++
|
|
182
186
|
return keep
|
|
183
187
|
}
|