@tilua/compiler 2.3.0 → 3.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/dist/index.cjs CHANGED
@@ -28,8 +28,12 @@ __export(index_exports, {
28
28
  });
29
29
  module.exports = __toCommonJS(index_exports);
30
30
 
31
+ // node_modules/tsup/assets/cjs_shims.js
32
+ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
33
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
34
+
31
35
  // src/bundle.ts
32
- var import_node_fs = require("fs");
36
+ var import_node_fs2 = require("fs");
33
37
  var import_node_path2 = require("path");
34
38
  var import_parser3 = require("@tilua/parser");
35
39
  var import_luau_parser2 = require("luau-parser");
@@ -57,10 +61,10 @@ var nil = () => ({ type: "NilLiteral", ...span() });
57
61
  var boolean = (value) => ({ type: "BooleanLiteral", value, ...span() });
58
62
  var number = (value, raw = String(value)) => ({ type: "NumberLiteral", value, raw, ...span() });
59
63
  var string = (value) => ({ type: "StringLiteral", value, raw: "", ...span() });
60
- var member = (object, property) => isLuauName(property) ? { type: "MemberExpression", object, property: identifier(property), ...span() } : index(object, string(property));
61
- var index = (object, key) => ({ type: "IndexExpression", object, index: key, ...span() });
64
+ var member = (object2, property) => isLuauName(property) ? { type: "MemberExpression", object: object2, property: identifier(property), ...span() } : index(object2, string(property));
65
+ var index = (object2, key) => ({ type: "IndexExpression", object: object2, index: key, ...span() });
62
66
  var call = (callee, args) => ({ type: "CallExpression", callee, arguments: args, ...span() });
63
- var methodCall = (object, method, args) => ({ type: "MethodCallExpression", object, method: identifier(method), arguments: args, ...span() });
67
+ var methodCall = (object2, method, args) => ({ type: "MethodCallExpression", object: object2, method: identifier(method), arguments: args, ...span() });
64
68
  var functionExpression = (func) => ({ type: "FunctionExpression", func, ...span() });
65
69
  var binary = (operator, left, right) => ({ type: "BinaryExpression", operator, left, right, ...span() });
66
70
  var unary = (operator, argument) => ({ type: "UnaryExpression", operator, argument, ...span() });
@@ -176,6 +180,62 @@ var Names = class _Names {
176
180
  }
177
181
  };
178
182
 
183
+ // src/language.ts
184
+ var import_node_fs = require("fs");
185
+ var read = (name) => (0, import_node_fs.readFileSync)(new URL(`../runtime/${name}`, importMetaUrl), "utf8");
186
+ var implemented = (source) => new Set([...source.matchAll(/function __NAME__\.(\w+)/g)].map((m) => m[1]));
187
+ var array = read("array.luau");
188
+ var string2 = read("string.luau");
189
+ var object = read("object.luau");
190
+ var arrayMethods = implemented(array);
191
+ var stringMethods = implemented(string2);
192
+ var objectMethods = implemented(object);
193
+ function every(type, is, seen = /* @__PURE__ */ new Set()) {
194
+ if (!type || seen.has(type)) return false;
195
+ seen.add(type);
196
+ if (type.kind === "union") {
197
+ return type.types.filter((m) => !(m.kind === "primitive" && m.name === "nil")).every((m) => every(m, is, seen));
198
+ }
199
+ if (type.kind === "typeParam") return every(type.constraint, is, seen);
200
+ return is(type);
201
+ }
202
+ var isArray = (type) => every(type, (t) => t.kind === "array" || t.kind === "tuple");
203
+ var isString = (type) => every(type, (t) => t.kind === "primitive" && t.name === "string" || t.kind === "literal" && t.base === "string" || t.kind === "templateLiteral");
204
+ function objectKeys(type) {
205
+ const members = type?.kind === "union" ? type.types : type ? [type] : [];
206
+ const orders = [];
207
+ let open = false;
208
+ for (const member2 of members) {
209
+ const keys = [];
210
+ for (const part of member2.kind === "intersection" ? member2.types : [member2]) {
211
+ if (part.kind !== "object") continue;
212
+ for (const key of part.properties.keys()) if (!keys.includes(key)) keys.push(key);
213
+ if (part.indexer) open = true;
214
+ }
215
+ orders.push(keys);
216
+ }
217
+ const order = JSON.stringify(orders[0] ?? []);
218
+ const known = orders.length && orders.every((keys) => JSON.stringify(keys) === order) ? `{ ${orders[0].map((key) => JSON.stringify(key)).join(", ")} }` : "nil";
219
+ return { known, open: String(open) };
220
+ }
221
+ var plugin = {
222
+ runtime: { array, string: string2, object },
223
+ methodCall({ method, receiver, use }) {
224
+ if (isString(receiver)) {
225
+ return stringMethods.has(method) ? { callee: `${use("string")}.${method}` } : void 0;
226
+ }
227
+ if (isArray(receiver)) {
228
+ return arrayMethods.has(method) ? { callee: `${use("array")}.${method}` } : void 0;
229
+ }
230
+ if (objectMethods.has(method)) {
231
+ const keys = objectKeys(receiver);
232
+ return { callee: `${use("object")}.${method}`, prepend: [keys.known, keys.open] };
233
+ }
234
+ return void 0;
235
+ }
236
+ };
237
+ var languageLowering = { plugin, from: "tilua" };
238
+
179
239
  // src/lower.ts
180
240
  function lower(program2, scopes, options = {}) {
181
241
  return new Lowerer(program2, scopes, options).run();
@@ -359,21 +419,34 @@ var Lowerer = class {
359
419
  if (id === void 0) return node.name;
360
420
  return this.scopes.bindings.get(id)?.kind === "global" ? node.name : void 0;
361
421
  }
362
- /** What a library says `receiver:method(...)` is. The last library
363
- * loaded is asked first, so a project's own library can answer for a
364
- * method an earlier one also claims; no answer leaves an ordinary Luau
365
- * method call, which is what a value that answers to the method itself
366
- * wants (`text:upper()`). */
422
+ /** The language's own lowering, then each library's, in load order. A
423
+ * runtime is named by its lowering's place here (`loweringRuntime`). */
424
+ get lowerings() {
425
+ return this.allLowerings ??= [languageLowering, ...this.options.lowerings ?? []];
426
+ }
427
+ allLowerings;
428
+ /** What `receiver:method(...)` becomes, when Luau alone would not run it.
429
+ *
430
+ * A method the receiver's metatable gave it — the analyzer says so, and
431
+ * whose metatable it was (`methodSources`) — is asked of whoever declared
432
+ * that metatable, and only them: the language lowers its own
433
+ * (`names:filter(f)` becomes a call into its runtime), a library its own,
434
+ * and one the program declared is taken at its word. Any other method is
435
+ * a member of the receiver's own, which a library may still claim
436
+ * (`console:log`), the last library loaded first. No answer leaves an
437
+ * ordinary Luau method call: `text:upper()` reaches Lua's own. */
367
438
  loweredMethodCall(node) {
368
- const lowerings = this.options.lowerings;
369
- if (!lowerings?.some((l) => l.plugin.methodCall)) return void 0;
439
+ const lowerings = this.lowerings;
440
+ const source = this.options.types?.methodSources.get(node);
441
+ const asked = source?.origin === "language" ? [0] : source?.origin === "library" ? lowerings.flatMap((l, i) => l.library === source.library ? [i] : []) : source?.origin === "program" ? [] : lowerings.map((_, i) => i).slice(1).reverse();
442
+ if (!asked.some((i) => lowerings[i].plugin.methodCall)) return void 0;
370
443
  const receiver = this.options.types?.typeOf.get(node.object);
371
444
  const receiverGlobal = this.globalName(node.object);
372
445
  const info = this.lazyArguments(node.arguments);
373
- for (let i = lowerings.length - 1; i >= 0; i--) {
374
- const plugin = lowerings[i].plugin;
375
- if (!plugin.methodCall) continue;
376
- const answer = plugin.methodCall({
446
+ for (const i of asked) {
447
+ const plugin2 = lowerings[i].plugin;
448
+ if (!plugin2.methodCall) continue;
449
+ const answer = plugin2.methodCall({
377
450
  method: node.method.name,
378
451
  receiver,
379
452
  receiverGlobal,
@@ -396,15 +469,15 @@ var Lowerer = class {
396
469
  }
397
470
  /** What a library says a call to a global — `print(x)` — is. */
398
471
  loweredGlobalCall(node) {
399
- const lowerings = this.options.lowerings;
472
+ const lowerings = this.lowerings;
400
473
  if (!lowerings?.some((l) => l.plugin.globalCall)) return void 0;
401
474
  const name = this.globalName(node.callee);
402
475
  if (name === void 0) return void 0;
403
476
  const info = this.lazyArguments(node.arguments);
404
477
  for (let i = lowerings.length - 1; i >= 0; i--) {
405
- const plugin = lowerings[i].plugin;
406
- if (!plugin.globalCall) continue;
407
- const answer = plugin.globalCall({
478
+ const plugin2 = lowerings[i].plugin;
479
+ if (!plugin2.globalCall) continue;
480
+ const answer = plugin2.globalCall({
408
481
  name,
409
482
  at: this.callSite(node.callee),
410
483
  get arguments() {
@@ -418,7 +491,7 @@ var Lowerer = class {
418
491
  }
419
492
  /** What a library says a global read as a value — `local p = print` — is. */
420
493
  loweredGlobalValue(node) {
421
- const lowerings = this.options.lowerings;
494
+ const lowerings = this.lowerings;
422
495
  if (!lowerings?.some((l) => l.plugin.globalValue)) return void 0;
423
496
  const name = this.globalName(node);
424
497
  if (name === void 0) return void 0;
@@ -448,7 +521,7 @@ var Lowerer = class {
448
521
  try {
449
522
  return (0, import_luau_parser.parseExpressionFromSource)(source);
450
523
  } catch (error) {
451
- this.report(node, `'${this.options.lowerings[index2].from}' lowered this to Luau that does not parse: ${JSON.stringify(source)} (${error.message})`);
524
+ this.report(node, `'${this.lowerings[index2].from}' lowered this to Luau that does not parse: ${JSON.stringify(source)} (${error.message})`);
452
525
  return void 0;
453
526
  }
454
527
  }
@@ -469,8 +542,8 @@ var Lowerer = class {
469
542
  ], true)));
470
543
  }
471
544
  for (const { index: index2, runtime: runtime2, name } of this.loweringUsed) {
472
- const { plugin, from } = this.options.lowerings[index2];
473
- const source = plugin.runtime?.[runtime2];
545
+ const { plugin: plugin2, from } = this.lowerings[index2];
546
+ const source = plugin2.runtime?.[runtime2];
474
547
  if (source === void 0) {
475
548
  this.diagnostics.push({
476
549
  message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
@@ -805,6 +878,7 @@ var Lowerer = class {
805
878
  case "ExportTypeAliasStatement":
806
879
  case "DeclareStatement":
807
880
  case "DeclareClassStatement":
881
+ case "DeclareMetatableStatement":
808
882
  case "ErrorStatement":
809
883
  return [];
810
884
  case "VariableDeclaration":
@@ -882,12 +956,13 @@ var Lowerer = class {
882
956
  }];
883
957
  case "GenericForStatement": {
884
958
  const prelude = [];
959
+ const variable = declared(node.variable);
885
960
  let item;
886
- if (node.variable.type === "IdentifierPattern") {
887
- item = this.name(node.variable.name);
961
+ if (variable.type === "IdentifierPattern") {
962
+ item = this.name(variable.name);
888
963
  } else {
889
964
  item = this.names.fresh("item");
890
- prelude.push(...this.destructure(node.variable, identifier(item), "declare"));
965
+ prelude.push(...this.destructure(variable, identifier(item), "declare"));
891
966
  }
892
967
  const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
893
968
  let source = this.expression(node.iterator);
@@ -1154,7 +1229,7 @@ end
1154
1229
  * level, where every name is declared up front — nothing is declared,
1155
1230
  * only assigned. */
1156
1231
  variableDeclaration(node, mode) {
1157
- const target = node.name;
1232
+ const target = declared(node.name);
1158
1233
  if (!node.init) {
1159
1234
  const names = identifierPatterns(target);
1160
1235
  if (mode === "declare") return [local(names.map((p) => this.name(p.name)), [])];
@@ -1196,6 +1271,12 @@ end
1196
1271
  const reads = [];
1197
1272
  const after = [];
1198
1273
  const bind = (target, value, fallback) => {
1274
+ if (target.type === "MemberExpression" || target.type === "IndexExpression") {
1275
+ const reference = this.expression(target);
1276
+ reads.push({ name: "", target: reference, value, temp: false });
1277
+ if (fallback) after.push(this.defaultValue(reference, fallback));
1278
+ return;
1279
+ }
1199
1280
  if (target.type === "IdentifierPattern") {
1200
1281
  const name2 = this.name(target.name);
1201
1282
  const reference = mode === "declare" ? identifier(name2) : this.reference(target);
@@ -1268,6 +1349,11 @@ end
1268
1349
  * a temporary that a nested pattern then destructures (`then`). The
1269
1350
  * statement creating it is pushed onto `after`. */
1270
1351
  restTarget(target, initial, mode, after) {
1352
+ if (target.type === "MemberExpression" || target.type === "IndexExpression") {
1353
+ const reference = this.expression(target);
1354
+ after.push(assign([reference], [initial]));
1355
+ return { target: reference, then: [] };
1356
+ }
1271
1357
  if (target.type === "IdentifierPattern") {
1272
1358
  if (mode === "declare") {
1273
1359
  const name2 = this.name(target.name);
@@ -1393,11 +1479,11 @@ end
1393
1479
  callValues(node) {
1394
1480
  const chain = optionalChain(node);
1395
1481
  if (chain) return this.optionalChainExpression(chain);
1396
- const object = linkObject(node);
1397
- if (node.type === "CallExpression" && object.type === "Identifier") {
1398
- return this.link(node, this.reference(object));
1482
+ const object2 = linkObject(node);
1483
+ if (node.type === "CallExpression" && object2.type === "Identifier") {
1484
+ return this.link(node, this.reference(object2));
1399
1485
  }
1400
- return this.link(node, this.expression(object));
1486
+ return this.link(node, this.expression(object2));
1401
1487
  }
1402
1488
  /** A call is one value in tilua, and Luau would hand on every value one
1403
1489
  * returns in the last place of an argument list or a `return`: it is
@@ -1416,11 +1502,13 @@ end
1416
1502
  * the last value of a list expands, so the whole list is built as an
1417
1503
  * array first and that is what expands. A call written last is one
1418
1504
  * value — see `keptToOne`. */
1419
- arguments(list) {
1505
+ arguments(written) {
1506
+ const { items: list, many } = packs(written);
1420
1507
  const spreads = list.filter((a) => a.type === "SpreadElement");
1421
1508
  if (!spreads.length) {
1422
1509
  const lowered = list.map((a) => this.expression(a));
1423
- return lowered.length ? [...lowered.slice(0, -1), this.keptToOne(lowered[lowered.length - 1])] : lowered;
1510
+ const last2 = list.length - 1;
1511
+ return lowered.length && !many.has(list[last2]) ? [...lowered.slice(0, -1), this.keptToOne(lowered[last2])] : lowered;
1424
1512
  }
1425
1513
  const unpack = (value) => call(member(this.builtin("table"), "unpack"), [value]);
1426
1514
  const last = list[list.length - 1];
@@ -1434,16 +1522,16 @@ end
1434
1522
  }))];
1435
1523
  }
1436
1524
  /** One link of an access chain, read from `object`. */
1437
- link(node, object) {
1525
+ link(node, object2) {
1438
1526
  switch (node.type) {
1439
1527
  case "MemberExpression":
1440
- return member(object, node.property.name);
1528
+ return member(object2, node.property.name);
1441
1529
  case "IndexExpression":
1442
- return index(object, this.expression(node.index));
1530
+ return index(object2, this.expression(node.index));
1443
1531
  case "CallExpression": {
1444
1532
  const lowered = this.loweredGlobalCall(node);
1445
1533
  const args = this.arguments(node.arguments);
1446
- if (!lowered) return call(object, args);
1534
+ if (!lowered) return call(object2, args);
1447
1535
  return call(calleePath(lowered.callee), [...lowered.prepend, ...args]);
1448
1536
  }
1449
1537
  case "MethodCallExpression": {
@@ -1452,14 +1540,14 @@ end
1452
1540
  if (lowered) {
1453
1541
  return call(calleePath(lowered.callee), [
1454
1542
  ...lowered.prepend,
1455
- ...lowered.passReceiver ? [object] : [],
1543
+ ...lowered.passReceiver ? [object2] : [],
1456
1544
  ...args
1457
1545
  ]);
1458
1546
  }
1459
1547
  if (!isLuauName(node.method.name)) {
1460
1548
  this.report(node.method, `'${node.method.name}' is a Luau keyword and cannot be called with ':'`);
1461
1549
  }
1462
- return methodCall(object, node.method.name, args);
1550
+ return methodCall(object2, node.method.name, args);
1463
1551
  }
1464
1552
  }
1465
1553
  }
@@ -1480,8 +1568,8 @@ end
1480
1568
  }
1481
1569
  return out;
1482
1570
  }
1483
- applySegment(segment, object) {
1484
- return segment.reduce((value, link) => this.link(link, value), object);
1571
+ applySegment(segment, object2) {
1572
+ return segment.reduce((value, link) => this.link(link, value), object2);
1485
1573
  }
1486
1574
  /** `a?.b:m()` as a statement:
1487
1575
  * `do local ref = a if ref ~= nil then ref.b:m() end end` */
@@ -1557,9 +1645,9 @@ end
1557
1645
  const before = [];
1558
1646
  let target;
1559
1647
  if (node.target.type === "MemberExpression" || node.target.type === "IndexExpression") {
1560
- const object = this.expression(node.target.object);
1648
+ const object2 = this.expression(node.target.object);
1561
1649
  const objectName = this.names.fresh("target");
1562
- before.push(local([objectName], [object]));
1650
+ before.push(local([objectName], [object2]));
1563
1651
  if (node.target.type === "MemberExpression") {
1564
1652
  target = member(identifier(objectName), node.target.property.name);
1565
1653
  } else {
@@ -1681,8 +1769,9 @@ end
1681
1769
  /** `[1, ...xs, 2]`. Without a spread it is a Luau sequence; with one, the
1682
1770
  * runs of plain elements and the spread arrays are joined by `concat`. */
1683
1771
  arrayExpression(node) {
1684
- if (!node.elements.some((e) => e.type === "SpreadElement")) {
1685
- return table(node.elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
1772
+ const elements = packs(node.elements).items;
1773
+ if (!elements.some((e) => e.type === "SpreadElement")) {
1774
+ return table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
1686
1775
  }
1687
1776
  const parts = [];
1688
1777
  let current = [];
@@ -1694,7 +1783,7 @@ end
1694
1783
  })));
1695
1784
  current = [];
1696
1785
  };
1697
- for (const element of node.elements) {
1786
+ for (const element of elements) {
1698
1787
  if (element.type === "SpreadElement") {
1699
1788
  flush(false);
1700
1789
  parts.push(this.expression(element.argument));
@@ -1706,6 +1795,29 @@ end
1706
1795
  return call(this.helper("concat"), parts);
1707
1796
  }
1708
1797
  };
1798
+ function packs(list) {
1799
+ const items = [];
1800
+ const many = /* @__PURE__ */ new Set();
1801
+ const add = (elements) => {
1802
+ for (const element of elements) {
1803
+ if (element.type === "SpreadElement" && element.argument.type === "ArrayExpression") {
1804
+ const inner = element.argument.elements;
1805
+ add(inner);
1806
+ const last = inner[inner.length - 1];
1807
+ if (last && (last.type === "CallExpression" || last.type === "MethodCallExpression")) many.add(last);
1808
+ } else {
1809
+ items.push(element);
1810
+ }
1811
+ }
1812
+ };
1813
+ add(list);
1814
+ items.forEach((item, i) => {
1815
+ if (!many.has(item) || i === items.length - 1) return;
1816
+ many.delete(item);
1817
+ items[i] = { type: "SpreadElement", argument: { type: "ArrayExpression", elements: [item], ...spanOf(item) }, ...spanOf(item) };
1818
+ });
1819
+ return { items, many };
1820
+ }
1709
1821
  function isLink(node) {
1710
1822
  return node.type === "MemberExpression" || node.type === "IndexExpression" || node.type === "CallExpression" || node.type === "MethodCallExpression";
1711
1823
  }
@@ -1754,10 +1866,19 @@ function memberChain(e) {
1754
1866
  }
1755
1867
  return void 0;
1756
1868
  }
1869
+ function declared(target) {
1870
+ if (target.type === "MemberExpression" || target.type === "IndexExpression") {
1871
+ throw new Error("a declaration binds names, not a member or an index");
1872
+ }
1873
+ return target;
1874
+ }
1757
1875
  function identifierPatterns(target) {
1758
1876
  switch (target.type) {
1759
1877
  case "IdentifierPattern":
1760
1878
  return [target];
1879
+ case "MemberExpression":
1880
+ case "IndexExpression":
1881
+ return [];
1761
1882
  case "ObjectPattern":
1762
1883
  return [...target.properties.flatMap((p) => identifierPatterns(p.value)), ...target.rest ? identifierPatterns(target.rest) : []];
1763
1884
  case "ArrayPattern":
@@ -1944,15 +2065,15 @@ async function loadLowerings(modules) {
1944
2065
  for (const module2 of modules) {
1945
2066
  try {
1946
2067
  const loaded = await import((0, import_node_url.pathToFileURL)(module2.file).href);
1947
- const plugin = loaded.default;
1948
- if (!plugin || typeof plugin !== "object") {
2068
+ const plugin2 = loaded.default;
2069
+ if (!plugin2 || typeof plugin2 !== "object") {
1949
2070
  problems.push({
1950
2071
  file: module2.file,
1951
2072
  message: `'${module2.from}' lowering module has no default export`
1952
2073
  });
1953
2074
  continue;
1954
2075
  }
1955
- lowerings.push({ plugin, from: module2.from });
2076
+ lowerings.push({ plugin: plugin2, from: module2.from, library: module2.library });
1956
2077
  } catch (error) {
1957
2078
  problems.push({
1958
2079
  file: module2.file,
@@ -2204,7 +2325,7 @@ ${G} = {
2204
2325
  }
2205
2326
  function stampOf(file) {
2206
2327
  try {
2207
- const at = (0, import_node_fs.statSync)(file);
2328
+ const at = (0, import_node_fs2.statSync)(file);
2208
2329
  return `${at.size}:${at.mtimeMs}`;
2209
2330
  } catch {
2210
2331
  return void 0;
@@ -2220,7 +2341,7 @@ function parseFile(file, diagnostics, directives) {
2220
2341
  }
2221
2342
  let text;
2222
2343
  try {
2223
- text = (0, import_node_fs.readFileSync)(file, "utf8");
2344
+ text = (0, import_node_fs2.readFileSync)(file, "utf8");
2224
2345
  } catch {
2225
2346
  diagnostics.push({ file, message: "Cannot read file", line: 1, column: 1, category: "module" });
2226
2347
  return void 0;
@@ -2247,14 +2368,14 @@ var libraryCache = /* @__PURE__ */ new Map();
2247
2368
  function parsedLibrary(file) {
2248
2369
  let stamp;
2249
2370
  try {
2250
- const at = (0, import_node_fs.statSync)(file);
2371
+ const at = (0, import_node_fs2.statSync)(file);
2251
2372
  stamp = `${at.size}:${at.mtimeMs}`;
2252
2373
  } catch {
2253
2374
  stamp = "";
2254
2375
  }
2255
2376
  const cached = libraryCache.get(file);
2256
2377
  if (cached && cached.stamp === stamp) return cached.program;
2257
- const program2 = (0, import_parser3.parse)((0, import_node_fs.readFileSync)(file, "utf8"));
2378
+ const program2 = (0, import_parser3.parse)((0, import_node_fs2.readFileSync)(file, "utf8"));
2258
2379
  libraryCache.set(file, { stamp, program: program2 });
2259
2380
  return program2;
2260
2381
  }
@@ -2277,7 +2398,7 @@ function analyzeModules(modules, config) {
2277
2398
  const done = analyzed.get(file);
2278
2399
  if (done) return done;
2279
2400
  const remembered = moduleAnalyses.get(file);
2280
- if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program2 && [...remembered.read].every(([read, stamp]) => stampOf(read) === stamp)) {
2401
+ if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program2 && [...remembered.read].every(([read2, stamp]) => stampOf(read2) === stamp)) {
2281
2402
  analyzed.set(file, remembered.result);
2282
2403
  readWhile.set(file, remembered.read);
2283
2404
  return remembered.result;
@@ -2301,12 +2422,12 @@ function analyzeModules(modules, config) {
2301
2422
  const result = { types, diagnostics: said };
2302
2423
  if (partials === before) {
2303
2424
  analyzed.set(file, result);
2304
- const read = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2425
+ const read2 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2305
2426
  const own = stampOf(file);
2306
- if (own !== void 0) read.set(file, own);
2307
- readWhile.set(file, read);
2308
- if ([...read.values()].every((stamp) => stamp !== void 0)) {
2309
- moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read, result });
2427
+ if (own !== void 0) read2.set(file, own);
2428
+ readWhile.set(file, read2);
2429
+ if ([...read2.values()].every((stamp) => stamp !== void 0)) {
2430
+ moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read: read2, result });
2310
2431
  }
2311
2432
  }
2312
2433
  return result;
@@ -2315,11 +2436,11 @@ function analyzeModules(modules, config) {
2315
2436
  const target = (0, import_parser3.resolveModulePath)(file, specifier, config);
2316
2437
  if (!target) return void 0;
2317
2438
  const noteRead = () => {
2318
- const read = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2319
- readWhile.set(file, read);
2439
+ const read2 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2440
+ readWhile.set(file, read2);
2320
2441
  const stamp = stampOf(target);
2321
- if (stamp !== void 0) read.set(target, stamp);
2322
- for (const [below, belowStamp] of readWhile.get(target) ?? []) read.set(below, belowStamp);
2442
+ if (stamp !== void 0) read2.set(target, stamp);
2443
+ for (const [below, belowStamp] of readWhile.get(target) ?? []) read2.set(below, belowStamp);
2323
2444
  };
2324
2445
  if (inProgress.has(target)) {
2325
2446
  partials++;
@@ -2333,7 +2454,7 @@ function analyzeModules(modules, config) {
2333
2454
  let program2 = byFile.get(target)?.program;
2334
2455
  if (!program2) {
2335
2456
  try {
2336
- program2 = (0, import_parser3.parse)((0, import_node_fs.readFileSync)(target, "utf8"));
2457
+ program2 = (0, import_parser3.parse)((0, import_node_fs2.readFileSync)(target, "utf8"));
2337
2458
  } catch {
2338
2459
  return void 0;
2339
2460
  }
@@ -2375,7 +2496,7 @@ function allStatements(statements) {
2375
2496
  }
2376
2497
 
2377
2498
  // src/compile.ts
2378
- var import_node_fs2 = require("fs");
2499
+ var import_node_fs3 = require("fs");
2379
2500
  var import_node_path3 = require("path");
2380
2501
  var import_parser4 = require("@tilua/parser");
2381
2502
  var import_luau_parser3 = require("luau-parser");
@@ -2403,7 +2524,7 @@ async function compile(source, config) {
2403
2524
  diagnostics.push({ message: p.message, line: p.line ?? 1, column: p.column ?? 1 });
2404
2525
  }
2405
2526
  for (const p of loweringProblems) diagnostics.push({ message: p.message, line: 1, column: 1 });
2406
- const libs = libraries.files.map((file) => (0, import_parser4.parse)((0, import_node_fs2.readFileSync)(file, "utf8")));
2527
+ const libs = libraries.files.map((file) => (0, import_parser4.parse)((0, import_node_fs3.readFileSync)(file, "utf8")));
2407
2528
  const lowered = lower(program2, scopes, {
2408
2529
  types: (0, import_parser4.analyzeTypes)(program2, scopes, { libs, diagnostics: false }),
2409
2530
  lowerings,
package/dist/index.d.cts CHANGED
@@ -29,6 +29,10 @@ interface LoadedLowering {
29
29
  readonly plugin: LoweringPlugin;
30
30
  /** The package it came from, for reporting. */
31
31
  readonly from: string;
32
+ /** The package's definitions, as their index in the libraries the
33
+ * analyzer was given: a method read from a metatable they declare is
34
+ * this lowering's to answer. Absent for the language's own. */
35
+ readonly library?: number;
32
36
  }
33
37
  interface LoweringProblem {
34
38
  readonly file: string;
@@ -40,6 +44,7 @@ interface LoweringProblem {
40
44
  declare function loadLowerings(modules: readonly {
41
45
  file: string;
42
46
  from: string;
47
+ library?: number;
43
48
  }[]): Promise<{
44
49
  lowerings: LoadedLowering[];
45
50
  problems: LoweringProblem[];
package/dist/index.d.ts CHANGED
@@ -29,6 +29,10 @@ interface LoadedLowering {
29
29
  readonly plugin: LoweringPlugin;
30
30
  /** The package it came from, for reporting. */
31
31
  readonly from: string;
32
+ /** The package's definitions, as their index in the libraries the
33
+ * analyzer was given: a method read from a metatable they declare is
34
+ * this lowering's to answer. Absent for the language's own. */
35
+ readonly library?: number;
32
36
  }
33
37
  interface LoweringProblem {
34
38
  readonly file: string;
@@ -40,6 +44,7 @@ interface LoweringProblem {
40
44
  declare function loadLowerings(modules: readonly {
41
45
  file: string;
42
46
  from: string;
47
+ library?: number;
43
48
  }[]): Promise<{
44
49
  lowerings: LoadedLowering[];
45
50
  problems: LoweringProblem[];
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  lower,
5
5
  program,
6
6
  resolveConfig
7
- } from "./chunk-HE6YH7U3.js";
7
+ } from "./chunk-X4DM2BX2.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": "2.3.0",
3
+ "version": "3.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",
@@ -9,7 +9,8 @@
9
9
  "tilua": "dist/cli.js"
10
10
  },
11
11
  "files": [
12
- "dist"
12
+ "dist",
13
+ "runtime"
13
14
  ],
14
15
  "exports": {
15
16
  ".": {
@@ -37,7 +38,7 @@
37
38
  "type": "module",
38
39
  "dependencies": {
39
40
  "luau-parser": "^1.0.3",
40
- "@tilua/parser": "^2.3.0"
41
+ "@tilua/parser": "^3.0.0"
41
42
  },
42
43
  "devDependencies": {
43
44
  "@types/node": "^22.20.2",