@tilua/compiler 3.1.0 → 4.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/README.md +24 -3
- package/dist/{chunk-VANZBLCL.js → chunk-VZ7XC4BG.js} +100 -23
- package/dist/cli.cjs +100 -23
- package/dist/cli.js +1 -1
- package/dist/index.cjs +100 -23
- 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/runtime/array.luau +5 -5
- package/runtime/object.luau +4 -4
- package/runtime/string.luau +2 -2
package/README.md
CHANGED
|
@@ -54,9 +54,10 @@ JavaScript module the build loads.
|
|
|
54
54
|
| tilua | Luau |
|
|
55
55
|
|---|---|
|
|
56
56
|
| `const { a, b } = value` | `local a, b = value.a, value.b` |
|
|
57
|
-
| `const [x, ...rest] = list` | `local x = list[1]; local rest = table.move(list, 2, #list, 1, {})` |
|
|
57
|
+
| `const [x, ...rest] = list` | `local x = list[1]; local rest = table.move(list, 2, #list, 1, {})` — `{}` written down as an array |
|
|
58
58
|
| `const { a = 1 } = t` | `local a = t.a; if a == nil then a = 1 end` |
|
|
59
|
-
| `[1, 2]` / `{ a: 1, b }` | `{ 1, 2 }` / `{ a = 1, b = b }` |
|
|
59
|
+
| `[1, 2]` / `{ a: 1, b }` | `tilua_asArray({ 1, 2 })` / `{ a = 1, b = b }` — see `typeof` below |
|
|
60
|
+
| `typeof v` | `tilua_typeof(v)`, or `tilua_typeof(v, "array")` where `v`'s type already says which table it is |
|
|
60
61
|
| `{ ...base, a: 1 }` / `[...xs, 1]` | a small helper copying the parts in order |
|
|
61
62
|
| `` `${a} any` `` | `("%s any"):format(tostring(a))` |
|
|
62
63
|
| `a?.b` | `if a == nil then nil else a.b` |
|
|
@@ -77,6 +78,26 @@ JavaScript module the build loads.
|
|
|
77
78
|
| `x as T`, `x satisfies T`, types, `declare` | removed |
|
|
78
79
|
| `names:filter(f)` | whatever the type library that declared `filter` says — see below |
|
|
79
80
|
|
|
81
|
+
## `typeof`, arrays and objects
|
|
82
|
+
|
|
83
|
+
Luau cannot tell an array from an object: both are tables, and an empty one
|
|
84
|
+
has nothing to go by. So every array the program makes is written down as
|
|
85
|
+
one where it is made — `[a, b]`, a rest parameter, `scriptArgs`, what
|
|
86
|
+
`:map`, `:filter`, `:keys` and the rest answer — in a table that holds its
|
|
87
|
+
keys weakly, one for the whole bundle. `tilua_asArray(t)` does that and hands
|
|
88
|
+
`t` back.
|
|
89
|
+
|
|
90
|
+
`typeof v` is Luau's `typeof` (Lua 5.1's `type`) for anything but a table.
|
|
91
|
+
For a table it answers, in order:
|
|
92
|
+
|
|
93
|
+
1. what `v`'s type says, where every table it can be is an array, or every
|
|
94
|
+
one an object — passed by the compiler, so nothing is looked up;
|
|
95
|
+
2. `"array"` if it was written down as one;
|
|
96
|
+
3. `"object"` if it has a metatable — an instance of a class;
|
|
97
|
+
4. `"array"` if it has a first element, and `"object"` otherwise: a table the
|
|
98
|
+
program did not make (one `JSONDecode` answered) is read by its shape, and
|
|
99
|
+
an empty one of those is an `"object"`.
|
|
100
|
+
|
|
80
101
|
## Classes
|
|
81
102
|
|
|
82
103
|
`class` is sugar over the Lua idiom, and it lowers to that idiom and nothing
|
|
@@ -185,7 +206,7 @@ argument (`arguments`: type, the code it was written as, and what a name was
|
|
|
185
206
|
declared as). An answer can `prepend` Luau expressions ahead of the written
|
|
186
207
|
arguments. `globalCall` and `globalValue` answer for a global, such as
|
|
187
208
|
`print(x)` or a bare `print`. A runtime can read `__LINES__` to reach the
|
|
188
|
-
bundle's line map
|
|
209
|
+
bundle's line map, and wraps a new array it answers with in `__ARRAY__(...)`. See the `@tilua/parser` README for the details.
|
|
189
210
|
`console:log` is not built into the compiler: `@tilua-types/lua` implements it
|
|
190
211
|
with these hooks.
|
|
191
212
|
|
|
@@ -210,11 +210,11 @@ var Lowerer = class {
|
|
|
210
210
|
origins = /* @__PURE__ */ new WeakMap();
|
|
211
211
|
run() {
|
|
212
212
|
const body = this.options.module ? this.module(this.options.module) : this.topLevel(this.source.body.statements);
|
|
213
|
+
const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [this.array(table([{ type: "TableFieldPositional", value: vararg() }]))])] : [];
|
|
213
214
|
const helpers = this.helperDefinitions();
|
|
214
215
|
const captured = [...this.builtins].map(([global, local2]) => local([local2], [identifier(global)]));
|
|
215
|
-
const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: vararg() }])])] : [];
|
|
216
216
|
return {
|
|
217
|
-
statements: [...
|
|
217
|
+
statements: [...captured, ...helpers, ...scriptArgs, ...this.classRuntimeStatements(), ...body],
|
|
218
218
|
exportsName: this.exportsName,
|
|
219
219
|
module: this.info,
|
|
220
220
|
diagnostics: this.diagnostics,
|
|
@@ -264,11 +264,36 @@ var Lowerer = class {
|
|
|
264
264
|
helper(kind) {
|
|
265
265
|
let name = this.helpers.get(kind);
|
|
266
266
|
if (!name) {
|
|
267
|
-
name = this.names.fresh(`tilua_${kind}`);
|
|
267
|
+
name = this.names.fresh(`tilua_${kind === "array" ? "asArray" : kind}`);
|
|
268
268
|
this.helpers.set(kind, name);
|
|
269
269
|
}
|
|
270
270
|
return identifier(name);
|
|
271
271
|
}
|
|
272
|
+
// `typeof v` tells an array from an object, which Luau cannot: both are
|
|
273
|
+
// tables. So every array the program makes — `[a, b]`, a rest parameter,
|
|
274
|
+
// what `:map` answers — is written down as one, in a table that holds its
|
|
275
|
+
// keys weakly, and `typeof` looks there. A table nothing wrote down (one a
|
|
276
|
+
// Lua library made) is told by its type where that says, and by its shape
|
|
277
|
+
// where it does not.
|
|
278
|
+
/** `value`, a new array, written down as one. */
|
|
279
|
+
array(value) {
|
|
280
|
+
const marked = call(this.helper("array"), [value]);
|
|
281
|
+
this.marked.add(marked);
|
|
282
|
+
return marked;
|
|
283
|
+
}
|
|
284
|
+
/** The calls `array` made: each answers the one table it was given. */
|
|
285
|
+
marked = /* @__PURE__ */ new WeakSet();
|
|
286
|
+
/** Luau reaching the record of arrays: the bundle's, or this file's own. */
|
|
287
|
+
arrays() {
|
|
288
|
+
return this.options.module?.arrays ?? this.helper("arrays").name;
|
|
289
|
+
}
|
|
290
|
+
typeofExpression(node) {
|
|
291
|
+
const known = this.options.types?.typeofTables.get(node);
|
|
292
|
+
let argument = node.argument;
|
|
293
|
+
while (argument.type === "ParenthesizedExpression") argument = argument.expression;
|
|
294
|
+
const value = this.expression(argument);
|
|
295
|
+
return call(this.helper("typeof"), known ? [value, string(known)] : [this.keptToOne(value)]);
|
|
296
|
+
}
|
|
272
297
|
/** The local a library's runtime table gets in this file, emitting it the
|
|
273
298
|
* first time something asks. Keyed by library and by the key the library
|
|
274
299
|
* itself chose, so two libraries' tables never collide. */
|
|
@@ -463,6 +488,46 @@ var Lowerer = class {
|
|
|
463
488
|
}
|
|
464
489
|
helperDefinitions() {
|
|
465
490
|
const out = [];
|
|
491
|
+
const runtimes = this.runtimeDefinitions();
|
|
492
|
+
if (this.helpers.has("concat")) this.helper("array");
|
|
493
|
+
const marker = this.helpers.get("array");
|
|
494
|
+
const typeOf = this.helpers.get("typeof");
|
|
495
|
+
if (marker || typeOf) {
|
|
496
|
+
const arrays = this.arrays();
|
|
497
|
+
const own = this.helpers.get("arrays");
|
|
498
|
+
if (own) {
|
|
499
|
+
out.push(...parseLuau(`local ${own} = ${this.builtin("setmetatable").name}({}, { __mode = "k" })`).body.statements);
|
|
500
|
+
}
|
|
501
|
+
if (marker) {
|
|
502
|
+
out.push(...parseLuau(`
|
|
503
|
+
local function ${marker}(t)
|
|
504
|
+
${arrays}[t] = true
|
|
505
|
+
return t
|
|
506
|
+
end`).body.statements);
|
|
507
|
+
}
|
|
508
|
+
if (typeOf) {
|
|
509
|
+
out.push(...parseLuau(`
|
|
510
|
+
local function ${typeOf}(value, known)
|
|
511
|
+
local name = ${this.builtin(this.lua51 ? "type" : "typeof").name}(value)
|
|
512
|
+
if name ~= "table" then
|
|
513
|
+
return name
|
|
514
|
+
end
|
|
515
|
+
if known ~= nil then
|
|
516
|
+
return known
|
|
517
|
+
end
|
|
518
|
+
if ${arrays}[value] then
|
|
519
|
+
return "array"
|
|
520
|
+
end
|
|
521
|
+
if ${this.builtin("getmetatable").name}(value) ~= nil then
|
|
522
|
+
return "object"
|
|
523
|
+
end
|
|
524
|
+
if #value > 0 then
|
|
525
|
+
return "array"
|
|
526
|
+
end
|
|
527
|
+
return "object"
|
|
528
|
+
end`).body.statements);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
466
531
|
const assign2 = this.helpers.get("assign");
|
|
467
532
|
if (assign2) {
|
|
468
533
|
out.push(localFunction(assign2, functionBody(["target"], [
|
|
@@ -477,25 +542,11 @@ var Lowerer = class {
|
|
|
477
542
|
returns([identifier("target")])
|
|
478
543
|
], true)));
|
|
479
544
|
}
|
|
480
|
-
|
|
481
|
-
const { plugin: plugin2, from } = this.lowerings[index2];
|
|
482
|
-
const source = plugin2.runtime?.[runtime2];
|
|
483
|
-
if (source === void 0) {
|
|
484
|
-
this.diagnostics.push({
|
|
485
|
-
message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
|
|
486
|
-
line: 1,
|
|
487
|
-
column: 1
|
|
488
|
-
});
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
const lines = this.options.module?.lines ?? "nil";
|
|
492
|
-
const fail = this.options.module?.fail ?? "nil";
|
|
493
|
-
out.push(...parseLuau(source.replace(/__NAME__/g, name).replace(/__LINES__/g, lines).replace(/__FAIL__/g, fail)).body.statements);
|
|
494
|
-
}
|
|
545
|
+
out.push(...runtimes);
|
|
495
546
|
const concat = this.helpers.get("concat");
|
|
496
547
|
if (concat) {
|
|
497
548
|
out.push(localFunction(concat, functionBody([], [
|
|
498
|
-
local(["result"], [table([])]),
|
|
549
|
+
local(["result"], [this.array(table([]))]),
|
|
499
550
|
numericFor("i", number(1), selectCount(this.builtin("select")), [
|
|
500
551
|
local(["part"], [call(this.builtin("select"), [identifier("i"), vararg()])]),
|
|
501
552
|
callStatement(call(member(this.builtin("table"), "move"), [
|
|
@@ -511,6 +562,26 @@ var Lowerer = class {
|
|
|
511
562
|
}
|
|
512
563
|
return out;
|
|
513
564
|
}
|
|
565
|
+
/** The runtime tables the file's libraries were asked for. */
|
|
566
|
+
runtimeDefinitions() {
|
|
567
|
+
const out = [];
|
|
568
|
+
for (const { index: index2, runtime: runtime2, name } of this.loweringUsed) {
|
|
569
|
+
const { plugin: plugin2, from } = this.lowerings[index2];
|
|
570
|
+
const source = plugin2.runtime?.[runtime2];
|
|
571
|
+
if (source === void 0) {
|
|
572
|
+
this.diagnostics.push({
|
|
573
|
+
message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
|
|
574
|
+
line: 1,
|
|
575
|
+
column: 1
|
|
576
|
+
});
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
const lines = this.options.module?.lines ?? "nil";
|
|
580
|
+
const fail = this.options.module?.fail ?? "nil";
|
|
581
|
+
out.push(...parseLuau(source.replace(/__NAME__/g, name).replace(/__LINES__/g, lines).replace(/__FAIL__/g, fail).replace(/__ARRAY__/g, () => this.helper("array").name)).body.statements);
|
|
582
|
+
}
|
|
583
|
+
return out;
|
|
584
|
+
}
|
|
514
585
|
// --------------------------------------------------------
|
|
515
586
|
// Modules
|
|
516
587
|
// --------------------------------------------------------
|
|
@@ -1263,7 +1334,7 @@ end
|
|
|
1263
1334
|
number(pattern.elements.length + 1),
|
|
1264
1335
|
unary("#", source),
|
|
1265
1336
|
number(1),
|
|
1266
|
-
table([])
|
|
1337
|
+
this.array(table([]))
|
|
1267
1338
|
]);
|
|
1268
1339
|
const rest = this.restTarget(pattern.rest, elements, mode, after);
|
|
1269
1340
|
after.push(...rest.then);
|
|
@@ -1317,7 +1388,7 @@ end
|
|
|
1317
1388
|
const names = [];
|
|
1318
1389
|
for (const p of params) {
|
|
1319
1390
|
if (p.rest) {
|
|
1320
|
-
prelude.push(local([this.name(p.name)], [table([{ type: "TableFieldPositional", value: vararg() }])]));
|
|
1391
|
+
prelude.push(local([this.name(p.name)], [this.array(table([{ type: "TableFieldPositional", value: vararg() }]))]));
|
|
1321
1392
|
continue;
|
|
1322
1393
|
}
|
|
1323
1394
|
const name = p.pattern ? this.names.fresh("arg") : this.name(p.name);
|
|
@@ -1375,6 +1446,7 @@ end
|
|
|
1375
1446
|
return binary(node.operator, left, right);
|
|
1376
1447
|
}
|
|
1377
1448
|
case "UnaryExpression":
|
|
1449
|
+
if (node.operator === "typeof") return this.typeofExpression(node);
|
|
1378
1450
|
return unary(node.operator, this.expression(node.argument));
|
|
1379
1451
|
case "SuperExpression":
|
|
1380
1452
|
return this.superClassReference(node);
|
|
@@ -1429,7 +1501,7 @@ end
|
|
|
1429
1501
|
* kept to one there, `f((g()))`. Every value is taken only where the
|
|
1430
1502
|
* program asks for them, as an array's last element: `[g()]`. */
|
|
1431
1503
|
keptToOne(value) {
|
|
1432
|
-
return expandsToMany(value) ? parenthesized(value) : value;
|
|
1504
|
+
return expandsToMany(value) && !this.marked.has(value) ? parenthesized(value) : value;
|
|
1433
1505
|
}
|
|
1434
1506
|
/** Is this `scriptArgs` the language's own, not a name the file declared? */
|
|
1435
1507
|
isLanguageGlobal(node) {
|
|
@@ -1710,7 +1782,7 @@ end
|
|
|
1710
1782
|
arrayExpression(node) {
|
|
1711
1783
|
const elements = packs(node.elements).items;
|
|
1712
1784
|
if (!elements.some((e) => e.type === "SpreadElement")) {
|
|
1713
|
-
return table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
|
|
1785
|
+
return this.array(table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) }))));
|
|
1714
1786
|
}
|
|
1715
1787
|
const parts = [];
|
|
1716
1788
|
let current = [];
|
|
@@ -2100,6 +2172,7 @@ async function bundle(options) {
|
|
|
2100
2172
|
require: requireExpression,
|
|
2101
2173
|
lines: `${G}.lines`,
|
|
2102
2174
|
fail: `${G}.fail`,
|
|
2175
|
+
arrays: `${G}.arrays`,
|
|
2103
2176
|
resolve: (specifier) => {
|
|
2104
2177
|
const target = resolveModulePath(file, specifier, config);
|
|
2105
2178
|
if (!target || target.endsWith(".d.tilua") || !sources.has(target)) return void 0;
|
|
@@ -2145,6 +2218,7 @@ async function bundle(options) {
|
|
|
2145
2218
|
const assignment = program2.body.statements[1];
|
|
2146
2219
|
if ([...modules.values()].some((m) => m.usesScriptArgs)) {
|
|
2147
2220
|
program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
|
|
2221
|
+
program2.body.statements.push(...parseLuau2(`${G}.arrays[scriptArgs] = true`).body.statements);
|
|
2148
2222
|
}
|
|
2149
2223
|
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;
|
|
2150
2224
|
if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
|
|
@@ -2188,6 +2262,9 @@ function runtime(G) {
|
|
|
2188
2262
|
local ${G}
|
|
2189
2263
|
${G} = {
|
|
2190
2264
|
modules = {},
|
|
2265
|
+
-- Every array the program made, so \`typeof\` can tell one from an object.
|
|
2266
|
+
-- The keys are held weakly: being written down keeps no array alive.
|
|
2267
|
+
arrays = setmetatable({}, { __mode = "k" }),
|
|
2191
2268
|
-- Filled in just before the entry runs: bundle line -> { file, line }.
|
|
2192
2269
|
lines = nil,
|
|
2193
2270
|
-- What an error nothing caught says, in the project's files: the bundle's
|
package/dist/cli.cjs
CHANGED
|
@@ -226,11 +226,11 @@ var Lowerer = class {
|
|
|
226
226
|
origins = /* @__PURE__ */ new WeakMap();
|
|
227
227
|
run() {
|
|
228
228
|
const body = this.options.module ? this.module(this.options.module) : this.topLevel(this.source.body.statements);
|
|
229
|
+
const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [this.array(table([{ type: "TableFieldPositional", value: vararg() }]))])] : [];
|
|
229
230
|
const helpers = this.helperDefinitions();
|
|
230
231
|
const captured = [...this.builtins].map(([global, local2]) => local([local2], [identifier(global)]));
|
|
231
|
-
const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: vararg() }])])] : [];
|
|
232
232
|
return {
|
|
233
|
-
statements: [...
|
|
233
|
+
statements: [...captured, ...helpers, ...scriptArgs, ...this.classRuntimeStatements(), ...body],
|
|
234
234
|
exportsName: this.exportsName,
|
|
235
235
|
module: this.info,
|
|
236
236
|
diagnostics: this.diagnostics,
|
|
@@ -280,11 +280,36 @@ var Lowerer = class {
|
|
|
280
280
|
helper(kind) {
|
|
281
281
|
let name = this.helpers.get(kind);
|
|
282
282
|
if (!name) {
|
|
283
|
-
name = this.names.fresh(`tilua_${kind}`);
|
|
283
|
+
name = this.names.fresh(`tilua_${kind === "array" ? "asArray" : kind}`);
|
|
284
284
|
this.helpers.set(kind, name);
|
|
285
285
|
}
|
|
286
286
|
return identifier(name);
|
|
287
287
|
}
|
|
288
|
+
// `typeof v` tells an array from an object, which Luau cannot: both are
|
|
289
|
+
// tables. So every array the program makes — `[a, b]`, a rest parameter,
|
|
290
|
+
// what `:map` answers — is written down as one, in a table that holds its
|
|
291
|
+
// keys weakly, and `typeof` looks there. A table nothing wrote down (one a
|
|
292
|
+
// Lua library made) is told by its type where that says, and by its shape
|
|
293
|
+
// where it does not.
|
|
294
|
+
/** `value`, a new array, written down as one. */
|
|
295
|
+
array(value) {
|
|
296
|
+
const marked = call(this.helper("array"), [value]);
|
|
297
|
+
this.marked.add(marked);
|
|
298
|
+
return marked;
|
|
299
|
+
}
|
|
300
|
+
/** The calls `array` made: each answers the one table it was given. */
|
|
301
|
+
marked = /* @__PURE__ */ new WeakSet();
|
|
302
|
+
/** Luau reaching the record of arrays: the bundle's, or this file's own. */
|
|
303
|
+
arrays() {
|
|
304
|
+
return this.options.module?.arrays ?? this.helper("arrays").name;
|
|
305
|
+
}
|
|
306
|
+
typeofExpression(node) {
|
|
307
|
+
const known = this.options.types?.typeofTables.get(node);
|
|
308
|
+
let argument = node.argument;
|
|
309
|
+
while (argument.type === "ParenthesizedExpression") argument = argument.expression;
|
|
310
|
+
const value = this.expression(argument);
|
|
311
|
+
return call(this.helper("typeof"), known ? [value, string(known)] : [this.keptToOne(value)]);
|
|
312
|
+
}
|
|
288
313
|
/** The local a library's runtime table gets in this file, emitting it the
|
|
289
314
|
* first time something asks. Keyed by library and by the key the library
|
|
290
315
|
* itself chose, so two libraries' tables never collide. */
|
|
@@ -479,6 +504,46 @@ var Lowerer = class {
|
|
|
479
504
|
}
|
|
480
505
|
helperDefinitions() {
|
|
481
506
|
const out2 = [];
|
|
507
|
+
const runtimes = this.runtimeDefinitions();
|
|
508
|
+
if (this.helpers.has("concat")) this.helper("array");
|
|
509
|
+
const marker = this.helpers.get("array");
|
|
510
|
+
const typeOf = this.helpers.get("typeof");
|
|
511
|
+
if (marker || typeOf) {
|
|
512
|
+
const arrays = this.arrays();
|
|
513
|
+
const own = this.helpers.get("arrays");
|
|
514
|
+
if (own) {
|
|
515
|
+
out2.push(...(0, import_luau_parser.parse)(`local ${own} = ${this.builtin("setmetatable").name}({}, { __mode = "k" })`).body.statements);
|
|
516
|
+
}
|
|
517
|
+
if (marker) {
|
|
518
|
+
out2.push(...(0, import_luau_parser.parse)(`
|
|
519
|
+
local function ${marker}(t)
|
|
520
|
+
${arrays}[t] = true
|
|
521
|
+
return t
|
|
522
|
+
end`).body.statements);
|
|
523
|
+
}
|
|
524
|
+
if (typeOf) {
|
|
525
|
+
out2.push(...(0, import_luau_parser.parse)(`
|
|
526
|
+
local function ${typeOf}(value, known)
|
|
527
|
+
local name = ${this.builtin(this.lua51 ? "type" : "typeof").name}(value)
|
|
528
|
+
if name ~= "table" then
|
|
529
|
+
return name
|
|
530
|
+
end
|
|
531
|
+
if known ~= nil then
|
|
532
|
+
return known
|
|
533
|
+
end
|
|
534
|
+
if ${arrays}[value] then
|
|
535
|
+
return "array"
|
|
536
|
+
end
|
|
537
|
+
if ${this.builtin("getmetatable").name}(value) ~= nil then
|
|
538
|
+
return "object"
|
|
539
|
+
end
|
|
540
|
+
if #value > 0 then
|
|
541
|
+
return "array"
|
|
542
|
+
end
|
|
543
|
+
return "object"
|
|
544
|
+
end`).body.statements);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
482
547
|
const assign2 = this.helpers.get("assign");
|
|
483
548
|
if (assign2) {
|
|
484
549
|
out2.push(localFunction(assign2, functionBody(["target"], [
|
|
@@ -493,25 +558,11 @@ var Lowerer = class {
|
|
|
493
558
|
returns([identifier("target")])
|
|
494
559
|
], true)));
|
|
495
560
|
}
|
|
496
|
-
|
|
497
|
-
const { plugin: plugin2, from } = this.lowerings[index2];
|
|
498
|
-
const source = plugin2.runtime?.[runtime2];
|
|
499
|
-
if (source === void 0) {
|
|
500
|
-
this.diagnostics.push({
|
|
501
|
-
message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
|
|
502
|
-
line: 1,
|
|
503
|
-
column: 1
|
|
504
|
-
});
|
|
505
|
-
continue;
|
|
506
|
-
}
|
|
507
|
-
const lines = this.options.module?.lines ?? "nil";
|
|
508
|
-
const fail = this.options.module?.fail ?? "nil";
|
|
509
|
-
out2.push(...(0, import_luau_parser.parse)(source.replace(/__NAME__/g, name).replace(/__LINES__/g, lines).replace(/__FAIL__/g, fail)).body.statements);
|
|
510
|
-
}
|
|
561
|
+
out2.push(...runtimes);
|
|
511
562
|
const concat = this.helpers.get("concat");
|
|
512
563
|
if (concat) {
|
|
513
564
|
out2.push(localFunction(concat, functionBody([], [
|
|
514
|
-
local(["result"], [table([])]),
|
|
565
|
+
local(["result"], [this.array(table([]))]),
|
|
515
566
|
numericFor("i", number(1), selectCount(this.builtin("select")), [
|
|
516
567
|
local(["part"], [call(this.builtin("select"), [identifier("i"), vararg()])]),
|
|
517
568
|
callStatement(call(member(this.builtin("table"), "move"), [
|
|
@@ -527,6 +578,26 @@ var Lowerer = class {
|
|
|
527
578
|
}
|
|
528
579
|
return out2;
|
|
529
580
|
}
|
|
581
|
+
/** The runtime tables the file's libraries were asked for. */
|
|
582
|
+
runtimeDefinitions() {
|
|
583
|
+
const out2 = [];
|
|
584
|
+
for (const { index: index2, runtime: runtime2, name } of this.loweringUsed) {
|
|
585
|
+
const { plugin: plugin2, from } = this.lowerings[index2];
|
|
586
|
+
const source = plugin2.runtime?.[runtime2];
|
|
587
|
+
if (source === void 0) {
|
|
588
|
+
this.diagnostics.push({
|
|
589
|
+
message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
|
|
590
|
+
line: 1,
|
|
591
|
+
column: 1
|
|
592
|
+
});
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
const lines = this.options.module?.lines ?? "nil";
|
|
596
|
+
const fail = this.options.module?.fail ?? "nil";
|
|
597
|
+
out2.push(...(0, import_luau_parser.parse)(source.replace(/__NAME__/g, name).replace(/__LINES__/g, lines).replace(/__FAIL__/g, fail).replace(/__ARRAY__/g, () => this.helper("array").name)).body.statements);
|
|
598
|
+
}
|
|
599
|
+
return out2;
|
|
600
|
+
}
|
|
530
601
|
// --------------------------------------------------------
|
|
531
602
|
// Modules
|
|
532
603
|
// --------------------------------------------------------
|
|
@@ -1279,7 +1350,7 @@ end
|
|
|
1279
1350
|
number(pattern.elements.length + 1),
|
|
1280
1351
|
unary("#", source),
|
|
1281
1352
|
number(1),
|
|
1282
|
-
table([])
|
|
1353
|
+
this.array(table([]))
|
|
1283
1354
|
]);
|
|
1284
1355
|
const rest = this.restTarget(pattern.rest, elements, mode, after);
|
|
1285
1356
|
after.push(...rest.then);
|
|
@@ -1333,7 +1404,7 @@ end
|
|
|
1333
1404
|
const names = [];
|
|
1334
1405
|
for (const p of params) {
|
|
1335
1406
|
if (p.rest) {
|
|
1336
|
-
prelude.push(local([this.name(p.name)], [table([{ type: "TableFieldPositional", value: vararg() }])]));
|
|
1407
|
+
prelude.push(local([this.name(p.name)], [this.array(table([{ type: "TableFieldPositional", value: vararg() }]))]));
|
|
1337
1408
|
continue;
|
|
1338
1409
|
}
|
|
1339
1410
|
const name = p.pattern ? this.names.fresh("arg") : this.name(p.name);
|
|
@@ -1391,6 +1462,7 @@ end
|
|
|
1391
1462
|
return binary(node.operator, left, right);
|
|
1392
1463
|
}
|
|
1393
1464
|
case "UnaryExpression":
|
|
1465
|
+
if (node.operator === "typeof") return this.typeofExpression(node);
|
|
1394
1466
|
return unary(node.operator, this.expression(node.argument));
|
|
1395
1467
|
case "SuperExpression":
|
|
1396
1468
|
return this.superClassReference(node);
|
|
@@ -1445,7 +1517,7 @@ end
|
|
|
1445
1517
|
* kept to one there, `f((g()))`. Every value is taken only where the
|
|
1446
1518
|
* program asks for them, as an array's last element: `[g()]`. */
|
|
1447
1519
|
keptToOne(value) {
|
|
1448
|
-
return expandsToMany(value) ? parenthesized(value) : value;
|
|
1520
|
+
return expandsToMany(value) && !this.marked.has(value) ? parenthesized(value) : value;
|
|
1449
1521
|
}
|
|
1450
1522
|
/** Is this `scriptArgs` the language's own, not a name the file declared? */
|
|
1451
1523
|
isLanguageGlobal(node) {
|
|
@@ -1726,7 +1798,7 @@ end
|
|
|
1726
1798
|
arrayExpression(node) {
|
|
1727
1799
|
const elements = packs(node.elements).items;
|
|
1728
1800
|
if (!elements.some((e) => e.type === "SpreadElement")) {
|
|
1729
|
-
return table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
|
|
1801
|
+
return this.array(table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) }))));
|
|
1730
1802
|
}
|
|
1731
1803
|
const parts = [];
|
|
1732
1804
|
let current = [];
|
|
@@ -2097,6 +2169,7 @@ async function bundle(options) {
|
|
|
2097
2169
|
require: requireExpression,
|
|
2098
2170
|
lines: `${G}.lines`,
|
|
2099
2171
|
fail: `${G}.fail`,
|
|
2172
|
+
arrays: `${G}.arrays`,
|
|
2100
2173
|
resolve: (specifier) => {
|
|
2101
2174
|
const target = (0, import_parser6.resolveModulePath)(file, specifier, config2);
|
|
2102
2175
|
if (!target || target.endsWith(".d.tilua") || !sources.has(target)) return void 0;
|
|
@@ -2142,6 +2215,7 @@ async function bundle(options) {
|
|
|
2142
2215
|
const assignment = program.body.statements[1];
|
|
2143
2216
|
if ([...modules.values()].some((m) => m.usesScriptArgs)) {
|
|
2144
2217
|
program.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
|
|
2218
|
+
program.body.statements.push(...(0, import_luau_parser2.parse)(`${G}.arrays[scriptArgs] = true`).body.statements);
|
|
2145
2219
|
}
|
|
2146
2220
|
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;
|
|
2147
2221
|
if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
|
|
@@ -2185,6 +2259,9 @@ function runtime(G) {
|
|
|
2185
2259
|
local ${G}
|
|
2186
2260
|
${G} = {
|
|
2187
2261
|
modules = {},
|
|
2262
|
+
-- Every array the program made, so \`typeof\` can tell one from an object.
|
|
2263
|
+
-- The keys are held weakly: being written down keeps no array alive.
|
|
2264
|
+
arrays = setmetatable({}, { __mode = "k" }),
|
|
2188
2265
|
-- Filled in just before the entry runs: bundle line -> { file, line }.
|
|
2189
2266
|
lines = nil,
|
|
2190
2267
|
-- What an error nothing caught says, in the project's files: the bundle's
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -250,11 +250,11 @@ var Lowerer = class {
|
|
|
250
250
|
origins = /* @__PURE__ */ new WeakMap();
|
|
251
251
|
run() {
|
|
252
252
|
const body = this.options.module ? this.module(this.options.module) : this.topLevel(this.source.body.statements);
|
|
253
|
+
const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [this.array(table([{ type: "TableFieldPositional", value: vararg() }]))])] : [];
|
|
253
254
|
const helpers = this.helperDefinitions();
|
|
254
255
|
const captured = [...this.builtins].map(([global, local2]) => local([local2], [identifier(global)]));
|
|
255
|
-
const scriptArgs = this.usesScriptArgs && !this.options.module ? [local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: vararg() }])])] : [];
|
|
256
256
|
return {
|
|
257
|
-
statements: [...
|
|
257
|
+
statements: [...captured, ...helpers, ...scriptArgs, ...this.classRuntimeStatements(), ...body],
|
|
258
258
|
exportsName: this.exportsName,
|
|
259
259
|
module: this.info,
|
|
260
260
|
diagnostics: this.diagnostics,
|
|
@@ -304,11 +304,36 @@ var Lowerer = class {
|
|
|
304
304
|
helper(kind) {
|
|
305
305
|
let name = this.helpers.get(kind);
|
|
306
306
|
if (!name) {
|
|
307
|
-
name = this.names.fresh(`tilua_${kind}`);
|
|
307
|
+
name = this.names.fresh(`tilua_${kind === "array" ? "asArray" : kind}`);
|
|
308
308
|
this.helpers.set(kind, name);
|
|
309
309
|
}
|
|
310
310
|
return identifier(name);
|
|
311
311
|
}
|
|
312
|
+
// `typeof v` tells an array from an object, which Luau cannot: both are
|
|
313
|
+
// tables. So every array the program makes — `[a, b]`, a rest parameter,
|
|
314
|
+
// what `:map` answers — is written down as one, in a table that holds its
|
|
315
|
+
// keys weakly, and `typeof` looks there. A table nothing wrote down (one a
|
|
316
|
+
// Lua library made) is told by its type where that says, and by its shape
|
|
317
|
+
// where it does not.
|
|
318
|
+
/** `value`, a new array, written down as one. */
|
|
319
|
+
array(value) {
|
|
320
|
+
const marked = call(this.helper("array"), [value]);
|
|
321
|
+
this.marked.add(marked);
|
|
322
|
+
return marked;
|
|
323
|
+
}
|
|
324
|
+
/** The calls `array` made: each answers the one table it was given. */
|
|
325
|
+
marked = /* @__PURE__ */ new WeakSet();
|
|
326
|
+
/** Luau reaching the record of arrays: the bundle's, or this file's own. */
|
|
327
|
+
arrays() {
|
|
328
|
+
return this.options.module?.arrays ?? this.helper("arrays").name;
|
|
329
|
+
}
|
|
330
|
+
typeofExpression(node) {
|
|
331
|
+
const known = this.options.types?.typeofTables.get(node);
|
|
332
|
+
let argument = node.argument;
|
|
333
|
+
while (argument.type === "ParenthesizedExpression") argument = argument.expression;
|
|
334
|
+
const value = this.expression(argument);
|
|
335
|
+
return call(this.helper("typeof"), known ? [value, string(known)] : [this.keptToOne(value)]);
|
|
336
|
+
}
|
|
312
337
|
/** The local a library's runtime table gets in this file, emitting it the
|
|
313
338
|
* first time something asks. Keyed by library and by the key the library
|
|
314
339
|
* itself chose, so two libraries' tables never collide. */
|
|
@@ -503,6 +528,46 @@ var Lowerer = class {
|
|
|
503
528
|
}
|
|
504
529
|
helperDefinitions() {
|
|
505
530
|
const out = [];
|
|
531
|
+
const runtimes = this.runtimeDefinitions();
|
|
532
|
+
if (this.helpers.has("concat")) this.helper("array");
|
|
533
|
+
const marker = this.helpers.get("array");
|
|
534
|
+
const typeOf = this.helpers.get("typeof");
|
|
535
|
+
if (marker || typeOf) {
|
|
536
|
+
const arrays = this.arrays();
|
|
537
|
+
const own = this.helpers.get("arrays");
|
|
538
|
+
if (own) {
|
|
539
|
+
out.push(...(0, import_luau_parser.parse)(`local ${own} = ${this.builtin("setmetatable").name}({}, { __mode = "k" })`).body.statements);
|
|
540
|
+
}
|
|
541
|
+
if (marker) {
|
|
542
|
+
out.push(...(0, import_luau_parser.parse)(`
|
|
543
|
+
local function ${marker}(t)
|
|
544
|
+
${arrays}[t] = true
|
|
545
|
+
return t
|
|
546
|
+
end`).body.statements);
|
|
547
|
+
}
|
|
548
|
+
if (typeOf) {
|
|
549
|
+
out.push(...(0, import_luau_parser.parse)(`
|
|
550
|
+
local function ${typeOf}(value, known)
|
|
551
|
+
local name = ${this.builtin(this.lua51 ? "type" : "typeof").name}(value)
|
|
552
|
+
if name ~= "table" then
|
|
553
|
+
return name
|
|
554
|
+
end
|
|
555
|
+
if known ~= nil then
|
|
556
|
+
return known
|
|
557
|
+
end
|
|
558
|
+
if ${arrays}[value] then
|
|
559
|
+
return "array"
|
|
560
|
+
end
|
|
561
|
+
if ${this.builtin("getmetatable").name}(value) ~= nil then
|
|
562
|
+
return "object"
|
|
563
|
+
end
|
|
564
|
+
if #value > 0 then
|
|
565
|
+
return "array"
|
|
566
|
+
end
|
|
567
|
+
return "object"
|
|
568
|
+
end`).body.statements);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
506
571
|
const assign2 = this.helpers.get("assign");
|
|
507
572
|
if (assign2) {
|
|
508
573
|
out.push(localFunction(assign2, functionBody(["target"], [
|
|
@@ -517,25 +582,11 @@ var Lowerer = class {
|
|
|
517
582
|
returns([identifier("target")])
|
|
518
583
|
], true)));
|
|
519
584
|
}
|
|
520
|
-
|
|
521
|
-
const { plugin: plugin2, from } = this.lowerings[index2];
|
|
522
|
-
const source = plugin2.runtime?.[runtime2];
|
|
523
|
-
if (source === void 0) {
|
|
524
|
-
this.diagnostics.push({
|
|
525
|
-
message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
|
|
526
|
-
line: 1,
|
|
527
|
-
column: 1
|
|
528
|
-
});
|
|
529
|
-
continue;
|
|
530
|
-
}
|
|
531
|
-
const lines = this.options.module?.lines ?? "nil";
|
|
532
|
-
const fail = this.options.module?.fail ?? "nil";
|
|
533
|
-
out.push(...(0, import_luau_parser.parse)(source.replace(/__NAME__/g, name).replace(/__LINES__/g, lines).replace(/__FAIL__/g, fail)).body.statements);
|
|
534
|
-
}
|
|
585
|
+
out.push(...runtimes);
|
|
535
586
|
const concat = this.helpers.get("concat");
|
|
536
587
|
if (concat) {
|
|
537
588
|
out.push(localFunction(concat, functionBody([], [
|
|
538
|
-
local(["result"], [table([])]),
|
|
589
|
+
local(["result"], [this.array(table([]))]),
|
|
539
590
|
numericFor("i", number(1), selectCount(this.builtin("select")), [
|
|
540
591
|
local(["part"], [call(this.builtin("select"), [identifier("i"), vararg()])]),
|
|
541
592
|
callStatement(call(member(this.builtin("table"), "move"), [
|
|
@@ -551,6 +602,26 @@ var Lowerer = class {
|
|
|
551
602
|
}
|
|
552
603
|
return out;
|
|
553
604
|
}
|
|
605
|
+
/** The runtime tables the file's libraries were asked for. */
|
|
606
|
+
runtimeDefinitions() {
|
|
607
|
+
const out = [];
|
|
608
|
+
for (const { index: index2, runtime: runtime2, name } of this.loweringUsed) {
|
|
609
|
+
const { plugin: plugin2, from } = this.lowerings[index2];
|
|
610
|
+
const source = plugin2.runtime?.[runtime2];
|
|
611
|
+
if (source === void 0) {
|
|
612
|
+
this.diagnostics.push({
|
|
613
|
+
message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
|
|
614
|
+
line: 1,
|
|
615
|
+
column: 1
|
|
616
|
+
});
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
const lines = this.options.module?.lines ?? "nil";
|
|
620
|
+
const fail = this.options.module?.fail ?? "nil";
|
|
621
|
+
out.push(...(0, import_luau_parser.parse)(source.replace(/__NAME__/g, name).replace(/__LINES__/g, lines).replace(/__FAIL__/g, fail).replace(/__ARRAY__/g, () => this.helper("array").name)).body.statements);
|
|
622
|
+
}
|
|
623
|
+
return out;
|
|
624
|
+
}
|
|
554
625
|
// --------------------------------------------------------
|
|
555
626
|
// Modules
|
|
556
627
|
// --------------------------------------------------------
|
|
@@ -1303,7 +1374,7 @@ end
|
|
|
1303
1374
|
number(pattern.elements.length + 1),
|
|
1304
1375
|
unary("#", source),
|
|
1305
1376
|
number(1),
|
|
1306
|
-
table([])
|
|
1377
|
+
this.array(table([]))
|
|
1307
1378
|
]);
|
|
1308
1379
|
const rest = this.restTarget(pattern.rest, elements, mode, after);
|
|
1309
1380
|
after.push(...rest.then);
|
|
@@ -1357,7 +1428,7 @@ end
|
|
|
1357
1428
|
const names = [];
|
|
1358
1429
|
for (const p of params) {
|
|
1359
1430
|
if (p.rest) {
|
|
1360
|
-
prelude.push(local([this.name(p.name)], [table([{ type: "TableFieldPositional", value: vararg() }])]));
|
|
1431
|
+
prelude.push(local([this.name(p.name)], [this.array(table([{ type: "TableFieldPositional", value: vararg() }]))]));
|
|
1361
1432
|
continue;
|
|
1362
1433
|
}
|
|
1363
1434
|
const name = p.pattern ? this.names.fresh("arg") : this.name(p.name);
|
|
@@ -1415,6 +1486,7 @@ end
|
|
|
1415
1486
|
return binary(node.operator, left, right);
|
|
1416
1487
|
}
|
|
1417
1488
|
case "UnaryExpression":
|
|
1489
|
+
if (node.operator === "typeof") return this.typeofExpression(node);
|
|
1418
1490
|
return unary(node.operator, this.expression(node.argument));
|
|
1419
1491
|
case "SuperExpression":
|
|
1420
1492
|
return this.superClassReference(node);
|
|
@@ -1469,7 +1541,7 @@ end
|
|
|
1469
1541
|
* kept to one there, `f((g()))`. Every value is taken only where the
|
|
1470
1542
|
* program asks for them, as an array's last element: `[g()]`. */
|
|
1471
1543
|
keptToOne(value) {
|
|
1472
|
-
return expandsToMany(value) ? parenthesized(value) : value;
|
|
1544
|
+
return expandsToMany(value) && !this.marked.has(value) ? parenthesized(value) : value;
|
|
1473
1545
|
}
|
|
1474
1546
|
/** Is this `scriptArgs` the language's own, not a name the file declared? */
|
|
1475
1547
|
isLanguageGlobal(node) {
|
|
@@ -1750,7 +1822,7 @@ end
|
|
|
1750
1822
|
arrayExpression(node) {
|
|
1751
1823
|
const elements = packs(node.elements).items;
|
|
1752
1824
|
if (!elements.some((e) => e.type === "SpreadElement")) {
|
|
1753
|
-
return table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
|
|
1825
|
+
return this.array(table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) }))));
|
|
1754
1826
|
}
|
|
1755
1827
|
const parts = [];
|
|
1756
1828
|
let current = [];
|
|
@@ -2121,6 +2193,7 @@ async function bundle(options) {
|
|
|
2121
2193
|
require: requireExpression,
|
|
2122
2194
|
lines: `${G}.lines`,
|
|
2123
2195
|
fail: `${G}.fail`,
|
|
2196
|
+
arrays: `${G}.arrays`,
|
|
2124
2197
|
resolve: (specifier) => {
|
|
2125
2198
|
const target = (0, import_parser6.resolveModulePath)(file, specifier, config);
|
|
2126
2199
|
if (!target || target.endsWith(".d.tilua") || !sources.has(target)) return void 0;
|
|
@@ -2166,6 +2239,7 @@ async function bundle(options) {
|
|
|
2166
2239
|
const assignment = program2.body.statements[1];
|
|
2167
2240
|
if ([...modules.values()].some((m) => m.usesScriptArgs)) {
|
|
2168
2241
|
program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
|
|
2242
|
+
program2.body.statements.push(...(0, import_luau_parser2.parse)(`${G}.arrays[scriptArgs] = true`).body.statements);
|
|
2169
2243
|
}
|
|
2170
2244
|
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;
|
|
2171
2245
|
if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
|
|
@@ -2209,6 +2283,9 @@ function runtime(G) {
|
|
|
2209
2283
|
local ${G}
|
|
2210
2284
|
${G} = {
|
|
2211
2285
|
modules = {},
|
|
2286
|
+
-- Every array the program made, so \`typeof\` can tell one from an object.
|
|
2287
|
+
-- The keys are held weakly: being written down keeps no array alive.
|
|
2288
|
+
arrays = setmetatable({}, { __mode = "k" }),
|
|
2212
2289
|
-- Filled in just before the entry runs: bundle line -> { file, line }.
|
|
2213
2290
|
lines = nil,
|
|
2214
2291
|
-- What an error nothing caught says, in the project's files: the bundle's
|
package/dist/index.d.cts
CHANGED
|
@@ -100,6 +100,9 @@ interface ModuleContext {
|
|
|
100
100
|
* reads, as `__FAIL__`, to report an error from a callback the way an
|
|
101
101
|
* error that reached the entry is reported. */
|
|
102
102
|
readonly fail?: string;
|
|
103
|
+
/** Luau reaching the bundle's record of which tables are arrays, so that
|
|
104
|
+
* every module marks and reads the same one (`typeof`). */
|
|
105
|
+
readonly arrays?: string;
|
|
103
106
|
}
|
|
104
107
|
interface LowerOptions {
|
|
105
108
|
/** Lower the file as a module of a bundle. Without it, `import` and
|
package/dist/index.d.ts
CHANGED
|
@@ -100,6 +100,9 @@ interface ModuleContext {
|
|
|
100
100
|
* reads, as `__FAIL__`, to report an error from a callback the way an
|
|
101
101
|
* error that reached the entry is reported. */
|
|
102
102
|
readonly fail?: string;
|
|
103
|
+
/** Luau reaching the bundle's record of which tables are arrays, so that
|
|
104
|
+
* every module marks and reads the same one (`typeof`). */
|
|
105
|
+
readonly arrays?: string;
|
|
103
106
|
}
|
|
104
107
|
interface LowerOptions {
|
|
105
108
|
/** Lower the file as a module of a bundle. Without it, `import` and
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tilua/compiler",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.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",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"type": "module",
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"luau-parser": "^1.0.3",
|
|
41
|
-
"@tilua/parser": "^
|
|
41
|
+
"@tilua/parser": "^4.0.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^22.20.2",
|
package/runtime/array.luau
CHANGED
|
@@ -19,7 +19,7 @@ function __NAME__.findIndex(t, test)
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
function __NAME__.filter(t, test)
|
|
22
|
-
local out = {}
|
|
22
|
+
local out = __ARRAY__({})
|
|
23
23
|
for i = 1, #t do
|
|
24
24
|
if test(t[i], i) then
|
|
25
25
|
out[#out + 1] = t[i]
|
|
@@ -29,7 +29,7 @@ function __NAME__.filter(t, test)
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
function __NAME__.map(t, transform)
|
|
32
|
-
local out = {}
|
|
32
|
+
local out = __ARRAY__({})
|
|
33
33
|
for i = 1, #t do
|
|
34
34
|
out[i] = transform(t[i], i)
|
|
35
35
|
end
|
|
@@ -95,7 +95,7 @@ function __NAME__.join(t, separator)
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
function __NAME__.concat(t, ...)
|
|
98
|
-
local out = {}
|
|
98
|
+
local out = __ARRAY__({})
|
|
99
99
|
table.move(t, 1, #t, 1, out)
|
|
100
100
|
for i = 1, select("#", ...) do
|
|
101
101
|
local part = select(i, ...)
|
|
@@ -114,7 +114,7 @@ function __NAME__.slice(t, start, stop)
|
|
|
114
114
|
if to < 0 then to = n + to + 1 end
|
|
115
115
|
if from < 1 then from = 1 end
|
|
116
116
|
if to > n then to = n end
|
|
117
|
-
local out = {}
|
|
117
|
+
local out = __ARRAY__({})
|
|
118
118
|
for i = from, to do
|
|
119
119
|
out[#out + 1] = t[i]
|
|
120
120
|
end
|
|
@@ -123,7 +123,7 @@ end
|
|
|
123
123
|
|
|
124
124
|
-- One level, as JavaScript's `flat()` does by default.
|
|
125
125
|
function __NAME__.flat(t)
|
|
126
|
-
local out = {}
|
|
126
|
+
local out = __ARRAY__({})
|
|
127
127
|
for i = 1, #t do
|
|
128
128
|
local value = t[i]
|
|
129
129
|
if type(value) == "table" then
|
package/runtime/object.luau
CHANGED
|
@@ -5,7 +5,7 @@ local __NAME__ = {}
|
|
|
5
5
|
-- follow the named ones. With no one order to give (`known` is nil), every
|
|
6
6
|
-- key is listed, in the order `pairs` walks them.
|
|
7
7
|
local function keysOf(known, open, t)
|
|
8
|
-
local out = {}
|
|
8
|
+
local out = __ARRAY__({})
|
|
9
9
|
if known == nil then
|
|
10
10
|
for key in pairs(t) do
|
|
11
11
|
out[#out + 1] = key
|
|
@@ -37,7 +37,7 @@ end
|
|
|
37
37
|
-- rather than moving everything after it up one.
|
|
38
38
|
function __NAME__.values(known, open, t)
|
|
39
39
|
local keys = keysOf(known, open, t)
|
|
40
|
-
local out = {}
|
|
40
|
+
local out = __ARRAY__({})
|
|
41
41
|
for i = 1, #keys do
|
|
42
42
|
out[i] = t[keys[i]]
|
|
43
43
|
end
|
|
@@ -46,9 +46,9 @@ end
|
|
|
46
46
|
|
|
47
47
|
function __NAME__.entries(known, open, t)
|
|
48
48
|
local keys = keysOf(known, open, t)
|
|
49
|
-
local out = {}
|
|
49
|
+
local out = __ARRAY__({})
|
|
50
50
|
for i = 1, #keys do
|
|
51
|
-
out[i] = { keys[i], t[keys[i]] }
|
|
51
|
+
out[i] = __ARRAY__({ keys[i], t[keys[i]] })
|
|
52
52
|
end
|
|
53
53
|
return out
|
|
54
54
|
end
|
package/runtime/string.luau
CHANGED
|
@@ -88,7 +88,7 @@ local function values(...)
|
|
|
88
88
|
if select("#", ...) <= 1 and (...) == nil then
|
|
89
89
|
return nil
|
|
90
90
|
end
|
|
91
|
-
return { ... }
|
|
91
|
+
return __ARRAY__({ ... })
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
function __NAME__.find(s, pattern, init, plain)
|
|
@@ -107,7 +107,7 @@ function __NAME__.byte(s, i, j)
|
|
|
107
107
|
if j == nil then
|
|
108
108
|
return (string.byte(s, i))
|
|
109
109
|
end
|
|
110
|
-
return { string.byte(s, i, j) }
|
|
110
|
+
return __ARRAY__({ string.byte(s, i, j) })
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
-- An iterator function: each call is one match's captures, as an array.
|