Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/CompilerOptions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as ts from "typescript";

export interface CompilerOptions extends ts.CompilerOptions {
addHeader?: boolean;
noHeader?: boolean;
luaTarget?: string;
luaLibImport?: string;
}
Expand All @@ -18,4 +18,4 @@ export enum LuaTarget {
Lua52 = "5.2",
Lua53 = "5.3",
LuaJIT = "jit",
}
}
2 changes: 1 addition & 1 deletion src/LuaPrinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class LuaPrinter {
public print(block: tstl.Block, luaLibFeatures?: Set<LuaLibFeature>): string {
let header = "";

if (this.options.addHeader === undefined || this.options.addHeader === true) {
if (this.options.noHeader === undefined || this.options.noHeader === false) {
header += `--[[ Generated with https://github.com/Perryvw/TypescriptToLua ]]\n`;
}

Expand Down
140 changes: 79 additions & 61 deletions src/LuaTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,10 @@ export class LuaTransformer {
const fieldName = this.transformPropertyName(field.name);
const value = this.transformExpression(field.initializer);

const classField =
tstl.createTableIndexExpression(this.addExportToIdentifier(className, statement.name.text), fieldName);
const classField = tstl.createTableIndexExpression(
this.addExportToIdentifier(className),
fieldName
);

const fieldAssign = tstl.createAssignmentStatement(
classField,
Expand Down Expand Up @@ -400,6 +402,8 @@ export class LuaTransformer {

const result: tstl.Statement[] = [];

const classNameWithExport = this.addExportToIdentifier(className);

// Write class declaration
if (extendsType) {
const baseName = tstl.createIdentifier(extendsType.symbol.escapedName as string);
Expand All @@ -412,7 +416,7 @@ export class LuaTransformer {

if (!noClassOr) {
// className or baseName.new()
rhs = tstl.createBinaryExpression(className, rhs, tstl.SyntaxKind.OrOperator);
rhs = tstl.createBinaryExpression(classNameWithExport, rhs, tstl.SyntaxKind.OrOperator);
}

// (local) className = className or baseName.new()
Expand All @@ -427,10 +431,7 @@ export class LuaTransformer {

if (!noClassOr) {
// className or {}
rhs = tstl.createBinaryExpression(
this.addExportToIdentifier(className, statement.name.text),
rhs,
tstl.SyntaxKind.OrOperator);
rhs = tstl.createBinaryExpression(classNameWithExport, rhs, tstl.SyntaxKind.OrOperator);
}

// (local) className = className or {}
Expand All @@ -442,20 +443,16 @@ export class LuaTransformer {
}

// className.__index
const classIndex = tstl.createTableIndexExpression(
this.addExportToIdentifier(className, statement.name.text),
tstl.createStringLiteral("__index"));
const classIndex = tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("__index"));
// className.__index = className
const assignClassIndex = tstl.createAssignmentStatement(classIndex, className, undefined, statement);
const assignClassIndex = tstl.createAssignmentStatement(classIndex, classNameWithExport, undefined, statement);

result.push(assignClassIndex);

if (extendsType) {
const baseName = tstl.createIdentifier(extendsType.symbol.escapedName as string);
// className.__base = baseName
const classBase = tstl.createTableIndexExpression(
this.addExportToIdentifier(className, statement.name.text),
tstl.createStringLiteral("__base"));
const classBase = tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("__base"));

const assignClassBase = tstl.createAssignmentStatement(classBase, baseName, undefined, statement);

Expand All @@ -469,7 +466,7 @@ export class LuaTransformer {
this.selfIdentifier,
tstl.createCallExpression(
tstl.createIdentifier("setmetatable"),
[tstl.createTableExpression(), className]
[tstl.createTableExpression(), classNameWithExport]
)
);

Expand Down Expand Up @@ -498,11 +495,11 @@ export class LuaTransformer {
const ifConstructor = tstl.createIfStatement(
tstl.createBinaryExpression(
tstl.createIdentifier("construct"),
tstl.createTableIndexExpression(className, tstl.createStringLiteral("constructor")),
tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("constructor")),
tstl.SyntaxKind.AndOperator),
tstl.createBlock([
tstl.createExpressionStatement(tstl.createCallExpression(
tstl.createTableIndexExpression(className, tstl.createStringLiteral("constructor")),
tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("constructor")),
[this.selfIdentifier, tstl.createDotsLiteral()])),
]));

Expand All @@ -517,7 +514,7 @@ export class LuaTransformer {
// or function export.className.new(construct, ...) ... end
const newFunc = tstl.createAssignmentStatement(
tstl.createTableIndexExpression(
this.addExportToIdentifier(className, statement.name.text),
classNameWithExport,
tstl.createStringLiteral("new")),
tstl.createFunctionExpression(
tstl.createBlock(newFuncStatements),
Expand Down Expand Up @@ -593,7 +590,7 @@ export class LuaTransformer {

const result = tstl.createAssignmentStatement(
tstl.createTableIndexExpression(
this.addExportToIdentifier(className, classDeclaration.name.text),
this.addExportToIdentifier(className),
tstl.createStringLiteral("constructor")),
tstl.createFunctionExpression(body, params, dotsLiteral, restParamName, undefined, undefined),
undefined,
Expand All @@ -619,7 +616,7 @@ export class LuaTransformer {

return tstl.createAssignmentStatement(
tstl.createTableIndexExpression(
this.addExportToIdentifier(className, classDeclaration.name.text),
this.addExportToIdentifier(className),
tstl.createStringLiteral("get__" + name.text)),
accessorFunction
);
Expand All @@ -644,7 +641,7 @@ export class LuaTransformer {

return tstl.createAssignmentStatement(
tstl.createTableIndexExpression(
this.addExportToIdentifier(className, classDeclaration.name.text),
this.addExportToIdentifier(className),
tstl.createStringLiteral("set__" + name.text)),
accessorFunction
);
Expand Down Expand Up @@ -678,9 +675,10 @@ export class LuaTransformer {
restParamName
);

const parent = node.parent as ts.ClassLikeDeclaration;
return tstl.createAssignmentStatement(
tstl.createTableIndexExpression(
this.addExportToIdentifier(className, (node.parent as ts.ClassLikeDeclaration).name.text),
this.addExportToIdentifier(className),
methodName),
functionExpression,
undefined,
Expand Down Expand Up @@ -944,7 +942,7 @@ export class LuaTransformer {
);
const functionExpression = tstl.createFunctionExpression(body, params, dotsLiteral, restParamName);

return this.createLocalOrExportedDeclaration(name, functionExpression, undefined, functionDeclaration);
return this.createLocalOrExportedOrGlobalDeclaration(name, functionExpression, undefined, functionDeclaration);
}

public transformTypeAliasDeclaration(statement: ts.TypeAliasDeclaration): undefined {
Expand All @@ -970,9 +968,14 @@ export class LuaTransformer {
const identifierName = this.transformIdentifier(statement.name);
if (statement.initializer) {
const value = this.transformExpression(statement.initializer);
return this.createLocalOrExportedDeclaration(identifierName, value);
return this.createLocalOrExportedOrGlobalDeclaration(identifierName, value, undefined, statement);
} else {
return this.createLocalOrExportedDeclaration(identifierName, tstl.createNilLiteral());
return this.createLocalOrExportedOrGlobalDeclaration(
identifierName,
tstl.createNilLiteral(),
undefined,
statement
);
}
} else if (ts.isArrayBindingPattern(statement.name)) {
// Destructuring type
Expand All @@ -987,17 +990,27 @@ export class LuaTransformer {
// Don't unpack TupleReturn decorated functions
if (statement.initializer) {
if (tsHelper.isTupleReturnCall(statement.initializer, this.checker)) {
return this.createLocalOrExportedDeclaration(vars, this.transformExpression(statement.initializer));
return this.createLocalOrExportedOrGlobalDeclaration(
vars,
this.transformExpression(statement.initializer),
undefined,
statement
);
} else {
// local vars = this.transpileDestructingAssignmentValue(node.initializer);
const initializer = this.createUnpackCall(
this.transformExpression(statement.initializer),
statement.initializer
);
return this.createLocalOrExportedDeclaration(vars, initializer);
return this.createLocalOrExportedOrGlobalDeclaration(vars, initializer, undefined, statement);
}
} else {
return this.createLocalOrExportedDeclaration(vars, tstl.createNilLiteral());
return this.createLocalOrExportedOrGlobalDeclaration(
vars,
tstl.createNilLiteral(),
undefined,
statement
);
}
} else {
throw TSTLErrors.UnsupportedKind("variable declaration", statement.name.kind, statement);
Expand Down Expand Up @@ -2955,10 +2968,8 @@ export class LuaTransformer {
return scopeSymbol.exports.has(identifierName as ts.__String);
}

public addExportToIdentifier(identifier: tstl.Identifier, originalStr?: string)
: tstl.IdentifierOrTableIndexExpression {
const testStr = originalStr ? originalStr : identifier.text;
if (this.isIdentifierExported(testStr)) {
public addExportToIdentifier(identifier: tstl.Identifier): tstl.IdentifierOrTableIndexExpression {
if (this.isIdentifierExported(identifier.text)) {
return this.createExportedIdentifier(identifier);
}
return identifier;
Expand Down Expand Up @@ -3083,49 +3094,56 @@ export class LuaTransformer {
return filePath.replace(new RegExp("\\\\|\/", "g"), ".");
}

private createLocalOrExportedOrGlobalDeclaration(
lhs: tstl.Identifier | tstl.Identifier[],
rhs: tstl.Expression,
parent?: tstl.Node,
tsOriginal?: ts.Node
): tstl.Statement[]
{
const statements: tstl.Statement[] = [];
if (this.isModule || this.currentNamespace) {
statements.push(...this.createLocalOrExportedDeclaration(lhs, rhs, parent ,tsOriginal));
private shouldExportIdentifier(identifier: tstl.Identifier | tstl.Identifier[]): boolean {
if (!this.isModule && !this.currentNamespace) {
return false;
}
if (Array.isArray(identifier)) {
return identifier.some(i => this.isIdentifierExported(i.text));
} else {
statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal));
return this.isIdentifierExported(identifier.text);
}
return statements;
}

private createLocalOrExportedDeclaration(
private createLocalOrExportedOrGlobalDeclaration(
lhs: tstl.Identifier | tstl.Identifier[],
rhs: tstl.Expression,
parent?: tstl.Node,
tsOriginal?: ts.Node
): tstl.Statement[]
{
const statements: tstl.Statement[] = [];
if (!Array.isArray(lhs)) {
lhs = [lhs];
if (this.shouldExportIdentifier(lhs)) {
// exported
if (Array.isArray(lhs)) {
return [tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), rhs, parent)];
} else {
return [tstl.createAssignmentStatement(this.createExportedIdentifier(lhs), rhs, parent)];
}
}
const shouldExport = lhs.some(i => this.isIdentifierExported(i.text));
if (shouldExport) {
statements.push(
tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), rhs, parent));
} else {
// TODO this check probably should be moved out of this function or be improved?
if (tsOriginal &&
(ts.isFunctionLike(tsOriginal) || tsHelper.findFirstNodeAbove(tsOriginal, ts.isFunctionLike))) {
// Separate declaration from assignment to allow for recursion
statements.push(tstl.createVariableDeclarationStatement(lhs, undefined, parent));
statements.push(tstl.createAssignmentStatement(lhs, rhs, parent));

const insideFunction = this.scopeStack.some(s => s.type === ScopeType.Function);
const isLetOrConst = tsOriginal && ts.isVariableDeclaration(tsOriginal)
&& (tsOriginal.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
if (this.isModule || this.currentNamespace || insideFunction || isLetOrConst) {
// local
const isFunction =
tsOriginal
&& (ts.isFunctionDeclaration(tsOriginal)
|| (ts.isVariableDeclaration(tsOriginal) && ts.isFunctionLike(tsOriginal.initializer)));
if (isFunction) {
// Separate declaration from assignment for functions to allow recursion
return [
tstl.createVariableDeclarationStatement(lhs, undefined, parent, tsOriginal),
tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal),
];
} else {
statements.push(tstl.createVariableDeclarationStatement(lhs, rhs, parent));
return [tstl.createVariableDeclarationStatement(lhs, rhs, parent, tsOriginal)];
}

} else {
// global
return [tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal)];
}
return statements;
}

private validateFunctionAssignment(node: ts.Node, fromType: ts.Type, toType: ts.Type, toName?: string): void {
Expand Down
6 changes: 3 additions & 3 deletions test/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { LuaTransformer } from "../../src/LuaTransformer";

export function transpileString(str: string, options?: CompilerOptions, ignoreDiagnostics = true): string {
if (options) {
if (options.addHeader === undefined) {
options.addHeader = false;
if (options.noHeader === undefined) {
options.noHeader = true;
}
return compilerTranspileString(str, options, ignoreDiagnostics);
} else {
Expand All @@ -25,7 +25,7 @@ export function transpileString(str: string, options?: CompilerOptions, ignoreDi
luaLibImport: LuaLibImportKind.Require,
luaTarget: LuaTarget.Lua53,
target: ts.ScriptTarget.ES2015,
addHeader: false,
noHeader: true,
},
ignoreDiagnostics
);
Expand Down
4 changes: 2 additions & 2 deletions test/translation/ts/getSetAccessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class MyClass {
}
}

var instance = new MyClass();
let instance = new MyClass();
instance.field = 4;
const b = instance.field;
const c = (4 + instance.field)*3;
const c = (4 + instance.field)*3;
6 changes: 3 additions & 3 deletions test/unit/assignments.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class AssignmentTests {
@TestCase("true", "true")
@TestCase("false", "false")
@TestCase(`{a:3,b:"4"}`, `{a = 3, b = "4"}`)
@Test("Const assignment")
@Test("Let assignment")
public letAssignment(inp: string, out: string): void {
const lua = util.transpileString(`let myvar = ${inp};`);
Expect(lua).toBe(`local myvar = ${out};`);
Expand All @@ -53,10 +53,10 @@ export class AssignmentTests {
@TestCase("true", "true")
@TestCase("false", "false")
@TestCase(`{a:3,b:"4"}`, `{a = 3, b = "4"}`)
@Test("Const assignment")
@Test("Var assignment")
public varAssignment(inp: string, out: string): void {
const lua = util.transpileString(`var myvar = ${inp};`);
Expect(lua).toBe(`local myvar = ${out};`);
Expect(lua).toBe(`myvar = ${out};`);
}

@TestCase("var myvar;")
Expand Down