@tilua/compiler 1.1.0 → 2.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
@@ -65,10 +65,14 @@ JavaScript module the build loads.
65
65
  | `function f(n = 1, { x })` | `function f(n, arg) if n == nil then n = 1 end local x = arg.x ...` |
66
66
  | `const` / `let` | `local` |
67
67
  | `class C { … }` | one table for the class, one per instance — see below |
68
- | `new C(x)` | `C.new(x)` |
69
- | `[...]` | `{...}` — the varargs as an array |
68
+ | `return [a, b]` | `return { a, b }` — several results are an array |
69
+ | `for (const item in xs)` | `for _, item in xs do … end` — an array or a table walked for its values |
70
+ | `for (const item in step)` | `for item in step do … end` — an iterator function |
71
+ | `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]` |
72
+ | `pcall(f)`, and other globals Luau answers several values from | the type library's own function, answering one — see below |
70
73
  | `function f(a, ...rest)` | `function f(a, ...) local rest = {...}` |
71
- | `f(a, ...xs)` / `return ...xs` | `table.unpack(xs)` in the last position |
74
+ | `scriptArgs` | the chunk's own `...`, as `local scriptArgs = { ... }` |
75
+ | `f(a, ...xs)` | `table.unpack(xs)` in the last position |
72
76
  | `f(...xs, a)` | the list built first, then `table.unpack` of it |
73
77
  | `x as T`, `x satisfies T`, types, `declare` | removed |
74
78
  | `names:filter(f)` | whatever the type library that declared `filter` says — see below |
@@ -113,8 +117,16 @@ tilua_accessors(Dog)
113
117
 
114
118
  `__init` is what `super(...)` calls: it runs the constructor on an instance
115
119
  that already exists, so a derived class builds one table, not one per level.
116
- `new` is a real function on the class table — `new Dog(x)` and `Dog.new(x)`
117
- are the same call.
120
+ `new` is a real function on the class table, and `Dog.new(x)` is how an
121
+ instance is built — the way Luau builds one. An `abstract class` has no `new`,
122
+ and an `abstract` method no function: both exist only to be checked.
123
+
124
+ A method named for a metamethod — `__add`, `__tostring`, `__call`, … — is an
125
+ ordinary function on the class table, and since the class table is its
126
+ instances' metatable, it works as one. Luau reads metamethods off the
127
+ metatable with `rawget`, never through its `__index`, so a class would not
128
+ inherit its base's: `tilua_class` copies them into each class that extends
129
+ another, and one the class writes itself replaces the copy.
118
130
 
119
131
  Two links come with every class, and they cost an instance nothing because
120
132
  they live on the class table: `ClassObject`, which an instance reads through
@@ -180,14 +180,18 @@ var Lowerer = class {
180
180
  const body = this.options.module ? this.module(this.options.module) : this.topLevel(this.source.body.statements);
181
181
  const helpers = this.helperDefinitions();
182
182
  const captured = [...this.builtins].map(([global, local2]) => local([local2], [identifier(global)]));
183
+ const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: vararg() }])])] : [];
183
184
  return {
184
- statements: [...captured, ...helpers, ...this.classRuntimeStatements(), ...body],
185
+ statements: [...scriptArgs, ...captured, ...helpers, ...this.classRuntimeStatements(), ...body],
185
186
  exportsName: this.exportsName,
186
187
  module: this.info,
187
188
  diagnostics: this.diagnostics,
188
- origins: this.origins
189
+ origins: this.origins,
190
+ usesScriptArgs: this.usesScriptArgs
189
191
  };
190
192
  }
193
+ /** Whether the file reads `scriptArgs`, the language's own global. */
194
+ usesScriptArgs = false;
191
195
  report(node, message) {
192
196
  this.diagnostics.push({ message, line: node.line.start, column: node.column.start });
193
197
  }
@@ -312,6 +316,10 @@ var Lowerer = class {
312
316
  /** The name a global is read by at `node`, or `undefined` when `node` is
313
317
  * not a global — a local of the same name is the author's. */
314
318
  globalName(node) {
319
+ if (node.type === "MemberExpression" && !node.optional) {
320
+ const base = this.globalName(node.object);
321
+ return base === void 0 ? void 0 : `${base}.${node.property.name}`;
322
+ }
315
323
  if (node.type !== "Identifier") return void 0;
316
324
  const id = this.scopes.bindingOf.get(node);
317
325
  if (id === void 0) return node.name;
@@ -608,7 +616,7 @@ var Lowerer = class {
608
616
  break;
609
617
  }
610
618
  case "ReturnStatement":
611
- if (declaration.arguments.length) this.report(declaration, "A module cannot return a value; export it instead");
619
+ if (declaration.argument) this.report(declaration, "A module cannot return a value; export it instead");
612
620
  body.push(returns([]));
613
621
  break;
614
622
  case "ImportStatement":
@@ -787,7 +795,7 @@ var Lowerer = class {
787
795
  case "CallStatement": {
788
796
  const chain = optionalChain(node.expression);
789
797
  if (chain) return [this.optionalCallStatement(chain)];
790
- const expression = this.expression(node.expression);
798
+ const expression = this.callValues(node.expression);
791
799
  if (expression.type !== "CallExpression" && expression.type !== "MethodCallExpression") {
792
800
  this.report(node, "A statement must be a call");
793
801
  return [];
@@ -840,23 +848,26 @@ var Lowerer = class {
840
848
  }];
841
849
  case "GenericForStatement": {
842
850
  const prelude = [];
843
- const variables = node.variables.map((target) => {
844
- if (target.type === "IdentifierPattern") return this.name(target.name);
845
- const temp = this.names.fresh("item");
846
- prelude.push(...this.destructure(target, identifier(temp), "declare"));
847
- return temp;
848
- });
849
- if (variables.length === 1 && this.options.types?.iteratesValues.has(node)) {
850
- variables.unshift(this.names.fresh("_"));
851
+ let item;
852
+ if (node.variable.type === "IdentifierPattern") {
853
+ item = this.name(node.variable.name);
854
+ } else {
855
+ item = this.names.fresh("item");
856
+ prelude.push(...this.destructure(node.variable, identifier(item), "declare"));
851
857
  }
858
+ const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
859
+ let source = this.expression(node.iterator);
860
+ if (form.viaIter) source = methodCall(source, "__iter", []);
861
+ const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
862
+ const iterators = form.walks === "iteration" ? [call(this.builtin("unpack"), [source, number(1), number(3)])] : [source];
852
863
  return [genericFor(
853
864
  variables,
854
- node.iterators.map((e) => this.expression(e)),
865
+ iterators,
855
866
  this.loopBody51(this.block(node.body, prelude)).statements
856
867
  )];
857
868
  }
858
869
  case "ReturnStatement":
859
- return [returns(this.values(node.arguments))];
870
+ return [returns(node.argument ? [this.expression(node.argument)] : [])];
860
871
  case "BreakStatement":
861
872
  return [{ type: "BreakStatement", ...spanOf(node) }];
862
873
  case "ContinueStatement":
@@ -900,7 +911,7 @@ var Lowerer = class {
900
911
  // end
901
912
  // function Dog.speak(this) ... end
902
913
  //
903
- // `new Dog(x)` is `Dog.new(x)`, `dog:speak()` passes the instance
914
+ // `Dog.new(x)` builds one, `dog:speak()` passes the instance
904
915
  // as `this`, and `super.speak()` is `Animal.speak(this)` — the
905
916
  // base's own function, run on this instance.
906
917
  // ============================================================
@@ -926,6 +937,7 @@ var Lowerer = class {
926
937
  classRuntimeStatements() {
927
938
  if (!this.classHelpers) return [];
928
939
  const { build, accessors } = this.classHelpers;
940
+ const metamethods = `{ ${CLASS_METAMETHODS.map((name) => `"${name}"`).join(", ")} }`;
929
941
  return parseLuau(`
930
942
  local function ${build}(base)
931
943
  local class = { __getters = {}, __setters = {} }
@@ -936,6 +948,9 @@ local function ${build}(base)
936
948
  setmetatable(class, { __index = base })
937
949
  setmetatable(class.__getters, { __index = base.__getters })
938
950
  setmetatable(class.__setters, { __index = base.__setters })
951
+ for _, key in ipairs(${metamethods}) do
952
+ class[key] = base[key]
953
+ end
939
954
  end
940
955
  return class
941
956
  end
@@ -998,6 +1013,7 @@ end
998
1013
  }
999
1014
  break;
1000
1015
  case "ClassMethod":
1016
+ if (member2.isAbstract) break;
1001
1017
  out.push(this.functionStatement(
1002
1018
  member(self, member2.name.name),
1003
1019
  member2,
@@ -1019,7 +1035,7 @@ end
1019
1035
  }
1020
1036
  }
1021
1037
  out.push(this.classInit(node, self));
1022
- out.push(this.classNew(node, self));
1038
+ if (!node.isAbstract) out.push(this.classNew(node, self));
1023
1039
  out.push(callStatement(call(identifier(accessors), [self])));
1024
1040
  } finally {
1025
1041
  this.classContext = previous;
@@ -1297,6 +1313,10 @@ end
1297
1313
  }
1298
1314
  switch (node.type) {
1299
1315
  case "Identifier":
1316
+ if (node.name === "scriptArgs" && this.isLanguageGlobal(node)) {
1317
+ this.usesScriptArgs = true;
1318
+ return identifier("scriptArgs");
1319
+ }
1300
1320
  return this.loweredGlobalValue(node) ?? this.reference(node);
1301
1321
  case "NilLiteral":
1302
1322
  return nil();
@@ -1306,8 +1326,6 @@ end
1306
1326
  return number(node.value, this.numberRaw(node));
1307
1327
  case "StringLiteral":
1308
1328
  return string(node.value);
1309
- case "VarargExpression":
1310
- return vararg();
1311
1329
  // Only a recovering parse makes one, and a syntax error stops the build.
1312
1330
  case "ErrorExpression":
1313
1331
  this.report(node, "Syntax error");
@@ -1328,11 +1346,6 @@ end
1328
1346
  }
1329
1347
  case "UnaryExpression":
1330
1348
  return unary(node.operator, this.expression(node.argument));
1331
- case "NewExpression":
1332
- return call(
1333
- member(this.expression(node.callee), "new"),
1334
- this.values(node.arguments)
1335
- );
1336
1349
  case "SuperExpression":
1337
1350
  return this.superClassReference(node);
1338
1351
  case "SpreadElement":
@@ -1340,17 +1353,16 @@ end
1340
1353
  return nil();
1341
1354
  case "ClassExpression":
1342
1355
  return this.classExpression(node);
1343
- case "MemberExpression":
1344
- case "IndexExpression":
1345
1356
  case "CallExpression":
1346
- case "MethodCallExpression": {
1357
+ case "MethodCallExpression":
1358
+ return this.callValues(node);
1359
+ case "MemberExpression":
1360
+ case "IndexExpression": {
1347
1361
  const chain = optionalChain(node);
1348
1362
  if (chain) return this.optionalChainExpression(chain);
1349
- const object = linkObject(node);
1350
- if (node.type === "CallExpression" && object.type === "Identifier") {
1351
- return this.link(node, this.reference(object));
1352
- }
1353
- return this.link(node, this.expression(object));
1363
+ const global = node.type === "MemberExpression" ? this.loweredGlobalValue(node) : void 0;
1364
+ if (global) return global;
1365
+ return this.link(node, this.expression(linkObject(node)));
1354
1366
  }
1355
1367
  case "ParenthesizedExpression":
1356
1368
  return parenthesized(this.expression(node.expression));
@@ -1369,14 +1381,47 @@ end
1369
1381
  };
1370
1382
  }
1371
1383
  }
1384
+ /** A call. */
1385
+ callValues(node) {
1386
+ const chain = optionalChain(node);
1387
+ if (chain) return this.optionalChainExpression(chain);
1388
+ const object = linkObject(node);
1389
+ if (node.type === "CallExpression" && object.type === "Identifier") {
1390
+ return this.link(node, this.reference(object));
1391
+ }
1392
+ return this.link(node, this.expression(object));
1393
+ }
1394
+ /** A call is one value in tilua, and Luau would hand on every value one
1395
+ * in the last place of an argument list or an array returns. Types say
1396
+ * how many a call returns; where a type says nothing — `any`, `unknown`
1397
+ * — the call is kept to one: `f((g()))`. */
1398
+ keptToOne(nodes, values) {
1399
+ const node = nodes[nodes.length - 1];
1400
+ const last = values[values.length - 1];
1401
+ if (!node || !last || !expandsToMany(last)) return values;
1402
+ const type = this.options.types?.typeOf.get(node);
1403
+ if (type && type.kind !== "any" && type.kind !== "unknown") return values;
1404
+ return [...values.slice(0, -1), parenthesized(last)];
1405
+ }
1406
+ /** Is this `scriptArgs` the language's own, not a name the file declared? */
1407
+ isLanguageGlobal(node) {
1408
+ const id = this.bindingIdOf(node);
1409
+ return id === void 0 || this.scopes.bindings.get(id)?.kind === "global";
1410
+ }
1372
1411
  /** A list of values — a call's arguments, a `return`'s, a declaration's,
1373
1412
  * an assignment's. `f(a, ...xs)` is Lua's own last-value expansion,
1374
1413
  * `f(a, table.unpack(xs))`; a spread anywhere else cannot be, since only
1375
1414
  * the last value of a list expands, so the whole list is built as an
1376
- * array first and that is what expands. */
1377
- values(list) {
1415
+ * array first and that is what expands.
1416
+ *
1417
+ * `arguments` is set for a call's arguments, where Luau hands on every
1418
+ * value the last one returns — see `keptToOne`. */
1419
+ values(list, asArguments = false) {
1378
1420
  const spreads = list.filter((a) => a.type === "SpreadElement");
1379
- if (!spreads.length) return list.map((a) => this.expression(a));
1421
+ if (!spreads.length) {
1422
+ const lowered = list.map((a) => this.expression(a));
1423
+ return asArguments ? this.keptToOne(list, lowered) : lowered;
1424
+ }
1380
1425
  const unpack = (value) => call(member(this.builtin("table"), "unpack"), [value]);
1381
1426
  const last = list[list.length - 1];
1382
1427
  if (spreads.length === 1 && last.type === "SpreadElement") {
@@ -1397,13 +1442,13 @@ end
1397
1442
  return index(object, this.expression(node.index));
1398
1443
  case "CallExpression": {
1399
1444
  const lowered = this.loweredGlobalCall(node);
1400
- const args = this.values(node.arguments);
1401
- if (lowered) return call(calleePath(lowered.callee), [...lowered.prepend, ...args]);
1402
- return call(object, args);
1445
+ const args = this.values(node.arguments, true);
1446
+ if (!lowered) return call(object, args);
1447
+ return call(calleePath(lowered.callee), [...lowered.prepend, ...args]);
1403
1448
  }
1404
1449
  case "MethodCallExpression": {
1405
1450
  const lowered = this.loweredMethodCall(node);
1406
- const args = this.values(node.arguments);
1451
+ const args = this.values(node.arguments, true);
1407
1452
  if (lowered) {
1408
1453
  return call(calleePath(lowered.callee), [
1409
1454
  ...lowered.prepend,
@@ -1637,7 +1682,8 @@ end
1637
1682
  * runs of plain elements and the spread arrays are joined by `concat`. */
1638
1683
  arrayExpression(node) {
1639
1684
  if (!node.elements.some((e) => e.type === "SpreadElement")) {
1640
- return table(node.elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
1685
+ const elements = node.elements;
1686
+ return table(this.keptToOne(elements, elements.map((e) => this.expression(e))).map((value) => ({ type: "TableFieldPositional", value })));
1641
1687
  }
1642
1688
  const parts = [];
1643
1689
  let current = [];
@@ -1836,6 +1882,24 @@ function allNodes(root) {
1836
1882
  visit(root);
1837
1883
  return out;
1838
1884
  }
1885
+ var CLASS_METAMETHODS = [
1886
+ "__add",
1887
+ "__sub",
1888
+ "__mul",
1889
+ "__div",
1890
+ "__idiv",
1891
+ "__mod",
1892
+ "__pow",
1893
+ "__unm",
1894
+ "__concat",
1895
+ "__len",
1896
+ "__eq",
1897
+ "__lt",
1898
+ "__le",
1899
+ "__call",
1900
+ "__tostring",
1901
+ "__iter"
1902
+ ];
1839
1903
 
1840
1904
  // src/lowering.ts
1841
1905
  import { pathToFileURL } from "url";
@@ -1993,7 +2057,8 @@ async function bundle(options) {
1993
2057
  name: source.name,
1994
2058
  statements: lowered.statements,
1995
2059
  exportsName: lowered.exportsName,
1996
- info: lowered.module
2060
+ info: lowered.module,
2061
+ usesScriptArgs: lowered.usesScriptArgs
1997
2062
  });
1998
2063
  }
1999
2064
  for (const [file, fileDirectives] of directives) {
@@ -2018,6 +2083,9 @@ async function bundle(options) {
2018
2083
  }
2019
2084
  const program2 = parseLuau2(runtime(G));
2020
2085
  const assignment = program2.body.statements[1];
2086
+ if ([...modules.values()].some((m) => m.usesScriptArgs)) {
2087
+ program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
2088
+ }
2021
2089
  const modulesTable = assignment.type === "AssignmentStatement" && assignment.values[0].type === "TableExpression" ? assignment.values[0].fields.find((f) => f.type === "TableFieldNamed" && f.name.name === "modules")?.value : void 0;
2022
2090
  if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
2023
2091
  for (const module of modules.values()) {
package/dist/cli.cjs CHANGED
@@ -192,14 +192,18 @@ var Lowerer = class {
192
192
  const body = this.options.module ? this.module(this.options.module) : this.topLevel(this.source.body.statements);
193
193
  const helpers = this.helperDefinitions();
194
194
  const captured = [...this.builtins].map(([global, local2]) => local([local2], [identifier(global)]));
195
+ const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: vararg() }])])] : [];
195
196
  return {
196
- statements: [...captured, ...helpers, ...this.classRuntimeStatements(), ...body],
197
+ statements: [...scriptArgs, ...captured, ...helpers, ...this.classRuntimeStatements(), ...body],
197
198
  exportsName: this.exportsName,
198
199
  module: this.info,
199
200
  diagnostics: this.diagnostics,
200
- origins: this.origins
201
+ origins: this.origins,
202
+ usesScriptArgs: this.usesScriptArgs
201
203
  };
202
204
  }
205
+ /** Whether the file reads `scriptArgs`, the language's own global. */
206
+ usesScriptArgs = false;
203
207
  report(node, message) {
204
208
  this.diagnostics.push({ message, line: node.line.start, column: node.column.start });
205
209
  }
@@ -324,6 +328,10 @@ var Lowerer = class {
324
328
  /** The name a global is read by at `node`, or `undefined` when `node` is
325
329
  * not a global — a local of the same name is the author's. */
326
330
  globalName(node) {
331
+ if (node.type === "MemberExpression" && !node.optional) {
332
+ const base = this.globalName(node.object);
333
+ return base === void 0 ? void 0 : `${base}.${node.property.name}`;
334
+ }
327
335
  if (node.type !== "Identifier") return void 0;
328
336
  const id = this.scopes.bindingOf.get(node);
329
337
  if (id === void 0) return node.name;
@@ -620,7 +628,7 @@ var Lowerer = class {
620
628
  break;
621
629
  }
622
630
  case "ReturnStatement":
623
- if (declaration.arguments.length) this.report(declaration, "A module cannot return a value; export it instead");
631
+ if (declaration.argument) this.report(declaration, "A module cannot return a value; export it instead");
624
632
  body.push(returns([]));
625
633
  break;
626
634
  case "ImportStatement":
@@ -799,7 +807,7 @@ var Lowerer = class {
799
807
  case "CallStatement": {
800
808
  const chain = optionalChain(node.expression);
801
809
  if (chain) return [this.optionalCallStatement(chain)];
802
- const expression = this.expression(node.expression);
810
+ const expression = this.callValues(node.expression);
803
811
  if (expression.type !== "CallExpression" && expression.type !== "MethodCallExpression") {
804
812
  this.report(node, "A statement must be a call");
805
813
  return [];
@@ -852,23 +860,26 @@ var Lowerer = class {
852
860
  }];
853
861
  case "GenericForStatement": {
854
862
  const prelude = [];
855
- const variables = node.variables.map((target) => {
856
- if (target.type === "IdentifierPattern") return this.name(target.name);
857
- const temp = this.names.fresh("item");
858
- prelude.push(...this.destructure(target, identifier(temp), "declare"));
859
- return temp;
860
- });
861
- if (variables.length === 1 && this.options.types?.iteratesValues.has(node)) {
862
- variables.unshift(this.names.fresh("_"));
863
+ let item;
864
+ if (node.variable.type === "IdentifierPattern") {
865
+ item = this.name(node.variable.name);
866
+ } else {
867
+ item = this.names.fresh("item");
868
+ prelude.push(...this.destructure(node.variable, identifier(item), "declare"));
863
869
  }
870
+ const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
871
+ let source = this.expression(node.iterator);
872
+ if (form.viaIter) source = methodCall(source, "__iter", []);
873
+ const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
874
+ const iterators = form.walks === "iteration" ? [call(this.builtin("unpack"), [source, number(1), number(3)])] : [source];
864
875
  return [genericFor(
865
876
  variables,
866
- node.iterators.map((e) => this.expression(e)),
877
+ iterators,
867
878
  this.loopBody51(this.block(node.body, prelude)).statements
868
879
  )];
869
880
  }
870
881
  case "ReturnStatement":
871
- return [returns(this.values(node.arguments))];
882
+ return [returns(node.argument ? [this.expression(node.argument)] : [])];
872
883
  case "BreakStatement":
873
884
  return [{ type: "BreakStatement", ...spanOf(node) }];
874
885
  case "ContinueStatement":
@@ -912,7 +923,7 @@ var Lowerer = class {
912
923
  // end
913
924
  // function Dog.speak(this) ... end
914
925
  //
915
- // `new Dog(x)` is `Dog.new(x)`, `dog:speak()` passes the instance
926
+ // `Dog.new(x)` builds one, `dog:speak()` passes the instance
916
927
  // as `this`, and `super.speak()` is `Animal.speak(this)` — the
917
928
  // base's own function, run on this instance.
918
929
  // ============================================================
@@ -938,6 +949,7 @@ var Lowerer = class {
938
949
  classRuntimeStatements() {
939
950
  if (!this.classHelpers) return [];
940
951
  const { build, accessors } = this.classHelpers;
952
+ const metamethods = `{ ${CLASS_METAMETHODS.map((name) => `"${name}"`).join(", ")} }`;
941
953
  return (0, import_luau_parser.parse)(`
942
954
  local function ${build}(base)
943
955
  local class = { __getters = {}, __setters = {} }
@@ -948,6 +960,9 @@ local function ${build}(base)
948
960
  setmetatable(class, { __index = base })
949
961
  setmetatable(class.__getters, { __index = base.__getters })
950
962
  setmetatable(class.__setters, { __index = base.__setters })
963
+ for _, key in ipairs(${metamethods}) do
964
+ class[key] = base[key]
965
+ end
951
966
  end
952
967
  return class
953
968
  end
@@ -1010,6 +1025,7 @@ end
1010
1025
  }
1011
1026
  break;
1012
1027
  case "ClassMethod":
1028
+ if (member2.isAbstract) break;
1013
1029
  out2.push(this.functionStatement(
1014
1030
  member(self, member2.name.name),
1015
1031
  member2,
@@ -1031,7 +1047,7 @@ end
1031
1047
  }
1032
1048
  }
1033
1049
  out2.push(this.classInit(node, self));
1034
- out2.push(this.classNew(node, self));
1050
+ if (!node.isAbstract) out2.push(this.classNew(node, self));
1035
1051
  out2.push(callStatement(call(identifier(accessors), [self])));
1036
1052
  } finally {
1037
1053
  this.classContext = previous;
@@ -1309,6 +1325,10 @@ end
1309
1325
  }
1310
1326
  switch (node.type) {
1311
1327
  case "Identifier":
1328
+ if (node.name === "scriptArgs" && this.isLanguageGlobal(node)) {
1329
+ this.usesScriptArgs = true;
1330
+ return identifier("scriptArgs");
1331
+ }
1312
1332
  return this.loweredGlobalValue(node) ?? this.reference(node);
1313
1333
  case "NilLiteral":
1314
1334
  return nil();
@@ -1318,8 +1338,6 @@ end
1318
1338
  return number(node.value, this.numberRaw(node));
1319
1339
  case "StringLiteral":
1320
1340
  return string(node.value);
1321
- case "VarargExpression":
1322
- return vararg();
1323
1341
  // Only a recovering parse makes one, and a syntax error stops the build.
1324
1342
  case "ErrorExpression":
1325
1343
  this.report(node, "Syntax error");
@@ -1340,11 +1358,6 @@ end
1340
1358
  }
1341
1359
  case "UnaryExpression":
1342
1360
  return unary(node.operator, this.expression(node.argument));
1343
- case "NewExpression":
1344
- return call(
1345
- member(this.expression(node.callee), "new"),
1346
- this.values(node.arguments)
1347
- );
1348
1361
  case "SuperExpression":
1349
1362
  return this.superClassReference(node);
1350
1363
  case "SpreadElement":
@@ -1352,17 +1365,16 @@ end
1352
1365
  return nil();
1353
1366
  case "ClassExpression":
1354
1367
  return this.classExpression(node);
1355
- case "MemberExpression":
1356
- case "IndexExpression":
1357
1368
  case "CallExpression":
1358
- case "MethodCallExpression": {
1369
+ case "MethodCallExpression":
1370
+ return this.callValues(node);
1371
+ case "MemberExpression":
1372
+ case "IndexExpression": {
1359
1373
  const chain = optionalChain(node);
1360
1374
  if (chain) return this.optionalChainExpression(chain);
1361
- const object = linkObject(node);
1362
- if (node.type === "CallExpression" && object.type === "Identifier") {
1363
- return this.link(node, this.reference(object));
1364
- }
1365
- return this.link(node, this.expression(object));
1375
+ const global = node.type === "MemberExpression" ? this.loweredGlobalValue(node) : void 0;
1376
+ if (global) return global;
1377
+ return this.link(node, this.expression(linkObject(node)));
1366
1378
  }
1367
1379
  case "ParenthesizedExpression":
1368
1380
  return parenthesized(this.expression(node.expression));
@@ -1381,14 +1393,47 @@ end
1381
1393
  };
1382
1394
  }
1383
1395
  }
1396
+ /** A call. */
1397
+ callValues(node) {
1398
+ const chain = optionalChain(node);
1399
+ if (chain) return this.optionalChainExpression(chain);
1400
+ const object = linkObject(node);
1401
+ if (node.type === "CallExpression" && object.type === "Identifier") {
1402
+ return this.link(node, this.reference(object));
1403
+ }
1404
+ return this.link(node, this.expression(object));
1405
+ }
1406
+ /** A call is one value in tilua, and Luau would hand on every value one
1407
+ * in the last place of an argument list or an array returns. Types say
1408
+ * how many a call returns; where a type says nothing — `any`, `unknown`
1409
+ * — the call is kept to one: `f((g()))`. */
1410
+ keptToOne(nodes, values) {
1411
+ const node = nodes[nodes.length - 1];
1412
+ const last = values[values.length - 1];
1413
+ if (!node || !last || !expandsToMany(last)) return values;
1414
+ const type = this.options.types?.typeOf.get(node);
1415
+ if (type && type.kind !== "any" && type.kind !== "unknown") return values;
1416
+ return [...values.slice(0, -1), parenthesized(last)];
1417
+ }
1418
+ /** Is this `scriptArgs` the language's own, not a name the file declared? */
1419
+ isLanguageGlobal(node) {
1420
+ const id = this.bindingIdOf(node);
1421
+ return id === void 0 || this.scopes.bindings.get(id)?.kind === "global";
1422
+ }
1384
1423
  /** A list of values — a call's arguments, a `return`'s, a declaration's,
1385
1424
  * an assignment's. `f(a, ...xs)` is Lua's own last-value expansion,
1386
1425
  * `f(a, table.unpack(xs))`; a spread anywhere else cannot be, since only
1387
1426
  * the last value of a list expands, so the whole list is built as an
1388
- * array first and that is what expands. */
1389
- values(list) {
1427
+ * array first and that is what expands.
1428
+ *
1429
+ * `arguments` is set for a call's arguments, where Luau hands on every
1430
+ * value the last one returns — see `keptToOne`. */
1431
+ values(list, asArguments = false) {
1390
1432
  const spreads = list.filter((a) => a.type === "SpreadElement");
1391
- if (!spreads.length) return list.map((a) => this.expression(a));
1433
+ if (!spreads.length) {
1434
+ const lowered = list.map((a) => this.expression(a));
1435
+ return asArguments ? this.keptToOne(list, lowered) : lowered;
1436
+ }
1392
1437
  const unpack = (value) => call(member(this.builtin("table"), "unpack"), [value]);
1393
1438
  const last = list[list.length - 1];
1394
1439
  if (spreads.length === 1 && last.type === "SpreadElement") {
@@ -1409,13 +1454,13 @@ end
1409
1454
  return index(object, this.expression(node.index));
1410
1455
  case "CallExpression": {
1411
1456
  const lowered = this.loweredGlobalCall(node);
1412
- const args2 = this.values(node.arguments);
1413
- if (lowered) return call(calleePath(lowered.callee), [...lowered.prepend, ...args2]);
1414
- return call(object, args2);
1457
+ const args2 = this.values(node.arguments, true);
1458
+ if (!lowered) return call(object, args2);
1459
+ return call(calleePath(lowered.callee), [...lowered.prepend, ...args2]);
1415
1460
  }
1416
1461
  case "MethodCallExpression": {
1417
1462
  const lowered = this.loweredMethodCall(node);
1418
- const args2 = this.values(node.arguments);
1463
+ const args2 = this.values(node.arguments, true);
1419
1464
  if (lowered) {
1420
1465
  return call(calleePath(lowered.callee), [
1421
1466
  ...lowered.prepend,
@@ -1649,7 +1694,8 @@ end
1649
1694
  * runs of plain elements and the spread arrays are joined by `concat`. */
1650
1695
  arrayExpression(node) {
1651
1696
  if (!node.elements.some((e) => e.type === "SpreadElement")) {
1652
- return table(node.elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
1697
+ const elements = node.elements;
1698
+ return table(this.keptToOne(elements, elements.map((e) => this.expression(e))).map((value) => ({ type: "TableFieldPositional", value })));
1653
1699
  }
1654
1700
  const parts = [];
1655
1701
  let current = [];
@@ -1848,6 +1894,24 @@ function allNodes(root) {
1848
1894
  visit(root);
1849
1895
  return out2;
1850
1896
  }
1897
+ var CLASS_METAMETHODS = [
1898
+ "__add",
1899
+ "__sub",
1900
+ "__mul",
1901
+ "__div",
1902
+ "__idiv",
1903
+ "__mod",
1904
+ "__pow",
1905
+ "__unm",
1906
+ "__concat",
1907
+ "__len",
1908
+ "__eq",
1909
+ "__lt",
1910
+ "__le",
1911
+ "__call",
1912
+ "__tostring",
1913
+ "__iter"
1914
+ ];
1851
1915
 
1852
1916
  // src/linemap.ts
1853
1917
  function statementsOf(node) {
@@ -1987,7 +2051,8 @@ async function bundle(options) {
1987
2051
  name: source.name,
1988
2052
  statements: lowered.statements,
1989
2053
  exportsName: lowered.exportsName,
1990
- info: lowered.module
2054
+ info: lowered.module,
2055
+ usesScriptArgs: lowered.usesScriptArgs
1991
2056
  });
1992
2057
  }
1993
2058
  for (const [file, fileDirectives] of directives) {
@@ -2012,6 +2077,9 @@ async function bundle(options) {
2012
2077
  }
2013
2078
  const program = (0, import_luau_parser2.parse)(runtime(G));
2014
2079
  const assignment = program.body.statements[1];
2080
+ if ([...modules.values()].some((m) => m.usesScriptArgs)) {
2081
+ program.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
2082
+ }
2015
2083
  const modulesTable = assignment.type === "AssignmentStatement" && assignment.values[0].type === "TableExpression" ? assignment.values[0].fields.find((f) => f.type === "TableFieldNamed" && f.name.name === "modules")?.value : void 0;
2016
2084
  if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
2017
2085
  for (const module2 of modules.values()) {
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  bundle
4
- } from "./chunk-2IPPO4V3.js";
4
+ } from "./chunk-KG6W5XKA.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { writeFileSync } from "fs";
package/dist/index.cjs CHANGED
@@ -216,14 +216,18 @@ var Lowerer = class {
216
216
  const body = this.options.module ? this.module(this.options.module) : this.topLevel(this.source.body.statements);
217
217
  const helpers = this.helperDefinitions();
218
218
  const captured = [...this.builtins].map(([global, local2]) => local([local2], [identifier(global)]));
219
+ const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: vararg() }])])] : [];
219
220
  return {
220
- statements: [...captured, ...helpers, ...this.classRuntimeStatements(), ...body],
221
+ statements: [...scriptArgs, ...captured, ...helpers, ...this.classRuntimeStatements(), ...body],
221
222
  exportsName: this.exportsName,
222
223
  module: this.info,
223
224
  diagnostics: this.diagnostics,
224
- origins: this.origins
225
+ origins: this.origins,
226
+ usesScriptArgs: this.usesScriptArgs
225
227
  };
226
228
  }
229
+ /** Whether the file reads `scriptArgs`, the language's own global. */
230
+ usesScriptArgs = false;
227
231
  report(node, message) {
228
232
  this.diagnostics.push({ message, line: node.line.start, column: node.column.start });
229
233
  }
@@ -348,6 +352,10 @@ var Lowerer = class {
348
352
  /** The name a global is read by at `node`, or `undefined` when `node` is
349
353
  * not a global — a local of the same name is the author's. */
350
354
  globalName(node) {
355
+ if (node.type === "MemberExpression" && !node.optional) {
356
+ const base = this.globalName(node.object);
357
+ return base === void 0 ? void 0 : `${base}.${node.property.name}`;
358
+ }
351
359
  if (node.type !== "Identifier") return void 0;
352
360
  const id = this.scopes.bindingOf.get(node);
353
361
  if (id === void 0) return node.name;
@@ -644,7 +652,7 @@ var Lowerer = class {
644
652
  break;
645
653
  }
646
654
  case "ReturnStatement":
647
- if (declaration.arguments.length) this.report(declaration, "A module cannot return a value; export it instead");
655
+ if (declaration.argument) this.report(declaration, "A module cannot return a value; export it instead");
648
656
  body.push(returns([]));
649
657
  break;
650
658
  case "ImportStatement":
@@ -823,7 +831,7 @@ var Lowerer = class {
823
831
  case "CallStatement": {
824
832
  const chain = optionalChain(node.expression);
825
833
  if (chain) return [this.optionalCallStatement(chain)];
826
- const expression = this.expression(node.expression);
834
+ const expression = this.callValues(node.expression);
827
835
  if (expression.type !== "CallExpression" && expression.type !== "MethodCallExpression") {
828
836
  this.report(node, "A statement must be a call");
829
837
  return [];
@@ -876,23 +884,26 @@ var Lowerer = class {
876
884
  }];
877
885
  case "GenericForStatement": {
878
886
  const prelude = [];
879
- const variables = node.variables.map((target) => {
880
- if (target.type === "IdentifierPattern") return this.name(target.name);
881
- const temp = this.names.fresh("item");
882
- prelude.push(...this.destructure(target, identifier(temp), "declare"));
883
- return temp;
884
- });
885
- if (variables.length === 1 && this.options.types?.iteratesValues.has(node)) {
886
- variables.unshift(this.names.fresh("_"));
887
+ let item;
888
+ if (node.variable.type === "IdentifierPattern") {
889
+ item = this.name(node.variable.name);
890
+ } else {
891
+ item = this.names.fresh("item");
892
+ prelude.push(...this.destructure(node.variable, identifier(item), "declare"));
887
893
  }
894
+ const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
895
+ let source = this.expression(node.iterator);
896
+ if (form.viaIter) source = methodCall(source, "__iter", []);
897
+ const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
898
+ const iterators = form.walks === "iteration" ? [call(this.builtin("unpack"), [source, number(1), number(3)])] : [source];
888
899
  return [genericFor(
889
900
  variables,
890
- node.iterators.map((e) => this.expression(e)),
901
+ iterators,
891
902
  this.loopBody51(this.block(node.body, prelude)).statements
892
903
  )];
893
904
  }
894
905
  case "ReturnStatement":
895
- return [returns(this.values(node.arguments))];
906
+ return [returns(node.argument ? [this.expression(node.argument)] : [])];
896
907
  case "BreakStatement":
897
908
  return [{ type: "BreakStatement", ...spanOf(node) }];
898
909
  case "ContinueStatement":
@@ -936,7 +947,7 @@ var Lowerer = class {
936
947
  // end
937
948
  // function Dog.speak(this) ... end
938
949
  //
939
- // `new Dog(x)` is `Dog.new(x)`, `dog:speak()` passes the instance
950
+ // `Dog.new(x)` builds one, `dog:speak()` passes the instance
940
951
  // as `this`, and `super.speak()` is `Animal.speak(this)` — the
941
952
  // base's own function, run on this instance.
942
953
  // ============================================================
@@ -962,6 +973,7 @@ var Lowerer = class {
962
973
  classRuntimeStatements() {
963
974
  if (!this.classHelpers) return [];
964
975
  const { build, accessors } = this.classHelpers;
976
+ const metamethods = `{ ${CLASS_METAMETHODS.map((name) => `"${name}"`).join(", ")} }`;
965
977
  return (0, import_luau_parser.parse)(`
966
978
  local function ${build}(base)
967
979
  local class = { __getters = {}, __setters = {} }
@@ -972,6 +984,9 @@ local function ${build}(base)
972
984
  setmetatable(class, { __index = base })
973
985
  setmetatable(class.__getters, { __index = base.__getters })
974
986
  setmetatable(class.__setters, { __index = base.__setters })
987
+ for _, key in ipairs(${metamethods}) do
988
+ class[key] = base[key]
989
+ end
975
990
  end
976
991
  return class
977
992
  end
@@ -1034,6 +1049,7 @@ end
1034
1049
  }
1035
1050
  break;
1036
1051
  case "ClassMethod":
1052
+ if (member2.isAbstract) break;
1037
1053
  out.push(this.functionStatement(
1038
1054
  member(self, member2.name.name),
1039
1055
  member2,
@@ -1055,7 +1071,7 @@ end
1055
1071
  }
1056
1072
  }
1057
1073
  out.push(this.classInit(node, self));
1058
- out.push(this.classNew(node, self));
1074
+ if (!node.isAbstract) out.push(this.classNew(node, self));
1059
1075
  out.push(callStatement(call(identifier(accessors), [self])));
1060
1076
  } finally {
1061
1077
  this.classContext = previous;
@@ -1333,6 +1349,10 @@ end
1333
1349
  }
1334
1350
  switch (node.type) {
1335
1351
  case "Identifier":
1352
+ if (node.name === "scriptArgs" && this.isLanguageGlobal(node)) {
1353
+ this.usesScriptArgs = true;
1354
+ return identifier("scriptArgs");
1355
+ }
1336
1356
  return this.loweredGlobalValue(node) ?? this.reference(node);
1337
1357
  case "NilLiteral":
1338
1358
  return nil();
@@ -1342,8 +1362,6 @@ end
1342
1362
  return number(node.value, this.numberRaw(node));
1343
1363
  case "StringLiteral":
1344
1364
  return string(node.value);
1345
- case "VarargExpression":
1346
- return vararg();
1347
1365
  // Only a recovering parse makes one, and a syntax error stops the build.
1348
1366
  case "ErrorExpression":
1349
1367
  this.report(node, "Syntax error");
@@ -1364,11 +1382,6 @@ end
1364
1382
  }
1365
1383
  case "UnaryExpression":
1366
1384
  return unary(node.operator, this.expression(node.argument));
1367
- case "NewExpression":
1368
- return call(
1369
- member(this.expression(node.callee), "new"),
1370
- this.values(node.arguments)
1371
- );
1372
1385
  case "SuperExpression":
1373
1386
  return this.superClassReference(node);
1374
1387
  case "SpreadElement":
@@ -1376,17 +1389,16 @@ end
1376
1389
  return nil();
1377
1390
  case "ClassExpression":
1378
1391
  return this.classExpression(node);
1379
- case "MemberExpression":
1380
- case "IndexExpression":
1381
1392
  case "CallExpression":
1382
- case "MethodCallExpression": {
1393
+ case "MethodCallExpression":
1394
+ return this.callValues(node);
1395
+ case "MemberExpression":
1396
+ case "IndexExpression": {
1383
1397
  const chain = optionalChain(node);
1384
1398
  if (chain) return this.optionalChainExpression(chain);
1385
- const object = linkObject(node);
1386
- if (node.type === "CallExpression" && object.type === "Identifier") {
1387
- return this.link(node, this.reference(object));
1388
- }
1389
- return this.link(node, this.expression(object));
1399
+ const global = node.type === "MemberExpression" ? this.loweredGlobalValue(node) : void 0;
1400
+ if (global) return global;
1401
+ return this.link(node, this.expression(linkObject(node)));
1390
1402
  }
1391
1403
  case "ParenthesizedExpression":
1392
1404
  return parenthesized(this.expression(node.expression));
@@ -1405,14 +1417,47 @@ end
1405
1417
  };
1406
1418
  }
1407
1419
  }
1420
+ /** A call. */
1421
+ callValues(node) {
1422
+ const chain = optionalChain(node);
1423
+ if (chain) return this.optionalChainExpression(chain);
1424
+ const object = linkObject(node);
1425
+ if (node.type === "CallExpression" && object.type === "Identifier") {
1426
+ return this.link(node, this.reference(object));
1427
+ }
1428
+ return this.link(node, this.expression(object));
1429
+ }
1430
+ /** A call is one value in tilua, and Luau would hand on every value one
1431
+ * in the last place of an argument list or an array returns. Types say
1432
+ * how many a call returns; where a type says nothing — `any`, `unknown`
1433
+ * — the call is kept to one: `f((g()))`. */
1434
+ keptToOne(nodes, values) {
1435
+ const node = nodes[nodes.length - 1];
1436
+ const last = values[values.length - 1];
1437
+ if (!node || !last || !expandsToMany(last)) return values;
1438
+ const type = this.options.types?.typeOf.get(node);
1439
+ if (type && type.kind !== "any" && type.kind !== "unknown") return values;
1440
+ return [...values.slice(0, -1), parenthesized(last)];
1441
+ }
1442
+ /** Is this `scriptArgs` the language's own, not a name the file declared? */
1443
+ isLanguageGlobal(node) {
1444
+ const id = this.bindingIdOf(node);
1445
+ return id === void 0 || this.scopes.bindings.get(id)?.kind === "global";
1446
+ }
1408
1447
  /** A list of values — a call's arguments, a `return`'s, a declaration's,
1409
1448
  * an assignment's. `f(a, ...xs)` is Lua's own last-value expansion,
1410
1449
  * `f(a, table.unpack(xs))`; a spread anywhere else cannot be, since only
1411
1450
  * the last value of a list expands, so the whole list is built as an
1412
- * array first and that is what expands. */
1413
- values(list) {
1451
+ * array first and that is what expands.
1452
+ *
1453
+ * `arguments` is set for a call's arguments, where Luau hands on every
1454
+ * value the last one returns — see `keptToOne`. */
1455
+ values(list, asArguments = false) {
1414
1456
  const spreads = list.filter((a) => a.type === "SpreadElement");
1415
- if (!spreads.length) return list.map((a) => this.expression(a));
1457
+ if (!spreads.length) {
1458
+ const lowered = list.map((a) => this.expression(a));
1459
+ return asArguments ? this.keptToOne(list, lowered) : lowered;
1460
+ }
1416
1461
  const unpack = (value) => call(member(this.builtin("table"), "unpack"), [value]);
1417
1462
  const last = list[list.length - 1];
1418
1463
  if (spreads.length === 1 && last.type === "SpreadElement") {
@@ -1433,13 +1478,13 @@ end
1433
1478
  return index(object, this.expression(node.index));
1434
1479
  case "CallExpression": {
1435
1480
  const lowered = this.loweredGlobalCall(node);
1436
- const args = this.values(node.arguments);
1437
- if (lowered) return call(calleePath(lowered.callee), [...lowered.prepend, ...args]);
1438
- return call(object, args);
1481
+ const args = this.values(node.arguments, true);
1482
+ if (!lowered) return call(object, args);
1483
+ return call(calleePath(lowered.callee), [...lowered.prepend, ...args]);
1439
1484
  }
1440
1485
  case "MethodCallExpression": {
1441
1486
  const lowered = this.loweredMethodCall(node);
1442
- const args = this.values(node.arguments);
1487
+ const args = this.values(node.arguments, true);
1443
1488
  if (lowered) {
1444
1489
  return call(calleePath(lowered.callee), [
1445
1490
  ...lowered.prepend,
@@ -1673,7 +1718,8 @@ end
1673
1718
  * runs of plain elements and the spread arrays are joined by `concat`. */
1674
1719
  arrayExpression(node) {
1675
1720
  if (!node.elements.some((e) => e.type === "SpreadElement")) {
1676
- return table(node.elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
1721
+ const elements = node.elements;
1722
+ return table(this.keptToOne(elements, elements.map((e) => this.expression(e))).map((value) => ({ type: "TableFieldPositional", value })));
1677
1723
  }
1678
1724
  const parts = [];
1679
1725
  let current = [];
@@ -1872,6 +1918,24 @@ function allNodes(root) {
1872
1918
  visit(root);
1873
1919
  return out;
1874
1920
  }
1921
+ var CLASS_METAMETHODS = [
1922
+ "__add",
1923
+ "__sub",
1924
+ "__mul",
1925
+ "__div",
1926
+ "__idiv",
1927
+ "__mod",
1928
+ "__pow",
1929
+ "__unm",
1930
+ "__concat",
1931
+ "__len",
1932
+ "__eq",
1933
+ "__lt",
1934
+ "__le",
1935
+ "__call",
1936
+ "__tostring",
1937
+ "__iter"
1938
+ ];
1875
1939
 
1876
1940
  // src/linemap.ts
1877
1941
  function statementsOf(node) {
@@ -2011,7 +2075,8 @@ async function bundle(options) {
2011
2075
  name: source.name,
2012
2076
  statements: lowered.statements,
2013
2077
  exportsName: lowered.exportsName,
2014
- info: lowered.module
2078
+ info: lowered.module,
2079
+ usesScriptArgs: lowered.usesScriptArgs
2015
2080
  });
2016
2081
  }
2017
2082
  for (const [file, fileDirectives] of directives) {
@@ -2036,6 +2101,9 @@ async function bundle(options) {
2036
2101
  }
2037
2102
  const program2 = (0, import_luau_parser2.parse)(runtime(G));
2038
2103
  const assignment = program2.body.statements[1];
2104
+ if ([...modules.values()].some((m) => m.usesScriptArgs)) {
2105
+ program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
2106
+ }
2039
2107
  const modulesTable = assignment.type === "AssignmentStatement" && assignment.values[0].type === "TableExpression" ? assignment.values[0].fields.find((f) => f.type === "TableFieldNamed" && f.name.name === "modules")?.value : void 0;
2040
2108
  if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
2041
2109
  for (const module2 of modules.values()) {
package/dist/index.d.cts CHANGED
@@ -142,6 +142,9 @@ interface LowerResult {
142
142
  * file it was lowered from, this is what turns a line of the bundle back
143
143
  * into a place someone can open. */
144
144
  readonly origins: WeakMap<L.Statement, number>;
145
+ /** The file reads `scriptArgs`: whatever runs it has to set it up, from
146
+ * the chunk's own `...` — this file, compiled alone, does it itself. */
147
+ readonly usesScriptArgs: boolean;
145
148
  }
146
149
  /** How a module's exports behave at runtime, beyond what its code assigns. */
147
150
  interface ModuleInfo {
package/dist/index.d.ts CHANGED
@@ -142,6 +142,9 @@ interface LowerResult {
142
142
  * file it was lowered from, this is what turns a line of the bundle back
143
143
  * into a place someone can open. */
144
144
  readonly origins: WeakMap<L.Statement, number>;
145
+ /** The file reads `scriptArgs`: whatever runs it has to set it up, from
146
+ * the chunk's own `...` — this file, compiled alone, does it itself. */
147
+ readonly usesScriptArgs: boolean;
145
148
  }
146
149
  /** How a module's exports behave at runtime, beyond what its code assigns. */
147
150
  interface ModuleInfo {
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  lower,
5
5
  program,
6
6
  resolveConfig
7
- } from "./chunk-2IPPO4V3.js";
7
+ } from "./chunk-KG6W5XKA.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": "1.1.0",
3
+ "version": "2.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",
@@ -37,7 +37,7 @@
37
37
  "type": "module",
38
38
  "dependencies": {
39
39
  "luau-parser": "^1.0.3",
40
- "@tilua/parser": "^1.1.0"
40
+ "@tilua/parser": "^2.0.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^22.20.2",