@tilua/compiler 6.1.0 → 7.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 CHANGED
@@ -1,7 +1,9 @@
1
1
  # @tilua/compiler
2
2
 
3
3
  Compiles a [tilua](https://marketplace.visualstudio.com/search?term=tilua)
4
- project to one Luau file. Each file is parsed by
4
+ project to one Lua file — Lua that runs on Lua 5.1 to 5.4, LuaJIT and Luau
5
+ alike, or Luau where a library says the project is Luau (see [Lua and
6
+ Luau](#lua-and-luau)). Each file is parsed by
5
7
  [`@tilua/parser`](https://www.npmjs.com/package/@tilua/parser), its AST lowered
6
8
  to a `luau-parser` AST, and that AST printed by `luau-parser`.
7
9
 
@@ -12,7 +14,7 @@ npx tilua src/main.tilua --out build/main.luau
12
14
 
13
15
  ```
14
16
  tilua <entry> [--out <file>] [--output single|chunks|modules] [--config <tilua.config.json>]
15
- [--noCheck] [--target luau|lua51]
17
+ [--noCheck]
16
18
  ```
17
19
 
18
20
  Every module the entry imports is bundled in. Problems are reported as
@@ -38,7 +40,7 @@ const result = await bundle({
38
40
  // A config file's path, or its contents:
39
41
  config: { types: ["roblox"], paths: { "@shared/*": ["src/shared/*"] } },
40
42
  })
41
- result.code // the Luau bundle, unless a module failed
43
+ result.code // the Lua bundle, unless a module failed
42
44
  result.files // [{ path, code, modules }] — one, unless `output` says otherwise
43
45
  result.diagnostics // { file, line, column, message, category: "syntax" | "module" | "type" | "config" }
44
46
 
@@ -56,10 +58,10 @@ JavaScript module the build loads.
56
58
 
57
59
  ## What becomes what
58
60
 
59
- | tilua | Luau |
61
+ | tilua | Lua |
60
62
  |---|---|
61
63
  | `const { a, b } = value` | `local a, b = value.a, value.b` |
62
- | `const [x, ...rest] = list` | `local x = list[1]; local rest = table.move(list, 2, #list, 1, {})` — `{}` written down as an array |
64
+ | `const [x, ...rest] = list` | `local x = list[1]; local rest = tilua_move(list, 2, #list, 1, {})` — `table.move` where the Lua has it; `{}` written down as an array |
63
65
  | `const { a = 1 } = t` | `local a = t.a; if a == nil then a = 1 end` |
64
66
  | `[1, 2]` / `{ a: 1, b }` | `tilua_asArray({ 1, 2 })` / `{ a = 1, b = b }` — see `typeof` below |
65
67
  | `typeof v` | `tilua_typeof(v)`, or `tilua_typeof(v, "array")` where `v`'s type already says which table it is |
@@ -99,22 +101,33 @@ JavaScript module the build loads.
99
101
  | `x as T`, `x satisfies T`, types, `interface`, `export type { … }`, `declare` | removed |
100
102
  | `names:filter(f)` | whatever the type library that declared `filter` says — see below |
101
103
 
102
- ## Lua 5.1
104
+ ## Lua and Luau
103
105
 
104
- `"target": "lua51"` (or `--target lua51`) writes what stock Lua 5.1 runs. On
105
- top of the table above:
106
+ The compiler knows Lua. What it writes is Lua 5.1's syntax, and runs on Lua
107
+ 5.1 to 5.4, LuaJIT and Luau alike: `table.move`, `table.unpack` and `typeof`
108
+ are used where the Lua has them and stood in for where it does not.
106
109
 
107
- | Luau | Lua 5.1 |
108
- |---|---|
109
- | `a += b`, `a // b`, `continue`, `if c then a else b`, `1_000`, `0b101` | assignments, `math.floor`, a `break` out of a one-pass `repeat`, `and`/`or` or a call, plain numbers |
110
- | `for _, item in xs do` | `ipairs(xs)` where `xs` is an array by its type; otherwise `tilua_each(xs)`, which walks a table as Luau would — its `__iter` if it has one, `next` if not |
111
- | `if a == nil then nil else a.b` (`a?.b`) | the function form, which keeps a `false` |
112
- | `table.move`, `table.unpack` | `tilua_move`, `unpack` |
113
- | `@native` and other attributes | dropped |
110
+ A Lua with more syntax is a type library's to say — its lowering lists it
111
+ (`syntax`, see [What a type library lowers](#what-a-type-library-lowers)). `@tilua-types/luau` says
112
+ Luau's, and `@tilua-types/roblox` loads it, so a Roblox project is written as
113
+ Luau without asking:
114
+
115
+ | written | Lua (no library) | Luau (`"types": ["luau"]`, or `["roblox"]`) |
116
+ |---|---|---|
117
+ | `a += b`, `a // b` | `a = a + (b)`, `math.floor(a / (b))` | as written |
118
+ | `continue` | a `break` out of a one-pass `repeat` | as written |
119
+ | `c ? a : b`, `a?.b`, `a ?? b` | `and`/`or` where neither arm can be `false`, else a function called on the spot | `if c then a else b` |
120
+ | `for (const x in xs)` | `ipairs(xs)` where `xs` is an array by its type; otherwise `tilua_each(xs)`, which walks a table as Luau would — its `__iter` if it has one, `next` if not | `for _, x in xs do` |
121
+ | `1_000`, `0b101` | plain numbers | as written |
122
+ | `@native` and other attributes | dropped | kept |
123
+ | another file of the bundle | `loadfile` | `require` by path |
114
124
 
115
- An object's `freeze` does nothing there and `isFrozen` answers `false`: Lua 5.1
116
- cannot freeze a table. `npm test` with `LUA51` naming a Lua 5.1 interpreter
117
- builds a program for both targets and checks they print the same.
125
+ An object's `freeze` does nothing on a Lua without `table.freeze`, and
126
+ `isFrozen` answers `false`. `npm test` with `LUA51` naming a Lua 5.1
127
+ interpreter builds a program both ways and checks they print the same.
128
+
129
+ The config's `target` is gone: `"target": "lua51"` is now what every build
130
+ is, and `"luau"` is `"types": ["luau"]`.
118
131
 
119
132
  ## `typeof`, arrays and objects
120
133
 
@@ -249,6 +262,14 @@ declared as). An answer can `prepend` Luau expressions ahead of the written
249
262
  arguments. `globalCall` and `globalValue` answer for a global, such as
250
263
  `print(x)` or a bare `print`. A runtime can read `__LINES__` to reach the
251
264
  bundle's line map, and wraps a new array it answers with in `__ARRAY__(...)`. See the `@tilua/parser` README for the details.
265
+
266
+ A library for a Lua with more syntax than 5.1's lists it, and the output uses
267
+ it (see [Lua and Luau](#lua-and-luau)):
268
+
269
+ ```js
270
+ export default { syntax: ["compoundAssignment", "continue", "ifExpression", "floorDivision",
271
+ "iteration", "attributes", "numberLiterals", "requireByPath"] }
272
+ ```
252
273
  The standard library's own lowering (src/standard.ts) is written with these
253
274
  hooks too; `"noLib": true` leaves it out with the library.
254
275
 
@@ -334,6 +355,32 @@ Modules follow ES module rules, including when they import each other:
334
355
  loaded by calling it. The path is a string literal; the module it names is
335
356
  part of the bundle like any other.
336
357
 
358
+ ## Tree shaking
359
+
360
+ `"treeShaking": true` in `tilua.config.json` (or `bundle({ treeShaking })`)
361
+ leaves out of the bundle what the entry never reaches:
362
+
363
+ - **Declarations nothing reads.** A top-level function, class or `const`
364
+ that nothing kept reads, and whose value costs nothing to leave unmade — a
365
+ literal, a function, a class whose statics are not calls. A `const` made by
366
+ a call stays: the call is something the module does.
367
+ - **Exports nothing imports.** `import { a }` reads `a`, `M.a` reads `a` of
368
+ `import * as M`, and anything else done with `M` — or `import("./x")` —
369
+ reads every export. `export { a } from` and `export * from` pass a read on;
370
+ the entry's exports are always read.
371
+ - **Modules nothing needs.** A module none of whose exports are read, and
372
+ that does nothing as it runs, is not bundled. One that does something —
373
+ prints, registers, connects — still runs where it is imported, as an ES
374
+ module does, even if nothing it exports is read.
375
+ - **Runtime functions nothing calls.** The language's and the libraries'
376
+ runtime tables keep the members the program calls, and what those call:
377
+ `xs:map(f):join(",")` brings `map` and `join`, not the rest of the array
378
+ methods.
379
+
380
+ Off by default: what is left out is decided from the code, and code that
381
+ reaches a module by a name only the running program knows — `G.require` of a
382
+ string built at runtime — is not something it can see.
383
+
337
384
  ## Several files
338
385
 
339
386
  `"output"` in `tilua.config.json` (or `--output`, or `bundle({ output })`)
@@ -373,12 +420,12 @@ that file, once, the first time one of its modules is asked for — by an
373
420
  `import()`, or by an `import` statement in a module that was itself loaded
374
421
  late. So a file costs nothing until then.
375
422
 
376
- How a file is loaded is the one thing the two targets do not share:
423
+ How a file is loaded depends on the Lua (see [Lua and Luau](#lua-and-luau)):
377
424
 
378
- | `target` | loads a file with |
425
+ | Lua | loads a file with |
379
426
  |---|---|
380
- | `"luau"` | `require("./main_src_shop")(G)` — Luau's `require` by path, read from the entry's own file. In Roblox each file is a ModuleScript beside the entry's |
381
- | `"lua51"` | `loadfile(folder .. "main_src_shop.luau")()(G)`, where `folder` is the entry's own, read off `debug.getinfo` |
427
+ | any | `loadfile(folder .. "main_src_shop.luau")()(G)`, where `folder` is the entry's own, read off `debug.getinfo` |
428
+ | Luau (`requireByPath`) | `require("./main_src_shop")(G)` — `require` by path, read from the entry's own file. In Roblox each file is a ModuleScript beside the entry's |
382
429
 
383
430
  Either way the files have to stay where they were written, relative to the
384
431
  entry's.