@tilua/compiler 7.0.0 → 8.0.0

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/README.md CHANGED
@@ -74,9 +74,10 @@ JavaScript module the build loads.
74
74
  | `const` / `let` | `local` |
75
75
  | `class C { … }` | one table for the class, one per instance — see below |
76
76
  | `return [a, b]` | `return { a, b }` — several results are an array |
77
- | `for (const item in xs)` | `for _, item in xs do … end` — an array or a table walked for its values |
78
- | `for (const item in step)` | `for item in step do … end` — an iterator function |
79
- | `for (const [k, v] in pairs(t))` | `for item in unpack(pairs(t), 1, 3) do local k, v = item[1], item[2] … end` — an iteration is `[step, state, first]` |
77
+ | `for (const item of xs)` | `for _, item in xs do … end` — an array or a table walked for its values |
78
+ | `for (const item of step)` | `for item in step do … end` — an iterator function |
79
+ | `for (const [k, v] of pairs(t))` | `for item in unpack(pairs(t), 1, 3) do local k, v = item[1], item[2] … end` — an iteration is `[step, state, first]` |
80
+ | `for (const key in t)` | `for key in pairs(t) do … end` — a table's keys, as in TypeScript |
80
81
  | `t ??= v` | `if t == nil then t = v end` — what addresses `t` read once, into locals |
81
82
  | `{ m() { … } }` | `{ m = function(this) … end }` — called with `:` |
82
83
  | `break outer` from a loop inside `outer` | a flag `outer` declares, raised, and a `break`; after each loop on the way out, a check that breaks again — or, at `outer`, does the `break` or `continue` |
@@ -117,7 +118,7 @@ Luau without asking:
117
118
  | `a += b`, `a // b` | `a = a + (b)`, `math.floor(a / (b))` | as written |
118
119
  | `continue` | a `break` out of a one-pass `repeat` | as written |
119
120
  | `c ? a : b`, `a?.b`, `a ?? b` | `and`/`or` where neither arm can be `false`, else a function called on the spot | `if c then a else b` |
120
- | `for (const x in xs)` | `ipairs(xs)` where `xs` is an array by its type; otherwise `tilua_each(xs)`, which walks a table as Luau would — its `__iter` if it has one, `next` if not | `for _, x in xs do` |
121
+ | `for (const x of xs)` | `ipairs(xs)` where `xs` is an array by its type; otherwise `tilua_each(xs)`, which walks a table as Luau would — its `__iter` if it has one, `next` if not | `for _, x in xs do` |
121
122
  | `1_000`, `0b101` | plain numbers | as written |
122
123
  | `@native` and other attributes | dropped | kept |
123
124
  | another file of the bundle | `loadfile` | `require` by path |
@@ -430,6 +431,17 @@ How a file is loaded depends on the Lua (see [Lua and Luau](#lua-and-luau)):
430
431
  Either way the files have to stay where they were written, relative to the
431
432
  entry's.
432
433
 
434
+ <!-- compatibility:start -->
435
+ ## Compatibility
436
+
437
+ `@tilua/compiler@8.0.0` works with these tilua packages. *Released with* is the
438
+ version it was built and tested against.
439
+
440
+ | Package | Range | Released with | |
441
+ | --- | --- | --- | --- |
442
+ | `@tilua/parser` | `^8.0.0` | 8.0.0 | dependency |
443
+ <!-- compatibility:end -->
444
+
433
445
  ## Development
434
446
 
435
447
  ```bash
@@ -1448,8 +1448,15 @@ end`).body.statements, out);
1448
1448
  item = this.names.fresh("item");
1449
1449
  prelude.push(...this.destructure(variable, identifier(item), "declare"));
1450
1450
  }
1451
- const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
1451
+ const form = this.options.types?.loops.get(node) ?? { walks: node.over === "keys" ? "keys" : "values", viaIter: false };
1452
1452
  let source = this.expression(node.iterator);
1453
+ if (form.walks === "keys") {
1454
+ return [genericFor(
1455
+ [item],
1456
+ [call(this.builtin("pairs"), [source])],
1457
+ this.loopBody51(this.block(node.body, prelude)).statements
1458
+ )];
1459
+ }
1453
1460
  if (form.viaIter) source = methodCall(source, "__iter", []);
1454
1461
  const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
1455
1462
  let iterators = form.walks === "iteration" ? [call(this.helper("unpack"), [source, number(1), number(3)])] : [source];
@@ -2570,6 +2577,7 @@ function usesVararg(node) {
2570
2577
  return Object.values(record).some(usesVararg);
2571
2578
  }
2572
2579
  function calleePath(path) {
2580
+ if (!/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)*$/.test(path)) return parseExpressionFromSource(path);
2573
2581
  const [head, ...rest] = path.split(".");
2574
2582
  return rest.reduce((value, name) => member(value, name), identifier(head));
2575
2583
  }
@@ -2791,6 +2799,7 @@ import {
2791
2799
  directivesOf,
2792
2800
  applyDirectives,
2793
2801
  UNUSED_EXPECT_ERROR,
2802
+ UNUSED_EXPECT_WARNING,
2794
2803
  ParseError,
2795
2804
  LexError,
2796
2805
  luauString as luauString4
@@ -3212,7 +3221,7 @@ async function bundle(options) {
3212
3221
  }
3213
3222
  for (const [file, fileDirectives] of directives) {
3214
3223
  const semantic = diagnostics.filter((d) => d.file === file && (d.category === "scope" || d.category === "type"));
3215
- const { kept, unusedExpectErrors } = applyDirectives(fileDirectives, semantic, (d) => d.line);
3224
+ const { kept, unusedExpectErrors, unusedExpectWarnings } = applyDirectives(fileDirectives, semantic, (d) => d.line, (d) => d.severity === "warning");
3216
3225
  const suppressed = new Set(semantic.filter((d) => !kept.includes(d)));
3217
3226
  const remaining = diagnostics.filter((d) => !suppressed.has(d));
3218
3227
  diagnostics.length = 0;
@@ -3221,6 +3230,9 @@ async function bundle(options) {
3221
3230
  for (const d of unusedExpectErrors) {
3222
3231
  diagnostics.push({ file, message: UNUSED_EXPECT_ERROR, line: d.line, column: d.column, category: "type" });
3223
3232
  }
3233
+ for (const d of unusedExpectWarnings) {
3234
+ diagnostics.push({ file, message: UNUSED_EXPECT_WARNING, line: d.line, column: d.column, category: "type", severity: "warning" });
3235
+ }
3224
3236
  }
3225
3237
  const moduleProblems = new Set(diagnostics.filter((d) => d.category === "module").map((d) => `${d.file}:${d.line}:${d.column}:${d.message}`));
3226
3238
  const reported = diagnostics.filter((d) => d.category !== "type" || !moduleProblems.has(`${d.file}:${d.line}:${d.column}:${d.message}`));
package/dist/cli.cjs CHANGED
@@ -1465,8 +1465,15 @@ end`).body.statements, out2);
1465
1465
  item = this.names.fresh("item");
1466
1466
  prelude.push(...this.destructure(variable, identifier(item), "declare"));
1467
1467
  }
1468
- const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
1468
+ const form = this.options.types?.loops.get(node) ?? { walks: node.over === "keys" ? "keys" : "values", viaIter: false };
1469
1469
  let source = this.expression(node.iterator);
1470
+ if (form.walks === "keys") {
1471
+ return [genericFor(
1472
+ [item],
1473
+ [call(this.builtin("pairs"), [source])],
1474
+ this.loopBody51(this.block(node.body, prelude)).statements
1475
+ )];
1476
+ }
1470
1477
  if (form.viaIter) source = methodCall(source, "__iter", []);
1471
1478
  const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
1472
1479
  let iterators = form.walks === "iteration" ? [call(this.helper("unpack"), [source, number(1), number(3)])] : [source];
@@ -2587,6 +2594,7 @@ function usesVararg(node) {
2587
2594
  return Object.values(record).some(usesVararg);
2588
2595
  }
2589
2596
  function calleePath(path) {
2597
+ if (!/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)*$/.test(path)) return (0, import_luau_parser.parseExpressionFromSource)(path);
2590
2598
  const [head, ...rest] = path.split(".");
2591
2599
  return rest.reduce((value, name) => member(value, name), identifier(head));
2592
2600
  }
@@ -3209,7 +3217,7 @@ async function bundle(options) {
3209
3217
  }
3210
3218
  for (const [file, fileDirectives] of directives) {
3211
3219
  const semantic = diagnostics.filter((d) => d.file === file && (d.category === "scope" || d.category === "type"));
3212
- const { kept, unusedExpectErrors } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line);
3220
+ const { kept, unusedExpectErrors, unusedExpectWarnings } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line, (d) => d.severity === "warning");
3213
3221
  const suppressed = new Set(semantic.filter((d) => !kept.includes(d)));
3214
3222
  const remaining = diagnostics.filter((d) => !suppressed.has(d));
3215
3223
  diagnostics.length = 0;
@@ -3218,6 +3226,9 @@ async function bundle(options) {
3218
3226
  for (const d of unusedExpectErrors) {
3219
3227
  diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_ERROR, line: d.line, column: d.column, category: "type" });
3220
3228
  }
3229
+ for (const d of unusedExpectWarnings) {
3230
+ diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_WARNING, line: d.line, column: d.column, category: "type", severity: "warning" });
3231
+ }
3221
3232
  }
3222
3233
  const moduleProblems = new Set(diagnostics.filter((d) => d.category === "module").map((d) => `${d.file}:${d.line}:${d.column}:${d.message}`));
3223
3234
  const reported = diagnostics.filter((d) => d.category !== "type" || !moduleProblems.has(`${d.file}:${d.line}:${d.column}:${d.message}`));
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  bundle,
4
4
  resolveConfig
5
- } from "./chunk-NM3EVX2J.js";
5
+ } from "./chunk-TOP7NC3Z.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { mkdirSync, writeFileSync } from "fs";
package/dist/index.cjs CHANGED
@@ -1488,8 +1488,15 @@ end`).body.statements, out);
1488
1488
  item = this.names.fresh("item");
1489
1489
  prelude.push(...this.destructure(variable, identifier(item), "declare"));
1490
1490
  }
1491
- const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
1491
+ const form = this.options.types?.loops.get(node) ?? { walks: node.over === "keys" ? "keys" : "values", viaIter: false };
1492
1492
  let source = this.expression(node.iterator);
1493
+ if (form.walks === "keys") {
1494
+ return [genericFor(
1495
+ [item],
1496
+ [call(this.builtin("pairs"), [source])],
1497
+ this.loopBody51(this.block(node.body, prelude)).statements
1498
+ )];
1499
+ }
1493
1500
  if (form.viaIter) source = methodCall(source, "__iter", []);
1494
1501
  const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
1495
1502
  let iterators = form.walks === "iteration" ? [call(this.helper("unpack"), [source, number(1), number(3)])] : [source];
@@ -2610,6 +2617,7 @@ function usesVararg(node) {
2610
2617
  return Object.values(record).some(usesVararg);
2611
2618
  }
2612
2619
  function calleePath(path) {
2620
+ if (!/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)*$/.test(path)) return (0, import_luau_parser.parseExpressionFromSource)(path);
2613
2621
  const [head, ...rest] = path.split(".");
2614
2622
  return rest.reduce((value, name) => member(value, name), identifier(head));
2615
2623
  }
@@ -3232,7 +3240,7 @@ async function bundle(options) {
3232
3240
  }
3233
3241
  for (const [file, fileDirectives] of directives) {
3234
3242
  const semantic = diagnostics.filter((d) => d.file === file && (d.category === "scope" || d.category === "type"));
3235
- const { kept, unusedExpectErrors } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line);
3243
+ const { kept, unusedExpectErrors, unusedExpectWarnings } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line, (d) => d.severity === "warning");
3236
3244
  const suppressed = new Set(semantic.filter((d) => !kept.includes(d)));
3237
3245
  const remaining = diagnostics.filter((d) => !suppressed.has(d));
3238
3246
  diagnostics.length = 0;
@@ -3241,6 +3249,9 @@ async function bundle(options) {
3241
3249
  for (const d of unusedExpectErrors) {
3242
3250
  diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_ERROR, line: d.line, column: d.column, category: "type" });
3243
3251
  }
3252
+ for (const d of unusedExpectWarnings) {
3253
+ diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_WARNING, line: d.line, column: d.column, category: "type", severity: "warning" });
3254
+ }
3244
3255
  }
3245
3256
  const moduleProblems = new Set(diagnostics.filter((d) => d.category === "module").map((d) => `${d.file}:${d.line}:${d.column}:${d.message}`));
3246
3257
  const reported = diagnostics.filter((d) => d.category !== "type" || !moduleProblems.has(`${d.file}:${d.line}:${d.column}:${d.message}`));
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  lower,
5
5
  program,
6
6
  resolveConfig
7
- } from "./chunk-NM3EVX2J.js";
7
+ } from "./chunk-TOP7NC3Z.js";
8
8
 
9
9
  // src/compile.ts
10
10
  import { readFileSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tilua/compiler",
3
- "version": "7.0.0",
3
+ "version": "8.0.0",
4
4
  "description": "Compiles tilua to Luau: lowers the @tilua/parser AST to a luau-parser AST and prints it",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -38,7 +38,7 @@
38
38
  "type": "module",
39
39
  "dependencies": {
40
40
  "luau-parser": "^1.0.3",
41
- "@tilua/parser": "^7.0.0"
41
+ "@tilua/parser": "^8.0.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^22.20.2",