Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions build-lualib.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
require("ts-node/register/transpile-only");
const fs = require("fs");
const path = require("path");
const ts = require("typescript");
const tstl = require("./src");
const { loadLuaLibFeatures } = require("./src/LuaLib");

const configFileName = path.resolve(__dirname, "src/lualib/tsconfig.json");
const { diagnostics } = tstl.transpileProject(configFileName);
const { diagnostics } = tstl.transpileLuaLibProject(configFileName);
diagnostics.forEach(tstl.createDiagnosticReporter(true));

const bundlePath = path.join(__dirname, "dist/lualib/lualib_bundle.lua");
if (fs.existsSync(bundlePath)) {
fs.unlinkSync(bundlePath);
}

fs.writeFileSync(bundlePath, loadLuaLibFeatures(Object.values(tstl.LuaLibFeature), ts.sys));
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"dist/**/*.js",
"dist/**/*.lua",
"dist/**/*.ts",
"language-extensions/**/*.ts"
"language-extensions/**/*.ts",
"dist/lualib/*.json"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 2 additions & 0 deletions src/CompilerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export type CompilerOptions = OmitIndexSignature<ts.CompilerOptions> & {
plugins?: Array<ts.PluginImport | TransformerImport>;
sourceMapTraceback?: boolean;
tstlVerbose?: boolean;
/** @internal */
luaLibCompilation?: boolean;
[option: string]: any;
};

Expand Down
8 changes: 6 additions & 2 deletions src/LuaAST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// because we don't create the AST from text

import * as ts from "typescript";
import { LuaLibFeature } from "./transformation/utils/lualib";
import { LuaLibFeature } from "./LuaLib";
import { castArray } from "./utils";

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

export function isFile(node: Node): node is File {
Expand All @@ -205,12 +207,14 @@ export function createFile(
statements: Statement[],
luaLibFeatures: Set<LuaLibFeature>,
trivia: string,
tsOriginal?: ts.Node
tsOriginal?: ts.Node,
exports?: string[]
): File {
const file = createNode(SyntaxKind.File, tsOriginal) as File;
file.statements = statements;
file.luaLibFeatures = luaLibFeatures;
file.trivia = trivia;
file.exports = exports;
return file;
}

Expand Down
138 changes: 74 additions & 64 deletions src/LuaLib.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as path from "path";
import { EmitHost } from "./transpilation";
import * as lua from "./LuaAST";

export enum LuaLibFeature {
ArrayConcat = "ArrayConcat",
Expand Down Expand Up @@ -99,61 +100,42 @@ export enum LuaLibFeature {
Unpack = "Unpack",
}

/* eslint-disable @typescript-eslint/naming-convention */
const luaLibDependencies: Partial<Record<LuaLibFeature, LuaLibFeature[]>> = {
ArrayConcat: [LuaLibFeature.ArrayIsArray],
ArrayFlat: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
ArrayFlatMap: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
Await: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise],
Decorate: [LuaLibFeature.ObjectGetOwnPropertyDescriptor, LuaLibFeature.SetDescriptor, LuaLibFeature.ObjectAssign],
DelegatedYield: [LuaLibFeature.StringAccess],
Delete: [LuaLibFeature.ObjectGetOwnPropertyDescriptors, LuaLibFeature.Error, LuaLibFeature.New],
Error: [LuaLibFeature.Class, LuaLibFeature.ClassExtends, LuaLibFeature.New],
FunctionBind: [LuaLibFeature.Unpack],
Generator: [LuaLibFeature.Symbol],
InstanceOf: [LuaLibFeature.Symbol],
Iterator: [LuaLibFeature.Symbol],
NumberToString: [LuaLibFeature.StringAccess],
ObjectDefineProperty: [LuaLibFeature.CloneDescriptor, LuaLibFeature.SetDescriptor],
ObjectFromEntries: [LuaLibFeature.Iterator, LuaLibFeature.Symbol],
Promise: [
LuaLibFeature.ArrayPush,
LuaLibFeature.Class,
LuaLibFeature.FunctionBind,
LuaLibFeature.InstanceOf,
LuaLibFeature.New,
],
PromiseAll: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise, LuaLibFeature.Iterator],
PromiseAllSettled: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise, LuaLibFeature.Iterator],
PromiseAny: [
LuaLibFeature.ArrayPush,
LuaLibFeature.InstanceOf,
LuaLibFeature.New,
LuaLibFeature.Promise,
LuaLibFeature.Iterator,
],
PromiseRace: [
LuaLibFeature.ArrayPush,
LuaLibFeature.InstanceOf,
LuaLibFeature.New,
LuaLibFeature.Promise,
LuaLibFeature.Iterator,
],
ParseFloat: [LuaLibFeature.StringAccess],
ParseInt: [LuaLibFeature.StringSubstr, LuaLibFeature.StringSubstring],
SetDescriptor: [LuaLibFeature.CloneDescriptor],
Spread: [LuaLibFeature.Iterator, LuaLibFeature.StringAccess, LuaLibFeature.Unpack],
StringSplit: [LuaLibFeature.StringSubstring, LuaLibFeature.StringAccess],
SymbolRegistry: [LuaLibFeature.Symbol],

Map: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
Set: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
WeakMap: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
WeakSet: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
};
/* eslint-enable @typescript-eslint/naming-convention */

export function loadLuaLibFeatures(features: Iterable<LuaLibFeature>, emitHost: EmitHost): string {
export interface LuaLibFeatureInfo {
dependencies?: LuaLibFeature[];
exports: string[];
}
export type LuaLibModulesInfo = Record<LuaLibFeature, LuaLibFeatureInfo>;

export const luaLibModulesInfoFileName = "lualib_module_info.json";
let luaLibModulesInfo: LuaLibModulesInfo | undefined;
export function getLuaLibModulesInfo(emitHost: EmitHost): LuaLibModulesInfo {
if (luaLibModulesInfo === undefined) {
const lualibPath = path.resolve(__dirname, `../dist/lualib/${luaLibModulesInfoFileName}`);
const result = emitHost.readFile(lualibPath);
if (result !== undefined) {
luaLibModulesInfo = JSON.parse(result) as LuaLibModulesInfo;
} else {
throw new Error(`Could not load lualib dependencies from '${lualibPath}'`);
}
}
return luaLibModulesInfo;
}

export function readLuaLibFeature(feature: LuaLibFeature, emitHost: EmitHost): string {
const featurePath = path.resolve(__dirname, `../dist/lualib/${feature}.lua`);
const luaLibFeature = emitHost.readFile(featurePath);
if (luaLibFeature === undefined) {
throw new Error(`Could not load lualib feature from '${featurePath}'`);
}
return luaLibFeature;
}

export function loadInlineLualibFeatures(
features: Iterable<LuaLibFeature>,
emitHost: EmitHost,
luaLibModulesInfo: LuaLibModulesInfo = getLuaLibModulesInfo(emitHost),
readFeature: (feature: LuaLibFeature) => string = feature => readLuaLibFeature(feature, emitHost)
): string {
let result = "";

const loadedFeatures = new Set<LuaLibFeature>();
Expand All @@ -162,18 +144,12 @@ export function loadLuaLibFeatures(features: Iterable<LuaLibFeature>, emitHost:
if (loadedFeatures.has(feature)) return;
loadedFeatures.add(feature);

const dependencies = luaLibDependencies[feature];
const dependencies = luaLibModulesInfo[feature]?.dependencies;
if (dependencies) {
dependencies.forEach(load);
}

const featurePath = path.resolve(__dirname, `../dist/lualib/${feature}.lua`);
const luaLibFeature = emitHost.readFile(featurePath);
if (luaLibFeature !== undefined) {
result += luaLibFeature + "\n";
} else {
throw new Error(`Could not load lualib feature from '${featurePath}'`);
}
const luaLibFeature = readFeature(feature);
result += luaLibFeature + "\n";
}

for (const feature of features) {
Expand All @@ -183,6 +159,40 @@ export function loadLuaLibFeatures(features: Iterable<LuaLibFeature>, emitHost:
return result;
}

export function loadImportedLualibFeatures(
features: Iterable<LuaLibFeature>,
emitHost: EmitHost,
alwaysRequire = false
): lua.Statement[] {
const luaLibModuleInfo = getLuaLibModulesInfo(emitHost);

const imports = Array.from(features).flatMap(feature => luaLibModuleInfo[feature].exports);

const requireCall = lua.createCallExpression(lua.createIdentifier("require"), [
lua.createStringLiteral("lualib_bundle"),
]);
if (imports.length === 0) {
if (alwaysRequire) {
return [lua.createExpressionStatement(requireCall)];
}
return [];
}

const luaLibId = lua.createIdentifier("____lualib");
const importStatement = lua.createVariableDeclarationStatement(luaLibId, requireCall);
const statements: lua.Statement[] = [importStatement];
// local <export> = ____luaLib.<export>
for (const item of imports) {
statements.push(
lua.createVariableDeclarationStatement(
lua.createIdentifier(item),
lua.createTableIndexExpression(luaLibId, lua.createStringLiteral(item))
)
);
}
return statements;
}

let luaLibBundleContent: string;
export function getLuaLibBundle(emitHost: EmitHost): string {
if (luaLibBundleContent === undefined) {
Expand Down
20 changes: 13 additions & 7 deletions src/LuaPrinter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import * as path from "path";
import { Mapping, SourceMapGenerator, SourceNode } from "source-map";
import { getEmitPath } from ".";
import * as ts from "typescript";
import { CompilerOptions, isBundleEnabled, LuaLibImportKind } from "./CompilerOptions";
import * as lua from "./LuaAST";
import { loadLuaLibFeatures, LuaLibFeature } from "./LuaLib";
import { loadInlineLualibFeatures, LuaLibFeature, loadImportedLualibFeatures } from "./LuaLib";
import { isValidLuaIdentifier, shouldAllowUnicode } from "./transformation/utils/safe-names";
import { EmitHost } from "./transpilation";
import { EmitHost, getEmitPath } from "./transpilation";
import { intersperse, normalizeSlashes } from "./utils";

// https://www.lua.org/pil/2.4.html
Expand Down Expand Up @@ -233,18 +232,25 @@ export class LuaPrinter {
if (!this.options.noHeader) {
header += tstlHeader;
}
let statements = file.statements;

const luaLibImport = this.options.luaLibImport ?? LuaLibImportKind.Require;
if (
luaLibImport === LuaLibImportKind.Always ||
(luaLibImport === LuaLibImportKind.Require && file.luaLibFeatures.size > 0)
) {
// Require lualib bundle
header += 'require("lualib_bundle");\n';
// Import lualib features
const importStatements = loadImportedLualibFeatures(
file.luaLibFeatures,
this.emitHost,
luaLibImport === LuaLibImportKind.Always
);

statements = importStatements.concat(statements);
} else if (luaLibImport === LuaLibImportKind.Inline && file.luaLibFeatures.size > 0) {
// Inline lualib features
header += "-- Lua Library inline imports\n";
header += loadLuaLibFeatures(file.luaLibFeatures, this.emitHost);
header += loadInlineLualibFeatures(file.luaLibFeatures, this.emitHost);
}

if (this.options.sourceMapTraceback && !isBundleEnabled(this.options)) {
Expand All @@ -253,7 +259,7 @@ export class LuaPrinter {
header += `${LuaPrinter.sourceMapTracebackPlaceholder}\n`;
}

return this.concatNodes(header, ...this.printStatementArray(file.statements));
return this.concatNodes(header, ...this.printStatementArray(statements));
}

protected pushIndent(): void {
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayConcat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayConcat(this: void, arr1: any[], ...args: any[]): any[] {
export function __TS__ArrayConcat(this: void, arr1: any[], ...args: any[]): any[] {
Copy link
Copy Markdown
Member

@lolleko lolleko Feb 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to make Array a class like set/map?
To give people the ability to overwrite array built ins.

EDIT: same applies to Object

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that might cause problems when interacting with existing lua code. Could be done in separate PR, see #262

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it would be annoying for end users to have to mix Array and LuaArray, for example my game API returns lots of LuaArray

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope for this PR, this should be considered in a separate PR.

const out: any[] = [];
for (const val of arr1) {
out[out.length] = val;
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayEntries.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://262.ecma-international.org/10.0/#sec-array.prototype.entries
function __TS__ArrayEntries<T>(this: void, array: T[]): IterableIterator<[number, T]> {
export function __TS__ArrayEntries<T>(this: void, array: T[]): IterableIterator<[number, T]> {
let key = 0;
return {
[Symbol.iterator](): IterableIterator<[number, T]> {
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayEvery.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayEvery<T>(
export function __TS__ArrayEvery<T>(
this: void,
arr: T[],
callbackfn: (value: T, index?: number, array?: any[]) => boolean
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayFilter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayFilter<T>(
export function __TS__ArrayFilter<T>(
this: void,
arr: T[],
callbackfn: (value: T, index?: number, array?: any[]) => boolean
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayFind.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-array.prototype.find
function __TS__ArrayFind<T>(
export function __TS__ArrayFind<T>(
this: void,
arr: T[],
predicate: (value: T, index: number, obj: T[]) => unknown
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayFindIndex.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayFindIndex<T>(
export function __TS__ArrayFindIndex<T>(
this: void,
arr: T[],
callbackFn: (element: T, index?: number, array?: T[]) => boolean
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayFlat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] {
export function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] {
let result: any[] = [];
for (const value of array) {
if (depth > 0 && Array.isArray(value)) {
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayFlatMap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayFlatMap<T, U>(
export function __TS__ArrayFlatMap<T, U>(
this: void,
array: T[],
callback: (value: T, index: number, array: T[]) => U | readonly U[]
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayForEach.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayForEach<T>(
export function __TS__ArrayForEach<T>(
this: void,
arr: T[],
callbackFn: (value: T, index?: number, array?: any[]) => any
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayIncludes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.includes
function __TS__ArrayIncludes<T>(this: T[], searchElement: T, fromIndex = 0): boolean {
export function __TS__ArrayIncludes<T>(this: T[], searchElement: T, fromIndex = 0): boolean {
const len = this.length;
let k = fromIndex;

Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayIndexOf.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayIndexOf<T>(this: void, arr: T[], searchElement: T, fromIndex?: number): number {
export function __TS__ArrayIndexOf<T>(this: void, arr: T[], searchElement: T, fromIndex?: number): number {
const len = arr.length;
if (len === 0) {
return -1;
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayIsArray.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
declare type NextEmptyCheck = (this: void, table: any, index: undefined) => unknown | undefined;

function __TS__ArrayIsArray(this: void, value: any): value is any[] {
export function __TS__ArrayIsArray(this: void, value: any): value is any[] {
// Workaround to determine if value is an array or not (fails in case of objects without keys)
// See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/737
return type(value) === "table" && (1 in value || (next as NextEmptyCheck)(value, undefined) === undefined);
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayJoin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayJoin(this: unknown[], separator = ",") {
export function __TS__ArrayJoin(this: unknown[], separator = ",") {
let result = "";
for (const [index, value] of ipairs(this)) {
if (index > 1) result += separator;
Expand Down
6 changes: 5 additions & 1 deletion src/lualib/ArrayMap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
function __TS__ArrayMap<T, U>(this: void, arr: T[], callbackfn: (value: T, index?: number, array?: T[]) => U): U[] {
export function __TS__ArrayMap<T, U>(
this: void,
arr: T[],
callbackfn: (value: T, index?: number, array?: T[]) => U
): U[] {
const newArray: U[] = [];
for (let i = 0; i < arr.length; i++) {
newArray[i] = callbackfn(arr[i], i, arr);
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayPush.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function __TS__ArrayPush<T>(this: void, arr: T[], ...items: T[]): number {
export function __TS__ArrayPush<T>(this: void, arr: T[], ...items: T[]): number {
for (const item of items) {
arr[arr.length] = item;
}
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/ArrayReduce.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.reduce
function __TS__ArrayReduce<TElement, TAccumulator>(
export function __TS__ArrayReduce<TElement, TAccumulator>(
this: void,
arr: TElement[],
callbackFn: (accumulator: TAccumulator, currentValue: TElement, index: number, array: TElement[]) => TAccumulator,
Expand Down
Loading