@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/{chunk-HE6YH7U3.js → chunk-X4DM2BX2.js} +179 -62
- package/dist/cli.cjs +187 -66
- package/dist/cli.js +1 -1
- package/dist/index.cjs +187 -66
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -1
- package/package.json +4 -3
- package/runtime/array.luau +179 -0
- package/runtime/object.luau +54 -0
- package/runtime/string.luau +119 -0
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
|
|
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 = (
|
|
61
|
-
var index = (
|
|
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 = (
|
|
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
|
-
/**
|
|
363
|
-
*
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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.
|
|
369
|
-
|
|
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 (
|
|
374
|
-
const
|
|
375
|
-
if (!
|
|
376
|
-
const answer =
|
|
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.
|
|
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
|
|
406
|
-
if (!
|
|
407
|
-
const answer =
|
|
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.
|
|
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.
|
|
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.
|
|
473
|
-
const source =
|
|
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 (
|
|
887
|
-
item = this.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(
|
|
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
|
|
1397
|
-
if (node.type === "CallExpression" &&
|
|
1398
|
-
return this.link(node, this.reference(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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,
|
|
1525
|
+
link(node, object2) {
|
|
1438
1526
|
switch (node.type) {
|
|
1439
1527
|
case "MemberExpression":
|
|
1440
|
-
return member(
|
|
1528
|
+
return member(object2, node.property.name);
|
|
1441
1529
|
case "IndexExpression":
|
|
1442
|
-
return 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(
|
|
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 ? [
|
|
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(
|
|
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,
|
|
1484
|
-
return segment.reduce((value, link) => this.link(link, value),
|
|
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
|
|
1648
|
+
const object2 = this.expression(node.target.object);
|
|
1561
1649
|
const objectName = this.names.fresh("target");
|
|
1562
|
-
before.push(local([objectName], [
|
|
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
|
-
|
|
1685
|
-
|
|
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
|
|
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
|
|
1948
|
-
if (!
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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(([
|
|
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
|
|
2425
|
+
const read2 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
2305
2426
|
const own = stampOf(file);
|
|
2306
|
-
if (own !== void 0)
|
|
2307
|
-
readWhile.set(file,
|
|
2308
|
-
if ([...
|
|
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
|
|
2319
|
-
readWhile.set(file,
|
|
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)
|
|
2322
|
-
for (const [below, belowStamp] of readWhile.get(target) ?? [])
|
|
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,
|
|
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
|
|
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,
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tilua/compiler",
|
|
3
|
-
"version": "
|
|
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": "^
|
|
41
|
+
"@tilua/parser": "^3.0.0"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/node": "^22.20.2",
|