@tilua/compiler 1.1.0 → 2.1.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 +17 -5
- package/dist/{chunk-2IPPO4V3.js → chunk-TBSJRVKA.js} +205 -60
- package/dist/cli.cjs +204 -59
- package/dist/cli.js +1 -1
- package/dist/index.cjs +204 -59
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/package.json +2 -2
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.
|
|
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.
|
|
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
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
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
|
-
|
|
901
|
+
iterators,
|
|
891
902
|
this.loopBody51(this.block(node.body, prelude)).statements
|
|
892
903
|
)];
|
|
893
904
|
}
|
|
894
905
|
case "ReturnStatement":
|
|
895
|
-
return [returns(this.
|
|
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
|
|
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
|
|
1386
|
-
if (
|
|
1387
|
-
|
|
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
|
-
|
|
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)
|
|
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(
|
|
1438
|
-
return call(
|
|
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
|
-
|
|
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()) {
|
|
@@ -2172,7 +2240,22 @@ ${G} = {
|
|
|
2172
2240
|
}
|
|
2173
2241
|
`;
|
|
2174
2242
|
}
|
|
2243
|
+
function stampOf(file) {
|
|
2244
|
+
try {
|
|
2245
|
+
const at = (0, import_node_fs.statSync)(file);
|
|
2246
|
+
return `${at.size}:${at.mtimeMs}`;
|
|
2247
|
+
} catch {
|
|
2248
|
+
return void 0;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
var parsedFiles = /* @__PURE__ */ new Map();
|
|
2175
2252
|
function parseFile(file, diagnostics, directives) {
|
|
2253
|
+
const stamp = stampOf(file);
|
|
2254
|
+
const cached = stamp !== void 0 ? parsedFiles.get(file) : void 0;
|
|
2255
|
+
if (cached && cached.stamp === stamp) {
|
|
2256
|
+
directives.set(file, cached.directives);
|
|
2257
|
+
return { program: cached.program, text: cached.text };
|
|
2258
|
+
}
|
|
2176
2259
|
let text;
|
|
2177
2260
|
try {
|
|
2178
2261
|
text = (0, import_node_fs.readFileSync)(file, "utf8");
|
|
@@ -2182,7 +2265,9 @@ function parseFile(file, diagnostics, directives) {
|
|
|
2182
2265
|
}
|
|
2183
2266
|
try {
|
|
2184
2267
|
const program2 = (0, import_parser3.parse)(text);
|
|
2185
|
-
|
|
2268
|
+
const found = (0, import_parser3.directivesOf)(text);
|
|
2269
|
+
directives.set(file, found);
|
|
2270
|
+
if (stamp !== void 0) parsedFiles.set(file, { stamp, program: program2, text, directives: found });
|
|
2186
2271
|
return { program: program2, text };
|
|
2187
2272
|
} catch (error) {
|
|
2188
2273
|
if (error instanceof import_parser3.ParseError || error instanceof import_parser3.LexError) {
|
|
@@ -2196,22 +2281,93 @@ function parseFile(file, diagnostics, directives) {
|
|
|
2196
2281
|
function importedSpecifiers(program2) {
|
|
2197
2282
|
return program2.body.statements.flatMap((s) => s.type === "ImportStatement" || s.type === "ExportAllStatement" || s.type === "ExportNamedStatement" && s.source ? [s.source.value] : []);
|
|
2198
2283
|
}
|
|
2284
|
+
var libraryCache = /* @__PURE__ */ new Map();
|
|
2285
|
+
function parsedLibrary(file) {
|
|
2286
|
+
let stamp;
|
|
2287
|
+
try {
|
|
2288
|
+
const at = (0, import_node_fs.statSync)(file);
|
|
2289
|
+
stamp = `${at.size}:${at.mtimeMs}`;
|
|
2290
|
+
} catch {
|
|
2291
|
+
stamp = "";
|
|
2292
|
+
}
|
|
2293
|
+
const cached = libraryCache.get(file);
|
|
2294
|
+
if (cached && cached.stamp === stamp) return cached.program;
|
|
2295
|
+
const program2 = (0, import_parser3.parse)((0, import_node_fs.readFileSync)(file, "utf8"));
|
|
2296
|
+
libraryCache.set(file, { stamp, program: program2 });
|
|
2297
|
+
return program2;
|
|
2298
|
+
}
|
|
2299
|
+
var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
2199
2300
|
function analyzeModules(modules, config) {
|
|
2200
2301
|
const out = [];
|
|
2201
2302
|
const analyses = /* @__PURE__ */ new Map();
|
|
2202
2303
|
const libraries = config ? (0, import_parser3.resolveTypeLibraries)(config) : { files: [], lowerings: [], problems: [] };
|
|
2203
2304
|
for (const p of libraries.problems) out.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
2204
|
-
const libs = libraries.files.map(
|
|
2305
|
+
const libs = libraries.files.map(parsedLibrary);
|
|
2205
2306
|
const globals = libs.flatMap((lib) => lib.body.statements.flatMap((s) => s.type === "DeclareStatement" ? [s.name] : []));
|
|
2206
2307
|
const byFile = new Map(modules.map((m) => [m.file, m]));
|
|
2207
2308
|
const exportsCache = /* @__PURE__ */ new Map();
|
|
2208
2309
|
const inProgress = /* @__PURE__ */ new Set();
|
|
2310
|
+
const analyzed = /* @__PURE__ */ new Map();
|
|
2311
|
+
let partials = 0;
|
|
2312
|
+
const readWhile = /* @__PURE__ */ new Map();
|
|
2313
|
+
const settingFor = `${libraries.files.join("|")}#${config?.directory ?? ""}#${JSON.stringify(config?.paths ?? {})}`;
|
|
2314
|
+
const analyzeModule = (file, program2) => {
|
|
2315
|
+
const done = analyzed.get(file);
|
|
2316
|
+
if (done) return done;
|
|
2317
|
+
const remembered = moduleAnalyses.get(file);
|
|
2318
|
+
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)) {
|
|
2319
|
+
analyzed.set(file, remembered.result);
|
|
2320
|
+
readWhile.set(file, remembered.read);
|
|
2321
|
+
return remembered.result;
|
|
2322
|
+
}
|
|
2323
|
+
const scopes = (0, import_parser3.analyzeScopes)(program2, { builtinGlobals: globals, reportUndeclared: libs.length > 0 });
|
|
2324
|
+
const said = [];
|
|
2325
|
+
for (const d of scopes.diagnostics) {
|
|
2326
|
+
if (d.kind !== "undeclared") continue;
|
|
2327
|
+
said.push({ file, message: d.message, line: d.node.line.start, column: d.node.column.start, category: "type" });
|
|
2328
|
+
}
|
|
2329
|
+
const before = partials;
|
|
2330
|
+
const types = (0, import_parser3.analyzeTypes)(program2, scopes, {
|
|
2331
|
+
libs,
|
|
2332
|
+
resolveModule: resolverFor(file),
|
|
2333
|
+
reportUnknownTypes: libs.length > 0
|
|
2334
|
+
});
|
|
2335
|
+
for (const d of types.diagnostics) {
|
|
2336
|
+
const at = d.node;
|
|
2337
|
+
said.push({ file, message: d.message, line: at.line.start, column: at.column.start, category: "type" });
|
|
2338
|
+
}
|
|
2339
|
+
const result = { types, diagnostics: said };
|
|
2340
|
+
if (partials === before) {
|
|
2341
|
+
analyzed.set(file, result);
|
|
2342
|
+
const read = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
2343
|
+
const own = stampOf(file);
|
|
2344
|
+
if (own !== void 0) read.set(file, own);
|
|
2345
|
+
readWhile.set(file, read);
|
|
2346
|
+
if ([...read.values()].every((stamp) => stamp !== void 0)) {
|
|
2347
|
+
moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read, result });
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
return result;
|
|
2351
|
+
};
|
|
2209
2352
|
const resolverFor = (file) => (specifier) => {
|
|
2210
2353
|
const target = (0, import_parser3.resolveModulePath)(file, specifier, config);
|
|
2211
2354
|
if (!target) return void 0;
|
|
2212
|
-
|
|
2355
|
+
const noteRead = () => {
|
|
2356
|
+
const read = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
2357
|
+
readWhile.set(file, read);
|
|
2358
|
+
const stamp = stampOf(target);
|
|
2359
|
+
if (stamp !== void 0) read.set(target, stamp);
|
|
2360
|
+
for (const [below, belowStamp] of readWhile.get(target) ?? []) read.set(below, belowStamp);
|
|
2361
|
+
};
|
|
2362
|
+
if (inProgress.has(target)) {
|
|
2363
|
+
partials++;
|
|
2364
|
+
return { values: /* @__PURE__ */ new Map(), types: /* @__PURE__ */ new Map(), partial: true };
|
|
2365
|
+
}
|
|
2213
2366
|
const cached = exportsCache.get(target);
|
|
2214
|
-
if (cached)
|
|
2367
|
+
if (cached) {
|
|
2368
|
+
noteRead();
|
|
2369
|
+
return cached;
|
|
2370
|
+
}
|
|
2215
2371
|
let program2 = byFile.get(target)?.program;
|
|
2216
2372
|
if (!program2) {
|
|
2217
2373
|
try {
|
|
@@ -2223,30 +2379,19 @@ function analyzeModules(modules, config) {
|
|
|
2223
2379
|
inProgress.add(target);
|
|
2224
2380
|
try {
|
|
2225
2381
|
const scopes = (0, import_parser3.analyzeScopes)(program2, { builtinGlobals: globals });
|
|
2226
|
-
const types = (0, import_parser3.analyzeTypes)(program2, scopes, { libs, resolveModule: resolverFor(target), diagnostics: false });
|
|
2382
|
+
const types = byFile.has(target) ? analyzeModule(target, program2).types : (0, import_parser3.analyzeTypes)(program2, scopes, { libs, resolveModule: resolverFor(target), diagnostics: false });
|
|
2227
2383
|
const exports2 = (0, import_parser3.moduleExports)(program2, scopes, types, resolverFor(target));
|
|
2228
2384
|
exportsCache.set(target, exports2);
|
|
2385
|
+
noteRead();
|
|
2229
2386
|
return exports2;
|
|
2230
2387
|
} finally {
|
|
2231
2388
|
inProgress.delete(target);
|
|
2232
2389
|
}
|
|
2233
2390
|
};
|
|
2234
2391
|
for (const module2 of modules) {
|
|
2235
|
-
const
|
|
2236
|
-
for (const d of scopes.diagnostics) {
|
|
2237
|
-
if (d.kind !== "undeclared") continue;
|
|
2238
|
-
out.push({ file: module2.file, message: d.message, line: d.node.line.start, column: d.node.column.start, category: "type" });
|
|
2239
|
-
}
|
|
2240
|
-
const types = (0, import_parser3.analyzeTypes)(module2.program, scopes, {
|
|
2241
|
-
libs,
|
|
2242
|
-
resolveModule: resolverFor(module2.file),
|
|
2243
|
-
reportUnknownTypes: libs.length > 0
|
|
2244
|
-
});
|
|
2392
|
+
const { types, diagnostics } = analyzeModule(module2.file, module2.program);
|
|
2245
2393
|
analyses.set(module2.file, types);
|
|
2246
|
-
|
|
2247
|
-
const at = d.node;
|
|
2248
|
-
out.push({ file: module2.file, message: d.message, line: at.line.start, column: at.column.start, category: "type" });
|
|
2249
|
-
}
|
|
2394
|
+
out.push(...diagnostics);
|
|
2250
2395
|
}
|
|
2251
2396
|
return { types: analyses, diagnostics: out, lowerings: [...libraries.lowerings] };
|
|
2252
2397
|
}
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tilua/compiler",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.1.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": "^
|
|
40
|
+
"@tilua/parser": "^2.1.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^22.20.2",
|