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.
@@ -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: '$unused', src: { kind: 'const', value: 99 } },
75
- { op: 'assign', dst: '$used', src: { kind: 'const', value: 1 } },
76
- ], { op: 'return', value: { kind: 'var', name: '$used' } });
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('$used');
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: '$unused', src: { kind: 'const', value: 0 } },
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 === '$unused')).toBe(false);
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 });
@@ -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
- const keep = readVars.has(instr.dst);
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.4",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "redscript-mc",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "A high-level programming language that compiles to Minecraft datapacks",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -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: '$unused', src: { kind: 'const', value: 99 } },
83
- { op: 'assign', dst: '$used', src: { kind: 'const', value: 1 } },
84
- ], { op: 'return', value: { kind: 'var', name: '$used' } })
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('$used')
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: '$unused', src: { kind: 'const', value: 0 } },
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 === '$unused')).toBe(false)
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 })
@@ -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
- const keep = readVars.has(instr.dst)
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
  }