redscript-mc 1.2.14 → 1.2.16

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.
@@ -172,6 +172,8 @@ var require_lexer = __commonJS({
172
172
  foreach: "foreach",
173
173
  match: "match",
174
174
  return: "return",
175
+ break: "break",
176
+ continue: "continue",
175
177
  as: "as",
176
178
  at: "at",
177
179
  in: "in",
@@ -1042,6 +1044,16 @@ var require_parser = __commonJS({
1042
1044
  if (this.check("return")) {
1043
1045
  return this.parseReturnStmt();
1044
1046
  }
1047
+ if (this.check("break")) {
1048
+ const token = this.advance();
1049
+ this.match(";");
1050
+ return this.withLoc({ kind: "break" }, token);
1051
+ }
1052
+ if (this.check("continue")) {
1053
+ const token = this.advance();
1054
+ this.match(";");
1055
+ return this.withLoc({ kind: "continue" }, token);
1056
+ }
1045
1057
  if (this.check("if")) {
1046
1058
  return this.parseIfStmt();
1047
1059
  }
@@ -1164,8 +1176,8 @@ var require_parser = __commonJS({
1164
1176
  const iterable = this.parseExpr();
1165
1177
  this.expect(")");
1166
1178
  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)) {
1179
+ const execIdentKeywords = ["positioned", "rotated", "facing", "anchored", "align", "on", "summon"];
1180
+ if (this.check("as") || this.check("at") || this.check("in") || this.check("ident") && execIdentKeywords.includes(this.peek().value)) {
1169
1181
  let context = "";
1170
1182
  while (!this.check("{") && !this.check("eof")) {
1171
1183
  context += this.advance().value + " ";
@@ -1224,29 +1236,152 @@ var require_parser = __commonJS({
1224
1236
  } else if (this.match("at")) {
1225
1237
  const selector = this.parseSelector();
1226
1238
  subcommands.push({ kind: "at", selector });
1227
- } else if (this.match("if")) {
1228
- if (this.peek().kind === "ident" && this.peek().value === "entity") {
1239
+ } else if (this.checkIdent("positioned")) {
1240
+ this.advance();
1241
+ if (this.match("as")) {
1242
+ const selector = this.parseSelector();
1243
+ subcommands.push({ kind: "positioned_as", selector });
1244
+ } else {
1245
+ const x = this.parseCoordToken();
1246
+ const y = this.parseCoordToken();
1247
+ const z = this.parseCoordToken();
1248
+ subcommands.push({ kind: "positioned", x, y, z });
1249
+ }
1250
+ } else if (this.checkIdent("rotated")) {
1251
+ this.advance();
1252
+ if (this.match("as")) {
1253
+ const selector = this.parseSelector();
1254
+ subcommands.push({ kind: "rotated_as", selector });
1255
+ } else {
1256
+ const yaw = this.parseCoordToken();
1257
+ const pitch = this.parseCoordToken();
1258
+ subcommands.push({ kind: "rotated", yaw, pitch });
1259
+ }
1260
+ } else if (this.checkIdent("facing")) {
1261
+ this.advance();
1262
+ if (this.checkIdent("entity")) {
1229
1263
  this.advance();
1264
+ const selector = this.parseSelector();
1265
+ const anchor = this.checkIdent("eyes") || this.checkIdent("feet") ? this.advance().value : "feet";
1266
+ subcommands.push({ kind: "facing_entity", selector, anchor });
1267
+ } else {
1268
+ const x = this.parseCoordToken();
1269
+ const y = this.parseCoordToken();
1270
+ const z = this.parseCoordToken();
1271
+ subcommands.push({ kind: "facing", x, y, z });
1230
1272
  }
1231
- const selectorOrVar = this.parseSelectorOrVarSelector();
1232
- subcommands.push({ kind: "if_entity", ...selectorOrVar });
1233
- } else if (this.match("unless")) {
1234
- if (this.peek().kind === "ident" && this.peek().value === "entity") {
1273
+ } else if (this.checkIdent("anchored")) {
1274
+ this.advance();
1275
+ const anchor = this.advance().value;
1276
+ subcommands.push({ kind: "anchored", anchor });
1277
+ } else if (this.checkIdent("align")) {
1278
+ this.advance();
1279
+ const axes = this.advance().value;
1280
+ subcommands.push({ kind: "align", axes });
1281
+ } else if (this.checkIdent("on")) {
1282
+ this.advance();
1283
+ const relation = this.advance().value;
1284
+ subcommands.push({ kind: "on", relation });
1285
+ } else if (this.checkIdent("summon")) {
1286
+ this.advance();
1287
+ const entity = this.advance().value;
1288
+ subcommands.push({ kind: "summon", entity });
1289
+ } else if (this.checkIdent("store")) {
1290
+ this.advance();
1291
+ const storeType = this.advance().value;
1292
+ if (this.checkIdent("score")) {
1235
1293
  this.advance();
1294
+ const target = this.advance().value;
1295
+ const targetObj = this.advance().value;
1296
+ if (storeType === "result") {
1297
+ subcommands.push({ kind: "store_result", target, targetObj });
1298
+ } else {
1299
+ subcommands.push({ kind: "store_success", target, targetObj });
1300
+ }
1301
+ } else {
1302
+ this.error("store currently only supports score target");
1236
1303
  }
1237
- const selectorOrVar = this.parseSelectorOrVarSelector();
1238
- subcommands.push({ kind: "unless_entity", ...selectorOrVar });
1304
+ } else if (this.match("if")) {
1305
+ this.parseExecuteCondition(subcommands, "if");
1306
+ } else if (this.match("unless")) {
1307
+ this.parseExecuteCondition(subcommands, "unless");
1239
1308
  } else if (this.match("in")) {
1240
- const dim = this.expect("ident").value;
1309
+ let dim = this.advance().value;
1310
+ if (this.match(":")) {
1311
+ dim += ":" + this.advance().value;
1312
+ }
1241
1313
  subcommands.push({ kind: "in", dimension: dim });
1242
1314
  } else {
1243
- this.error(`Unexpected token in execute statement: ${this.peek().kind}`);
1315
+ this.error(`Unexpected token in execute statement: ${this.peek().kind} (${this.peek().value})`);
1244
1316
  }
1245
1317
  }
1246
1318
  this.expect("run");
1247
1319
  const body = this.parseBlock();
1248
1320
  return this.withLoc({ kind: "execute", subcommands, body }, executeToken);
1249
1321
  }
1322
+ parseExecuteCondition(subcommands, type) {
1323
+ if (this.checkIdent("entity") || this.check("selector")) {
1324
+ if (this.checkIdent("entity"))
1325
+ this.advance();
1326
+ const selectorOrVar = this.parseSelectorOrVarSelector();
1327
+ subcommands.push({ kind: type === "if" ? "if_entity" : "unless_entity", ...selectorOrVar });
1328
+ } else if (this.checkIdent("block")) {
1329
+ this.advance();
1330
+ const x = this.parseCoordToken();
1331
+ const y = this.parseCoordToken();
1332
+ const z = this.parseCoordToken();
1333
+ const block = this.parseBlockId();
1334
+ subcommands.push({ kind: type === "if" ? "if_block" : "unless_block", pos: [x, y, z], block });
1335
+ } else if (this.checkIdent("score")) {
1336
+ this.advance();
1337
+ const target = this.advance().value;
1338
+ const targetObj = this.advance().value;
1339
+ if (this.checkIdent("matches")) {
1340
+ this.advance();
1341
+ const range = this.advance().value;
1342
+ subcommands.push({ kind: type === "if" ? "if_score_range" : "unless_score_range", target, targetObj, range });
1343
+ } else {
1344
+ const op = this.advance().value;
1345
+ const source = this.advance().value;
1346
+ const sourceObj = this.advance().value;
1347
+ subcommands.push({
1348
+ kind: type === "if" ? "if_score" : "unless_score",
1349
+ target,
1350
+ targetObj,
1351
+ op,
1352
+ source,
1353
+ sourceObj
1354
+ });
1355
+ }
1356
+ } else {
1357
+ this.error(`Unknown condition type after ${type}`);
1358
+ }
1359
+ }
1360
+ parseCoordToken() {
1361
+ const token = this.peek();
1362
+ if (token.kind === "rel_coord" || token.kind === "local_coord" || token.kind === "int_lit" || token.kind === "float_lit" || token.kind === "-" || token.kind === "ident") {
1363
+ return this.advance().value;
1364
+ }
1365
+ this.error(`Expected coordinate, got ${token.kind}`);
1366
+ return "~";
1367
+ }
1368
+ parseBlockId() {
1369
+ let id = this.advance().value;
1370
+ if (this.match(":")) {
1371
+ id += ":" + this.advance().value;
1372
+ }
1373
+ if (this.check("[")) {
1374
+ id += this.advance().value;
1375
+ while (!this.check("]") && !this.check("eof")) {
1376
+ id += this.advance().value;
1377
+ }
1378
+ id += this.advance().value;
1379
+ }
1380
+ return id;
1381
+ }
1382
+ checkIdent(value) {
1383
+ return this.check("ident") && this.peek().value === value;
1384
+ }
1250
1385
  parseExprStmt() {
1251
1386
  const expr = this.parseExpr();
1252
1387
  this.expect(";");
@@ -3128,7 +3263,7 @@ var require_lowering = __commonJS({
3128
3263
  exports2.Lowering = void 0;
3129
3264
  var builder_1 = require_builder();
3130
3265
  var diagnostics_1 = require_diagnostics();
3131
- var path = __importStar(require("path"));
3266
+ var path2 = __importStar(require("path"));
3132
3267
  var types_1 = require_types();
3133
3268
  var BUILTINS2 = {
3134
3269
  say: ([msg]) => `say ${msg}`,
@@ -3245,20 +3380,20 @@ var require_lowering = __commonJS({
3245
3380
  var NAMESPACED_ENTITY_TYPE_RE = /^[a-z0-9_.-]+:[a-z0-9_./-]+$/;
3246
3381
  var BARE_ENTITY_TYPE_RE = /^[a-z0-9_./-]+$/;
3247
3382
  var ENTITY_TO_MC_TYPE = {
3248
- Player: "player",
3249
- Zombie: "zombie",
3250
- Skeleton: "skeleton",
3251
- Creeper: "creeper",
3252
- Spider: "spider",
3253
- Enderman: "enderman",
3254
- Pig: "pig",
3255
- Cow: "cow",
3256
- Sheep: "sheep",
3257
- Chicken: "chicken",
3258
- Villager: "villager",
3259
- ArmorStand: "armor_stand",
3260
- Item: "item",
3261
- Arrow: "arrow"
3383
+ Player: "minecraft:player",
3384
+ Zombie: "minecraft:zombie",
3385
+ Skeleton: "minecraft:skeleton",
3386
+ Creeper: "minecraft:creeper",
3387
+ Spider: "minecraft:spider",
3388
+ Enderman: "minecraft:enderman",
3389
+ Pig: "minecraft:pig",
3390
+ Cow: "minecraft:cow",
3391
+ Sheep: "minecraft:sheep",
3392
+ Chicken: "minecraft:chicken",
3393
+ Villager: "minecraft:villager",
3394
+ ArmorStand: "minecraft:armor_stand",
3395
+ Item: "minecraft:item",
3396
+ Arrow: "minecraft:arrow"
3262
3397
  };
3263
3398
  function normalizeSelector(selector, warnings) {
3264
3399
  return selector.replace(/type=([^,\]]+)/g, (match, entityType) => {
@@ -3314,6 +3449,7 @@ var require_lowering = __commonJS({
3314
3449
  this.currentContext = {};
3315
3450
  this.blockPosVars = /* @__PURE__ */ new Map();
3316
3451
  this.structDefs = /* @__PURE__ */ new Map();
3452
+ this.structDecls = /* @__PURE__ */ new Map();
3317
3453
  this.enumDefs = /* @__PURE__ */ new Map();
3318
3454
  this.functionDefaults = /* @__PURE__ */ new Map();
3319
3455
  this.constValues = /* @__PURE__ */ new Map();
@@ -3321,18 +3457,185 @@ var require_lowering = __commonJS({
3321
3457
  this.varTypes = /* @__PURE__ */ new Map();
3322
3458
  this.floatVars = /* @__PURE__ */ new Set();
3323
3459
  this.worldObjCounter = 0;
3460
+ this.loopStack = [];
3461
+ this.currentFnParamNames = /* @__PURE__ */ new Set();
3462
+ this.currentFnMacroParams = /* @__PURE__ */ new Set();
3463
+ this.macroFunctionInfo = /* @__PURE__ */ new Map();
3324
3464
  this.namespace = namespace;
3325
3465
  this.sourceRanges = sourceRanges;
3326
3466
  LoweringBuilder.resetTempCounter();
3327
3467
  }
3468
+ // ---------------------------------------------------------------------------
3469
+ // MC Macro pre-scan: identify which function params need macro treatment
3470
+ // ---------------------------------------------------------------------------
3471
+ preScanMacroFunctions(program) {
3472
+ for (const fn of program.declarations) {
3473
+ const paramNames = new Set(fn.params.map((p) => p.name));
3474
+ const macroParams = /* @__PURE__ */ new Set();
3475
+ this.preScanStmts(fn.body, paramNames, macroParams);
3476
+ if (macroParams.size > 0) {
3477
+ this.macroFunctionInfo.set(fn.name, [...macroParams]);
3478
+ }
3479
+ }
3480
+ for (const implBlock of program.implBlocks ?? []) {
3481
+ for (const method of implBlock.methods) {
3482
+ const paramNames = new Set(method.params.map((p) => p.name));
3483
+ const macroParams = /* @__PURE__ */ new Set();
3484
+ this.preScanStmts(method.body, paramNames, macroParams);
3485
+ if (macroParams.size > 0) {
3486
+ this.macroFunctionInfo.set(`${implBlock.typeName}_${method.name}`, [...macroParams]);
3487
+ }
3488
+ }
3489
+ }
3490
+ }
3491
+ preScanStmts(stmts, paramNames, macroParams) {
3492
+ for (const stmt of stmts) {
3493
+ this.preScanStmt(stmt, paramNames, macroParams);
3494
+ }
3495
+ }
3496
+ preScanStmt(stmt, paramNames, macroParams) {
3497
+ switch (stmt.kind) {
3498
+ case "expr":
3499
+ this.preScanExpr(stmt.expr, paramNames, macroParams);
3500
+ break;
3501
+ case "let":
3502
+ this.preScanExpr(stmt.init, paramNames, macroParams);
3503
+ break;
3504
+ case "return":
3505
+ if (stmt.value)
3506
+ this.preScanExpr(stmt.value, paramNames, macroParams);
3507
+ break;
3508
+ case "if":
3509
+ this.preScanExpr(stmt.cond, paramNames, macroParams);
3510
+ this.preScanStmts(stmt.then, paramNames, macroParams);
3511
+ if (stmt.else_)
3512
+ this.preScanStmts(stmt.else_, paramNames, macroParams);
3513
+ break;
3514
+ case "while":
3515
+ this.preScanExpr(stmt.cond, paramNames, macroParams);
3516
+ this.preScanStmts(stmt.body, paramNames, macroParams);
3517
+ break;
3518
+ case "for":
3519
+ if (stmt.init)
3520
+ this.preScanStmt(stmt.init, paramNames, macroParams);
3521
+ this.preScanExpr(stmt.cond, paramNames, macroParams);
3522
+ this.preScanStmts(stmt.body, paramNames, macroParams);
3523
+ break;
3524
+ case "for_range":
3525
+ this.preScanStmts(stmt.body, paramNames, macroParams);
3526
+ break;
3527
+ case "foreach":
3528
+ this.preScanStmts(stmt.body, paramNames, macroParams);
3529
+ break;
3530
+ case "match":
3531
+ this.preScanExpr(stmt.expr, paramNames, macroParams);
3532
+ for (const arm of stmt.arms) {
3533
+ this.preScanStmts(arm.body, paramNames, macroParams);
3534
+ }
3535
+ break;
3536
+ case "as_block":
3537
+ case "at_block":
3538
+ this.preScanStmts(stmt.body, paramNames, macroParams);
3539
+ break;
3540
+ case "execute":
3541
+ this.preScanStmts(stmt.body, paramNames, macroParams);
3542
+ break;
3543
+ }
3544
+ }
3545
+ preScanExpr(expr, paramNames, macroParams) {
3546
+ if (expr.kind === "call" && BUILTINS2[expr.fn] !== void 0) {
3547
+ for (const arg of expr.args) {
3548
+ if (arg.kind === "ident" && paramNames.has(arg.name)) {
3549
+ macroParams.add(arg.name);
3550
+ }
3551
+ }
3552
+ return;
3553
+ }
3554
+ if (expr.kind === "call") {
3555
+ for (const arg of expr.args)
3556
+ this.preScanExpr(arg, paramNames, macroParams);
3557
+ } else if (expr.kind === "binary") {
3558
+ this.preScanExpr(expr.left, paramNames, macroParams);
3559
+ this.preScanExpr(expr.right, paramNames, macroParams);
3560
+ } else if (expr.kind === "unary") {
3561
+ this.preScanExpr(expr.operand, paramNames, macroParams);
3562
+ } else if (expr.kind === "assign") {
3563
+ this.preScanExpr(expr.value, paramNames, macroParams);
3564
+ }
3565
+ }
3566
+ // ---------------------------------------------------------------------------
3567
+ // Macro helpers
3568
+ // ---------------------------------------------------------------------------
3569
+ /**
3570
+ * If `expr` is a function parameter that needs macro treatment (runtime value
3571
+ * used in a literal position), returns the param name; otherwise null.
3572
+ */
3573
+ tryGetMacroParam(expr) {
3574
+ if (expr.kind !== "ident")
3575
+ return null;
3576
+ if (!this.currentFnParamNames.has(expr.name))
3577
+ return null;
3578
+ if (this.constValues.has(expr.name))
3579
+ return null;
3580
+ if (this.stringValues.has(expr.name))
3581
+ return null;
3582
+ return expr.name;
3583
+ }
3584
+ /**
3585
+ * Converts an expression to a string for use as a builtin arg.
3586
+ * If the expression is a macro param, returns `$(name)` and sets macroParam.
3587
+ */
3588
+ exprToBuiltinArg(expr) {
3589
+ const macroParam = this.tryGetMacroParam(expr);
3590
+ if (macroParam) {
3591
+ return { str: `$(${macroParam})`, macroParam };
3592
+ }
3593
+ if (expr.kind === "struct_lit" || expr.kind === "array_lit") {
3594
+ return { str: this.exprToSnbt(expr) };
3595
+ }
3596
+ return { str: this.exprToString(expr) };
3597
+ }
3598
+ /**
3599
+ * Emits a call to a macro function, setting up both scoreboard params
3600
+ * (for arithmetic use) and NBT macro args (for coordinate/literal use).
3601
+ */
3602
+ emitMacroFunctionCall(fnName, args, macroParamNames, fnDecl) {
3603
+ const params = fnDecl?.params ?? [];
3604
+ const loweredArgs = args.map((arg) => this.lowerExpr(arg));
3605
+ for (let i = 0; i < loweredArgs.length; i++) {
3606
+ const operand = loweredArgs[i];
3607
+ if (operand.kind === "const") {
3608
+ this.builder.emitRaw(`scoreboard players set $p${i} rs ${operand.value}`);
3609
+ } else if (operand.kind === "var") {
3610
+ this.builder.emitRaw(`scoreboard players operation $p${i} rs = ${operand.name} rs`);
3611
+ }
3612
+ }
3613
+ for (const macroParam of macroParamNames) {
3614
+ const paramIdx = params.findIndex((p) => p.name === macroParam);
3615
+ if (paramIdx < 0 || paramIdx >= loweredArgs.length)
3616
+ continue;
3617
+ const operand = loweredArgs[paramIdx];
3618
+ if (operand.kind === "const") {
3619
+ this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${operand.value}`);
3620
+ } else if (operand.kind === "var") {
3621
+ this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} rs`);
3622
+ }
3623
+ }
3624
+ this.builder.emitRaw(`function ${this.namespace}:${fnName} with storage rs:macro_args`);
3625
+ const dst = this.builder.freshTemp();
3626
+ this.builder.emitRaw(`scoreboard players operation ${dst} rs = $ret rs`);
3627
+ return { kind: "var", name: dst };
3628
+ }
3328
3629
  lower(program) {
3329
3630
  this.namespace = program.namespace;
3631
+ this.preScanMacroFunctions(program);
3330
3632
  for (const struct of program.structs ?? []) {
3331
3633
  const fields = /* @__PURE__ */ new Map();
3332
3634
  for (const field of struct.fields) {
3333
3635
  fields.set(field.name, field.type);
3334
3636
  }
3335
3637
  this.structDefs.set(struct.name, fields);
3638
+ this.structDecls.set(struct.name, struct);
3336
3639
  }
3337
3640
  for (const enumDecl of program.enums ?? []) {
3338
3641
  const variants = /* @__PURE__ */ new Map();
@@ -3400,6 +3703,8 @@ var require_lowering = __commonJS({
3400
3703
  this.blockPosVars = /* @__PURE__ */ new Map();
3401
3704
  this.stringValues = /* @__PURE__ */ new Map();
3402
3705
  this.builder = new LoweringBuilder();
3706
+ this.currentFnParamNames = new Set(runtimeParams.map((p) => p.name));
3707
+ this.currentFnMacroParams = /* @__PURE__ */ new Set();
3403
3708
  if (staticEventDec) {
3404
3709
  for (let i = 0; i < fn.params.length; i++) {
3405
3710
  const param = fn.params[i];
@@ -3489,6 +3794,11 @@ var require_lowering = __commonJS({
3489
3794
  if (tickRate && tickRate > 1) {
3490
3795
  this.wrapWithTickRate(irFn, tickRate);
3491
3796
  }
3797
+ if (this.currentFnMacroParams.size > 0) {
3798
+ irFn.isMacroFunction = true;
3799
+ irFn.macroParamNames = [...this.currentFnMacroParams];
3800
+ this.macroFunctionInfo.set(loweredName, irFn.macroParamNames);
3801
+ }
3492
3802
  this.functions.push(irFn);
3493
3803
  }
3494
3804
  getTickRate(decorators) {
@@ -3549,6 +3859,12 @@ var require_lowering = __commonJS({
3549
3859
  case "return":
3550
3860
  this.lowerReturnStmt(stmt);
3551
3861
  break;
3862
+ case "break":
3863
+ this.lowerBreakStmt();
3864
+ break;
3865
+ case "continue":
3866
+ this.lowerContinueStmt();
3867
+ break;
3552
3868
  case "if":
3553
3869
  this.lowerIfStmt(stmt);
3554
3870
  break;
@@ -3580,6 +3896,7 @@ var require_lowering = __commonJS({
3580
3896
  this.lowerExecuteStmt(stmt);
3581
3897
  break;
3582
3898
  case "raw":
3899
+ this.checkRawCommandInterpolation(stmt.cmd, stmt.span);
3583
3900
  this.builder.emitRaw(stmt.cmd);
3584
3901
  break;
3585
3902
  }
@@ -3614,12 +3931,25 @@ var require_lowering = __commonJS({
3614
3931
  if (stmt.init.kind === "struct_lit" && stmt.type?.kind === "struct") {
3615
3932
  const structName = stmt.type.name.toLowerCase();
3616
3933
  for (const field of stmt.init.fields) {
3617
- const path2 = `rs:heap ${structName}_${stmt.name}.${field.name}`;
3934
+ const path3 = `rs:heap ${structName}_${stmt.name}.${field.name}`;
3618
3935
  const fieldValue = this.lowerExpr(field.value);
3619
3936
  if (fieldValue.kind === "const") {
3620
- this.builder.emitRaw(`data modify storage ${path2} set value ${fieldValue.value}`);
3937
+ this.builder.emitRaw(`data modify storage ${path3} set value ${fieldValue.value}`);
3621
3938
  } else if (fieldValue.kind === "var") {
3622
- this.builder.emitRaw(`execute store result storage ${path2} int 1 run scoreboard players get ${fieldValue.name} rs`);
3939
+ this.builder.emitRaw(`execute store result storage ${path3} int 1 run scoreboard players get ${fieldValue.name} rs`);
3940
+ }
3941
+ }
3942
+ return;
3943
+ }
3944
+ if ((stmt.init.kind === "call" || stmt.init.kind === "static_call") && stmt.type?.kind === "struct") {
3945
+ this.lowerExpr(stmt.init);
3946
+ const structDecl = this.structDecls.get(stmt.type.name);
3947
+ if (structDecl) {
3948
+ const structName = stmt.type.name.toLowerCase();
3949
+ for (const field of structDecl.fields) {
3950
+ const srcPath = `rs:heap __ret_struct.${field.name}`;
3951
+ const dstPath = `rs:heap ${structName}_${stmt.name}.${field.name}`;
3952
+ this.builder.emitRaw(`data modify storage ${dstPath} set from storage ${srcPath}`);
3623
3953
  }
3624
3954
  }
3625
3955
  return;
@@ -3665,12 +3995,39 @@ var require_lowering = __commonJS({
3665
3995
  }
3666
3996
  lowerReturnStmt(stmt) {
3667
3997
  if (stmt.value) {
3998
+ if (stmt.value.kind === "struct_lit") {
3999
+ for (const field of stmt.value.fields) {
4000
+ const path3 = `rs:heap __ret_struct.${field.name}`;
4001
+ const fieldValue = this.lowerExpr(field.value);
4002
+ if (fieldValue.kind === "const") {
4003
+ this.builder.emitRaw(`data modify storage ${path3} set value ${fieldValue.value}`);
4004
+ } else if (fieldValue.kind === "var") {
4005
+ this.builder.emitRaw(`execute store result storage ${path3} int 1 run scoreboard players get ${fieldValue.name} rs`);
4006
+ }
4007
+ }
4008
+ this.builder.emitReturn({ kind: "const", value: 0 });
4009
+ return;
4010
+ }
3668
4011
  const value = this.lowerExpr(stmt.value);
3669
4012
  this.builder.emitReturn(value);
3670
4013
  } else {
3671
4014
  this.builder.emitReturn();
3672
4015
  }
3673
4016
  }
4017
+ lowerBreakStmt() {
4018
+ if (this.loopStack.length === 0) {
4019
+ throw new diagnostics_1.DiagnosticError("LoweringError", "break statement outside of loop", { line: 1, col: 1 });
4020
+ }
4021
+ const loop = this.loopStack[this.loopStack.length - 1];
4022
+ this.builder.emitJump(loop.breakLabel);
4023
+ }
4024
+ lowerContinueStmt() {
4025
+ if (this.loopStack.length === 0) {
4026
+ throw new diagnostics_1.DiagnosticError("LoweringError", "continue statement outside of loop", { line: 1, col: 1 });
4027
+ }
4028
+ const loop = this.loopStack[this.loopStack.length - 1];
4029
+ this.builder.emitJump(loop.continueLabel);
4030
+ }
3674
4031
  lowerIfStmt(stmt) {
3675
4032
  if (stmt.cond.kind === "is_check") {
3676
4033
  this.lowerIsCheckIfStmt(stmt);
@@ -3739,11 +4096,13 @@ var require_lowering = __commonJS({
3739
4096
  const condVar = this.lowerExpr(stmt.cond);
3740
4097
  const condName = this.operandToVar(condVar);
3741
4098
  this.builder.emitJumpIf(condName, bodyLabel, exitLabel);
4099
+ this.loopStack.push({ breakLabel: exitLabel, continueLabel: checkLabel });
3742
4100
  this.builder.startBlock(bodyLabel);
3743
4101
  this.lowerBlock(stmt.body);
3744
4102
  if (!this.builder.isBlockSealed()) {
3745
4103
  this.builder.emitJump(checkLabel);
3746
4104
  }
4105
+ this.loopStack.pop();
3747
4106
  this.builder.startBlock(exitLabel);
3748
4107
  }
3749
4108
  lowerForStmt(stmt) {
@@ -3752,18 +4111,23 @@ var require_lowering = __commonJS({
3752
4111
  }
3753
4112
  const checkLabel = this.builder.freshLabel("for_check");
3754
4113
  const bodyLabel = this.builder.freshLabel("for_body");
4114
+ const continueLabel = this.builder.freshLabel("for_continue");
3755
4115
  const exitLabel = this.builder.freshLabel("for_exit");
3756
4116
  this.builder.emitJump(checkLabel);
3757
4117
  this.builder.startBlock(checkLabel);
3758
4118
  const condVar = this.lowerExpr(stmt.cond);
3759
4119
  const condName = this.operandToVar(condVar);
3760
4120
  this.builder.emitJumpIf(condName, bodyLabel, exitLabel);
4121
+ this.loopStack.push({ breakLabel: exitLabel, continueLabel });
3761
4122
  this.builder.startBlock(bodyLabel);
3762
4123
  this.lowerBlock(stmt.body);
3763
- this.lowerExpr(stmt.step);
3764
4124
  if (!this.builder.isBlockSealed()) {
3765
- this.builder.emitJump(checkLabel);
4125
+ this.builder.emitJump(continueLabel);
3766
4126
  }
4127
+ this.builder.startBlock(continueLabel);
4128
+ this.lowerExpr(stmt.step);
4129
+ this.builder.emitJump(checkLabel);
4130
+ this.loopStack.pop();
3767
4131
  this.builder.startBlock(exitLabel);
3768
4132
  }
3769
4133
  lowerForRangeStmt(stmt) {
@@ -3841,12 +4205,27 @@ var require_lowering = __commonJS({
3841
4205
  defaultArm = arm;
3842
4206
  continue;
3843
4207
  }
3844
- const patternValue = this.lowerExpr(arm.pattern);
3845
- if (patternValue.kind !== "const") {
3846
- throw new Error("Match patterns must lower to compile-time constants");
4208
+ let matchCondition;
4209
+ if (arm.pattern.kind === "range_lit") {
4210
+ const range = arm.pattern.range;
4211
+ if (range.min !== void 0 && range.max !== void 0) {
4212
+ matchCondition = `${range.min}..${range.max}`;
4213
+ } else if (range.min !== void 0) {
4214
+ matchCondition = `${range.min}..`;
4215
+ } else if (range.max !== void 0) {
4216
+ matchCondition = `..${range.max}`;
4217
+ } else {
4218
+ matchCondition = "0..";
4219
+ }
4220
+ } else {
4221
+ const patternValue = this.lowerExpr(arm.pattern);
4222
+ if (patternValue.kind !== "const") {
4223
+ throw new Error("Match patterns must lower to compile-time constants");
4224
+ }
4225
+ matchCondition = String(patternValue.value);
3847
4226
  }
3848
4227
  const subFnName = `${this.currentFn}/match_${this.foreachCounter++}`;
3849
- this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 if score ${subject} rs matches ${patternValue.value} run function ${this.namespace}:${subFnName}`);
4228
+ this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 if score ${subject} rs matches ${matchCondition} run function ${this.namespace}:${subFnName}`);
3850
4229
  this.emitMatchArmSubFunction(subFnName, matchedVar, arm.body, true);
3851
4230
  }
3852
4231
  if (defaultArm) {
@@ -3994,12 +4373,47 @@ var require_lowering = __commonJS({
3994
4373
  const parts = ["execute"];
3995
4374
  for (const sub of stmt.subcommands) {
3996
4375
  switch (sub.kind) {
4376
+ // Context modifiers
3997
4377
  case "as":
3998
4378
  parts.push(`as ${this.selectorToString(sub.selector)}`);
3999
4379
  break;
4000
4380
  case "at":
4001
4381
  parts.push(`at ${this.selectorToString(sub.selector)}`);
4002
4382
  break;
4383
+ case "positioned":
4384
+ parts.push(`positioned ${sub.x} ${sub.y} ${sub.z}`);
4385
+ break;
4386
+ case "positioned_as":
4387
+ parts.push(`positioned as ${this.selectorToString(sub.selector)}`);
4388
+ break;
4389
+ case "rotated":
4390
+ parts.push(`rotated ${sub.yaw} ${sub.pitch}`);
4391
+ break;
4392
+ case "rotated_as":
4393
+ parts.push(`rotated as ${this.selectorToString(sub.selector)}`);
4394
+ break;
4395
+ case "facing":
4396
+ parts.push(`facing ${sub.x} ${sub.y} ${sub.z}`);
4397
+ break;
4398
+ case "facing_entity":
4399
+ parts.push(`facing entity ${this.selectorToString(sub.selector)} ${sub.anchor}`);
4400
+ break;
4401
+ case "anchored":
4402
+ parts.push(`anchored ${sub.anchor}`);
4403
+ break;
4404
+ case "align":
4405
+ parts.push(`align ${sub.axes}`);
4406
+ break;
4407
+ case "in":
4408
+ parts.push(`in ${sub.dimension}`);
4409
+ break;
4410
+ case "on":
4411
+ parts.push(`on ${sub.relation}`);
4412
+ break;
4413
+ case "summon":
4414
+ parts.push(`summon ${sub.entity}`);
4415
+ break;
4416
+ // Conditions
4003
4417
  case "if_entity":
4004
4418
  if (sub.selector) {
4005
4419
  parts.push(`if entity ${this.selectorToString(sub.selector)}`);
@@ -4016,8 +4430,30 @@ var require_lowering = __commonJS({
4016
4430
  parts.push(`unless entity ${this.selectorToString(sel)}`);
4017
4431
  }
4018
4432
  break;
4019
- case "in":
4020
- parts.push(`in ${sub.dimension}`);
4433
+ case "if_block":
4434
+ parts.push(`if block ${sub.pos[0]} ${sub.pos[1]} ${sub.pos[2]} ${sub.block}`);
4435
+ break;
4436
+ case "unless_block":
4437
+ parts.push(`unless block ${sub.pos[0]} ${sub.pos[1]} ${sub.pos[2]} ${sub.block}`);
4438
+ break;
4439
+ case "if_score":
4440
+ parts.push(`if score ${sub.target} ${sub.targetObj} ${sub.op} ${sub.source} ${sub.sourceObj}`);
4441
+ break;
4442
+ case "unless_score":
4443
+ parts.push(`unless score ${sub.target} ${sub.targetObj} ${sub.op} ${sub.source} ${sub.sourceObj}`);
4444
+ break;
4445
+ case "if_score_range":
4446
+ parts.push(`if score ${sub.target} ${sub.targetObj} matches ${sub.range}`);
4447
+ break;
4448
+ case "unless_score_range":
4449
+ parts.push(`unless score ${sub.target} ${sub.targetObj} matches ${sub.range}`);
4450
+ break;
4451
+ // Store
4452
+ case "store_result":
4453
+ parts.push(`store result score ${sub.target} ${sub.targetObj}`);
4454
+ break;
4455
+ case "store_success":
4456
+ parts.push(`store success score ${sub.target} ${sub.targetObj}`);
4021
4457
  break;
4022
4458
  }
4023
4459
  }
@@ -4136,9 +4572,9 @@ var require_lowering = __commonJS({
4136
4572
  }
4137
4573
  if (varType?.kind === "struct") {
4138
4574
  const structName = varType.name.toLowerCase();
4139
- const path2 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
4575
+ const path3 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
4140
4576
  const dst = this.builder.freshTemp();
4141
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path2}`);
4577
+ this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path3}`);
4142
4578
  return { kind: "var", name: dst };
4143
4579
  }
4144
4580
  if (varType?.kind === "array" && expr.field === "len") {
@@ -4176,20 +4612,20 @@ var require_lowering = __commonJS({
4176
4612
  }
4177
4613
  if (varType?.kind === "struct") {
4178
4614
  const structName = varType.name.toLowerCase();
4179
- const path2 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
4615
+ const path3 = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
4180
4616
  const value2 = this.lowerExpr(expr.value);
4181
4617
  if (expr.op === "=") {
4182
4618
  if (value2.kind === "const") {
4183
- this.builder.emitRaw(`data modify storage ${path2} set value ${value2.value}`);
4619
+ this.builder.emitRaw(`data modify storage ${path3} set value ${value2.value}`);
4184
4620
  } else if (value2.kind === "var") {
4185
- this.builder.emitRaw(`execute store result storage ${path2} int 1 run scoreboard players get ${value2.name} rs`);
4621
+ this.builder.emitRaw(`execute store result storage ${path3} int 1 run scoreboard players get ${value2.name} rs`);
4186
4622
  }
4187
4623
  } else {
4188
4624
  const dst = this.builder.freshTemp();
4189
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path2}`);
4625
+ this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path3}`);
4190
4626
  const binOp = expr.op.slice(0, -1);
4191
4627
  this.builder.emitBinop(dst, { kind: "var", name: dst }, binOp, value2);
4192
- this.builder.emitRaw(`execute store result storage ${path2} int 1 run scoreboard players get ${dst} rs`);
4628
+ this.builder.emitRaw(`execute store result storage ${path3} int 1 run scoreboard players get ${dst} rs`);
4193
4629
  }
4194
4630
  return { kind: "const", value: 0 };
4195
4631
  }
@@ -4384,6 +4820,21 @@ var require_lowering = __commonJS({
4384
4820
  }
4385
4821
  const implMethod = this.resolveInstanceMethod(expr);
4386
4822
  if (implMethod) {
4823
+ const receiver = expr.args[0];
4824
+ if (receiver?.kind === "ident") {
4825
+ const receiverType = this.inferExprType(receiver);
4826
+ if (receiverType?.kind === "struct") {
4827
+ const structDecl = this.structDecls.get(receiverType.name);
4828
+ const structName = receiverType.name.toLowerCase();
4829
+ if (structDecl) {
4830
+ for (const field of structDecl.fields) {
4831
+ const srcPath = `rs:heap ${structName}_${receiver.name}.${field.name}`;
4832
+ const dstPath = `rs:heap ${structName}_self.${field.name}`;
4833
+ this.builder.emitRaw(`data modify storage ${dstPath} set from storage ${srcPath}`);
4834
+ }
4835
+ }
4836
+ }
4837
+ }
4387
4838
  return this.emitMethodCall(implMethod.loweredName, implMethod.fn, expr.args);
4388
4839
  }
4389
4840
  const fnDecl = this.fnDecls.get(expr.fn);
@@ -4413,8 +4864,16 @@ var require_lowering = __commonJS({
4413
4864
  }
4414
4865
  const stdlibCallSite = this.getStdlibCallSiteContext(fnDecl, getSpan(expr));
4415
4866
  const targetFn = callbackBindings.size > 0 || stdlibCallSite ? this.ensureSpecializedFunctionWithContext(fnDecl, callbackBindings, stdlibCallSite) : expr.fn;
4867
+ const macroParams = this.macroFunctionInfo.get(targetFn);
4868
+ if (macroParams && macroParams.length > 0) {
4869
+ return this.emitMacroFunctionCall(targetFn, runtimeArgs, macroParams, fnDecl);
4870
+ }
4416
4871
  return this.emitDirectFunctionCall(targetFn, runtimeArgs);
4417
4872
  }
4873
+ const macroParamsForUnknown = this.macroFunctionInfo.get(expr.fn);
4874
+ if (macroParamsForUnknown && macroParamsForUnknown.length > 0) {
4875
+ return this.emitMacroFunctionCall(expr.fn, fullArgs, macroParamsForUnknown, void 0);
4876
+ }
4418
4877
  return this.emitDirectFunctionCall(expr.fn, fullArgs);
4419
4878
  }
4420
4879
  lowerStaticCallExpr(expr) {
@@ -4541,6 +5000,8 @@ var require_lowering = __commonJS({
4541
5000
  const savedBlockPosVars = new Map(this.blockPosVars);
4542
5001
  const savedStringValues = new Map(this.stringValues);
4543
5002
  const savedVarTypes = new Map(this.varTypes);
5003
+ const savedCurrentFnParamNames = new Set(this.currentFnParamNames);
5004
+ const savedCurrentFnMacroParams = new Set(this.currentFnMacroParams);
4544
5005
  try {
4545
5006
  return callback();
4546
5007
  } finally {
@@ -4556,6 +5017,8 @@ var require_lowering = __commonJS({
4556
5017
  this.blockPosVars = savedBlockPosVars;
4557
5018
  this.stringValues = savedStringValues;
4558
5019
  this.varTypes = savedVarTypes;
5020
+ this.currentFnParamNames = savedCurrentFnParamNames;
5021
+ this.currentFnMacroParams = savedCurrentFnMacroParams;
4559
5022
  }
4560
5023
  }
4561
5024
  lowerBuiltinCall(name, args, callSpan) {
@@ -4702,9 +5165,9 @@ var require_lowering = __commonJS({
4702
5165
  const dst = this.builder.freshTemp();
4703
5166
  const targetType = this.exprToString(args[0]);
4704
5167
  const target = targetType === "entity" ? this.exprToTargetString(args[1]) : this.exprToString(args[1]);
4705
- const path2 = this.exprToString(args[2]);
5168
+ const path3 = this.exprToString(args[2]);
4706
5169
  const scale = args[3] ? this.exprToString(args[3]) : "1";
4707
- this.builder.emitRaw(`execute store result score ${dst} rs run data get ${targetType} ${target} ${path2} ${scale}`);
5170
+ this.builder.emitRaw(`execute store result score ${dst} rs run data get ${targetType} ${target} ${path3} ${scale}`);
4708
5171
  return { kind: "var", name: dst };
4709
5172
  }
4710
5173
  if (name === "data_merge") {
@@ -4764,23 +5227,31 @@ var require_lowering = __commonJS({
4764
5227
  code: "W_DEPRECATED",
4765
5228
  ...callSpan ? { line: callSpan.line, col: callSpan.col } : {}
4766
5229
  });
4767
- const tpCommand = this.lowerTpCommand(args);
4768
- if (tpCommand) {
4769
- this.builder.emitRaw(tpCommand);
5230
+ const tpResult = this.lowerTpCommandMacroAware(args);
5231
+ if (tpResult) {
5232
+ this.builder.emitRaw(tpResult.cmd);
4770
5233
  }
4771
5234
  return { kind: "const", value: 0 };
4772
5235
  }
4773
5236
  if (name === "tp") {
4774
- const tpCommand = this.lowerTpCommand(args);
4775
- if (tpCommand) {
4776
- this.builder.emitRaw(tpCommand);
5237
+ const tpResult = this.lowerTpCommandMacroAware(args);
5238
+ if (tpResult) {
5239
+ this.builder.emitRaw(tpResult.cmd);
4777
5240
  }
4778
5241
  return { kind: "const", value: 0 };
4779
5242
  }
4780
- const strArgs = args.map((arg) => arg.kind === "struct_lit" || arg.kind === "array_lit" ? this.exprToSnbt(arg) : this.exprToString(arg));
4781
- const cmd = BUILTINS2[name](strArgs);
5243
+ const argResults = args.map((arg) => this.exprToBuiltinArg(arg));
5244
+ const hasMacroArg = argResults.some((r) => r.macroParam !== void 0);
5245
+ if (hasMacroArg) {
5246
+ argResults.forEach((r) => {
5247
+ if (r.macroParam)
5248
+ this.currentFnMacroParams.add(r.macroParam);
5249
+ });
5250
+ }
5251
+ const strArgs = argResults.map((r) => r.str);
5252
+ const cmd = BUILTINS2[name]?.(strArgs);
4782
5253
  if (cmd) {
4783
- this.builder.emitRaw(cmd);
5254
+ this.builder.emitRaw(hasMacroArg ? `$${cmd}` : cmd);
4784
5255
  }
4785
5256
  return { kind: "const", value: 0 };
4786
5257
  }
@@ -5221,8 +5692,8 @@ var require_lowering = __commonJS({
5221
5692
  return (hash >>> 0).toString(16).padStart(8, "0").slice(0, 4);
5222
5693
  }
5223
5694
  isStdlibFile(filePath) {
5224
- const normalized = path.normalize(filePath);
5225
- const stdlibSegment = `${path.sep}src${path.sep}stdlib${path.sep}`;
5695
+ const normalized = path2.normalize(filePath);
5696
+ const stdlibSegment = `${path2.sep}src${path2.sep}stdlib${path2.sep}`;
5226
5697
  return normalized.includes(stdlibSegment);
5227
5698
  }
5228
5699
  filePathForSpan(span) {
@@ -5280,6 +5751,35 @@ var require_lowering = __commonJS({
5280
5751
  }
5281
5752
  return null;
5282
5753
  }
5754
+ lowerTpCommandMacroAware(args) {
5755
+ const pos0 = args[0] ? this.resolveBlockPosExpr(args[0]) : null;
5756
+ const pos1 = args[1] ? this.resolveBlockPosExpr(args[1]) : null;
5757
+ if (args.length === 1 && pos0) {
5758
+ return { cmd: `tp ${emitBlockPos(pos0)}` };
5759
+ }
5760
+ if (args.length === 2 && pos1) {
5761
+ return { cmd: `tp ${this.exprToString(args[0])} ${emitBlockPos(pos1)}` };
5762
+ }
5763
+ if (args.length >= 2) {
5764
+ const argResults = args.map((a) => this.exprToBuiltinArg(a));
5765
+ const hasMacro = argResults.some((r) => r.macroParam !== void 0);
5766
+ if (hasMacro) {
5767
+ argResults.forEach((r) => {
5768
+ if (r.macroParam)
5769
+ this.currentFnMacroParams.add(r.macroParam);
5770
+ });
5771
+ const strs = argResults.map((r) => r.str);
5772
+ if (args.length === 2) {
5773
+ return { cmd: `$tp ${strs[0]} ${strs[1]}` };
5774
+ }
5775
+ if (args.length === 4) {
5776
+ return { cmd: `$tp ${strs[0]} ${strs[1]} ${strs[2]} ${strs[3]}` };
5777
+ }
5778
+ }
5779
+ }
5780
+ const plain = this.lowerTpCommand(args);
5781
+ return plain ? { cmd: plain } : null;
5782
+ }
5283
5783
  resolveBlockPosExpr(expr) {
5284
5784
  if (expr.kind === "blockpos") {
5285
5785
  return expr;
@@ -5373,6 +5873,28 @@ var require_lowering = __commonJS({
5373
5873
  }
5374
5874
  return void 0;
5375
5875
  }
5876
+ /**
5877
+ * Checks a raw() command string for `${...}` interpolation containing runtime variables.
5878
+ * - If the interpolated name is a compile-time constant → OK, no error.
5879
+ * - If the interpolated name is a runtime variable → DiagnosticError.
5880
+ * This catches the common mistake of writing raw("say ${score}") expecting interpolation,
5881
+ * which would silently emit a literal `${score}` in the MC command.
5882
+ */
5883
+ checkRawCommandInterpolation(cmd, span) {
5884
+ const interpRe = /\$\{([^}]+)\}/g;
5885
+ let match;
5886
+ while ((match = interpRe.exec(cmd)) !== null) {
5887
+ const name = match[1].trim();
5888
+ if (/^\d+(\.\d+)?$/.test(name) || name === "true" || name === "false") {
5889
+ continue;
5890
+ }
5891
+ if (this.constValues.has(name)) {
5892
+ continue;
5893
+ }
5894
+ const loc = span ?? { line: 1, col: 1 };
5895
+ throw new diagnostics_1.DiagnosticError("LoweringError", `raw() command contains runtime variable interpolation '\${${name}}'. Variables cannot be interpolated into raw commands at compile time. Use f-string messages for say/tell/announce, or MC macro syntax '$(${name})' for MC 1.20.2+ commands.`, loc);
5896
+ }
5897
+ }
5376
5898
  resolveInstanceMethod(expr) {
5377
5899
  const receiver = expr.args[0];
5378
5900
  if (!receiver) {
@@ -5647,6 +6169,7 @@ var require_commands = __commonJS({
5647
6169
  setblockSavedCommands: 0,
5648
6170
  deadCodeRemoved: 0,
5649
6171
  constantFolds: 0,
6172
+ inlinedTrivialFunctions: 0,
5650
6173
  totalCommandsBefore: 0,
5651
6174
  totalCommandsAfter: 0
5652
6175
  };
@@ -5943,11 +6466,81 @@ var require_commands = __commonJS({
5943
6466
  stats.totalCommandsAfter = optimized.reduce((sum, fn) => sum + fn.commands.length, 0);
5944
6467
  return { functions: optimized, stats };
5945
6468
  }
6469
+ function inlineTrivialFunctions(functions) {
6470
+ const FUNCTION_CMD_RE = /^function ([^:]+):(.+)$/;
6471
+ const trivialMap = /* @__PURE__ */ new Map();
6472
+ const emptyFunctions = /* @__PURE__ */ new Set();
6473
+ const SYSTEM_FUNCTIONS = /* @__PURE__ */ new Set(["__tick", "__load"]);
6474
+ for (const fn of functions) {
6475
+ if (SYSTEM_FUNCTIONS.has(fn.name) || fn.name.startsWith("__trigger_")) {
6476
+ continue;
6477
+ }
6478
+ const nonCommentCmds = fn.commands.filter((cmd) => !cmd.cmd.startsWith("#"));
6479
+ if (nonCommentCmds.length === 0 && fn.name.includes("/")) {
6480
+ emptyFunctions.add(fn.name);
6481
+ } else if (nonCommentCmds.length === 1 && fn.name.includes("/")) {
6482
+ const match = nonCommentCmds[0].cmd.match(FUNCTION_CMD_RE);
6483
+ if (match) {
6484
+ trivialMap.set(fn.name, match[2]);
6485
+ }
6486
+ }
6487
+ }
6488
+ let changed = true;
6489
+ while (changed) {
6490
+ changed = false;
6491
+ for (const [from, to] of trivialMap) {
6492
+ if (emptyFunctions.has(to)) {
6493
+ trivialMap.delete(from);
6494
+ emptyFunctions.add(from);
6495
+ changed = true;
6496
+ } else {
6497
+ const finalTarget = trivialMap.get(to);
6498
+ if (finalTarget && finalTarget !== to) {
6499
+ trivialMap.set(from, finalTarget);
6500
+ changed = true;
6501
+ }
6502
+ }
6503
+ }
6504
+ }
6505
+ const totalRemoved = trivialMap.size + emptyFunctions.size;
6506
+ if (totalRemoved === 0) {
6507
+ return { functions, stats: {} };
6508
+ }
6509
+ const removedNames = /* @__PURE__ */ new Set([...trivialMap.keys(), ...emptyFunctions]);
6510
+ const result = [];
6511
+ for (const fn of functions) {
6512
+ if (removedNames.has(fn.name)) {
6513
+ continue;
6514
+ }
6515
+ const rewrittenCmds = [];
6516
+ for (const cmd of fn.commands) {
6517
+ const emptyCallMatch = cmd.cmd.match(/^(?:execute .* run )?function ([^:]+):([^\s]+)$/);
6518
+ if (emptyCallMatch) {
6519
+ const targetFn = emptyCallMatch[2];
6520
+ if (emptyFunctions.has(targetFn)) {
6521
+ continue;
6522
+ }
6523
+ }
6524
+ const rewritten = cmd.cmd.replace(/function ([^:]+):([^\s]+)/g, (match, ns, fnPath) => {
6525
+ const target = trivialMap.get(fnPath);
6526
+ return target ? `function ${ns}:${target}` : match;
6527
+ });
6528
+ rewrittenCmds.push({ ...cmd, cmd: rewritten });
6529
+ }
6530
+ result.push({ name: fn.name, commands: rewrittenCmds });
6531
+ }
6532
+ return {
6533
+ functions: result,
6534
+ stats: { inlinedTrivialFunctions: totalRemoved }
6535
+ };
6536
+ }
5946
6537
  function optimizeCommandFunctions(functions) {
5947
6538
  const initial = cloneFunctions(functions);
5948
6539
  const stats = createEmptyOptimizationStats();
5949
6540
  stats.totalCommandsBefore = initial.reduce((sum, fn) => sum + fn.commands.length, 0);
5950
- const licm = applyLICM(initial);
6541
+ const inlined = inlineTrivialFunctions(initial);
6542
+ mergeOptimizationStats(stats, inlined.stats);
6543
+ const licm = applyLICM(inlined.functions);
5951
6544
  mergeOptimizationStats(stats, licm.stats);
5952
6545
  const cse = applyCSE(licm.functions);
5953
6546
  mergeOptimizationStats(stats, cse.stats);
@@ -6249,6 +6842,7 @@ var require_dce = __commonJS({
6249
6842
  this.localReads = /* @__PURE__ */ new Set();
6250
6843
  this.localDeclIds = /* @__PURE__ */ new WeakMap();
6251
6844
  this.localIdCounter = 0;
6845
+ this.warnings = [];
6252
6846
  }
6253
6847
  eliminate(program) {
6254
6848
  this.functionMap.clear();
@@ -6256,6 +6850,7 @@ var require_dce = __commonJS({
6256
6850
  this.usedConstants.clear();
6257
6851
  this.localReads.clear();
6258
6852
  this.localIdCounter = 0;
6853
+ this.warnings.length = 0;
6259
6854
  for (const fn of program.declarations) {
6260
6855
  this.functionMap.set(fn.name, fn);
6261
6856
  }
@@ -6290,7 +6885,7 @@ var require_dce = __commonJS({
6290
6885
  findEntryPoints(program) {
6291
6886
  const entries = /* @__PURE__ */ new Set();
6292
6887
  for (const fn of program.declarations) {
6293
- if (fn.name === "main") {
6888
+ if (!fn.name.startsWith("_")) {
6294
6889
  entries.add(fn.name);
6295
6890
  }
6296
6891
  if (fn.decorators.some((decorator) => [
@@ -6304,7 +6899,6 @@ var require_dce = __commonJS({
6304
6899
  "on_login",
6305
6900
  "on_join_team",
6306
6901
  "keep"
6307
- // Prevent DCE from removing this function
6308
6902
  ].includes(decorator.name))) {
6309
6903
  entries.add(fn.name);
6310
6904
  }
@@ -6415,6 +7009,8 @@ var require_dce = __commonJS({
6415
7009
  this.collectNestedStmtRefs(stmt, scope);
6416
7010
  break;
6417
7011
  case "raw":
7012
+ case "break":
7013
+ case "continue":
6418
7014
  break;
6419
7015
  }
6420
7016
  }
@@ -6575,6 +7171,12 @@ var require_dce = __commonJS({
6575
7171
  }
6576
7172
  return [copySpan({ ...stmt, init }, stmt)];
6577
7173
  }
7174
+ this.warnings.push({
7175
+ message: `Unused variable '${stmt.name}'`,
7176
+ code: "W_UNUSED_VAR",
7177
+ line: stmt.span?.line,
7178
+ col: stmt.span?.col
7179
+ });
6578
7180
  if (isPureExpr(init)) {
6579
7181
  return [];
6580
7182
  }
@@ -6672,6 +7274,10 @@ var require_dce = __commonJS({
6672
7274
  return [copySpan({ ...stmt, body: this.transformBlock(stmt.body, scope) }, stmt)];
6673
7275
  case "raw":
6674
7276
  return [stmt];
7277
+ case "break":
7278
+ return [stmt];
7279
+ case "continue":
7280
+ return [stmt];
6675
7281
  }
6676
7282
  }
6677
7283
  transformExpr(expr, scope) {
@@ -6758,7 +7364,9 @@ var require_dce = __commonJS({
6758
7364
  };
6759
7365
  exports2.DeadCodeEliminator = DeadCodeEliminator;
6760
7366
  function eliminateDeadCode(program) {
6761
- return new DeadCodeEliminator().eliminate(program);
7367
+ const eliminator = new DeadCodeEliminator();
7368
+ const result = eliminator.eliminate(program);
7369
+ return { program: result, warnings: eliminator.warnings };
6762
7370
  }
6763
7371
  }
6764
7372
  });
@@ -6931,8 +7539,12 @@ var require_mcfunction = __commonJS({
6931
7539
  commands: entry.commands
6932
7540
  })));
6933
7541
  const commandMap = new Map(optimized.functions.map((fn) => [fn.name, fn.commands]));
7542
+ const optimizedNames = new Set(optimized.functions.map((fn) => fn.name));
6934
7543
  return {
6935
- files: files.map((file) => {
7544
+ files: files.filter((file) => {
7545
+ const functionName = toFunctionName(file);
7546
+ return !functionName || optimizedNames.has(functionName);
7547
+ }).map((file) => {
6936
7548
  const functionName = toFunctionName(file);
6937
7549
  if (!functionName)
6938
7550
  return file;
@@ -7086,11 +7698,11 @@ var require_mcfunction = __commonJS({
7086
7698
  if (!eventTrigger) {
7087
7699
  continue;
7088
7700
  }
7089
- let path = "";
7701
+ let path2 = "";
7090
7702
  let criteria = {};
7091
7703
  switch (eventTrigger.kind) {
7092
7704
  case "advancement":
7093
- path = `data/${ns}/advancements/on_advancement_${fn.name}.json`;
7705
+ path2 = `data/${ns}/advancements/on_advancement_${fn.name}.json`;
7094
7706
  criteria = {
7095
7707
  trigger: {
7096
7708
  trigger: `minecraft:${eventTrigger.value}`
@@ -7098,7 +7710,7 @@ var require_mcfunction = __commonJS({
7098
7710
  };
7099
7711
  break;
7100
7712
  case "craft":
7101
- path = `data/${ns}/advancements/on_craft_${fn.name}.json`;
7713
+ path2 = `data/${ns}/advancements/on_craft_${fn.name}.json`;
7102
7714
  criteria = {
7103
7715
  crafted: {
7104
7716
  trigger: "minecraft:inventory_changed",
@@ -7113,7 +7725,7 @@ var require_mcfunction = __commonJS({
7113
7725
  };
7114
7726
  break;
7115
7727
  case "death":
7116
- path = `data/${ns}/advancements/on_death_${fn.name}.json`;
7728
+ path2 = `data/${ns}/advancements/on_death_${fn.name}.json`;
7117
7729
  criteria = {
7118
7730
  death: {
7119
7731
  trigger: "minecraft:entity_killed_player"
@@ -7125,7 +7737,7 @@ var require_mcfunction = __commonJS({
7125
7737
  continue;
7126
7738
  }
7127
7739
  advancements.push({
7128
- path,
7740
+ path: path2,
7129
7741
  content: JSON.stringify({
7130
7742
  criteria,
7131
7743
  rewards: {
@@ -7195,8 +7807,8 @@ var require_compile = __commonJS({
7195
7807
  exports2.preprocessSource = preprocessSource;
7196
7808
  exports2.compile = compile;
7197
7809
  exports2.formatCompileError = formatCompileError;
7198
- var fs = __importStar(require("fs"));
7199
- var path = __importStar(require("path"));
7810
+ var fs2 = __importStar(require("fs"));
7811
+ var path2 = __importStar(require("path"));
7200
7812
  var lexer_1 = require_lexer();
7201
7813
  var parser_1 = require_parser();
7202
7814
  var lowering_1 = require_lowering();
@@ -7219,7 +7831,7 @@ var require_compile = __commonJS({
7219
7831
  const { filePath } = options;
7220
7832
  const seen = options.seen ?? /* @__PURE__ */ new Set();
7221
7833
  if (filePath) {
7222
- seen.add(path.resolve(filePath));
7834
+ seen.add(path2.resolve(filePath));
7223
7835
  }
7224
7836
  const lines = source.split("\n");
7225
7837
  const imports = [];
@@ -7233,12 +7845,12 @@ var require_compile = __commonJS({
7233
7845
  if (!filePath) {
7234
7846
  throw new diagnostics_1.DiagnosticError("ParseError", "Import statements require a file path", { line: i + 1, col: 1 }, lines);
7235
7847
  }
7236
- const importPath = path.resolve(path.dirname(filePath), match[1]);
7848
+ const importPath = path2.resolve(path2.dirname(filePath), match[1]);
7237
7849
  if (!seen.has(importPath)) {
7238
7850
  seen.add(importPath);
7239
7851
  let importedSource;
7240
7852
  try {
7241
- importedSource = fs.readFileSync(importPath, "utf-8");
7853
+ importedSource = fs2.readFileSync(importPath, "utf-8");
7242
7854
  } catch {
7243
7855
  throw new diagnostics_1.DiagnosticError("ParseError", `Cannot import '${match[1]}'`, { file: filePath, line: i + 1, col: 1 }, lines);
7244
7856
  }
@@ -7266,7 +7878,7 @@ var require_compile = __commonJS({
7266
7878
  ranges.push({
7267
7879
  startLine: lineOffset + 1,
7268
7880
  endLine: lineOffset + countLines(body),
7269
- filePath: path.resolve(filePath)
7881
+ filePath: path2.resolve(filePath)
7270
7882
  });
7271
7883
  }
7272
7884
  return { source: combined, ranges };
@@ -7284,7 +7896,8 @@ var require_compile = __commonJS({
7284
7896
  sourceLines = preprocessedSource.split("\n");
7285
7897
  const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
7286
7898
  const parsedAst = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
7287
- const ast = shouldRunDce ? (0, dce_1.eliminateDeadCode)(parsedAst) : parsedAst;
7899
+ const dceResult = shouldRunDce ? (0, dce_1.eliminateDeadCode)(parsedAst) : { program: parsedAst, warnings: [] };
7900
+ const ast = dceResult.program;
7288
7901
  const ir = new lowering_1.Lowering(namespace, preprocessed.ranges).lower(ast);
7289
7902
  const optimized = shouldOptimize ? { ...ir, functions: ir.functions.map((fn) => (0, passes_1.optimize)(fn)) } : ir;
7290
7903
  const generated = (0, mcfunction_1.generateDatapackWithStats)(optimized);
@@ -7364,7 +7977,7 @@ var require_mc_validator = __commonJS({
7364
7977
  })();
7365
7978
  Object.defineProperty(exports2, "__esModule", { value: true });
7366
7979
  exports2.MCCommandValidator = void 0;
7367
- var fs = __importStar(require("fs"));
7980
+ var fs2 = __importStar(require("fs"));
7368
7981
  var FUNCTION_ID_RE = /^[0-9a-z_.-]+:[0-9a-z_./-]+$/i;
7369
7982
  var INTEGER_RE = /^-?\d+$/;
7370
7983
  var SCORE_RANGE_RE = /^-?\d+\.\.$|^\.\.-?\d+$|^-?\d+\.\.-?\d+$|^-?\d+$/;
@@ -7377,7 +7990,7 @@ var require_mc_validator = __commonJS({
7377
7990
  var SCOREBOARD_OPERATIONS = /* @__PURE__ */ new Set(["=", "+=", "-=", "*=", "/=", "%=", "<", ">", "><"]);
7378
7991
  var MCCommandValidator = class {
7379
7992
  constructor(commandsPath) {
7380
- const parsed = JSON.parse(fs.readFileSync(commandsPath, "utf-8"));
7993
+ const parsed = JSON.parse(fs2.readFileSync(commandsPath, "utf-8"));
7381
7994
  this.root = parsed.root;
7382
7995
  this.rootChildren = parsed.root.children ?? [];
7383
7996
  }
@@ -7653,9 +8266,10 @@ var require_dist = __commonJS({
7653
8266
  "../../dist/index.js"(exports2) {
7654
8267
  "use strict";
7655
8268
  Object.defineProperty(exports2, "__esModule", { value: true });
7656
- exports2.MCCommandValidator = exports2.generateDatapack = exports2.optimize = exports2.Lowering = exports2.TypeChecker = exports2.Parser = exports2.Lexer = void 0;
8269
+ exports2.MCCommandValidator = exports2.generateDatapack = exports2.optimize = exports2.Lowering = exports2.TypeChecker = exports2.Parser = exports2.Lexer = exports2.version = void 0;
7657
8270
  exports2.compile = compile;
7658
8271
  exports2.check = check;
8272
+ exports2.version = "1.2.11";
7659
8273
  var lexer_1 = require_lexer();
7660
8274
  var parser_1 = require_parser();
7661
8275
  var typechecker_1 = require_typechecker();
@@ -7675,7 +8289,8 @@ var require_dist = __commonJS({
7675
8289
  const preprocessedSource = preprocessed.source;
7676
8290
  const tokens = new lexer_1.Lexer(preprocessedSource, filePath).tokenize();
7677
8291
  const parsedAst = new parser_1.Parser(tokens, preprocessedSource, filePath).parse(namespace);
7678
- const ast = shouldRunDce ? (0, dce_1.eliminateDeadCode)(parsedAst) : parsedAst;
8292
+ const dceResult = shouldRunDce ? (0, dce_1.eliminateDeadCode)(parsedAst) : { program: parsedAst, warnings: [] };
8293
+ const ast = dceResult.program;
7679
8294
  let typeErrors;
7680
8295
  if (shouldTypeCheck) {
7681
8296
  const checker = new typechecker_1.TypeChecker(preprocessedSource, filePath);
@@ -7725,7 +8340,7 @@ var require_dist = __commonJS({
7725
8340
  ast,
7726
8341
  ir: optimizedIR,
7727
8342
  typeErrors,
7728
- warnings: lowering.warnings,
8343
+ warnings: [...dceResult.warnings, ...lowering.warnings],
7729
8344
  stats: optimizationStats
7730
8345
  };
7731
8346
  }
@@ -8950,6 +9565,8 @@ function registerCompletionProvider(context) {
8950
9565
 
8951
9566
  // src/symbols.ts
8952
9567
  var vscode4 = __toESM(require("vscode"));
9568
+ var path = __toESM(require("path"));
9569
+ var fs = __toESM(require("fs"));
8953
9570
  var DECL_RE = /\b(fn|let|const|struct|enum)\s+(\w+)/g;
8954
9571
  function findDeclarations(doc) {
8955
9572
  const text = doc.getText();
@@ -9028,6 +9645,94 @@ function findAllOccurrences(doc, word) {
9028
9645
  function escapeRegex(s) {
9029
9646
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9030
9647
  }
9648
+ var builtinLineCache = null;
9649
+ function getBuiltinDtsPath(context) {
9650
+ return path.join(context.extensionPath, "builtins.d.mcrs");
9651
+ }
9652
+ function loadBuiltinLines(dtsPath) {
9653
+ if (builtinLineCache) return builtinLineCache;
9654
+ const cache = /* @__PURE__ */ new Map();
9655
+ try {
9656
+ const content = fs.readFileSync(dtsPath, "utf-8");
9657
+ const lines = content.split("\n");
9658
+ for (let i = 0; i < lines.length; i++) {
9659
+ const m = lines[i].match(/^declare fn (\w+)\(/);
9660
+ if (m) {
9661
+ cache.set(m[1], i);
9662
+ }
9663
+ }
9664
+ } catch {
9665
+ }
9666
+ builtinLineCache = cache;
9667
+ return cache;
9668
+ }
9669
+ var KNOWN_BUILTINS = /* @__PURE__ */ new Set([
9670
+ "say",
9671
+ "tell",
9672
+ "tellraw",
9673
+ "announce",
9674
+ "title",
9675
+ "subtitle",
9676
+ "actionbar",
9677
+ "title_times",
9678
+ "give",
9679
+ "kill",
9680
+ "effect",
9681
+ "effect_clear",
9682
+ "clear",
9683
+ "kick",
9684
+ "xp_add",
9685
+ "xp_set",
9686
+ "tp",
9687
+ "tp_to",
9688
+ "setblock",
9689
+ "fill",
9690
+ "clone",
9691
+ "summon",
9692
+ "particle",
9693
+ "playsound",
9694
+ "weather",
9695
+ "time_set",
9696
+ "time_add",
9697
+ "gamerule",
9698
+ "difficulty",
9699
+ "tag_add",
9700
+ "tag_remove",
9701
+ "scoreboard_get",
9702
+ "score",
9703
+ "scoreboard_set",
9704
+ "scoreboard_display",
9705
+ "scoreboard_hide",
9706
+ "scoreboard_add_objective",
9707
+ "scoreboard_remove_objective",
9708
+ "random",
9709
+ "random_native",
9710
+ "random_sequence",
9711
+ "data_get",
9712
+ "data_merge",
9713
+ "bossbar_add",
9714
+ "bossbar_set_value",
9715
+ "bossbar_set_max",
9716
+ "bossbar_set_color",
9717
+ "bossbar_set_style",
9718
+ "bossbar_set_visible",
9719
+ "bossbar_set_players",
9720
+ "bossbar_remove",
9721
+ "bossbar_get_value",
9722
+ "team_add",
9723
+ "team_remove",
9724
+ "team_join",
9725
+ "team_leave",
9726
+ "team_option",
9727
+ "set_new",
9728
+ "set_add",
9729
+ "set_contains",
9730
+ "set_remove",
9731
+ "set_clear",
9732
+ "setTimeout",
9733
+ "setInterval",
9734
+ "clearInterval"
9735
+ ]);
9031
9736
  function registerSymbolProviders(context) {
9032
9737
  const selector = { language: "redscript", scheme: "file" };
9033
9738
  context.subscriptions.push(
@@ -9037,6 +9742,18 @@ function registerSymbolProviders(context) {
9037
9742
  const wordRange = doc.getWordRangeAtPosition(position);
9038
9743
  if (!wordRange) return null;
9039
9744
  const word = doc.getText(wordRange);
9745
+ const line = doc.lineAt(position.line).text;
9746
+ const afterWord = line.slice(wordRange.end.character).trimStart();
9747
+ if (afterWord.startsWith("(") && KNOWN_BUILTINS.has(word)) {
9748
+ const dtsPath = getBuiltinDtsPath(context);
9749
+ const lines = loadBuiltinLines(dtsPath);
9750
+ const lineNum = lines.get(word);
9751
+ if (lineNum !== void 0) {
9752
+ const dtsUri = vscode4.Uri.file(dtsPath);
9753
+ const pos = new vscode4.Position(lineNum, 0);
9754
+ return new vscode4.Location(dtsUri, pos);
9755
+ }
9756
+ }
9040
9757
  const structType = isStructLiteralField(doc, position, word);
9041
9758
  if (structType) {
9042
9759
  const structFields = findStructFields(doc);