Skip to content

Commit 558b7b4

Browse files
committed
Basic lualib as modules
1 parent f64a7aa commit 558b7b4

119 files changed

Lines changed: 501 additions & 302 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build-lualib.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,8 @@ const fs = require("fs");
33
const path = require("path");
44
const ts = require("typescript");
55
const tstl = require("./src");
6-
const { loadLuaLibFeatures } = require("./src/LuaLib");
6+
const { loadInlineLualibFeatures } = require("./src/LuaLib");
77

88
const configFileName = path.resolve(__dirname, "src/lualib/tsconfig.json");
99
const { diagnostics } = tstl.transpileProject(configFileName);
1010
diagnostics.forEach(tstl.createDiagnosticReporter(true));
11-
12-
const bundlePath = path.join(__dirname, "dist/lualib/lualib_bundle.lua");
13-
if (fs.existsSync(bundlePath)) {
14-
fs.unlinkSync(bundlePath);
15-
}
16-
17-
fs.writeFileSync(bundlePath, loadLuaLibFeatures(Object.values(tstl.LuaLibFeature), ts.sys));

src/CompilerOptions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export type CompilerOptions = OmitIndexSignature<ts.CompilerOptions> & {
2727
luaBundleEntry?: string;
2828
luaTarget?: LuaTarget;
2929
luaLibImport?: LuaLibImportKind;
30+
luaLibProject?: boolean;
3031
luaPlugins?: LuaPluginImport[];
3132
noImplicitSelf?: boolean;
3233
noHeader?: boolean;

src/LuaAST.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// because we don't create the AST from text
66

77
import * as ts from "typescript";
8-
import { LuaLibFeature } from "./transformation/utils/lualib";
8+
import { LuaLibFeature } from "./LuaLib";
99
import { castArray } from "./utils";
1010

1111
export enum SyntaxKind {
@@ -195,6 +195,8 @@ export interface File extends Node {
195195
statements: Statement[];
196196
luaLibFeatures: Set<LuaLibFeature>;
197197
trivia: string;
198+
// Only used in lualibCompile, this is the values the lua lib feature exports/loaded when imported
199+
exports?: string[];
198200
}
199201

200202
export function isFile(node: Node): node is File {
@@ -205,12 +207,14 @@ export function createFile(
205207
statements: Statement[],
206208
luaLibFeatures: Set<LuaLibFeature>,
207209
trivia: string,
208-
tsOriginal?: ts.Node
210+
tsOriginal?: ts.Node,
211+
exports?: string[]
209212
): File {
210213
const file = createNode(SyntaxKind.File, tsOriginal) as File;
211214
file.statements = statements;
212215
file.luaLibFeatures = luaLibFeatures;
213216
file.trivia = trivia;
217+
file.exports = exports;
214218
return file;
215219
}
216220

src/LuaLib.ts

Lines changed: 69 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as path from "path";
22
import { EmitHost } from "./transpilation";
3+
import * as lua from "./LuaAST";
34

45
export enum LuaLibFeature {
56
ArrayConcat = "ArrayConcat",
@@ -99,81 +100,51 @@ export enum LuaLibFeature {
99100
Unpack = "Unpack",
100101
}
101102

102-
/* eslint-disable @typescript-eslint/naming-convention */
103-
const luaLibDependencies: Partial<Record<LuaLibFeature, LuaLibFeature[]>> = {
104-
ArrayConcat: [LuaLibFeature.ArrayIsArray],
105-
ArrayFlat: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
106-
ArrayFlatMap: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
107-
Await: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise],
108-
Decorate: [LuaLibFeature.ObjectGetOwnPropertyDescriptor, LuaLibFeature.SetDescriptor, LuaLibFeature.ObjectAssign],
109-
DelegatedYield: [LuaLibFeature.StringAccess],
110-
Delete: [LuaLibFeature.ObjectGetOwnPropertyDescriptors, LuaLibFeature.Error, LuaLibFeature.New],
111-
Error: [LuaLibFeature.Class, LuaLibFeature.ClassExtends, LuaLibFeature.New],
112-
FunctionBind: [LuaLibFeature.Unpack],
113-
Generator: [LuaLibFeature.Symbol],
114-
InstanceOf: [LuaLibFeature.Symbol],
115-
Iterator: [LuaLibFeature.Symbol],
116-
NumberToString: [LuaLibFeature.StringAccess],
117-
ObjectDefineProperty: [LuaLibFeature.CloneDescriptor, LuaLibFeature.SetDescriptor],
118-
ObjectFromEntries: [LuaLibFeature.Iterator, LuaLibFeature.Symbol],
119-
Promise: [
120-
LuaLibFeature.ArrayPush,
121-
LuaLibFeature.Class,
122-
LuaLibFeature.FunctionBind,
123-
LuaLibFeature.InstanceOf,
124-
LuaLibFeature.New,
125-
],
126-
PromiseAll: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise, LuaLibFeature.Iterator],
127-
PromiseAllSettled: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise, LuaLibFeature.Iterator],
128-
PromiseAny: [
129-
LuaLibFeature.ArrayPush,
130-
LuaLibFeature.InstanceOf,
131-
LuaLibFeature.New,
132-
LuaLibFeature.Promise,
133-
LuaLibFeature.Iterator,
134-
],
135-
PromiseRace: [
136-
LuaLibFeature.ArrayPush,
137-
LuaLibFeature.InstanceOf,
138-
LuaLibFeature.New,
139-
LuaLibFeature.Promise,
140-
LuaLibFeature.Iterator,
141-
],
142-
ParseFloat: [LuaLibFeature.StringAccess],
143-
ParseInt: [LuaLibFeature.StringSubstr, LuaLibFeature.StringSubstring],
144-
SetDescriptor: [LuaLibFeature.CloneDescriptor],
145-
Spread: [LuaLibFeature.Iterator, LuaLibFeature.StringAccess, LuaLibFeature.Unpack],
146-
StringSplit: [LuaLibFeature.StringSubstring, LuaLibFeature.StringAccess],
147-
SymbolRegistry: [LuaLibFeature.Symbol],
148-
149-
Map: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
150-
Set: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
151-
WeakMap: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
152-
WeakSet: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
153-
};
154-
/* eslint-enable @typescript-eslint/naming-convention */
155-
156-
export function loadLuaLibFeatures(features: Iterable<LuaLibFeature>, emitHost: EmitHost): string {
103+
export interface LuaLibFeatureInfo {
104+
dependencies?: LuaLibFeature[];
105+
exports: string[];
106+
}
107+
export type LuaLibModulesInfo = Record<LuaLibFeature, LuaLibFeatureInfo>;
108+
109+
let luaLibModuleInfo: LuaLibModulesInfo | undefined;
110+
export function getLuaLibModuleInfo(emitHost: EmitHost): LuaLibModulesInfo {
111+
if (luaLibModuleInfo === undefined) {
112+
const lualibPath = path.resolve(__dirname, "../dist/lualib/lualib_dependencies.json");
113+
const result = emitHost.readFile(lualibPath);
114+
if (result !== undefined) {
115+
luaLibModuleInfo = JSON.parse(result) as LuaLibModulesInfo;
116+
} else {
117+
throw new Error(`Could not load lualib dependencies from '${lualibPath}'`);
118+
}
119+
}
120+
return luaLibModuleInfo;
121+
}
122+
123+
export function readLuaLibFeature(feature: LuaLibFeature, emitHost: EmitHost): string {
124+
const featurePath = path.resolve(__dirname, `../dist/lualib/${feature}.lua`);
125+
const luaLibFeature = emitHost.readFile(featurePath);
126+
if (luaLibFeature === undefined) {
127+
throw new Error(`Could not load lualib feature from '${featurePath}'`);
128+
}
129+
return luaLibFeature;
130+
}
131+
132+
export function loadInlineLualibFeatures(features: Iterable<LuaLibFeature>, emitHost: EmitHost): string {
157133
let result = "";
158134

159135
const loadedFeatures = new Set<LuaLibFeature>();
160136

137+
const luaLibDependencyMap = getLuaLibModuleInfo(emitHost);
161138
function load(feature: LuaLibFeature): void {
162139
if (loadedFeatures.has(feature)) return;
163140
loadedFeatures.add(feature);
164141

165-
const dependencies = luaLibDependencies[feature];
142+
const dependencies = luaLibDependencyMap[feature]?.dependencies;
166143
if (dependencies) {
167144
dependencies.forEach(load);
168145
}
169-
170-
const featurePath = path.resolve(__dirname, `../dist/lualib/${feature}.lua`);
171-
const luaLibFeature = emitHost.readFile(featurePath);
172-
if (luaLibFeature !== undefined) {
173-
result += luaLibFeature + "\n";
174-
} else {
175-
throw new Error(`Could not load lualib feature from '${featurePath}'`);
176-
}
146+
const luaLibFeature = readLuaLibFeature(feature, emitHost);
147+
result += luaLibFeature + "\n";
177148
}
178149

179150
for (const feature of features) {
@@ -183,6 +154,40 @@ export function loadLuaLibFeatures(features: Iterable<LuaLibFeature>, emitHost:
183154
return result;
184155
}
185156

157+
export function loadImportedLualibFeatures(
158+
features: Iterable<LuaLibFeature>,
159+
emitHost: EmitHost,
160+
alwaysRequire = false
161+
): lua.Statement[] {
162+
const luaLibModuleInfo = getLuaLibModuleInfo(emitHost);
163+
164+
const imports = Array.from(features).flatMap(feature => luaLibModuleInfo[feature].exports);
165+
166+
const requireCall = lua.createCallExpression(lua.createIdentifier("require"), [
167+
lua.createStringLiteral("lualib_bundle"),
168+
]);
169+
if (imports.length === 0) {
170+
if (alwaysRequire) {
171+
return [lua.createExpressionStatement(requireCall)];
172+
}
173+
return [];
174+
}
175+
176+
const luaLibId = lua.createIdentifier("____lualib");
177+
const importStatement = lua.createVariableDeclarationStatement(luaLibId, requireCall);
178+
const statements: lua.Statement[] = [importStatement];
179+
// local <export> = ____luaLib.<export>
180+
for (const item of imports) {
181+
statements.push(
182+
lua.createVariableDeclarationStatement(
183+
lua.createIdentifier(item),
184+
lua.createTableIndexExpression(luaLibId, lua.createStringLiteral(item))
185+
)
186+
);
187+
}
188+
return statements;
189+
}
190+
186191
let luaLibBundleContent: string;
187192
export function getLuaLibBundle(emitHost: EmitHost): string {
188193
if (luaLibBundleContent === undefined) {

src/LuaPrinter.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import * as path from "path";
22
import { Mapping, SourceMapGenerator, SourceNode } from "source-map";
3-
import { getEmitPath } from ".";
43
import * as ts from "typescript";
54
import { CompilerOptions, isBundleEnabled, LuaLibImportKind } from "./CompilerOptions";
65
import * as lua from "./LuaAST";
7-
import { loadLuaLibFeatures, LuaLibFeature } from "./LuaLib";
6+
import { loadInlineLualibFeatures, LuaLibFeature, loadImportedLualibFeatures } from "./LuaLib";
87
import { isValidLuaIdentifier, shouldAllowUnicode } from "./transformation/utils/safe-names";
9-
import { EmitHost } from "./transpilation";
8+
import { EmitHost, getEmitPath } from "./transpilation";
109
import { intersperse, normalizeSlashes } from "./utils";
1110

1211
// https://www.lua.org/pil/2.4.html
@@ -239,12 +238,17 @@ export class LuaPrinter {
239238
luaLibImport === LuaLibImportKind.Always ||
240239
(luaLibImport === LuaLibImportKind.Require && file.luaLibFeatures.size > 0)
241240
) {
242-
// Require lualib bundle
243-
header += 'require("lualib_bundle");\n';
241+
// Import lualib features
242+
const importStatements = loadImportedLualibFeatures(
243+
file.luaLibFeatures,
244+
this.emitHost,
245+
luaLibImport === LuaLibImportKind.Always
246+
);
247+
header += this.concatNodes(...this.printStatementArray(importStatements)).toString();
244248
} else if (luaLibImport === LuaLibImportKind.Inline && file.luaLibFeatures.size > 0) {
245249
// Inline lualib features
246250
header += "-- Lua Library inline imports\n";
247-
header += loadLuaLibFeatures(file.luaLibFeatures, this.emitHost);
251+
header += loadInlineLualibFeatures(file.luaLibFeatures, this.emitHost);
248252
}
249253

250254
if (this.options.sourceMapTraceback && !isBundleEnabled(this.options)) {

src/cli/parse.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ export const optionDeclarations: CommandLineOption[] = [
4646
type: "enum",
4747
choices: Object.values(LuaLibImportKind),
4848
},
49+
{
50+
name: "luaLibProject",
51+
description: "If this project is lualib source.",
52+
type: "boolean",
53+
},
4954
{
5055
name: "luaTarget",
5156
aliases: ["lt"],

src/lualib/ArrayConcat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function __TS__ArrayConcat(this: void, arr1: any[], ...args: any[]): any[] {
1+
export function __TS__ArrayConcat(this: void, arr1: any[], ...args: any[]): any[] {
22
const out: any[] = [];
33
for (const val of arr1) {
44
out[out.length] = val;

src/lualib/ArrayEntries.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// https://262.ecma-international.org/10.0/#sec-array.prototype.entries
2-
function __TS__ArrayEntries<T>(this: void, array: T[]): IterableIterator<[number, T]> {
2+
export function __TS__ArrayEntries<T>(this: void, array: T[]): IterableIterator<[number, T]> {
33
let key = 0;
44
return {
55
[Symbol.iterator](): IterableIterator<[number, T]> {

src/lualib/ArrayEvery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function __TS__ArrayEvery<T>(
1+
export function __TS__ArrayEvery<T>(
22
this: void,
33
arr: T[],
44
callbackfn: (value: T, index?: number, array?: any[]) => boolean

src/lualib/ArrayFilter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function __TS__ArrayFilter<T>(
1+
export function __TS__ArrayFilter<T>(
22
this: void,
33
arr: T[],
44
callbackfn: (value: T, index?: number, array?: any[]) => boolean

0 commit comments

Comments
 (0)