redscript-mc 1.2.15 → 1.2.17
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 +39 -0
- package/README.md +13 -6
- package/builtins.d.mcrs +494 -0
- package/dist/builtins/metadata.d.ts +36 -0
- package/dist/builtins/metadata.js +1014 -0
- package/dist/cli.js +16 -6
- package/dist/lexer/index.js +9 -0
- package/dist/lowering/index.d.ts +12 -0
- package/dist/lowering/index.js +56 -0
- package/dist/parser/index.js +10 -3
- package/editors/vscode/builtins.d.mcrs +494 -0
- package/editors/vscode/out/extension.js +797 -80
- package/editors/vscode/package-lock.json +2 -2
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/src/symbols.ts +68 -0
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +1 -1
- package/package.json +1 -1
- package/src/builtins/metadata.ts +1118 -0
- package/src/cli.ts +17 -6
- package/src/lexer/index.ts +9 -0
- package/src/lowering/index.ts +59 -0
- package/src/parser/index.ts +12 -3
package/dist/cli.js
CHANGED
|
@@ -48,6 +48,7 @@ const cmdblock_1 = require("./codegen/cmdblock");
|
|
|
48
48
|
const structure_1 = require("./codegen/structure");
|
|
49
49
|
const diagnostics_1 = require("./diagnostics");
|
|
50
50
|
const repl_1 = require("./repl");
|
|
51
|
+
const metadata_1 = require("./builtins/metadata");
|
|
51
52
|
const fs = __importStar(require("fs"));
|
|
52
53
|
const path = __importStar(require("path"));
|
|
53
54
|
// Parse command line arguments
|
|
@@ -61,16 +62,18 @@ Usage:
|
|
|
61
62
|
redscript watch <dir> [-o <outdir>] [--namespace <ns>] [--hot-reload <url>]
|
|
62
63
|
redscript check <file>
|
|
63
64
|
redscript fmt <file.mcrs> [file2.mcrs ...]
|
|
65
|
+
redscript generate-dts [-o <file>]
|
|
64
66
|
redscript repl
|
|
65
67
|
redscript version
|
|
66
68
|
|
|
67
69
|
Commands:
|
|
68
|
-
compile
|
|
69
|
-
watch
|
|
70
|
-
check
|
|
71
|
-
fmt
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
compile Compile a RedScript file to a Minecraft datapack
|
|
71
|
+
watch Watch a directory for .mcrs file changes, recompile, and hot reload
|
|
72
|
+
check Check a RedScript file for errors without generating output
|
|
73
|
+
fmt Auto-format RedScript source files
|
|
74
|
+
generate-dts Generate builtin function declaration file (builtins.d.mcrs)
|
|
75
|
+
repl Start an interactive RedScript REPL
|
|
76
|
+
version Print the RedScript version
|
|
74
77
|
|
|
75
78
|
Options:
|
|
76
79
|
-o, --output <path> Output directory or file path, depending on target
|
|
@@ -414,6 +417,13 @@ async function main() {
|
|
|
414
417
|
}
|
|
415
418
|
break;
|
|
416
419
|
}
|
|
420
|
+
case 'generate-dts': {
|
|
421
|
+
const output = parsed.output ?? 'builtins.d.mcrs';
|
|
422
|
+
const dtsContent = (0, metadata_1.generateDts)();
|
|
423
|
+
fs.writeFileSync(output, dtsContent, 'utf-8');
|
|
424
|
+
console.log(`Generated ${output}`);
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
417
427
|
case 'repl':
|
|
418
428
|
await (0, repl_1.startRepl)(parsed.namespace ?? 'repl');
|
|
419
429
|
break;
|
package/dist/lexer/index.js
CHANGED
|
@@ -222,6 +222,15 @@ class Lexer {
|
|
|
222
222
|
value += this.advance();
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
+
// Check for ident (e.g. ~height → macro variable offset)
|
|
226
|
+
if (/[a-zA-Z_]/.test(this.peek())) {
|
|
227
|
+
let ident = '';
|
|
228
|
+
while (/[a-zA-Z0-9_]/.test(this.peek())) {
|
|
229
|
+
ident += this.advance();
|
|
230
|
+
}
|
|
231
|
+
// Store as rel_coord with embedded ident: ~height
|
|
232
|
+
value += ident;
|
|
233
|
+
}
|
|
225
234
|
this.addToken('rel_coord', value, startLine, startCol);
|
|
226
235
|
return;
|
|
227
236
|
}
|
package/dist/lowering/index.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export declare class Lowering {
|
|
|
60
60
|
* used in a literal position), returns the param name; otherwise null.
|
|
61
61
|
*/
|
|
62
62
|
private tryGetMacroParam;
|
|
63
|
+
private tryGetMacroParamByName;
|
|
63
64
|
/**
|
|
64
65
|
* Converts an expression to a string for use as a builtin arg.
|
|
65
66
|
* If the expression is a macro param, returns `$(name)` and sets macroParam.
|
|
@@ -151,6 +152,17 @@ export declare class Lowering {
|
|
|
151
152
|
private getArrayStorageName;
|
|
152
153
|
private inferLambdaReturnType;
|
|
153
154
|
private inferExprType;
|
|
155
|
+
/**
|
|
156
|
+
* Checks a raw() command string for `${...}` interpolation containing runtime variables.
|
|
157
|
+
* - If the interpolated expression is a numeric literal → OK (MC macro syntax).
|
|
158
|
+
* - If the interpolated name is a compile-time constant (in constValues) → OK.
|
|
159
|
+
* - If the interpolated name is a known runtime variable (in varMap) → DiagnosticError.
|
|
160
|
+
* - Unknown names → OK (could be MC macro params or external constants).
|
|
161
|
+
*
|
|
162
|
+
* This catches the common mistake of writing raw("say ${score}") expecting interpolation,
|
|
163
|
+
* which would silently emit a literal `${score}` in the MC command.
|
|
164
|
+
*/
|
|
165
|
+
private checkRawCommandInterpolation;
|
|
154
166
|
private resolveInstanceMethod;
|
|
155
167
|
private normalizeType;
|
|
156
168
|
private readArrayElement;
|
package/dist/lowering/index.js
CHANGED
|
@@ -354,6 +354,15 @@ class Lowering {
|
|
|
354
354
|
return null;
|
|
355
355
|
return expr.name;
|
|
356
356
|
}
|
|
357
|
+
tryGetMacroParamByName(name) {
|
|
358
|
+
if (!this.currentFnParamNames.has(name))
|
|
359
|
+
return null;
|
|
360
|
+
if (this.constValues.has(name))
|
|
361
|
+
return null;
|
|
362
|
+
if (this.stringValues.has(name))
|
|
363
|
+
return null;
|
|
364
|
+
return name;
|
|
365
|
+
}
|
|
357
366
|
/**
|
|
358
367
|
* Converts an expression to a string for use as a builtin arg.
|
|
359
368
|
* If the expression is a macro param, returns `$(name)` and sets macroParam.
|
|
@@ -363,6 +372,19 @@ class Lowering {
|
|
|
363
372
|
if (macroParam) {
|
|
364
373
|
return { str: `$(${macroParam})`, macroParam };
|
|
365
374
|
}
|
|
375
|
+
// Handle ~ident (e.g. ~height) - relative coord with variable offset
|
|
376
|
+
if (expr.kind === 'rel_coord' || expr.kind === 'local_coord') {
|
|
377
|
+
const val = expr.value; // e.g. "~height" or "^depth"
|
|
378
|
+
const prefix = val[0]; // ~ or ^
|
|
379
|
+
const rest = val.slice(1);
|
|
380
|
+
// If rest is an identifier (not a number), treat as macro param
|
|
381
|
+
if (rest && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(rest)) {
|
|
382
|
+
const paramName = this.tryGetMacroParamByName(rest);
|
|
383
|
+
if (paramName) {
|
|
384
|
+
return { str: `${prefix}$(${paramName})`, macroParam: paramName };
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
366
388
|
if (expr.kind === 'struct_lit' || expr.kind === 'array_lit') {
|
|
367
389
|
return { str: this.exprToSnbt(expr) };
|
|
368
390
|
}
|
|
@@ -704,6 +726,7 @@ class Lowering {
|
|
|
704
726
|
this.lowerExecuteStmt(stmt);
|
|
705
727
|
break;
|
|
706
728
|
case 'raw':
|
|
729
|
+
this.checkRawCommandInterpolation(stmt.cmd, stmt.span);
|
|
707
730
|
this.builder.emitRaw(stmt.cmd);
|
|
708
731
|
break;
|
|
709
732
|
}
|
|
@@ -2830,6 +2853,39 @@ class Lowering {
|
|
|
2830
2853
|
}
|
|
2831
2854
|
return undefined;
|
|
2832
2855
|
}
|
|
2856
|
+
/**
|
|
2857
|
+
* Checks a raw() command string for `${...}` interpolation containing runtime variables.
|
|
2858
|
+
* - If the interpolated expression is a numeric literal → OK (MC macro syntax).
|
|
2859
|
+
* - If the interpolated name is a compile-time constant (in constValues) → OK.
|
|
2860
|
+
* - If the interpolated name is a known runtime variable (in varMap) → DiagnosticError.
|
|
2861
|
+
* - Unknown names → OK (could be MC macro params or external constants).
|
|
2862
|
+
*
|
|
2863
|
+
* This catches the common mistake of writing raw("say ${score}") expecting interpolation,
|
|
2864
|
+
* which would silently emit a literal `${score}` in the MC command.
|
|
2865
|
+
*/
|
|
2866
|
+
checkRawCommandInterpolation(cmd, span) {
|
|
2867
|
+
const interpRe = /\$\{([^}]+)\}/g;
|
|
2868
|
+
let match;
|
|
2869
|
+
while ((match = interpRe.exec(cmd)) !== null) {
|
|
2870
|
+
const name = match[1].trim();
|
|
2871
|
+
// Numeric/boolean literals are fine (intentional MC macro syntax)
|
|
2872
|
+
if (/^\d+(\.\d+)?$/.test(name) || name === 'true' || name === 'false') {
|
|
2873
|
+
continue;
|
|
2874
|
+
}
|
|
2875
|
+
// Compile-time constants are fine
|
|
2876
|
+
if (this.constValues.has(name)) {
|
|
2877
|
+
continue;
|
|
2878
|
+
}
|
|
2879
|
+
// Only error if it's a known runtime variable (in varMap or function params)
|
|
2880
|
+
// Unknown identifiers are left alone (could be MC macro params the user intends)
|
|
2881
|
+
if (this.varMap.has(name) || this.currentFnParamNames.has(name)) {
|
|
2882
|
+
const loc = span ?? { line: 1, col: 1 };
|
|
2883
|
+
throw new diagnostics_1.DiagnosticError('LoweringError', `raw() command contains runtime variable interpolation '\${${name}}'. ` +
|
|
2884
|
+
`Variables cannot be interpolated into raw commands at compile time. ` +
|
|
2885
|
+
`Use f-string messages (say/tell/announce) or MC macro syntax '$(${name})' for MC 1.20.2+ commands.`, loc);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2833
2889
|
resolveInstanceMethod(expr) {
|
|
2834
2890
|
const receiver = expr.args[0];
|
|
2835
2891
|
if (!receiver) {
|
package/dist/parser/index.js
CHANGED
|
@@ -213,12 +213,19 @@ class Parser {
|
|
|
213
213
|
parseConstDecl() {
|
|
214
214
|
const constToken = this.expect('const');
|
|
215
215
|
const name = this.expect('ident').value;
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
let type;
|
|
217
|
+
if (this.match(':')) {
|
|
218
|
+
type = this.parseType();
|
|
219
|
+
}
|
|
218
220
|
this.expect('=');
|
|
219
221
|
const value = this.parseLiteralExpr();
|
|
220
222
|
this.match(';');
|
|
221
|
-
|
|
223
|
+
// Infer type from value if not provided
|
|
224
|
+
const inferredType = type ?? (value.kind === 'str_lit' ? { kind: 'named', name: 'string' } :
|
|
225
|
+
value.kind === 'bool_lit' ? { kind: 'named', name: 'bool' } :
|
|
226
|
+
value.kind === 'float_lit' ? { kind: 'named', name: 'float' } :
|
|
227
|
+
{ kind: 'named', name: 'int' });
|
|
228
|
+
return this.withLoc({ name, type: inferredType, value }, constToken);
|
|
222
229
|
}
|
|
223
230
|
parseGlobalDecl(mutable) {
|
|
224
231
|
const token = this.advance(); // consume 'let'
|