@tilua/compiler 9.1.1 → 9.1.3
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 +2 -2
- package/dist/{chunk-3RJVN4KC.js → chunk-YWRP7SXR.js} +78 -10
- package/dist/cli.cjs +76 -10
- package/dist/cli.js +1 -1
- package/dist/index.cjs +76 -10
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -546,12 +546,12 @@ a script that requires any of them knows what it got.
|
|
|
546
546
|
<!-- compatibility:start -->
|
|
547
547
|
## Compatibility
|
|
548
548
|
|
|
549
|
-
`@tilua/compiler@9.1.
|
|
549
|
+
`@tilua/compiler@9.1.3` works with these tilua packages. *Released with* is the
|
|
550
550
|
version it was built and tested against.
|
|
551
551
|
|
|
552
552
|
| Package | Range | Released with | |
|
|
553
553
|
| --- | --- | --- | --- |
|
|
554
|
-
| `@tilua/parser` | `^9.1.
|
|
554
|
+
| `@tilua/parser` | `^9.1.3` | 9.1.3 | dependency |
|
|
555
555
|
<!-- compatibility:end -->
|
|
556
556
|
|
|
557
557
|
## Development
|
|
@@ -710,6 +710,8 @@ var Lowerer = class {
|
|
|
710
710
|
receiverGlobal,
|
|
711
711
|
argumentCount: args.length,
|
|
712
712
|
at: this.callSite(name),
|
|
713
|
+
perFile: this.options.perFile ?? false,
|
|
714
|
+
report: (message) => this.diagnostics.push({ message, line: node.line.start, column: node.column.start }),
|
|
713
715
|
get arguments() {
|
|
714
716
|
return info();
|
|
715
717
|
},
|
|
@@ -739,6 +741,8 @@ var Lowerer = class {
|
|
|
739
741
|
options: lowerings[i].options ?? {},
|
|
740
742
|
name,
|
|
741
743
|
at: this.callSite(node.callee),
|
|
744
|
+
perFile: this.options.perFile ?? false,
|
|
745
|
+
report: (message) => this.diagnostics.push({ message, line: node.line.start, column: node.column.start }),
|
|
742
746
|
get arguments() {
|
|
743
747
|
return info();
|
|
744
748
|
},
|
|
@@ -754,11 +758,16 @@ var Lowerer = class {
|
|
|
754
758
|
if (!lowerings?.some((l) => l.plugin.globalValue)) return void 0;
|
|
755
759
|
const name = this.globalName(node);
|
|
756
760
|
if (name === void 0) return void 0;
|
|
761
|
+
const called = this.readingCallee;
|
|
757
762
|
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
758
763
|
const answer = lowerings[i].plugin.globalValue?.({
|
|
759
764
|
options: lowerings[i].options ?? {},
|
|
760
765
|
name,
|
|
761
766
|
at: this.callSite(node),
|
|
767
|
+
perFile: this.options.perFile ?? false,
|
|
768
|
+
report: (message) => {
|
|
769
|
+
if (!called) this.diagnostics.push({ message, line: node.line.start, column: node.column.start });
|
|
770
|
+
},
|
|
762
771
|
use: (runtime2) => this.loweringRuntime(i, runtime2)
|
|
763
772
|
});
|
|
764
773
|
if (answer !== void 0) return this.libraryExpression(answer, i, node);
|
|
@@ -2122,8 +2131,14 @@ end
|
|
|
2122
2131
|
if (node.type === "CallExpression" && object2.type === "Identifier") {
|
|
2123
2132
|
return this.link(node, this.reference(object2));
|
|
2124
2133
|
}
|
|
2125
|
-
|
|
2134
|
+
const callee = node.type === "CallExpression" && node.callee === object2;
|
|
2135
|
+
const reading = this.readingCallee;
|
|
2136
|
+
this.readingCallee = callee;
|
|
2137
|
+
const lowered = this.expression(object2);
|
|
2138
|
+
this.readingCallee = reading;
|
|
2139
|
+
return this.link(node, lowered);
|
|
2126
2140
|
}
|
|
2141
|
+
readingCallee = false;
|
|
2127
2142
|
/** A call is one value in tilua, and Luau would hand on every value one
|
|
2128
2143
|
* returns in the last place of an argument list or a `return`: it is
|
|
2129
2144
|
* kept to one there, `f((g()))`. Every value is taken only where the
|
|
@@ -2802,6 +2817,8 @@ import {
|
|
|
2802
2817
|
analyzeScopes,
|
|
2803
2818
|
analyzeTypes,
|
|
2804
2819
|
moduleExports,
|
|
2820
|
+
classesOf,
|
|
2821
|
+
exportsFingerprint,
|
|
2805
2822
|
resolveModulePath,
|
|
2806
2823
|
resolveTypeLibraries,
|
|
2807
2824
|
importExpressions,
|
|
@@ -3272,7 +3289,7 @@ async function bundle(options) {
|
|
|
3272
3289
|
for (let n = 2; taken.has(pathKey(runtimeFile)); n++) runtimeFile = join(outDir, `_tilua${n}.luau`);
|
|
3273
3290
|
for (let i = lowerings.length - 1; i >= 0 && !host; i--) {
|
|
3274
3291
|
const { plugin: plugin3, options: own } = lowerings[i];
|
|
3275
|
-
host = plugin3.files?.({ options: own ?? {}, directory: config?.directory ?? root, outDir, files: outputs, runtime: runtimeFile });
|
|
3292
|
+
host = plugin3.files?.({ options: own ?? {}, directory: config?.directory ?? root, rootDir, outDir, files: outputs, runtime: runtimeFile });
|
|
3276
3293
|
}
|
|
3277
3294
|
for (const problem of host?.problems ?? []) {
|
|
3278
3295
|
diagnostics.push({
|
|
@@ -3315,6 +3332,7 @@ async function bundle(options) {
|
|
|
3315
3332
|
const dynamicImports = /* @__PURE__ */ new Set();
|
|
3316
3333
|
const lowered2 = lower(source.program, source.scopes, {
|
|
3317
3334
|
names,
|
|
3335
|
+
perFile,
|
|
3318
3336
|
types: analysis.types.get(file),
|
|
3319
3337
|
lowerings,
|
|
3320
3338
|
noLib: config?.noLib,
|
|
@@ -3493,6 +3511,27 @@ ${G}.arrays[${G}.scriptArgs] = true`).body.statements);
|
|
|
3493
3511
|
files2.push({ path: runtimePath, code: `${runtimeCode}
|
|
3494
3512
|
${WRITTEN_BY_TILUA}: the runtime every file of the project requires.
|
|
3495
3513
|
`, modules: [] });
|
|
3514
|
+
try {
|
|
3515
|
+
const more = await host?.output?.();
|
|
3516
|
+
for (const { file, code } of more?.files ?? []) {
|
|
3517
|
+
if (isOutside(outDir, resolve2(file))) return stop(`A library's file has to go inside outDir, not at ${file}`);
|
|
3518
|
+
files2.push({ path: relative(outDir, file).replace(/\\/g, "/"), code: `${code}
|
|
3519
|
+
${WRITTEN_BY_TILUA}: a library's own file.
|
|
3520
|
+
`, modules: [] });
|
|
3521
|
+
}
|
|
3522
|
+
for (const problem of more?.problems ?? []) {
|
|
3523
|
+
diagnostics.push({
|
|
3524
|
+
file: problem.file ?? config?.path ?? anchor,
|
|
3525
|
+
message: problem.message,
|
|
3526
|
+
line: 1,
|
|
3527
|
+
column: 1,
|
|
3528
|
+
category: "config",
|
|
3529
|
+
...problem.severity === "warning" && { severity: "warning" }
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
} catch (error) {
|
|
3533
|
+
return stop(`A library could not write its files: ${error.message}`);
|
|
3534
|
+
}
|
|
3496
3535
|
return { code: files2[0].code, files: files2, modules: moduleNames, diagnostics };
|
|
3497
3536
|
}
|
|
3498
3537
|
const several = mode !== "single";
|
|
@@ -4049,7 +4088,11 @@ ${several ? `
|
|
|
4049
4088
|
})
|
|
4050
4089
|
record = { loading = true, exports = exports }
|
|
4051
4090
|
${G}.records[name] = record
|
|
4052
|
-
module
|
|
4091
|
+
-- A module runs once, so nothing keeps its body: anything can reach
|
|
4092
|
+
-- this table, and the body holds what the file kept to itself.
|
|
4093
|
+
local run = module.load
|
|
4094
|
+
module.load = nil
|
|
4095
|
+
run(exports)
|
|
4053
4096
|
record.loading = false
|
|
4054
4097
|
return exports
|
|
4055
4098
|
end,
|
|
@@ -4142,6 +4185,7 @@ function parsedLibrary(file) {
|
|
|
4142
4185
|
return program2;
|
|
4143
4186
|
}
|
|
4144
4187
|
var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
4188
|
+
var MAX_CYCLE_PASSES = 6;
|
|
4145
4189
|
function analyzeModules(modules, config) {
|
|
4146
4190
|
const out = [];
|
|
4147
4191
|
const analyses = /* @__PURE__ */ new Map();
|
|
@@ -4160,12 +4204,14 @@ function analyzeModules(modules, config) {
|
|
|
4160
4204
|
const inProgress = /* @__PURE__ */ new Set();
|
|
4161
4205
|
const analyzed = /* @__PURE__ */ new Map();
|
|
4162
4206
|
let partials = 0;
|
|
4207
|
+
const cycles = /* @__PURE__ */ new Set();
|
|
4208
|
+
const provisional = /* @__PURE__ */ new Map();
|
|
4163
4209
|
const readWhile = /* @__PURE__ */ new Map();
|
|
4164
4210
|
const settingFor = `${libraries.files.join("|")}#${config?.directory ?? ""}#${JSON.stringify(config?.paths ?? {})}`;
|
|
4165
4211
|
const analyzeModule = (file, program2) => {
|
|
4166
4212
|
const done = analyzed.get(file);
|
|
4167
4213
|
if (done) return done;
|
|
4168
|
-
const remembered = moduleAnalyses.get(file);
|
|
4214
|
+
const remembered = cycles.size ? void 0 : moduleAnalyses.get(file);
|
|
4169
4215
|
const script = scriptOf(file);
|
|
4170
4216
|
const ownLibs = script ? [...libs, script] : libs;
|
|
4171
4217
|
if (remembered && remembered.setting === settingFor && ownLibs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === ownLibs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
|
|
@@ -4193,6 +4239,8 @@ function analyzeModules(modules, config) {
|
|
|
4193
4239
|
const result2 = { types, diagnostics: said, scopes };
|
|
4194
4240
|
if (partials === before) {
|
|
4195
4241
|
analyzed.set(file, result2);
|
|
4242
|
+
}
|
|
4243
|
+
if (partials === before && !cycles.size) {
|
|
4196
4244
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
4197
4245
|
const own = stampOf(file);
|
|
4198
4246
|
if (own !== void 0) read3.set(file, own);
|
|
@@ -4215,7 +4263,8 @@ function analyzeModules(modules, config) {
|
|
|
4215
4263
|
};
|
|
4216
4264
|
if (inProgress.has(target)) {
|
|
4217
4265
|
partials++;
|
|
4218
|
-
|
|
4266
|
+
cycles.add(target);
|
|
4267
|
+
return provisional.get(target) ?? { values: /* @__PURE__ */ new Map(), types: /* @__PURE__ */ new Map(), partial: true };
|
|
4219
4268
|
}
|
|
4220
4269
|
const cached = exportsCache.get(target);
|
|
4221
4270
|
if (cached) {
|
|
@@ -4242,11 +4291,6 @@ function analyzeModules(modules, config) {
|
|
|
4242
4291
|
inProgress.delete(target);
|
|
4243
4292
|
}
|
|
4244
4293
|
};
|
|
4245
|
-
for (const module of modules) {
|
|
4246
|
-
const { types, diagnostics } = analyzeModule(module.file, module.program);
|
|
4247
|
-
analyses.set(module.file, types);
|
|
4248
|
-
out.push(...diagnostics);
|
|
4249
|
-
}
|
|
4250
4294
|
const exportsOf = (file) => {
|
|
4251
4295
|
const cached = exportsCache.get(file);
|
|
4252
4296
|
if (cached) return cached;
|
|
@@ -4256,6 +4300,30 @@ function analyzeModules(modules, config) {
|
|
|
4256
4300
|
exportsCache.set(file, exports);
|
|
4257
4301
|
return exports;
|
|
4258
4302
|
};
|
|
4303
|
+
const reported = out.length;
|
|
4304
|
+
const libraryClasses = classesOf(libs);
|
|
4305
|
+
const fingerprints = /* @__PURE__ */ new Map();
|
|
4306
|
+
for (let pass = 1; ; pass++) {
|
|
4307
|
+
out.length = reported;
|
|
4308
|
+
for (const module of modules) {
|
|
4309
|
+
const { types, diagnostics } = analyzeModule(module.file, module.program);
|
|
4310
|
+
analyses.set(module.file, types);
|
|
4311
|
+
out.push(...diagnostics);
|
|
4312
|
+
}
|
|
4313
|
+
if (!cycles.size || pass === MAX_CYCLE_PASSES) break;
|
|
4314
|
+
let settled = pass > 1;
|
|
4315
|
+
for (const file of cycles) {
|
|
4316
|
+
const exports = byFile.has(file) ? exportsOf(file) : exportsCache.get(file);
|
|
4317
|
+
if (exports && !exports.partial) provisional.set(file, exports);
|
|
4318
|
+
const fingerprint = exports && !exports.partial ? exportsFingerprint(exports, libraryClasses) : void 0;
|
|
4319
|
+
if (fingerprint === void 0 || fingerprint !== fingerprints.get(file)) settled = false;
|
|
4320
|
+
fingerprints.set(file, fingerprint);
|
|
4321
|
+
}
|
|
4322
|
+
if (settled) break;
|
|
4323
|
+
analyzed.clear();
|
|
4324
|
+
exportsCache.clear();
|
|
4325
|
+
readWhile.clear();
|
|
4326
|
+
}
|
|
4259
4327
|
return { types: analyses, diagnostics: out, lowerings: [...libraries.lowerings], exportsOf };
|
|
4260
4328
|
}
|
|
4261
4329
|
function allStatements(statements) {
|
package/dist/cli.cjs
CHANGED
|
@@ -727,6 +727,8 @@ var Lowerer = class {
|
|
|
727
727
|
receiverGlobal,
|
|
728
728
|
argumentCount: args2.length,
|
|
729
729
|
at: this.callSite(name),
|
|
730
|
+
perFile: this.options.perFile ?? false,
|
|
731
|
+
report: (message) => this.diagnostics.push({ message, line: node.line.start, column: node.column.start }),
|
|
730
732
|
get arguments() {
|
|
731
733
|
return info();
|
|
732
734
|
},
|
|
@@ -756,6 +758,8 @@ var Lowerer = class {
|
|
|
756
758
|
options: lowerings[i].options ?? {},
|
|
757
759
|
name,
|
|
758
760
|
at: this.callSite(node.callee),
|
|
761
|
+
perFile: this.options.perFile ?? false,
|
|
762
|
+
report: (message) => this.diagnostics.push({ message, line: node.line.start, column: node.column.start }),
|
|
759
763
|
get arguments() {
|
|
760
764
|
return info();
|
|
761
765
|
},
|
|
@@ -771,11 +775,16 @@ var Lowerer = class {
|
|
|
771
775
|
if (!lowerings?.some((l) => l.plugin.globalValue)) return void 0;
|
|
772
776
|
const name = this.globalName(node);
|
|
773
777
|
if (name === void 0) return void 0;
|
|
778
|
+
const called = this.readingCallee;
|
|
774
779
|
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
775
780
|
const answer = lowerings[i].plugin.globalValue?.({
|
|
776
781
|
options: lowerings[i].options ?? {},
|
|
777
782
|
name,
|
|
778
783
|
at: this.callSite(node),
|
|
784
|
+
perFile: this.options.perFile ?? false,
|
|
785
|
+
report: (message) => {
|
|
786
|
+
if (!called) this.diagnostics.push({ message, line: node.line.start, column: node.column.start });
|
|
787
|
+
},
|
|
779
788
|
use: (runtime2) => this.loweringRuntime(i, runtime2)
|
|
780
789
|
});
|
|
781
790
|
if (answer !== void 0) return this.libraryExpression(answer, i, node);
|
|
@@ -2139,8 +2148,14 @@ end
|
|
|
2139
2148
|
if (node.type === "CallExpression" && object2.type === "Identifier") {
|
|
2140
2149
|
return this.link(node, this.reference(object2));
|
|
2141
2150
|
}
|
|
2142
|
-
|
|
2151
|
+
const callee = node.type === "CallExpression" && node.callee === object2;
|
|
2152
|
+
const reading = this.readingCallee;
|
|
2153
|
+
this.readingCallee = callee;
|
|
2154
|
+
const lowered = this.expression(object2);
|
|
2155
|
+
this.readingCallee = reading;
|
|
2156
|
+
return this.link(node, lowered);
|
|
2143
2157
|
}
|
|
2158
|
+
readingCallee = false;
|
|
2144
2159
|
/** A call is one value in tilua, and Luau would hand on every value one
|
|
2145
2160
|
* returns in the last place of an argument list or a `return`: it is
|
|
2146
2161
|
* kept to one there, `f((g()))`. Every value is taken only where the
|
|
@@ -3265,7 +3280,7 @@ async function bundle(options) {
|
|
|
3265
3280
|
for (let n = 2; taken.has(pathKey(runtimeFile)); n++) runtimeFile = (0, import_node_path2.join)(outDir, `_tilua${n}.luau`);
|
|
3266
3281
|
for (let i = lowerings.length - 1; i >= 0 && !host; i--) {
|
|
3267
3282
|
const { plugin: plugin3, options: own } = lowerings[i];
|
|
3268
|
-
host = plugin3.files?.({ options: own ?? {}, directory: config2?.directory ?? root, outDir, files: outputs, runtime: runtimeFile });
|
|
3283
|
+
host = plugin3.files?.({ options: own ?? {}, directory: config2?.directory ?? root, rootDir, outDir, files: outputs, runtime: runtimeFile });
|
|
3269
3284
|
}
|
|
3270
3285
|
for (const problem of host?.problems ?? []) {
|
|
3271
3286
|
diagnostics.push({
|
|
@@ -3308,6 +3323,7 @@ async function bundle(options) {
|
|
|
3308
3323
|
const dynamicImports = /* @__PURE__ */ new Set();
|
|
3309
3324
|
const lowered2 = lower(source.program, source.scopes, {
|
|
3310
3325
|
names,
|
|
3326
|
+
perFile,
|
|
3311
3327
|
types: analysis.types.get(file),
|
|
3312
3328
|
lowerings,
|
|
3313
3329
|
noLib: config2?.noLib,
|
|
@@ -3486,6 +3502,27 @@ ${G}.arrays[${G}.scriptArgs] = true`).body.statements);
|
|
|
3486
3502
|
files2.push({ path: runtimePath, code: `${runtimeCode}
|
|
3487
3503
|
${WRITTEN_BY_TILUA}: the runtime every file of the project requires.
|
|
3488
3504
|
`, modules: [] });
|
|
3505
|
+
try {
|
|
3506
|
+
const more = await host?.output?.();
|
|
3507
|
+
for (const { file, code } of more?.files ?? []) {
|
|
3508
|
+
if (isOutside(outDir, (0, import_node_path2.resolve)(file))) return stop(`A library's file has to go inside outDir, not at ${file}`);
|
|
3509
|
+
files2.push({ path: (0, import_node_path2.relative)(outDir, file).replace(/\\/g, "/"), code: `${code}
|
|
3510
|
+
${WRITTEN_BY_TILUA}: a library's own file.
|
|
3511
|
+
`, modules: [] });
|
|
3512
|
+
}
|
|
3513
|
+
for (const problem of more?.problems ?? []) {
|
|
3514
|
+
diagnostics.push({
|
|
3515
|
+
file: problem.file ?? config2?.path ?? anchor,
|
|
3516
|
+
message: problem.message,
|
|
3517
|
+
line: 1,
|
|
3518
|
+
column: 1,
|
|
3519
|
+
category: "config",
|
|
3520
|
+
...problem.severity === "warning" && { severity: "warning" }
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
} catch (error) {
|
|
3524
|
+
return stop(`A library could not write its files: ${error.message}`);
|
|
3525
|
+
}
|
|
3489
3526
|
return { code: files2[0].code, files: files2, modules: moduleNames, diagnostics };
|
|
3490
3527
|
}
|
|
3491
3528
|
const several = mode !== "single";
|
|
@@ -4042,7 +4079,11 @@ ${several ? `
|
|
|
4042
4079
|
})
|
|
4043
4080
|
record = { loading = true, exports = exports }
|
|
4044
4081
|
${G}.records[name] = record
|
|
4045
|
-
module
|
|
4082
|
+
-- A module runs once, so nothing keeps its body: anything can reach
|
|
4083
|
+
-- this table, and the body holds what the file kept to itself.
|
|
4084
|
+
local run = module.load
|
|
4085
|
+
module.load = nil
|
|
4086
|
+
run(exports)
|
|
4046
4087
|
record.loading = false
|
|
4047
4088
|
return exports
|
|
4048
4089
|
end,
|
|
@@ -4135,6 +4176,7 @@ function parsedLibrary(file) {
|
|
|
4135
4176
|
return program2;
|
|
4136
4177
|
}
|
|
4137
4178
|
var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
4179
|
+
var MAX_CYCLE_PASSES = 6;
|
|
4138
4180
|
function analyzeModules(modules, config2) {
|
|
4139
4181
|
const out2 = [];
|
|
4140
4182
|
const analyses = /* @__PURE__ */ new Map();
|
|
@@ -4153,12 +4195,14 @@ function analyzeModules(modules, config2) {
|
|
|
4153
4195
|
const inProgress = /* @__PURE__ */ new Set();
|
|
4154
4196
|
const analyzed = /* @__PURE__ */ new Map();
|
|
4155
4197
|
let partials = 0;
|
|
4198
|
+
const cycles = /* @__PURE__ */ new Set();
|
|
4199
|
+
const provisional = /* @__PURE__ */ new Map();
|
|
4156
4200
|
const readWhile = /* @__PURE__ */ new Map();
|
|
4157
4201
|
const settingFor = `${libraries.files.join("|")}#${config2?.directory ?? ""}#${JSON.stringify(config2?.paths ?? {})}`;
|
|
4158
4202
|
const analyzeModule = (file, program2) => {
|
|
4159
4203
|
const done = analyzed.get(file);
|
|
4160
4204
|
if (done) return done;
|
|
4161
|
-
const remembered = moduleAnalyses.get(file);
|
|
4205
|
+
const remembered = cycles.size ? void 0 : moduleAnalyses.get(file);
|
|
4162
4206
|
const script = scriptOf(file);
|
|
4163
4207
|
const ownLibs = script ? [...libs, script] : libs;
|
|
4164
4208
|
if (remembered && remembered.setting === settingFor && ownLibs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === ownLibs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
|
|
@@ -4186,6 +4230,8 @@ function analyzeModules(modules, config2) {
|
|
|
4186
4230
|
const result2 = { types, diagnostics: said, scopes };
|
|
4187
4231
|
if (partials === before) {
|
|
4188
4232
|
analyzed.set(file, result2);
|
|
4233
|
+
}
|
|
4234
|
+
if (partials === before && !cycles.size) {
|
|
4189
4235
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
4190
4236
|
const own = stampOf(file);
|
|
4191
4237
|
if (own !== void 0) read3.set(file, own);
|
|
@@ -4208,7 +4254,8 @@ function analyzeModules(modules, config2) {
|
|
|
4208
4254
|
};
|
|
4209
4255
|
if (inProgress.has(target)) {
|
|
4210
4256
|
partials++;
|
|
4211
|
-
|
|
4257
|
+
cycles.add(target);
|
|
4258
|
+
return provisional.get(target) ?? { values: /* @__PURE__ */ new Map(), types: /* @__PURE__ */ new Map(), partial: true };
|
|
4212
4259
|
}
|
|
4213
4260
|
const cached = exportsCache.get(target);
|
|
4214
4261
|
if (cached) {
|
|
@@ -4235,11 +4282,6 @@ function analyzeModules(modules, config2) {
|
|
|
4235
4282
|
inProgress.delete(target);
|
|
4236
4283
|
}
|
|
4237
4284
|
};
|
|
4238
|
-
for (const module2 of modules) {
|
|
4239
|
-
const { types, diagnostics } = analyzeModule(module2.file, module2.program);
|
|
4240
|
-
analyses.set(module2.file, types);
|
|
4241
|
-
out2.push(...diagnostics);
|
|
4242
|
-
}
|
|
4243
4285
|
const exportsOf = (file) => {
|
|
4244
4286
|
const cached = exportsCache.get(file);
|
|
4245
4287
|
if (cached) return cached;
|
|
@@ -4249,6 +4291,30 @@ function analyzeModules(modules, config2) {
|
|
|
4249
4291
|
exportsCache.set(file, exports2);
|
|
4250
4292
|
return exports2;
|
|
4251
4293
|
};
|
|
4294
|
+
const reported = out2.length;
|
|
4295
|
+
const libraryClasses = (0, import_parser7.classesOf)(libs);
|
|
4296
|
+
const fingerprints = /* @__PURE__ */ new Map();
|
|
4297
|
+
for (let pass = 1; ; pass++) {
|
|
4298
|
+
out2.length = reported;
|
|
4299
|
+
for (const module2 of modules) {
|
|
4300
|
+
const { types, diagnostics } = analyzeModule(module2.file, module2.program);
|
|
4301
|
+
analyses.set(module2.file, types);
|
|
4302
|
+
out2.push(...diagnostics);
|
|
4303
|
+
}
|
|
4304
|
+
if (!cycles.size || pass === MAX_CYCLE_PASSES) break;
|
|
4305
|
+
let settled = pass > 1;
|
|
4306
|
+
for (const file of cycles) {
|
|
4307
|
+
const exports2 = byFile.has(file) ? exportsOf(file) : exportsCache.get(file);
|
|
4308
|
+
if (exports2 && !exports2.partial) provisional.set(file, exports2);
|
|
4309
|
+
const fingerprint = exports2 && !exports2.partial ? (0, import_parser7.exportsFingerprint)(exports2, libraryClasses) : void 0;
|
|
4310
|
+
if (fingerprint === void 0 || fingerprint !== fingerprints.get(file)) settled = false;
|
|
4311
|
+
fingerprints.set(file, fingerprint);
|
|
4312
|
+
}
|
|
4313
|
+
if (settled) break;
|
|
4314
|
+
analyzed.clear();
|
|
4315
|
+
exportsCache.clear();
|
|
4316
|
+
readWhile.clear();
|
|
4317
|
+
}
|
|
4252
4318
|
return { types: analyses, diagnostics: out2, lowerings: [...libraries.lowerings], exportsOf };
|
|
4253
4319
|
}
|
|
4254
4320
|
function allStatements(statements) {
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -751,6 +751,8 @@ var Lowerer = class {
|
|
|
751
751
|
receiverGlobal,
|
|
752
752
|
argumentCount: args.length,
|
|
753
753
|
at: this.callSite(name),
|
|
754
|
+
perFile: this.options.perFile ?? false,
|
|
755
|
+
report: (message) => this.diagnostics.push({ message, line: node.line.start, column: node.column.start }),
|
|
754
756
|
get arguments() {
|
|
755
757
|
return info();
|
|
756
758
|
},
|
|
@@ -780,6 +782,8 @@ var Lowerer = class {
|
|
|
780
782
|
options: lowerings[i].options ?? {},
|
|
781
783
|
name,
|
|
782
784
|
at: this.callSite(node.callee),
|
|
785
|
+
perFile: this.options.perFile ?? false,
|
|
786
|
+
report: (message) => this.diagnostics.push({ message, line: node.line.start, column: node.column.start }),
|
|
783
787
|
get arguments() {
|
|
784
788
|
return info();
|
|
785
789
|
},
|
|
@@ -795,11 +799,16 @@ var Lowerer = class {
|
|
|
795
799
|
if (!lowerings?.some((l) => l.plugin.globalValue)) return void 0;
|
|
796
800
|
const name = this.globalName(node);
|
|
797
801
|
if (name === void 0) return void 0;
|
|
802
|
+
const called = this.readingCallee;
|
|
798
803
|
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
799
804
|
const answer = lowerings[i].plugin.globalValue?.({
|
|
800
805
|
options: lowerings[i].options ?? {},
|
|
801
806
|
name,
|
|
802
807
|
at: this.callSite(node),
|
|
808
|
+
perFile: this.options.perFile ?? false,
|
|
809
|
+
report: (message) => {
|
|
810
|
+
if (!called) this.diagnostics.push({ message, line: node.line.start, column: node.column.start });
|
|
811
|
+
},
|
|
803
812
|
use: (runtime2) => this.loweringRuntime(i, runtime2)
|
|
804
813
|
});
|
|
805
814
|
if (answer !== void 0) return this.libraryExpression(answer, i, node);
|
|
@@ -2163,8 +2172,14 @@ end
|
|
|
2163
2172
|
if (node.type === "CallExpression" && object2.type === "Identifier") {
|
|
2164
2173
|
return this.link(node, this.reference(object2));
|
|
2165
2174
|
}
|
|
2166
|
-
|
|
2175
|
+
const callee = node.type === "CallExpression" && node.callee === object2;
|
|
2176
|
+
const reading = this.readingCallee;
|
|
2177
|
+
this.readingCallee = callee;
|
|
2178
|
+
const lowered = this.expression(object2);
|
|
2179
|
+
this.readingCallee = reading;
|
|
2180
|
+
return this.link(node, lowered);
|
|
2167
2181
|
}
|
|
2182
|
+
readingCallee = false;
|
|
2168
2183
|
/** A call is one value in tilua, and Luau would hand on every value one
|
|
2169
2184
|
* returns in the last place of an argument list or a `return`: it is
|
|
2170
2185
|
* kept to one there, `f((g()))`. Every value is taken only where the
|
|
@@ -3289,7 +3304,7 @@ async function bundle(options) {
|
|
|
3289
3304
|
for (let n = 2; taken.has(pathKey(runtimeFile)); n++) runtimeFile = (0, import_node_path2.join)(outDir, `_tilua${n}.luau`);
|
|
3290
3305
|
for (let i = lowerings.length - 1; i >= 0 && !host; i--) {
|
|
3291
3306
|
const { plugin: plugin3, options: own } = lowerings[i];
|
|
3292
|
-
host = plugin3.files?.({ options: own ?? {}, directory: config?.directory ?? root, outDir, files: outputs, runtime: runtimeFile });
|
|
3307
|
+
host = plugin3.files?.({ options: own ?? {}, directory: config?.directory ?? root, rootDir, outDir, files: outputs, runtime: runtimeFile });
|
|
3293
3308
|
}
|
|
3294
3309
|
for (const problem of host?.problems ?? []) {
|
|
3295
3310
|
diagnostics.push({
|
|
@@ -3332,6 +3347,7 @@ async function bundle(options) {
|
|
|
3332
3347
|
const dynamicImports = /* @__PURE__ */ new Set();
|
|
3333
3348
|
const lowered2 = lower(source.program, source.scopes, {
|
|
3334
3349
|
names,
|
|
3350
|
+
perFile,
|
|
3335
3351
|
types: analysis.types.get(file),
|
|
3336
3352
|
lowerings,
|
|
3337
3353
|
noLib: config?.noLib,
|
|
@@ -3510,6 +3526,27 @@ ${G}.arrays[${G}.scriptArgs] = true`).body.statements);
|
|
|
3510
3526
|
files2.push({ path: runtimePath, code: `${runtimeCode}
|
|
3511
3527
|
${WRITTEN_BY_TILUA}: the runtime every file of the project requires.
|
|
3512
3528
|
`, modules: [] });
|
|
3529
|
+
try {
|
|
3530
|
+
const more = await host?.output?.();
|
|
3531
|
+
for (const { file, code } of more?.files ?? []) {
|
|
3532
|
+
if (isOutside(outDir, (0, import_node_path2.resolve)(file))) return stop(`A library's file has to go inside outDir, not at ${file}`);
|
|
3533
|
+
files2.push({ path: (0, import_node_path2.relative)(outDir, file).replace(/\\/g, "/"), code: `${code}
|
|
3534
|
+
${WRITTEN_BY_TILUA}: a library's own file.
|
|
3535
|
+
`, modules: [] });
|
|
3536
|
+
}
|
|
3537
|
+
for (const problem of more?.problems ?? []) {
|
|
3538
|
+
diagnostics.push({
|
|
3539
|
+
file: problem.file ?? config?.path ?? anchor,
|
|
3540
|
+
message: problem.message,
|
|
3541
|
+
line: 1,
|
|
3542
|
+
column: 1,
|
|
3543
|
+
category: "config",
|
|
3544
|
+
...problem.severity === "warning" && { severity: "warning" }
|
|
3545
|
+
});
|
|
3546
|
+
}
|
|
3547
|
+
} catch (error) {
|
|
3548
|
+
return stop(`A library could not write its files: ${error.message}`);
|
|
3549
|
+
}
|
|
3513
3550
|
return { code: files2[0].code, files: files2, modules: moduleNames, diagnostics };
|
|
3514
3551
|
}
|
|
3515
3552
|
const several = mode !== "single";
|
|
@@ -4066,7 +4103,11 @@ ${several ? `
|
|
|
4066
4103
|
})
|
|
4067
4104
|
record = { loading = true, exports = exports }
|
|
4068
4105
|
${G}.records[name] = record
|
|
4069
|
-
module
|
|
4106
|
+
-- A module runs once, so nothing keeps its body: anything can reach
|
|
4107
|
+
-- this table, and the body holds what the file kept to itself.
|
|
4108
|
+
local run = module.load
|
|
4109
|
+
module.load = nil
|
|
4110
|
+
run(exports)
|
|
4070
4111
|
record.loading = false
|
|
4071
4112
|
return exports
|
|
4072
4113
|
end,
|
|
@@ -4159,6 +4200,7 @@ function parsedLibrary(file) {
|
|
|
4159
4200
|
return program2;
|
|
4160
4201
|
}
|
|
4161
4202
|
var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
4203
|
+
var MAX_CYCLE_PASSES = 6;
|
|
4162
4204
|
function analyzeModules(modules, config) {
|
|
4163
4205
|
const out = [];
|
|
4164
4206
|
const analyses = /* @__PURE__ */ new Map();
|
|
@@ -4177,12 +4219,14 @@ function analyzeModules(modules, config) {
|
|
|
4177
4219
|
const inProgress = /* @__PURE__ */ new Set();
|
|
4178
4220
|
const analyzed = /* @__PURE__ */ new Map();
|
|
4179
4221
|
let partials = 0;
|
|
4222
|
+
const cycles = /* @__PURE__ */ new Set();
|
|
4223
|
+
const provisional = /* @__PURE__ */ new Map();
|
|
4180
4224
|
const readWhile = /* @__PURE__ */ new Map();
|
|
4181
4225
|
const settingFor = `${libraries.files.join("|")}#${config?.directory ?? ""}#${JSON.stringify(config?.paths ?? {})}`;
|
|
4182
4226
|
const analyzeModule = (file, program2) => {
|
|
4183
4227
|
const done = analyzed.get(file);
|
|
4184
4228
|
if (done) return done;
|
|
4185
|
-
const remembered = moduleAnalyses.get(file);
|
|
4229
|
+
const remembered = cycles.size ? void 0 : moduleAnalyses.get(file);
|
|
4186
4230
|
const script = scriptOf(file);
|
|
4187
4231
|
const ownLibs = script ? [...libs, script] : libs;
|
|
4188
4232
|
if (remembered && remembered.setting === settingFor && ownLibs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === ownLibs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
|
|
@@ -4210,6 +4254,8 @@ function analyzeModules(modules, config) {
|
|
|
4210
4254
|
const result2 = { types, diagnostics: said, scopes };
|
|
4211
4255
|
if (partials === before) {
|
|
4212
4256
|
analyzed.set(file, result2);
|
|
4257
|
+
}
|
|
4258
|
+
if (partials === before && !cycles.size) {
|
|
4213
4259
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
4214
4260
|
const own = stampOf(file);
|
|
4215
4261
|
if (own !== void 0) read3.set(file, own);
|
|
@@ -4232,7 +4278,8 @@ function analyzeModules(modules, config) {
|
|
|
4232
4278
|
};
|
|
4233
4279
|
if (inProgress.has(target)) {
|
|
4234
4280
|
partials++;
|
|
4235
|
-
|
|
4281
|
+
cycles.add(target);
|
|
4282
|
+
return provisional.get(target) ?? { values: /* @__PURE__ */ new Map(), types: /* @__PURE__ */ new Map(), partial: true };
|
|
4236
4283
|
}
|
|
4237
4284
|
const cached = exportsCache.get(target);
|
|
4238
4285
|
if (cached) {
|
|
@@ -4259,11 +4306,6 @@ function analyzeModules(modules, config) {
|
|
|
4259
4306
|
inProgress.delete(target);
|
|
4260
4307
|
}
|
|
4261
4308
|
};
|
|
4262
|
-
for (const module2 of modules) {
|
|
4263
|
-
const { types, diagnostics } = analyzeModule(module2.file, module2.program);
|
|
4264
|
-
analyses.set(module2.file, types);
|
|
4265
|
-
out.push(...diagnostics);
|
|
4266
|
-
}
|
|
4267
4309
|
const exportsOf = (file) => {
|
|
4268
4310
|
const cached = exportsCache.get(file);
|
|
4269
4311
|
if (cached) return cached;
|
|
@@ -4273,6 +4315,30 @@ function analyzeModules(modules, config) {
|
|
|
4273
4315
|
exportsCache.set(file, exports2);
|
|
4274
4316
|
return exports2;
|
|
4275
4317
|
};
|
|
4318
|
+
const reported = out.length;
|
|
4319
|
+
const libraryClasses = (0, import_parser7.classesOf)(libs);
|
|
4320
|
+
const fingerprints = /* @__PURE__ */ new Map();
|
|
4321
|
+
for (let pass = 1; ; pass++) {
|
|
4322
|
+
out.length = reported;
|
|
4323
|
+
for (const module2 of modules) {
|
|
4324
|
+
const { types, diagnostics } = analyzeModule(module2.file, module2.program);
|
|
4325
|
+
analyses.set(module2.file, types);
|
|
4326
|
+
out.push(...diagnostics);
|
|
4327
|
+
}
|
|
4328
|
+
if (!cycles.size || pass === MAX_CYCLE_PASSES) break;
|
|
4329
|
+
let settled = pass > 1;
|
|
4330
|
+
for (const file of cycles) {
|
|
4331
|
+
const exports2 = byFile.has(file) ? exportsOf(file) : exportsCache.get(file);
|
|
4332
|
+
if (exports2 && !exports2.partial) provisional.set(file, exports2);
|
|
4333
|
+
const fingerprint = exports2 && !exports2.partial ? (0, import_parser7.exportsFingerprint)(exports2, libraryClasses) : void 0;
|
|
4334
|
+
if (fingerprint === void 0 || fingerprint !== fingerprints.get(file)) settled = false;
|
|
4335
|
+
fingerprints.set(file, fingerprint);
|
|
4336
|
+
}
|
|
4337
|
+
if (settled) break;
|
|
4338
|
+
analyzed.clear();
|
|
4339
|
+
exportsCache.clear();
|
|
4340
|
+
readWhile.clear();
|
|
4341
|
+
}
|
|
4276
4342
|
return { types: analyses, diagnostics: out, lowerings: [...libraries.lowerings], exportsOf };
|
|
4277
4343
|
}
|
|
4278
4344
|
function allStatements(statements) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as T from '@tilua/parser';
|
|
2
2
|
import { OutputMode, TiluaConfig, ConfigProblem, LoweringPlugin, TypeAnalysis, ScopeAnalysis } from '@tilua/parser';
|
|
3
|
-
export { EntryExports, EntryExportsLowering, FilesAnswer, FilesLayout, LoweringPlugin, LuaSyntax, MethodCall, MethodLowering, PluginContext } from '@tilua/parser';
|
|
3
|
+
export { EntryExports, EntryExportsLowering, FilesAnswer, FilesLayout, FilesOutput, FilesProblem, LoweringPlugin, LuaSyntax, MethodCall, MethodLowering, PluginContext } from '@tilua/parser';
|
|
4
4
|
import * as L from 'luau-parser';
|
|
5
5
|
|
|
6
6
|
/** What `tilua.config.json` holds. */
|
|
@@ -264,6 +264,8 @@ interface ModuleContext {
|
|
|
264
264
|
readonly arrays?: string;
|
|
265
265
|
}
|
|
266
266
|
interface LowerOptions {
|
|
267
|
+
/** The build is `"output": "files"`, as a library is told. */
|
|
268
|
+
readonly perFile?: boolean;
|
|
267
269
|
/** Lower the file as a module of a bundle. Without it, `import` and
|
|
268
270
|
* `export` are errors. */
|
|
269
271
|
readonly module?: ModuleContext;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as T from '@tilua/parser';
|
|
2
2
|
import { OutputMode, TiluaConfig, ConfigProblem, LoweringPlugin, TypeAnalysis, ScopeAnalysis } from '@tilua/parser';
|
|
3
|
-
export { EntryExports, EntryExportsLowering, FilesAnswer, FilesLayout, LoweringPlugin, LuaSyntax, MethodCall, MethodLowering, PluginContext } from '@tilua/parser';
|
|
3
|
+
export { EntryExports, EntryExportsLowering, FilesAnswer, FilesLayout, FilesOutput, FilesProblem, LoweringPlugin, LuaSyntax, MethodCall, MethodLowering, PluginContext } from '@tilua/parser';
|
|
4
4
|
import * as L from 'luau-parser';
|
|
5
5
|
|
|
6
6
|
/** What `tilua.config.json` holds. */
|
|
@@ -264,6 +264,8 @@ interface ModuleContext {
|
|
|
264
264
|
readonly arrays?: string;
|
|
265
265
|
}
|
|
266
266
|
interface LowerOptions {
|
|
267
|
+
/** The build is `"output": "files"`, as a library is told. */
|
|
268
|
+
readonly perFile?: boolean;
|
|
267
269
|
/** Lower the file as a module of a bundle. Without it, `import` and
|
|
268
270
|
* `export` are errors. */
|
|
269
271
|
readonly module?: ModuleContext;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tilua/compiler",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.3",
|
|
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
|
"license": "ISC",
|
|
38
38
|
"type": "module",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@tilua/parser": "^9.1.
|
|
40
|
+
"@tilua/parser": "^9.1.3",
|
|
41
41
|
"luau-parser": "^1.1.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|