redscript-mc 1.2.3 → 1.2.5
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/ast/types.d.ts +1 -0
- package/dist/lowering/index.js +3 -2
- package/dist/parser/index.js +13 -1
- package/editors/vscode/out/extension.js +14 -3
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +1 -1
- package/examples/spiral.mcrs +4 -2
- package/package.json +1 -1
- package/src/ast/types.ts +1 -1
- package/src/lowering/index.ts +3 -2
- package/src/parser/index.ts +15 -1
package/dist/ast/types.d.ts
CHANGED
package/dist/lowering/index.js
CHANGED
|
@@ -757,8 +757,9 @@ class Lowering {
|
|
|
757
757
|
// Extract body into a separate function
|
|
758
758
|
const subFnName = `${this.currentFn}/foreach_${this.foreachCounter++}`;
|
|
759
759
|
const selector = this.exprToString(stmt.iterable);
|
|
760
|
-
// Emit execute as ... run function ...
|
|
761
|
-
|
|
760
|
+
// Emit execute as ... [context modifiers] run function ...
|
|
761
|
+
const execContext = stmt.executeContext ? ` ${stmt.executeContext}` : '';
|
|
762
|
+
this.builder.emitRaw(`execute as ${selector}${execContext} run function ${this.namespace}:${subFnName}`);
|
|
762
763
|
// Create the sub-function
|
|
763
764
|
const savedBuilder = this.builder;
|
|
764
765
|
const savedVarMap = new Map(this.varMap);
|
package/dist/parser/index.js
CHANGED
|
@@ -534,8 +534,20 @@ class Parser {
|
|
|
534
534
|
this.expect('in');
|
|
535
535
|
const iterable = this.parseExpr();
|
|
536
536
|
this.expect(')');
|
|
537
|
+
// Parse optional execute context modifiers (at, positioned, rotated, facing, etc.)
|
|
538
|
+
let executeContext;
|
|
539
|
+
// Check for 'at' keyword or identifiers like 'positioned', 'rotated', 'facing', 'anchored', 'align'
|
|
540
|
+
const execIdentKeywords = ['positioned', 'rotated', 'facing', 'anchored', 'align'];
|
|
541
|
+
if (this.check('at') || this.check('in') || (this.check('ident') && execIdentKeywords.includes(this.peek().value))) {
|
|
542
|
+
// Collect everything until we hit '{'
|
|
543
|
+
let context = '';
|
|
544
|
+
while (!this.check('{') && !this.check('eof')) {
|
|
545
|
+
context += this.advance().value + ' ';
|
|
546
|
+
}
|
|
547
|
+
executeContext = context.trim();
|
|
548
|
+
}
|
|
537
549
|
const body = this.parseBlock();
|
|
538
|
-
return this.withLoc({ kind: 'foreach', binding, iterable, body }, foreachToken);
|
|
550
|
+
return this.withLoc({ kind: 'foreach', binding, iterable, body, executeContext }, foreachToken);
|
|
539
551
|
}
|
|
540
552
|
parseMatchStmt() {
|
|
541
553
|
const matchToken = this.expect('match');
|
|
@@ -1163,8 +1163,17 @@ var require_parser = __commonJS({
|
|
|
1163
1163
|
this.expect("in");
|
|
1164
1164
|
const iterable = this.parseExpr();
|
|
1165
1165
|
this.expect(")");
|
|
1166
|
+
let executeContext;
|
|
1167
|
+
const execIdentKeywords = ["positioned", "rotated", "facing", "anchored", "align"];
|
|
1168
|
+
if (this.check("at") || this.check("in") || this.check("ident") && execIdentKeywords.includes(this.peek().value)) {
|
|
1169
|
+
let context = "";
|
|
1170
|
+
while (!this.check("{") && !this.check("eof")) {
|
|
1171
|
+
context += this.advance().value + " ";
|
|
1172
|
+
}
|
|
1173
|
+
executeContext = context.trim();
|
|
1174
|
+
}
|
|
1166
1175
|
const body = this.parseBlock();
|
|
1167
|
-
return this.withLoc({ kind: "foreach", binding, iterable, body }, foreachToken);
|
|
1176
|
+
return this.withLoc({ kind: "foreach", binding, iterable, body, executeContext }, foreachToken);
|
|
1168
1177
|
}
|
|
1169
1178
|
parseMatchStmt() {
|
|
1170
1179
|
const matchToken = this.expect("match");
|
|
@@ -3799,7 +3808,8 @@ var require_lowering = __commonJS({
|
|
|
3799
3808
|
}
|
|
3800
3809
|
const subFnName = `${this.currentFn}/foreach_${this.foreachCounter++}`;
|
|
3801
3810
|
const selector = this.exprToString(stmt.iterable);
|
|
3802
|
-
|
|
3811
|
+
const execContext = stmt.executeContext ? ` ${stmt.executeContext}` : "";
|
|
3812
|
+
this.builder.emitRaw(`execute as ${selector}${execContext} run function ${this.namespace}:${subFnName}`);
|
|
3803
3813
|
const savedBuilder = this.builder;
|
|
3804
3814
|
const savedVarMap = new Map(this.varMap);
|
|
3805
3815
|
const savedContext = this.currentContext;
|
|
@@ -6122,7 +6132,8 @@ var require_passes = __commonJS({
|
|
|
6122
6132
|
...block,
|
|
6123
6133
|
instrs: block.instrs.filter((instr) => {
|
|
6124
6134
|
if (instr.op === "assign" || instr.op === "binop" || instr.op === "cmp") {
|
|
6125
|
-
const
|
|
6135
|
+
const isTemp = /^\$t\d+$/.test(instr.dst) || /^\$p\d+$/.test(instr.dst) || /^\$_\d+$/.test(instr.dst);
|
|
6136
|
+
const keep = !isTemp || readVars.has(instr.dst);
|
|
6126
6137
|
if (!keep)
|
|
6127
6138
|
removed++;
|
|
6128
6139
|
return keep;
|
|
@@ -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.6",
|
|
6
6
|
"publisher": "bkmashiro",
|
|
7
7
|
"icon": "icon.png",
|
|
8
8
|
"license": "MIT",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"patterns": [
|
|
134
134
|
{
|
|
135
135
|
"name": "keyword.control.redscript",
|
|
136
|
-
"match": "\\b(if|else|while|for|foreach|return|match|in|execute|as|at|unless|run|is)\\b"
|
|
136
|
+
"match": "\\b(if|else|while|for|foreach|return|match|in|execute|as|at|unless|run|is|positioned|rotated|facing|anchored|align)\\b"
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
"name": "keyword.declaration.redscript",
|
package/examples/spiral.mcrs
CHANGED
|
@@ -12,8 +12,10 @@ let running: bool = false;
|
|
|
12
12
|
// 每 tick 增加计数器
|
|
13
13
|
counter = counter + 1;
|
|
14
14
|
|
|
15
|
-
//
|
|
16
|
-
|
|
15
|
+
// 在每个玩家位置生成粒子
|
|
16
|
+
foreach (p in @a) at @s {
|
|
17
|
+
particle("minecraft:end_rod", ~0, ~1, ~0, 0.5, 0.5, 0.5, 0.1, 5);
|
|
18
|
+
}
|
|
17
19
|
|
|
18
20
|
// 每 20 ticks (1秒) 报告一次
|
|
19
21
|
if (counter % 20 == 0) {
|
package/package.json
CHANGED
package/src/ast/types.ts
CHANGED
|
@@ -192,7 +192,7 @@ export type Stmt =
|
|
|
192
192
|
| { kind: 'if'; cond: Expr; then: Block; else_?: Block; span?: Span }
|
|
193
193
|
| { kind: 'while'; cond: Expr; body: Block; span?: Span }
|
|
194
194
|
| { kind: 'for'; init?: Stmt; cond: Expr; step: Expr; body: Block; span?: Span }
|
|
195
|
-
| { kind: 'foreach'; binding: string; iterable: Expr; body: Block; span?: Span }
|
|
195
|
+
| { kind: 'foreach'; binding: string; iterable: Expr; body: Block; executeContext?: string; span?: Span }
|
|
196
196
|
| { kind: 'for_range'; varName: string; start: Expr; end: Expr; body: Block; span?: Span }
|
|
197
197
|
| { kind: 'match'; expr: Expr; arms: { pattern: Expr | null; body: Block }[]; span?: Span }
|
|
198
198
|
| { kind: 'as_block'; selector: EntitySelector; body: Block; span?: Span }
|
package/src/lowering/index.ts
CHANGED
|
@@ -898,8 +898,9 @@ export class Lowering {
|
|
|
898
898
|
const subFnName = `${this.currentFn}/foreach_${this.foreachCounter++}`
|
|
899
899
|
const selector = this.exprToString(stmt.iterable)
|
|
900
900
|
|
|
901
|
-
// Emit execute as ... run function ...
|
|
902
|
-
|
|
901
|
+
// Emit execute as ... [context modifiers] run function ...
|
|
902
|
+
const execContext = stmt.executeContext ? ` ${stmt.executeContext}` : ''
|
|
903
|
+
this.builder.emitRaw(`execute as ${selector}${execContext} run function ${this.namespace}:${subFnName}`)
|
|
903
904
|
|
|
904
905
|
// Create the sub-function
|
|
905
906
|
const savedBuilder = this.builder
|
package/src/parser/index.ts
CHANGED
|
@@ -645,9 +645,23 @@ export class Parser {
|
|
|
645
645
|
this.expect('in')
|
|
646
646
|
const iterable = this.parseExpr()
|
|
647
647
|
this.expect(')')
|
|
648
|
+
|
|
649
|
+
// Parse optional execute context modifiers (at, positioned, rotated, facing, etc.)
|
|
650
|
+
let executeContext: string | undefined
|
|
651
|
+
// Check for 'at' keyword or identifiers like 'positioned', 'rotated', 'facing', 'anchored', 'align'
|
|
652
|
+
const execIdentKeywords = ['positioned', 'rotated', 'facing', 'anchored', 'align']
|
|
653
|
+
if (this.check('at') || this.check('in') || (this.check('ident') && execIdentKeywords.includes(this.peek().value))) {
|
|
654
|
+
// Collect everything until we hit '{'
|
|
655
|
+
let context = ''
|
|
656
|
+
while (!this.check('{') && !this.check('eof')) {
|
|
657
|
+
context += this.advance().value + ' '
|
|
658
|
+
}
|
|
659
|
+
executeContext = context.trim()
|
|
660
|
+
}
|
|
661
|
+
|
|
648
662
|
const body = this.parseBlock()
|
|
649
663
|
|
|
650
|
-
return this.withLoc({ kind: 'foreach', binding, iterable, body }, foreachToken)
|
|
664
|
+
return this.withLoc({ kind: 'foreach', binding, iterable, body, executeContext }, foreachToken)
|
|
651
665
|
}
|
|
652
666
|
|
|
653
667
|
private parseMatchStmt(): Stmt {
|