@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/cli.cjs
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
5
|
+
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;
|
|
6
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
7
|
+
|
|
4
8
|
// src/cli.ts
|
|
5
|
-
var
|
|
9
|
+
var import_node_fs3 = require("fs");
|
|
6
10
|
var import_node_path3 = require("path");
|
|
7
11
|
|
|
8
12
|
// src/bundle.ts
|
|
9
|
-
var
|
|
13
|
+
var import_node_fs2 = require("fs");
|
|
10
14
|
var import_node_path2 = require("path");
|
|
11
15
|
var import_parser3 = require("@tilua/parser");
|
|
12
16
|
var import_luau_parser2 = require("luau-parser");
|
|
@@ -34,10 +38,10 @@ var nil = () => ({ type: "NilLiteral", ...span() });
|
|
|
34
38
|
var boolean = (value) => ({ type: "BooleanLiteral", value, ...span() });
|
|
35
39
|
var number = (value, raw = String(value)) => ({ type: "NumberLiteral", value, raw, ...span() });
|
|
36
40
|
var string = (value) => ({ type: "StringLiteral", value, raw: "", ...span() });
|
|
37
|
-
var member = (
|
|
38
|
-
var index = (
|
|
41
|
+
var member = (object2, property) => isLuauName(property) ? { type: "MemberExpression", object: object2, property: identifier(property), ...span() } : index(object2, string(property));
|
|
42
|
+
var index = (object2, key) => ({ type: "IndexExpression", object: object2, index: key, ...span() });
|
|
39
43
|
var call = (callee, args2) => ({ type: "CallExpression", callee, arguments: args2, ...span() });
|
|
40
|
-
var methodCall = (
|
|
44
|
+
var methodCall = (object2, method, args2) => ({ type: "MethodCallExpression", object: object2, method: identifier(method), arguments: args2, ...span() });
|
|
41
45
|
var functionExpression = (func) => ({ type: "FunctionExpression", func, ...span() });
|
|
42
46
|
var binary = (operator, left, right) => ({ type: "BinaryExpression", operator, left, right, ...span() });
|
|
43
47
|
var unary = (operator, argument) => ({ type: "UnaryExpression", operator, argument, ...span() });
|
|
@@ -152,6 +156,62 @@ var Names = class _Names {
|
|
|
152
156
|
}
|
|
153
157
|
};
|
|
154
158
|
|
|
159
|
+
// src/language.ts
|
|
160
|
+
var import_node_fs = require("fs");
|
|
161
|
+
var read = (name) => (0, import_node_fs.readFileSync)(new URL(`../runtime/${name}`, importMetaUrl), "utf8");
|
|
162
|
+
var implemented = (source) => new Set([...source.matchAll(/function __NAME__\.(\w+)/g)].map((m) => m[1]));
|
|
163
|
+
var array = read("array.luau");
|
|
164
|
+
var string2 = read("string.luau");
|
|
165
|
+
var object = read("object.luau");
|
|
166
|
+
var arrayMethods = implemented(array);
|
|
167
|
+
var stringMethods = implemented(string2);
|
|
168
|
+
var objectMethods = implemented(object);
|
|
169
|
+
function every(type, is, seen = /* @__PURE__ */ new Set()) {
|
|
170
|
+
if (!type || seen.has(type)) return false;
|
|
171
|
+
seen.add(type);
|
|
172
|
+
if (type.kind === "union") {
|
|
173
|
+
return type.types.filter((m) => !(m.kind === "primitive" && m.name === "nil")).every((m) => every(m, is, seen));
|
|
174
|
+
}
|
|
175
|
+
if (type.kind === "typeParam") return every(type.constraint, is, seen);
|
|
176
|
+
return is(type);
|
|
177
|
+
}
|
|
178
|
+
var isArray = (type) => every(type, (t) => t.kind === "array" || t.kind === "tuple");
|
|
179
|
+
var isString = (type) => every(type, (t) => t.kind === "primitive" && t.name === "string" || t.kind === "literal" && t.base === "string" || t.kind === "templateLiteral");
|
|
180
|
+
function objectKeys(type) {
|
|
181
|
+
const members = type?.kind === "union" ? type.types : type ? [type] : [];
|
|
182
|
+
const orders = [];
|
|
183
|
+
let open = false;
|
|
184
|
+
for (const member2 of members) {
|
|
185
|
+
const keys = [];
|
|
186
|
+
for (const part of member2.kind === "intersection" ? member2.types : [member2]) {
|
|
187
|
+
if (part.kind !== "object") continue;
|
|
188
|
+
for (const key of part.properties.keys()) if (!keys.includes(key)) keys.push(key);
|
|
189
|
+
if (part.indexer) open = true;
|
|
190
|
+
}
|
|
191
|
+
orders.push(keys);
|
|
192
|
+
}
|
|
193
|
+
const order = JSON.stringify(orders[0] ?? []);
|
|
194
|
+
const known = orders.length && orders.every((keys) => JSON.stringify(keys) === order) ? `{ ${orders[0].map((key) => JSON.stringify(key)).join(", ")} }` : "nil";
|
|
195
|
+
return { known, open: String(open) };
|
|
196
|
+
}
|
|
197
|
+
var plugin = {
|
|
198
|
+
runtime: { array, string: string2, object },
|
|
199
|
+
methodCall({ method, receiver, use }) {
|
|
200
|
+
if (isString(receiver)) {
|
|
201
|
+
return stringMethods.has(method) ? { callee: `${use("string")}.${method}` } : void 0;
|
|
202
|
+
}
|
|
203
|
+
if (isArray(receiver)) {
|
|
204
|
+
return arrayMethods.has(method) ? { callee: `${use("array")}.${method}` } : void 0;
|
|
205
|
+
}
|
|
206
|
+
if (objectMethods.has(method)) {
|
|
207
|
+
const keys = objectKeys(receiver);
|
|
208
|
+
return { callee: `${use("object")}.${method}`, prepend: [keys.known, keys.open] };
|
|
209
|
+
}
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
var languageLowering = { plugin, from: "tilua" };
|
|
214
|
+
|
|
155
215
|
// src/lower.ts
|
|
156
216
|
function lower(program, scopes, options = {}) {
|
|
157
217
|
return new Lowerer(program, scopes, options).run();
|
|
@@ -335,21 +395,34 @@ var Lowerer = class {
|
|
|
335
395
|
if (id === void 0) return node.name;
|
|
336
396
|
return this.scopes.bindings.get(id)?.kind === "global" ? node.name : void 0;
|
|
337
397
|
}
|
|
338
|
-
/**
|
|
339
|
-
*
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
398
|
+
/** The language's own lowering, then each library's, in load order. A
|
|
399
|
+
* runtime is named by its lowering's place here (`loweringRuntime`). */
|
|
400
|
+
get lowerings() {
|
|
401
|
+
return this.allLowerings ??= [languageLowering, ...this.options.lowerings ?? []];
|
|
402
|
+
}
|
|
403
|
+
allLowerings;
|
|
404
|
+
/** What `receiver:method(...)` becomes, when Luau alone would not run it.
|
|
405
|
+
*
|
|
406
|
+
* A method the receiver's metatable gave it — the analyzer says so, and
|
|
407
|
+
* whose metatable it was (`methodSources`) — is asked of whoever declared
|
|
408
|
+
* that metatable, and only them: the language lowers its own
|
|
409
|
+
* (`names:filter(f)` becomes a call into its runtime), a library its own,
|
|
410
|
+
* and one the program declared is taken at its word. Any other method is
|
|
411
|
+
* a member of the receiver's own, which a library may still claim
|
|
412
|
+
* (`console:log`), the last library loaded first. No answer leaves an
|
|
413
|
+
* ordinary Luau method call: `text:upper()` reaches Lua's own. */
|
|
343
414
|
loweredMethodCall(node) {
|
|
344
|
-
const lowerings = this.
|
|
345
|
-
|
|
415
|
+
const lowerings = this.lowerings;
|
|
416
|
+
const source = this.options.types?.methodSources.get(node);
|
|
417
|
+
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();
|
|
418
|
+
if (!asked.some((i) => lowerings[i].plugin.methodCall)) return void 0;
|
|
346
419
|
const receiver = this.options.types?.typeOf.get(node.object);
|
|
347
420
|
const receiverGlobal = this.globalName(node.object);
|
|
348
421
|
const info = this.lazyArguments(node.arguments);
|
|
349
|
-
for (
|
|
350
|
-
const
|
|
351
|
-
if (!
|
|
352
|
-
const answer =
|
|
422
|
+
for (const i of asked) {
|
|
423
|
+
const plugin2 = lowerings[i].plugin;
|
|
424
|
+
if (!plugin2.methodCall) continue;
|
|
425
|
+
const answer = plugin2.methodCall({
|
|
353
426
|
method: node.method.name,
|
|
354
427
|
receiver,
|
|
355
428
|
receiverGlobal,
|
|
@@ -372,15 +445,15 @@ var Lowerer = class {
|
|
|
372
445
|
}
|
|
373
446
|
/** What a library says a call to a global — `print(x)` — is. */
|
|
374
447
|
loweredGlobalCall(node) {
|
|
375
|
-
const lowerings = this.
|
|
448
|
+
const lowerings = this.lowerings;
|
|
376
449
|
if (!lowerings?.some((l) => l.plugin.globalCall)) return void 0;
|
|
377
450
|
const name = this.globalName(node.callee);
|
|
378
451
|
if (name === void 0) return void 0;
|
|
379
452
|
const info = this.lazyArguments(node.arguments);
|
|
380
453
|
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
381
|
-
const
|
|
382
|
-
if (!
|
|
383
|
-
const answer =
|
|
454
|
+
const plugin2 = lowerings[i].plugin;
|
|
455
|
+
if (!plugin2.globalCall) continue;
|
|
456
|
+
const answer = plugin2.globalCall({
|
|
384
457
|
name,
|
|
385
458
|
at: this.callSite(node.callee),
|
|
386
459
|
get arguments() {
|
|
@@ -394,7 +467,7 @@ var Lowerer = class {
|
|
|
394
467
|
}
|
|
395
468
|
/** What a library says a global read as a value — `local p = print` — is. */
|
|
396
469
|
loweredGlobalValue(node) {
|
|
397
|
-
const lowerings = this.
|
|
470
|
+
const lowerings = this.lowerings;
|
|
398
471
|
if (!lowerings?.some((l) => l.plugin.globalValue)) return void 0;
|
|
399
472
|
const name = this.globalName(node);
|
|
400
473
|
if (name === void 0) return void 0;
|
|
@@ -424,7 +497,7 @@ var Lowerer = class {
|
|
|
424
497
|
try {
|
|
425
498
|
return (0, import_luau_parser.parseExpressionFromSource)(source);
|
|
426
499
|
} catch (error) {
|
|
427
|
-
this.report(node, `'${this.
|
|
500
|
+
this.report(node, `'${this.lowerings[index2].from}' lowered this to Luau that does not parse: ${JSON.stringify(source)} (${error.message})`);
|
|
428
501
|
return void 0;
|
|
429
502
|
}
|
|
430
503
|
}
|
|
@@ -445,8 +518,8 @@ var Lowerer = class {
|
|
|
445
518
|
], true)));
|
|
446
519
|
}
|
|
447
520
|
for (const { index: index2, runtime: runtime2, name } of this.loweringUsed) {
|
|
448
|
-
const { plugin, from } = this.
|
|
449
|
-
const source =
|
|
521
|
+
const { plugin: plugin2, from } = this.lowerings[index2];
|
|
522
|
+
const source = plugin2.runtime?.[runtime2];
|
|
450
523
|
if (source === void 0) {
|
|
451
524
|
this.diagnostics.push({
|
|
452
525
|
message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
|
|
@@ -781,6 +854,7 @@ var Lowerer = class {
|
|
|
781
854
|
case "ExportTypeAliasStatement":
|
|
782
855
|
case "DeclareStatement":
|
|
783
856
|
case "DeclareClassStatement":
|
|
857
|
+
case "DeclareMetatableStatement":
|
|
784
858
|
case "ErrorStatement":
|
|
785
859
|
return [];
|
|
786
860
|
case "VariableDeclaration":
|
|
@@ -858,12 +932,13 @@ var Lowerer = class {
|
|
|
858
932
|
}];
|
|
859
933
|
case "GenericForStatement": {
|
|
860
934
|
const prelude = [];
|
|
935
|
+
const variable = declared(node.variable);
|
|
861
936
|
let item;
|
|
862
|
-
if (
|
|
863
|
-
item = this.name(
|
|
937
|
+
if (variable.type === "IdentifierPattern") {
|
|
938
|
+
item = this.name(variable.name);
|
|
864
939
|
} else {
|
|
865
940
|
item = this.names.fresh("item");
|
|
866
|
-
prelude.push(...this.destructure(
|
|
941
|
+
prelude.push(...this.destructure(variable, identifier(item), "declare"));
|
|
867
942
|
}
|
|
868
943
|
const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
|
|
869
944
|
let source = this.expression(node.iterator);
|
|
@@ -1130,7 +1205,7 @@ end
|
|
|
1130
1205
|
* level, where every name is declared up front — nothing is declared,
|
|
1131
1206
|
* only assigned. */
|
|
1132
1207
|
variableDeclaration(node, mode) {
|
|
1133
|
-
const target = node.name;
|
|
1208
|
+
const target = declared(node.name);
|
|
1134
1209
|
if (!node.init) {
|
|
1135
1210
|
const names = identifierPatterns(target);
|
|
1136
1211
|
if (mode === "declare") return [local(names.map((p) => this.name(p.name)), [])];
|
|
@@ -1172,6 +1247,12 @@ end
|
|
|
1172
1247
|
const reads = [];
|
|
1173
1248
|
const after = [];
|
|
1174
1249
|
const bind = (target, value, fallback) => {
|
|
1250
|
+
if (target.type === "MemberExpression" || target.type === "IndexExpression") {
|
|
1251
|
+
const reference = this.expression(target);
|
|
1252
|
+
reads.push({ name: "", target: reference, value, temp: false });
|
|
1253
|
+
if (fallback) after.push(this.defaultValue(reference, fallback));
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1175
1256
|
if (target.type === "IdentifierPattern") {
|
|
1176
1257
|
const name2 = this.name(target.name);
|
|
1177
1258
|
const reference = mode === "declare" ? identifier(name2) : this.reference(target);
|
|
@@ -1244,6 +1325,11 @@ end
|
|
|
1244
1325
|
* a temporary that a nested pattern then destructures (`then`). The
|
|
1245
1326
|
* statement creating it is pushed onto `after`. */
|
|
1246
1327
|
restTarget(target, initial, mode, after) {
|
|
1328
|
+
if (target.type === "MemberExpression" || target.type === "IndexExpression") {
|
|
1329
|
+
const reference = this.expression(target);
|
|
1330
|
+
after.push(assign([reference], [initial]));
|
|
1331
|
+
return { target: reference, then: [] };
|
|
1332
|
+
}
|
|
1247
1333
|
if (target.type === "IdentifierPattern") {
|
|
1248
1334
|
if (mode === "declare") {
|
|
1249
1335
|
const name2 = this.name(target.name);
|
|
@@ -1369,11 +1455,11 @@ end
|
|
|
1369
1455
|
callValues(node) {
|
|
1370
1456
|
const chain = optionalChain(node);
|
|
1371
1457
|
if (chain) return this.optionalChainExpression(chain);
|
|
1372
|
-
const
|
|
1373
|
-
if (node.type === "CallExpression" &&
|
|
1374
|
-
return this.link(node, this.reference(
|
|
1458
|
+
const object2 = linkObject(node);
|
|
1459
|
+
if (node.type === "CallExpression" && object2.type === "Identifier") {
|
|
1460
|
+
return this.link(node, this.reference(object2));
|
|
1375
1461
|
}
|
|
1376
|
-
return this.link(node, this.expression(
|
|
1462
|
+
return this.link(node, this.expression(object2));
|
|
1377
1463
|
}
|
|
1378
1464
|
/** A call is one value in tilua, and Luau would hand on every value one
|
|
1379
1465
|
* returns in the last place of an argument list or a `return`: it is
|
|
@@ -1392,11 +1478,13 @@ end
|
|
|
1392
1478
|
* the last value of a list expands, so the whole list is built as an
|
|
1393
1479
|
* array first and that is what expands. A call written last is one
|
|
1394
1480
|
* value — see `keptToOne`. */
|
|
1395
|
-
arguments(
|
|
1481
|
+
arguments(written) {
|
|
1482
|
+
const { items: list, many } = packs(written);
|
|
1396
1483
|
const spreads = list.filter((a) => a.type === "SpreadElement");
|
|
1397
1484
|
if (!spreads.length) {
|
|
1398
1485
|
const lowered = list.map((a) => this.expression(a));
|
|
1399
|
-
|
|
1486
|
+
const last2 = list.length - 1;
|
|
1487
|
+
return lowered.length && !many.has(list[last2]) ? [...lowered.slice(0, -1), this.keptToOne(lowered[last2])] : lowered;
|
|
1400
1488
|
}
|
|
1401
1489
|
const unpack = (value) => call(member(this.builtin("table"), "unpack"), [value]);
|
|
1402
1490
|
const last = list[list.length - 1];
|
|
@@ -1410,16 +1498,16 @@ end
|
|
|
1410
1498
|
}))];
|
|
1411
1499
|
}
|
|
1412
1500
|
/** One link of an access chain, read from `object`. */
|
|
1413
|
-
link(node,
|
|
1501
|
+
link(node, object2) {
|
|
1414
1502
|
switch (node.type) {
|
|
1415
1503
|
case "MemberExpression":
|
|
1416
|
-
return member(
|
|
1504
|
+
return member(object2, node.property.name);
|
|
1417
1505
|
case "IndexExpression":
|
|
1418
|
-
return index(
|
|
1506
|
+
return index(object2, this.expression(node.index));
|
|
1419
1507
|
case "CallExpression": {
|
|
1420
1508
|
const lowered = this.loweredGlobalCall(node);
|
|
1421
1509
|
const args2 = this.arguments(node.arguments);
|
|
1422
|
-
if (!lowered) return call(
|
|
1510
|
+
if (!lowered) return call(object2, args2);
|
|
1423
1511
|
return call(calleePath(lowered.callee), [...lowered.prepend, ...args2]);
|
|
1424
1512
|
}
|
|
1425
1513
|
case "MethodCallExpression": {
|
|
@@ -1428,14 +1516,14 @@ end
|
|
|
1428
1516
|
if (lowered) {
|
|
1429
1517
|
return call(calleePath(lowered.callee), [
|
|
1430
1518
|
...lowered.prepend,
|
|
1431
|
-
...lowered.passReceiver ? [
|
|
1519
|
+
...lowered.passReceiver ? [object2] : [],
|
|
1432
1520
|
...args2
|
|
1433
1521
|
]);
|
|
1434
1522
|
}
|
|
1435
1523
|
if (!isLuauName(node.method.name)) {
|
|
1436
1524
|
this.report(node.method, `'${node.method.name}' is a Luau keyword and cannot be called with ':'`);
|
|
1437
1525
|
}
|
|
1438
|
-
return methodCall(
|
|
1526
|
+
return methodCall(object2, node.method.name, args2);
|
|
1439
1527
|
}
|
|
1440
1528
|
}
|
|
1441
1529
|
}
|
|
@@ -1456,8 +1544,8 @@ end
|
|
|
1456
1544
|
}
|
|
1457
1545
|
return out2;
|
|
1458
1546
|
}
|
|
1459
|
-
applySegment(segment,
|
|
1460
|
-
return segment.reduce((value, link) => this.link(link, value),
|
|
1547
|
+
applySegment(segment, object2) {
|
|
1548
|
+
return segment.reduce((value, link) => this.link(link, value), object2);
|
|
1461
1549
|
}
|
|
1462
1550
|
/** `a?.b:m()` as a statement:
|
|
1463
1551
|
* `do local ref = a if ref ~= nil then ref.b:m() end end` */
|
|
@@ -1533,9 +1621,9 @@ end
|
|
|
1533
1621
|
const before = [];
|
|
1534
1622
|
let target;
|
|
1535
1623
|
if (node.target.type === "MemberExpression" || node.target.type === "IndexExpression") {
|
|
1536
|
-
const
|
|
1624
|
+
const object2 = this.expression(node.target.object);
|
|
1537
1625
|
const objectName = this.names.fresh("target");
|
|
1538
|
-
before.push(local([objectName], [
|
|
1626
|
+
before.push(local([objectName], [object2]));
|
|
1539
1627
|
if (node.target.type === "MemberExpression") {
|
|
1540
1628
|
target = member(identifier(objectName), node.target.property.name);
|
|
1541
1629
|
} else {
|
|
@@ -1657,8 +1745,9 @@ end
|
|
|
1657
1745
|
/** `[1, ...xs, 2]`. Without a spread it is a Luau sequence; with one, the
|
|
1658
1746
|
* runs of plain elements and the spread arrays are joined by `concat`. */
|
|
1659
1747
|
arrayExpression(node) {
|
|
1660
|
-
|
|
1661
|
-
|
|
1748
|
+
const elements = packs(node.elements).items;
|
|
1749
|
+
if (!elements.some((e) => e.type === "SpreadElement")) {
|
|
1750
|
+
return table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
|
|
1662
1751
|
}
|
|
1663
1752
|
const parts = [];
|
|
1664
1753
|
let current = [];
|
|
@@ -1670,7 +1759,7 @@ end
|
|
|
1670
1759
|
})));
|
|
1671
1760
|
current = [];
|
|
1672
1761
|
};
|
|
1673
|
-
for (const element of
|
|
1762
|
+
for (const element of elements) {
|
|
1674
1763
|
if (element.type === "SpreadElement") {
|
|
1675
1764
|
flush(false);
|
|
1676
1765
|
parts.push(this.expression(element.argument));
|
|
@@ -1682,6 +1771,29 @@ end
|
|
|
1682
1771
|
return call(this.helper("concat"), parts);
|
|
1683
1772
|
}
|
|
1684
1773
|
};
|
|
1774
|
+
function packs(list) {
|
|
1775
|
+
const items = [];
|
|
1776
|
+
const many = /* @__PURE__ */ new Set();
|
|
1777
|
+
const add = (elements) => {
|
|
1778
|
+
for (const element of elements) {
|
|
1779
|
+
if (element.type === "SpreadElement" && element.argument.type === "ArrayExpression") {
|
|
1780
|
+
const inner = element.argument.elements;
|
|
1781
|
+
add(inner);
|
|
1782
|
+
const last = inner[inner.length - 1];
|
|
1783
|
+
if (last && (last.type === "CallExpression" || last.type === "MethodCallExpression")) many.add(last);
|
|
1784
|
+
} else {
|
|
1785
|
+
items.push(element);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
};
|
|
1789
|
+
add(list);
|
|
1790
|
+
items.forEach((item, i) => {
|
|
1791
|
+
if (!many.has(item) || i === items.length - 1) return;
|
|
1792
|
+
many.delete(item);
|
|
1793
|
+
items[i] = { type: "SpreadElement", argument: { type: "ArrayExpression", elements: [item], ...spanOf(item) }, ...spanOf(item) };
|
|
1794
|
+
});
|
|
1795
|
+
return { items, many };
|
|
1796
|
+
}
|
|
1685
1797
|
function isLink(node) {
|
|
1686
1798
|
return node.type === "MemberExpression" || node.type === "IndexExpression" || node.type === "CallExpression" || node.type === "MethodCallExpression";
|
|
1687
1799
|
}
|
|
@@ -1730,10 +1842,19 @@ function memberChain(e) {
|
|
|
1730
1842
|
}
|
|
1731
1843
|
return void 0;
|
|
1732
1844
|
}
|
|
1845
|
+
function declared(target) {
|
|
1846
|
+
if (target.type === "MemberExpression" || target.type === "IndexExpression") {
|
|
1847
|
+
throw new Error("a declaration binds names, not a member or an index");
|
|
1848
|
+
}
|
|
1849
|
+
return target;
|
|
1850
|
+
}
|
|
1733
1851
|
function identifierPatterns(target) {
|
|
1734
1852
|
switch (target.type) {
|
|
1735
1853
|
case "IdentifierPattern":
|
|
1736
1854
|
return [target];
|
|
1855
|
+
case "MemberExpression":
|
|
1856
|
+
case "IndexExpression":
|
|
1857
|
+
return [];
|
|
1737
1858
|
case "ObjectPattern":
|
|
1738
1859
|
return [...target.properties.flatMap((p) => identifierPatterns(p.value)), ...target.rest ? identifierPatterns(target.rest) : []];
|
|
1739
1860
|
case "ArrayPattern":
|
|
@@ -1920,15 +2041,15 @@ async function loadLowerings(modules) {
|
|
|
1920
2041
|
for (const module2 of modules) {
|
|
1921
2042
|
try {
|
|
1922
2043
|
const loaded = await import((0, import_node_url.pathToFileURL)(module2.file).href);
|
|
1923
|
-
const
|
|
1924
|
-
if (!
|
|
2044
|
+
const plugin2 = loaded.default;
|
|
2045
|
+
if (!plugin2 || typeof plugin2 !== "object") {
|
|
1925
2046
|
problems.push({
|
|
1926
2047
|
file: module2.file,
|
|
1927
2048
|
message: `'${module2.from}' lowering module has no default export`
|
|
1928
2049
|
});
|
|
1929
2050
|
continue;
|
|
1930
2051
|
}
|
|
1931
|
-
lowerings.push({ plugin, from: module2.from });
|
|
2052
|
+
lowerings.push({ plugin: plugin2, from: module2.from, library: module2.library });
|
|
1932
2053
|
} catch (error) {
|
|
1933
2054
|
problems.push({
|
|
1934
2055
|
file: module2.file,
|
|
@@ -2180,7 +2301,7 @@ ${G} = {
|
|
|
2180
2301
|
}
|
|
2181
2302
|
function stampOf(file) {
|
|
2182
2303
|
try {
|
|
2183
|
-
const at = (0,
|
|
2304
|
+
const at = (0, import_node_fs2.statSync)(file);
|
|
2184
2305
|
return `${at.size}:${at.mtimeMs}`;
|
|
2185
2306
|
} catch {
|
|
2186
2307
|
return void 0;
|
|
@@ -2196,7 +2317,7 @@ function parseFile(file, diagnostics, directives) {
|
|
|
2196
2317
|
}
|
|
2197
2318
|
let text;
|
|
2198
2319
|
try {
|
|
2199
|
-
text = (0,
|
|
2320
|
+
text = (0, import_node_fs2.readFileSync)(file, "utf8");
|
|
2200
2321
|
} catch {
|
|
2201
2322
|
diagnostics.push({ file, message: "Cannot read file", line: 1, column: 1, category: "module" });
|
|
2202
2323
|
return void 0;
|
|
@@ -2223,14 +2344,14 @@ var libraryCache = /* @__PURE__ */ new Map();
|
|
|
2223
2344
|
function parsedLibrary(file) {
|
|
2224
2345
|
let stamp;
|
|
2225
2346
|
try {
|
|
2226
|
-
const at = (0,
|
|
2347
|
+
const at = (0, import_node_fs2.statSync)(file);
|
|
2227
2348
|
stamp = `${at.size}:${at.mtimeMs}`;
|
|
2228
2349
|
} catch {
|
|
2229
2350
|
stamp = "";
|
|
2230
2351
|
}
|
|
2231
2352
|
const cached = libraryCache.get(file);
|
|
2232
2353
|
if (cached && cached.stamp === stamp) return cached.program;
|
|
2233
|
-
const program = (0, import_parser3.parse)((0,
|
|
2354
|
+
const program = (0, import_parser3.parse)((0, import_node_fs2.readFileSync)(file, "utf8"));
|
|
2234
2355
|
libraryCache.set(file, { stamp, program });
|
|
2235
2356
|
return program;
|
|
2236
2357
|
}
|
|
@@ -2253,7 +2374,7 @@ function analyzeModules(modules, config2) {
|
|
|
2253
2374
|
const done = analyzed.get(file);
|
|
2254
2375
|
if (done) return done;
|
|
2255
2376
|
const remembered = moduleAnalyses.get(file);
|
|
2256
|
-
if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program && [...remembered.read].every(([
|
|
2377
|
+
if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program && [...remembered.read].every(([read2, stamp]) => stampOf(read2) === stamp)) {
|
|
2257
2378
|
analyzed.set(file, remembered.result);
|
|
2258
2379
|
readWhile.set(file, remembered.read);
|
|
2259
2380
|
return remembered.result;
|
|
@@ -2277,12 +2398,12 @@ function analyzeModules(modules, config2) {
|
|
|
2277
2398
|
const result = { types, diagnostics: said };
|
|
2278
2399
|
if (partials === before) {
|
|
2279
2400
|
analyzed.set(file, result);
|
|
2280
|
-
const
|
|
2401
|
+
const read2 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
2281
2402
|
const own = stampOf(file);
|
|
2282
|
-
if (own !== void 0)
|
|
2283
|
-
readWhile.set(file,
|
|
2284
|
-
if ([...
|
|
2285
|
-
moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program, read, result });
|
|
2403
|
+
if (own !== void 0) read2.set(file, own);
|
|
2404
|
+
readWhile.set(file, read2);
|
|
2405
|
+
if ([...read2.values()].every((stamp) => stamp !== void 0)) {
|
|
2406
|
+
moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program, read: read2, result });
|
|
2286
2407
|
}
|
|
2287
2408
|
}
|
|
2288
2409
|
return result;
|
|
@@ -2291,11 +2412,11 @@ function analyzeModules(modules, config2) {
|
|
|
2291
2412
|
const target = (0, import_parser3.resolveModulePath)(file, specifier, config2);
|
|
2292
2413
|
if (!target) return void 0;
|
|
2293
2414
|
const noteRead = () => {
|
|
2294
|
-
const
|
|
2295
|
-
readWhile.set(file,
|
|
2415
|
+
const read2 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
2416
|
+
readWhile.set(file, read2);
|
|
2296
2417
|
const stamp = stampOf(target);
|
|
2297
|
-
if (stamp !== void 0)
|
|
2298
|
-
for (const [below, belowStamp] of readWhile.get(target) ?? [])
|
|
2418
|
+
if (stamp !== void 0) read2.set(target, stamp);
|
|
2419
|
+
for (const [below, belowStamp] of readWhile.get(target) ?? []) read2.set(below, belowStamp);
|
|
2299
2420
|
};
|
|
2300
2421
|
if (inProgress.has(target)) {
|
|
2301
2422
|
partials++;
|
|
@@ -2309,7 +2430,7 @@ function analyzeModules(modules, config2) {
|
|
|
2309
2430
|
let program = byFile.get(target)?.program;
|
|
2310
2431
|
if (!program) {
|
|
2311
2432
|
try {
|
|
2312
|
-
program = (0, import_parser3.parse)((0,
|
|
2433
|
+
program = (0, import_parser3.parse)((0, import_node_fs2.readFileSync)(target, "utf8"));
|
|
2313
2434
|
} catch {
|
|
2314
2435
|
return void 0;
|
|
2315
2436
|
}
|
|
@@ -2389,7 +2510,7 @@ async function main(from) {
|
|
|
2389
2510
|
process.exit(1);
|
|
2390
2511
|
}
|
|
2391
2512
|
const target = out ?? from.replace(/\.tilua$/, "") + ".luau";
|
|
2392
|
-
(0,
|
|
2513
|
+
(0, import_node_fs3.writeFileSync)(target, result.code);
|
|
2393
2514
|
console.log(`${target}: ${result.modules.length} module${result.modules.length === 1 ? "" : "s"}`);
|
|
2394
2515
|
process.exit(result.diagnostics.length ? 1 : 0);
|
|
2395
2516
|
}
|