From c6bbdaa8b5d9ba4305d725188de38b07c7be4ee7 Mon Sep 17 00:00:00 2001 From: Lolleko Date: Sun, 20 Jan 2019 17:33:57 +0100 Subject: [PATCH 01/12] Implemented new export system --- src/LuaAST.ts | 4 +- src/LuaTransformer.ts | 141 +++++++++++++++++++++++++++++++++--------- src/TSHelper.ts | 15 ----- 3 files changed, 113 insertions(+), 47 deletions(-) diff --git a/src/LuaAST.ts b/src/LuaAST.ts index 0145daf74..059ee3f15 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -189,7 +189,7 @@ export function createDoStatement(statements?: Statement[], parent?: Node, tsOri // `local test1, test2 = 12, 42` or `local test1, test2` export interface VariableDeclarationStatement extends Statement { kind: SyntaxKind.VariableDeclarationStatement; - left: IdentifierOrTableIndexExpression[]; + left: Identifier[]; right?: Expression[]; } @@ -198,7 +198,7 @@ export function isVariableDeclarationStatement(node: Node): node is VariableDecl } export function createVariableDeclarationStatement( - left: IdentifierOrTableIndexExpression | IdentifierOrTableIndexExpression[], + left: Identifier | Identifier[], right?: Expression | Expression[], parent?: Node, tsOriginal?: ts.Node): VariableDeclarationStatement { diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index e0389b513..32aba3056 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -7,6 +7,7 @@ import * as tstl from "./LuaAST"; import {LuaLib, LuaLibFeature} from "./LuaLib"; import {ContextType, TSHelper as tsHelper} from "./TSHelper"; import {TSTLErrors} from "./TSTLErrors"; +import { isArray } from "util"; export type StatementVisitResult = tstl.Statement | tstl.Statement[] | undefined; export type ExpressionVisitResult = tstl.Expression | undefined; @@ -758,14 +759,9 @@ export class LuaTransformer { } else if (this.isModule && (ts.getCombinedModifierFlags(statement) & ts.ModifierFlags.Export)) { // exports.NS = exports.NS or {} const namespaceDeclaration = tstl.createAssignmentStatement( - tstl.createTableIndexExpression( - this.transformIdentifier(ts.createIdentifier("exports")), - this.transformIdentifier(statement.name as ts.Identifier) - ), + this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier)), tstl.createBinaryExpression( - tstl.createTableIndexExpression( - this.transformIdentifier(ts.createIdentifier("exports")), - this.transformIdentifier(statement.name as ts.Identifier)), + this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier)), tstl.createTableExpression(), tstl.SyntaxKind.OrOperator)); @@ -774,9 +770,7 @@ export class LuaTransformer { // local NS = exports.NS const localDeclaration = tstl.createVariableDeclarationStatement( this.transformIdentifier(statement.name as ts.Identifier), - tstl.createTableIndexExpression( - this.transformIdentifier(ts.createIdentifier("exports") as ts.Identifier), - this.transformIdentifier(statement.name as ts.Identifier))); + this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier))); result.push(localDeclaration); } else { @@ -919,7 +913,8 @@ export class LuaTransformer { } public transformVariableDeclaration(statement: ts.VariableDeclaration) - : [tstl.VariableDeclarationStatement] | [tstl.VariableDeclarationStatement, tstl.AssignmentStatement] + : [tstl.AssignmentStatement | tstl.VariableDeclarationStatement] + | [tstl.VariableDeclarationStatement, tstl.AssignmentStatement] { if (statement.initializer) { // Validate assignment @@ -929,6 +924,7 @@ export class LuaTransformer { } if (ts.isIdentifier(statement.name)) { + const isVariableExported = this.isIdentifierExported(statement.name.escapedText); // Find variable identifier const identifierName = this.transformIdentifier(statement.name); if (statement.initializer) { @@ -937,15 +933,38 @@ export class LuaTransformer { // Separate declaration and assignment for functions to allow recursion // local identifierName; identifierName = value; - return [tstl.createVariableDeclarationStatement(identifierName), - tstl.createAssignmentStatement(identifierName, value)]; + if (isVariableExported) { + return [tstl.createVariableDeclarationStatement(identifierName), + tstl.createAssignmentStatement( + this.createExportedIdentifier(identifierName), + value), + ]; + } else { + return [tstl.createVariableDeclarationStatement(identifierName), + tstl.createAssignmentStatement( + identifierName, + value), + ]; + } } else { // local identifierName = value; - return [tstl.createVariableDeclarationStatement(identifierName, value)]; + if (isVariableExported) { + return [tstl.createAssignmentStatement( + this.createExportedIdentifier(identifierName), value)]; + } else { + return [tstl.createVariableDeclarationStatement(identifierName, value)]; + } } } else { // local identifierName = nil; - return [tstl.createVariableDeclarationStatement(identifierName, tstl.createNilLiteral())]; + if (isVariableExported) { + return [tstl.createAssignmentStatement( + this.createExportedIdentifier(identifierName), tstl.createNilLiteral())]; + } else { + return [tstl.createVariableDeclarationStatement( + identifierName, tstl.createNilLiteral()), + ]; + } } } else if (ts.isArrayBindingPattern(statement.name)) { // Destructuring type @@ -956,25 +975,49 @@ export class LuaTransformer { } const vars = statement.name.elements.map(e => this.transformArrayBindingElement(e)); + const isSomeVariableExported = vars.some(i => this.isIdentifierExported(i.text)); // Don't unpack TupleReturn decorated functions if (statement.initializer) { if (tsHelper.isTupleReturnCall(statement.initializer, this.checker)) { // local vars = initializer; - return [tstl.createVariableDeclarationStatement( - vars, - this.transformExpression(statement.initializer) - )]; + if (isSomeVariableExported) { + return [tstl.createAssignmentStatement( + vars.map(i => this.createExportedIdentifier(i)), + this.transformExpression(statement.initializer) + )]; + } else { + return [tstl.createVariableDeclarationStatement( + vars, + this.transformExpression(statement.initializer) + )]; + } } else { // local vars = this.transpileDestructingAssignmentValue(node.initializer); const initializer = this.createUnpackCall( this.transformExpression(statement.initializer), statement.initializer ); - return [tstl.createVariableDeclarationStatement(vars, initializer)]; + if (isSomeVariableExported) { + return [ + tstl.createAssignmentStatement( + vars.map(i => this.createExportedIdentifier(i)), + initializer), + ]; + } else { + return [tstl.createVariableDeclarationStatement(vars, initializer)]; + } } } else { - return [tstl.createVariableDeclarationStatement(vars)]; + if (isSomeVariableExported) { + return [ + tstl.createAssignmentStatement( + vars.map(i => this.createExportedIdentifier(i)), + tstl.createNilLiteral()), + ]; + } else { + return [tstl.createVariableDeclarationStatement(vars)]; + } } } else { throw TSTLErrors.UnsupportedKind("variable declaration", statement.name.kind, statement); @@ -1144,7 +1187,9 @@ export class LuaTransformer { if (ts.isArrayBindingPattern(initializer.declarations[0].name)) { expression = this.createUnpackCall(expression, initializer); } - return tstl.createVariableDeclarationStatement(variableDeclarations[0].left, expression); + // we can safely assume that for vars are not exported and therefore declarationstatenents + return tstl.createVariableDeclarationStatement( + (variableDeclarations[0] as tstl.VariableDeclarationStatement).left, expression); } else { // Assignment to existing variable @@ -1486,7 +1531,7 @@ export class LuaTransformer { case ts.SyntaxKind.ElementAccessExpression: return this.transformElementAccessExpression(expression as ts.ElementAccessExpression); case ts.SyntaxKind.Identifier: - return this.transformIdentifier(expression as ts.Identifier); + return this.transformIdentifierExpression(expression as ts.Identifier); case ts.SyntaxKind.StringLiteral: case ts.SyntaxKind.NoSubstitutionTemplateLiteral: return this.transformStringLiteral(expression as ts.StringLiteral); @@ -2885,21 +2930,21 @@ export class LuaTransformer { } else if (ts.isStringLiteral(propertyName)) { return this.transformStringLiteral(propertyName); } else if (ts.isNumericLiteral(propertyName)) { - const value = +propertyName.text; + const value = Number(propertyName.text); return tstl.createNumericLiteral(value, undefined, propertyName); } else { return tstl.createStringLiteral(this.transformIdentifier(propertyName).text); } } - public transformIdentifier(epxression: ts.Identifier, parent?: tstl.Node): tstl.Identifier { - if (epxression.originalKeywordKind === ts.SyntaxKind.UndefinedKeyword) { + public transformIdentifier(expression: ts.Identifier): tstl.Identifier { + if (expression.originalKeywordKind === ts.SyntaxKind.UndefinedKeyword) { return tstl.createIdentifier("nil"); // TODO this is a hack that allows use to keep Identifier // as return time as changing that would break a lot of stuff. // But this should be changed to retun tstl.createNilLiteral() // at some point. } - let escapedText = epxression.escapedText as string; + let escapedText = expression.escapedText as string; const underScoreCharCode = "_".charCodeAt(0); if (escapedText.length >= 3 && escapedText.charCodeAt(0) === underScoreCharCode && escapedText.charCodeAt(1) === underScoreCharCode && escapedText.charCodeAt(2) === underScoreCharCode) { @@ -2907,9 +2952,36 @@ export class LuaTransformer { } if (this.luaKeywords.has(escapedText)) { - throw TSTLErrors.KeywordIdentifier(epxression); + throw TSTLErrors.KeywordIdentifier(expression); } - return tstl.createIdentifier(escapedText, parent, epxression); + return tstl.createIdentifier(escapedText, undefined, expression); + } + + public transformIdentifierExpression(expression: ts.Identifier): tstl.IdentifierOrTableIndexExpression { + if (this.isIdentifierExported(expression.escapedText)) { + return this.createExportedIdentifier(this.transformIdentifier(expression)); + } + return this.transformIdentifier(expression); + } + + public isIdentifierExported(identifierName: string | ts.__String): boolean { + if (!this.isModule) { + return false; + } + const currentScope = this.currentNamespace ? this.currentNamespace : this.currentSourceFile; + const scopeSymbol = this.checker.getSymbolAtLocation(currentScope) + ? this.checker.getSymbolAtLocation(currentScope) + : this.checker.getTypeAtLocation(currentScope).getSymbol(); + return scopeSymbol.exports.has(identifierName as ts.__String); + } + + public createExportedIdentifier(identifier: tstl.Identifier): tstl.TableIndexExpression { + const exportTable = this.currentNamespace + ? this.transformIdentifier(this.currentNamespace.name as ts.Identifier) + : tstl.createIdentifier("exports"); + return tstl.createTableIndexExpression( + exportTable, + tstl.createStringLiteral(identifier.text)); } public escapeString(text: string): string { @@ -3033,7 +3105,16 @@ export class LuaTransformer { || this.currentNamespace || (tsOriginal && tsHelper.findFirstNodeAbove(tsOriginal, ts.isFunctionLike)) ) { - statements.push(tstl.createVariableDeclarationStatement(lhs, undefined, parent)); + if (!isArray(lhs)) { + lhs = [lhs]; + } + const shouldExport = lhs.some(i => this.isIdentifierExported(i.text)); + if (shouldExport) { + statements.push( + tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), undefined, parent)); + } else { + statements.push(tstl.createVariableDeclarationStatement(lhs, undefined, parent)); + } } statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal)); return statements; diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 204d6726e..2c503ec69 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -85,21 +85,6 @@ export class TSHelper { return false; } - public static isIdentifierExported( - identifier: ts.Identifier, - scope: ts.ModuleDeclaration | ts.SourceFile, - checker: ts.TypeChecker - ): boolean - { - const identifierSymbol = checker.getTypeAtLocation(scope).getSymbol(); - if (identifierSymbol.exports) -  { - return identifierSymbol.exports.has(identifier.escapedText); - } - - return false; - } - public static isInDestructingAssignment(node: ts.Node): boolean { return node.parent && ((ts.isVariableDeclaration(node.parent) && ts.isArrayBindingPattern(node.parent.name)) || (ts.isBinaryExpression(node.parent) && ts.isArrayLiteralExpression(node.parent.left))); From 101d5ff4d08a1650670e1b3424bcb6a260d6f5af Mon Sep 17 00:00:00 2001 From: Lolleko Date: Sun, 20 Jan 2019 17:47:09 +0100 Subject: [PATCH 02/12] Fixed formatting --- src/LuaTransformer.ts | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 32aba3056..0a61c46fb 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -934,14 +934,16 @@ export class LuaTransformer { // local identifierName; identifierName = value; if (isVariableExported) { - return [tstl.createVariableDeclarationStatement(identifierName), - tstl.createAssignmentStatement( - this.createExportedIdentifier(identifierName), - value), + return [ + tstl.createVariableDeclarationStatement(identifierName), + tstl.createAssignmentStatement( + this.createExportedIdentifier(identifierName), + value), ]; } else { - return [tstl.createVariableDeclarationStatement(identifierName), - tstl.createAssignmentStatement( + return [ + tstl.createVariableDeclarationStatement(identifierName), + tstl.createAssignmentStatement( identifierName, value), ]; @@ -949,8 +951,11 @@ export class LuaTransformer { } else { // local identifierName = value; if (isVariableExported) { - return [tstl.createAssignmentStatement( - this.createExportedIdentifier(identifierName), value)]; + return [ + tstl.createAssignmentStatement( + this.createExportedIdentifier(identifierName), + value), + ]; } else { return [tstl.createVariableDeclarationStatement(identifierName, value)]; } @@ -958,11 +963,14 @@ export class LuaTransformer { } else { // local identifierName = nil; if (isVariableExported) { - return [tstl.createAssignmentStatement( - this.createExportedIdentifier(identifierName), tstl.createNilLiteral())]; + return [ + tstl.createAssignmentStatement( + this.createExportedIdentifier(identifierName), tstl.createNilLiteral()), + ]; } else { - return [tstl.createVariableDeclarationStatement( - identifierName, tstl.createNilLiteral()), + return [ + tstl.createVariableDeclarationStatement( + identifierName, tstl.createNilLiteral()), ]; } } From 2cd0859a7f4c068c83000c53177f88861a0a47f2 Mon Sep 17 00:00:00 2001 From: Lolleko Date: Sun, 20 Jan 2019 20:51:00 +0100 Subject: [PATCH 03/12] Fixed namespace translation test and almsot every other translation tes --- src/LuaPrinter.ts | 2 +- src/LuaTransformer.ts | 29 ++++++++--- test/translation/lua/classExtension1.lua | 2 +- test/translation/lua/classExtension2.lua | 2 +- test/translation/lua/classExtension3.lua | 4 +- test/translation/lua/classExtension4.lua | 2 +- test/translation/lua/classPureAbstract.lua | 4 +- .../translation/lua/functionRestArguments.lua | 2 +- test/translation/lua/getSetAccessors.lua | 8 ++-- test/translation/lua/methodRestArguments.lua | 6 +-- .../lua/modulesChangedVariableExport.lua | 9 ++-- .../lua/modulesFunctionNoExport.lua | 2 +- .../lua/modulesNamespaceExport.lua | 7 ++- .../lua/modulesNamespaceNoExport.lua | 2 +- .../modulesNamespaceWithMemberNoExport.lua | 13 ++--- .../translation/lua/modulesVariableExport.lua | 7 ++- test/translation/lua/namespace.lua | 9 ++-- test/translation/lua/namespaceMerge.lua | 48 ++++++++++--------- test/translation/lua/namespaceNested.lua | 10 ++-- test/translation/lua/namespacePhantom.lua | 2 +- test/translation/lua/returnDefault.lua | 2 +- .../lua/shorthandPropertyAssignment.lua | 2 +- test/translation/lua/tryCatch.lua | 2 +- test/translation/lua/tryCatchFinally.lua | 2 +- test/translation/lua/tryFinally.lua | 2 +- test/translation/lua/tupleReturn.lua | 10 ++-- 26 files changed, 104 insertions(+), 86 deletions(-) diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 3a64e93df..4777f7ca2 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -308,7 +308,7 @@ export class LuaPrinter { paramterArr.push(this.printDotsLiteral(expression.dots)); } - let result = `function (${paramterArr.join(", ")})\n`; + let result = `function(${paramterArr.join(", ")})\n`; this.pushIndent(); result += this.printBlock(expression.body); this.popIndent(); diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 0a61c46fb..10938c657 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -80,6 +80,20 @@ export class LuaTransformer { this.isModule = tsHelper.isFileModule(node); const statements = this.transformStatements(node.statements); + if (this.isModule) { + statements.unshift( + tstl.createVariableDeclarationStatement( + tstl.createIdentifier("exports"), + tstl.createBinaryExpression( + tstl.createIdentifier("exports"), + tstl.createTableExpression(), + tstl.SyntaxKind.OrOperator + ))); + statements.push( + tstl.createReturnStatement( + [tstl.createIdentifier("exports")] + )); + } return [tstl.createBlock(statements, undefined, node), this.luaLibFeatureSet]; } @@ -738,11 +752,11 @@ export class LuaTransformer { const namespaceDeclaration = tstl.createAssignmentStatement( tstl.createTableIndexExpression( this.transformIdentifier(this.currentNamespace.name as ts.Identifier), - this.transformIdentifier(statement.name as ts.Identifier)), + tstl.createStringLiteral(this.transformIdentifier(statement.name as ts.Identifier).text)), tstl.createBinaryExpression( tstl.createTableIndexExpression( this.transformIdentifier(this.currentNamespace.name as ts.Identifier), - this.transformIdentifier(statement.name as ts.Identifier)), + tstl.createStringLiteral(this.transformIdentifier(statement.name as ts.Identifier).text)), tstl.createTableExpression(), tstl.SyntaxKind.OrOperator)); @@ -753,7 +767,7 @@ export class LuaTransformer { this.transformIdentifier(statement.name as ts.Identifier), tstl.createTableIndexExpression( this.transformIdentifier(this.currentNamespace.name as ts.Identifier), - this.transformIdentifier(statement.name as ts.Identifier))); + tstl.createStringLiteral(this.transformIdentifier(statement.name as ts.Identifier).text))); result.push(localDeclaration); } else if (this.isModule && (ts.getCombinedModifierFlags(statement) & ts.ModifierFlags.Export)) { @@ -775,16 +789,17 @@ export class LuaTransformer { result.push(localDeclaration); } else { // local NS = NS or {} - const localDeclaration = tstl.createVariableDeclarationStatement( + // TODO this is somewhat redundant since createLocalOrGlobalDeclaration also handles exports + const localDeclaration = this.createLocalOrGlobalDeclaration( this.transformIdentifier(statement.name as ts.Identifier), tstl.createBinaryExpression( - tstl.createIdentifier("NS"), + this.transformIdentifier(statement.name as ts.Identifier), tstl.createTableExpression(), tstl.SyntaxKind.OrOperator ) ); - result.push(localDeclaration); + result.push(...localDeclaration); } // Set current namespace for nested NS @@ -794,7 +809,7 @@ export class LuaTransformer { // Transform moduleblock to block and visit it if (statement.body && ts.isModuleBlock(statement.body)) { - result.push(...this.transformStatements(statement.body.statements)); + result.push(tstl.createDoStatement(this.transformStatements(statement.body.statements))); } this.currentNamespace = previousNamespace; diff --git a/test/translation/lua/classExtension1.lua b/test/translation/lua/classExtension1.lua index 3aaae7b5d..ff9e5bb5d 100644 --- a/test/translation/lua/classExtension1.lua +++ b/test/translation/lua/classExtension1.lua @@ -1,2 +1,2 @@ -MyClass.myFunction = function (self) +MyClass.myFunction = function(self) end; diff --git a/test/translation/lua/classExtension2.lua b/test/translation/lua/classExtension2.lua index 826b14a59..94e8f655f 100644 --- a/test/translation/lua/classExtension2.lua +++ b/test/translation/lua/classExtension2.lua @@ -1,2 +1,2 @@ -TestClass.myFunction = function (self) +TestClass.myFunction = function(self) end; diff --git a/test/translation/lua/classExtension3.lua b/test/translation/lua/classExtension3.lua index 254b3f132..008d45956 100644 --- a/test/translation/lua/classExtension3.lua +++ b/test/translation/lua/classExtension3.lua @@ -1,4 +1,4 @@ -RenamedTestClass.myFunction = function (self) +RenamedTestClass.myFunction = function(self) end; -RenamedMyClass.myFunction = function (self) +RenamedMyClass.myFunction = function(self) end; diff --git a/test/translation/lua/classExtension4.lua b/test/translation/lua/classExtension4.lua index 46622a73d..8fcb73124 100644 --- a/test/translation/lua/classExtension4.lua +++ b/test/translation/lua/classExtension4.lua @@ -1,4 +1,4 @@ MyClass.test = "test"; MyClass.testP = "testP"; -MyClass.myFunction = function (self) +MyClass.myFunction = function(self) end; diff --git a/test/translation/lua/classPureAbstract.lua b/test/translation/lua/classPureAbstract.lua index 7fc6af804..63d61f0db 100644 --- a/test/translation/lua/classPureAbstract.lua +++ b/test/translation/lua/classPureAbstract.lua @@ -1,11 +1,11 @@ ClassB = ClassB or {}; ClassB.__index = ClassB; -ClassB.new = function (construct, ...) +ClassB.new = function(construct, ...) local self = setmetatable({}, ClassB); if construct and ClassB.constructor then ClassB.constructor(self, ...); end return self; end; -ClassB.constructor = function (self) +ClassB.constructor = function(self) end; diff --git a/test/translation/lua/functionRestArguments.lua b/test/translation/lua/functionRestArguments.lua index a1fbe94e0..25fe06c01 100644 --- a/test/translation/lua/functionRestArguments.lua +++ b/test/translation/lua/functionRestArguments.lua @@ -1,3 +1,3 @@ -varargsFunction = function (a, ...) +varargsFunction = function(a, ...) local b = ({...}); end; diff --git a/test/translation/lua/getSetAccessors.lua b/test/translation/lua/getSetAccessors.lua index 7af47a4c3..9fe62bbb6 100644 --- a/test/translation/lua/getSetAccessors.lua +++ b/test/translation/lua/getSetAccessors.lua @@ -1,18 +1,18 @@ MyClass = MyClass or {}; MyClass.__index = MyClass; -MyClass.new = function (construct, ...) +MyClass.new = function(construct, ...) local self = setmetatable({}, MyClass); if construct and MyClass.constructor then MyClass.constructor(self, ...); end return self; end; -MyClass.constructor = function (self) +MyClass.constructor = function(self) end; -MyClass.get__field = function (self) +MyClass.get__field = function(self) return self._field + 4; end; -MyClass.set__field = function (self, v) +MyClass.set__field = function(self, v) self._field = v * 2; end; local instance = MyClass.new(true); diff --git a/test/translation/lua/methodRestArguments.lua b/test/translation/lua/methodRestArguments.lua index de91da04d..236560407 100644 --- a/test/translation/lua/methodRestArguments.lua +++ b/test/translation/lua/methodRestArguments.lua @@ -1,14 +1,14 @@ MyClass = MyClass or {}; MyClass.__index = MyClass; -MyClass.new = function (construct, ...) +MyClass.new = function(construct, ...) local self = setmetatable({}, MyClass); if construct and MyClass.constructor then MyClass.constructor(self, ...); end return self; end; -MyClass.constructor = function (self) +MyClass.constructor = function(self) end; -MyClass.varargsFunction = function (self, a, ...) +MyClass.varargsFunction = function(self, a, ...) local b = ({...}); end; diff --git a/test/translation/lua/modulesChangedVariableExport.lua b/test/translation/lua/modulesChangedVariableExport.lua index 0c5c579bf..2776db6f6 100644 --- a/test/translation/lua/modulesChangedVariableExport.lua +++ b/test/translation/lua/modulesChangedVariableExport.lua @@ -1,5 +1,4 @@ -local exports = exports or {} -local test = nil; -test = 1; -exports.test = test -return exports \ No newline at end of file +local exports = exports or {}; +exports.test = nil; +exports.test = 1; +return exports; \ No newline at end of file diff --git a/test/translation/lua/modulesFunctionNoExport.lua b/test/translation/lua/modulesFunctionNoExport.lua index 490b4a36f..37ea15ea9 100644 --- a/test/translation/lua/modulesFunctionNoExport.lua +++ b/test/translation/lua/modulesFunctionNoExport.lua @@ -1,2 +1,2 @@ -publicFunc = function () +publicFunc = function() end; diff --git a/test/translation/lua/modulesNamespaceExport.lua b/test/translation/lua/modulesNamespaceExport.lua index 1572312b2..768cf737b 100644 --- a/test/translation/lua/modulesNamespaceExport.lua +++ b/test/translation/lua/modulesNamespaceExport.lua @@ -1,6 +1,5 @@ -local exports = exports or {} -local TestSpace = exports.TestSpace or TestSpace or {} +local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; do end -exports.TestSpace = TestSpace -return exports +return exports; \ No newline at end of file diff --git a/test/translation/lua/modulesNamespaceNoExport.lua b/test/translation/lua/modulesNamespaceNoExport.lua index 5c9ff3a1f..9f4892365 100644 --- a/test/translation/lua/modulesNamespaceNoExport.lua +++ b/test/translation/lua/modulesNamespaceNoExport.lua @@ -1,3 +1,3 @@ -TestSpace = TestSpace or {} +TestSpace = TestSpace or {}; do end diff --git a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua b/test/translation/lua/modulesNamespaceWithMemberNoExport.lua index a2afe84fe..7a1ec050b 100644 --- a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua +++ b/test/translation/lua/modulesNamespaceWithMemberNoExport.lua @@ -1,8 +1,9 @@ -local exports = exports or {} -local TestSpace = exports.TestSpace or TestSpace or {} +local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; do - local function innerFunc() - end + local innerFunc; + innerFunc = function() + end; end -exports.TestSpace = TestSpace -return exports +return exports; \ No newline at end of file diff --git a/test/translation/lua/modulesVariableExport.lua b/test/translation/lua/modulesVariableExport.lua index 3ecfdc4c3..76c98810f 100644 --- a/test/translation/lua/modulesVariableExport.lua +++ b/test/translation/lua/modulesVariableExport.lua @@ -1,4 +1,3 @@ -local exports = exports or {} -local test = "test"; -exports.test = test -return exports +local exports = exports or {}; +exports.test = "test"; +return exports; diff --git a/test/translation/lua/namespace.lua b/test/translation/lua/namespace.lua index c5a266c7f..8b4c78003 100644 --- a/test/translation/lua/namespace.lua +++ b/test/translation/lua/namespace.lua @@ -1,5 +1,6 @@ -myNamespace = myNamespace or {} +myNamespace = myNamespace or {}; do - local function nsMember() - end -end + local nsMember; + nsMember = function() + end; +end \ No newline at end of file diff --git a/test/translation/lua/namespaceMerge.lua b/test/translation/lua/namespaceMerge.lua index 58e982078..1e4d30117 100644 --- a/test/translation/lua/namespaceMerge.lua +++ b/test/translation/lua/namespaceMerge.lua @@ -1,33 +1,35 @@ -MergedClass = MergedClass or {} -MergedClass.__index = MergedClass -function MergedClass.new(construct, ...) - local self = setmetatable({}, MergedClass) +MergedClass = MergedClass or {}; +MergedClass.__index = MergedClass; +MergedClass.new = function(construct, ...) + local self =setmetatable({}, MergedClass); self.propertyFunc = function(____) -end - if construct and MergedClass.constructor then MergedClass.constructor(self, ...) end - return self -end -function MergedClass.constructor(self) -end -function MergedClass.staticMethodA(self) -end -function MergedClass.staticMethodB(self) + end; + if construct and MergedClass.constructor then + MergedClass.constructor(self, ...); + end + return self; +end; +MergedClass.constructor = function(self) +end; +MergedClass.staticMethodA = function(self) +end; +MergedClass.staticMethodB = function(self) self:staticMethodA(); -end -function MergedClass.methodA(self) -end -function MergedClass.methodB(self) +end; +MergedClass.methodA = function(self) +end; +MergedClass.methodB = function(self) self:methodA(); self:propertyFunc(); -end -MergedClass = MergedClass or {} +end; +MergedClass = MergedClass or {}; do - local function namespaceFunc() - end - MergedClass.namespaceFunc = namespaceFunc + local namespaceFunc; + namespaceFunc = function() + end; end local mergedClass = MergedClass.new(true); mergedClass:methodB(); mergedClass:propertyFunc(); MergedClass:staticMethodB(); -MergedClass.namespaceFunc(); +MergedClass.namespaceFunc(); \ No newline at end of file diff --git a/test/translation/lua/namespaceNested.lua b/test/translation/lua/namespaceNested.lua index bff87b32e..dd1006ee9 100644 --- a/test/translation/lua/namespaceNested.lua +++ b/test/translation/lua/namespaceNested.lua @@ -1,8 +1,10 @@ -myNamespace = myNamespace or {} +myNamespace = myNamespace or {}; do - local myNestedNamespace = myNestedNamespace or {} + myNamespace.myNestedNamespace = myNamespace.myNestedNamespace or {}; + local myNestedNamespace = myNamespace.myNestedNamespace; do - local function nsMember() - end + local nsMember; + nsMember = function() + end; end end diff --git a/test/translation/lua/namespacePhantom.lua b/test/translation/lua/namespacePhantom.lua index 86727cc4c..3844b51be 100644 --- a/test/translation/lua/namespacePhantom.lua +++ b/test/translation/lua/namespacePhantom.lua @@ -1,2 +1,2 @@ -nsMember = function () +nsMember = function() end; diff --git a/test/translation/lua/returnDefault.lua b/test/translation/lua/returnDefault.lua index df97fc8ea..a0e35c570 100644 --- a/test/translation/lua/returnDefault.lua +++ b/test/translation/lua/returnDefault.lua @@ -1,3 +1,3 @@ -myFunc = function () +myFunc = function() return; end; diff --git a/test/translation/lua/shorthandPropertyAssignment.lua b/test/translation/lua/shorthandPropertyAssignment.lua index 3be2aad3b..0c5898188 100644 --- a/test/translation/lua/shorthandPropertyAssignment.lua +++ b/test/translation/lua/shorthandPropertyAssignment.lua @@ -1,4 +1,4 @@ local f; -f = function (x) +f = function(x) return ({x = x}); end; diff --git a/test/translation/lua/tryCatch.lua b/test/translation/lua/tryCatch.lua index 46dfea6c0..f3194765e 100644 --- a/test/translation/lua/tryCatch.lua +++ b/test/translation/lua/tryCatch.lua @@ -1,5 +1,5 @@ do - local ____TS_try, er = pcall(function () + local ____TS_try, er = pcall(function() local a = 42; end); if not ____TS_try then diff --git a/test/translation/lua/tryCatchFinally.lua b/test/translation/lua/tryCatchFinally.lua index 64b54da9e..4b5caf9a6 100644 --- a/test/translation/lua/tryCatchFinally.lua +++ b/test/translation/lua/tryCatchFinally.lua @@ -1,5 +1,5 @@ do - local ____TS_try, er = pcall(function () + local ____TS_try, er = pcall(function() local a = 42; end); if not ____TS_try then diff --git a/test/translation/lua/tryFinally.lua b/test/translation/lua/tryFinally.lua index 91b09f1a2..a117b8bb2 100644 --- a/test/translation/lua/tryFinally.lua +++ b/test/translation/lua/tryFinally.lua @@ -1,5 +1,5 @@ do - pcall(function () + pcall(function() local a = 42; end); do diff --git a/test/translation/lua/tupleReturn.lua b/test/translation/lua/tupleReturn.lua index 85815cad7..a75c85272 100644 --- a/test/translation/lua/tupleReturn.lua +++ b/test/translation/lua/tupleReturn.lua @@ -1,4 +1,4 @@ -tupleReturn = function () +tupleReturn = function() return 0, "foobar"; end; tupleReturn(); @@ -13,16 +13,16 @@ e = ({tupleReturn()}); f = noTupleReturn(); foo(({tupleReturn()})); foo(noTupleReturn()); -tupleReturnFromVar = function () +tupleReturnFromVar = function() local r = {1, "baz"}; return table.unpack(r); end; -tupleReturnForward = function () +tupleReturnForward = function() return tupleReturn(); end; -tupleNoForward = function () +tupleNoForward = function() return ({tupleReturn()}); end; -tupleReturnUnpack = function () +tupleReturnUnpack = function() return table.unpack(tupleNoForward()); end; From 31b41b789c581d08689f1848e669fe4e4b9b1006 Mon Sep 17 00:00:00 2001 From: Lolleko Date: Sun, 20 Jan 2019 20:58:56 +0100 Subject: [PATCH 04/12] Change isArray to Array.isArray --- src/LuaTransformer.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 10938c657..c4e2ac06c 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -7,7 +7,6 @@ import * as tstl from "./LuaAST"; import {LuaLib, LuaLibFeature} from "./LuaLib"; import {ContextType, TSHelper as tsHelper} from "./TSHelper"; import {TSTLErrors} from "./TSTLErrors"; -import { isArray } from "util"; export type StatementVisitResult = tstl.Statement | tstl.Statement[] | undefined; export type ExpressionVisitResult = tstl.Expression | undefined; @@ -3128,7 +3127,7 @@ export class LuaTransformer { || this.currentNamespace || (tsOriginal && tsHelper.findFirstNodeAbove(tsOriginal, ts.isFunctionLike)) ) { - if (!isArray(lhs)) { + if (!Array.isArray(lhs)) { lhs = [lhs]; } const shouldExport = lhs.some(i => this.isIdentifierExported(i.text)); From 906df5088c6f35152f87ee3ebbeae3cee7e250cf Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sun, 20 Jan 2019 21:56:15 +0100 Subject: [PATCH 05/12] Fixed broken tests --- test/translation/lua/namespaceMerge.lua | 2 +- test/unit/expressions.spec.ts | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/test/translation/lua/namespaceMerge.lua b/test/translation/lua/namespaceMerge.lua index 1e4d30117..4fa661f8a 100644 --- a/test/translation/lua/namespaceMerge.lua +++ b/test/translation/lua/namespaceMerge.lua @@ -1,7 +1,7 @@ MergedClass = MergedClass or {}; MergedClass.__index = MergedClass; MergedClass.new = function(construct, ...) - local self =setmetatable({}, MergedClass); + local self = setmetatable({}, MergedClass); self.propertyFunc = function(____) end; if construct and MergedClass.constructor then diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 17580493d..8f5f8e716 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -13,9 +13,9 @@ export class ExpressionTests { @TestCase("--i", "i = i - 1;") @TestCase("!a", "not a;") @TestCase("-a", "-a;") - @TestCase("let a = delete tbl['test']", "local a = (function ()\n tbl.test = nil;\n return true;\nend)();") + @TestCase("let a = delete tbl['test']", "local a = (function()\n tbl.test = nil;\n return true;\nend)();") @TestCase("delete tbl['test']", "tbl.test = nil;") - @TestCase("let a = delete tbl.test", "local a = (function ()\n tbl.test = nil;\n return true;\nend)();") + @TestCase("let a = delete tbl.test", "local a = (function()\n tbl.test = nil;\n return true;\nend)();") @TestCase("delete tbl.test", "tbl.test = nil;") @Test("Unary expressions basic") public unaryBasic(input: string, lua: string): void { @@ -204,14 +204,6 @@ export class ExpressionTests { @TestCase("true ? undefined : true", undefined, { luaTarget: LuaTarget.LuaJIT }) @Test("Ternary operator") public ternaryOperator(input: string, expected: any, options?: ts.CompilerOptions): void { - console.log(util.transpileString( - `const literalValue = 'literal'; - let variableValue:string; - let maybeBooleanValue:string|boolean = false; - let maybeUndefinedValue:string|undefined; - return ${input};`, options - - )); const result = util.transpileAndExecute( `const literalValue = 'literal'; let variableValue:string; From 82b84cd1ea9eece703023c1e8e70b777b73ce1a6 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sun, 20 Jan 2019 22:31:15 +0100 Subject: [PATCH 06/12] Fixed undefined kind bug --- src/LuaTransformer.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index c4e2ac06c..ed42957fb 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -3001,6 +3001,7 @@ export class LuaTransformer { const exportTable = this.currentNamespace ? this.transformIdentifier(this.currentNamespace.name as ts.Identifier) : tstl.createIdentifier("exports"); + return tstl.createTableIndexExpression( exportTable, tstl.createStringLiteral(identifier.text)); @@ -3133,12 +3134,13 @@ export class LuaTransformer { const shouldExport = lhs.some(i => this.isIdentifierExported(i.text)); if (shouldExport) { statements.push( - tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), undefined, parent)); + tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), rhs, parent)); } else { - statements.push(tstl.createVariableDeclarationStatement(lhs, undefined, parent)); + statements.push(tstl.createVariableDeclarationStatement(lhs, rhs, parent)); } + } else { + statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal)); } - statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal)); return statements; } From 44c03be7e2a156de3cec03bb890e98b7b3e92e64 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Mon, 21 Jan 2019 11:47:29 -0700 Subject: [PATCH 07/12] Fixing remaining tests (#350) * Fixing remaining tests - Fixed exporting enum members - Fixed exporting namespace members in a non-module - (Re)Fixed recursive functions - Updated transformation tests with aesthetic changes * corrected class export transform tests (which re-breaks them right now) --- src/LuaTransformer.ts | 11 +++++-- test/translation/lua/modulesClassExport.lua | 25 ++++++++-------- .../lua/modulesClassWithMemberExport.lua | 29 ++++++++++--------- .../translation/lua/modulesFunctionExport.lua | 9 +++--- .../lua/modulesNamespaceExport.lua | 3 +- .../lua/modulesNamespaceExportEnum.lua | 15 +++++----- ...modulesNamespaceNestedWithMemberExport.lua | 17 +++++------ .../lua/modulesNamespaceWithMemberExport.lua | 13 ++++----- .../modulesNamespaceWithMemberNoExport.lua | 2 +- test/translation/lua/namespace.lua | 2 +- test/translation/lua/namespaceMerge.lua | 5 ++-- 11 files changed, 67 insertions(+), 64 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index ed42957fb..d86d697c3 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -853,7 +853,10 @@ export class LuaTransformer { )); } } else { - const table = this.transformIdentifier(enumDeclaration.name); + let table: tstl.Identifier | tstl.TableIndexExpression = this.transformIdentifier(enumDeclaration.name); + if (this.isIdentifierExported(enumDeclaration.name.text)) { + table = this.createExportedIdentifier(table); + } const property = tstl.createTableIndexExpression(table, memberName, undefined); result.push(tstl.createAssignmentStatement(property, enumMember.value, undefined, enumMember.original)); } @@ -2987,7 +2990,7 @@ export class LuaTransformer { } public isIdentifierExported(identifierName: string | ts.__String): boolean { - if (!this.isModule) { + if (!this.isModule && !this.currentNamespace) { return false; } const currentScope = this.currentNamespace ? this.currentNamespace : this.currentSourceFile; @@ -3136,7 +3139,9 @@ export class LuaTransformer { statements.push( tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), rhs, parent)); } else { - statements.push(tstl.createVariableDeclarationStatement(lhs, rhs, parent)); + // Separate declaration from assignment to allow for recursion + statements.push(tstl.createVariableDeclarationStatement(lhs, undefined, parent)); + statements.push(tstl.createAssignmentStatement(lhs, rhs, parent)); } } else { statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal)); diff --git a/test/translation/lua/modulesClassExport.lua b/test/translation/lua/modulesClassExport.lua index 9e09cb61f..a339f9482 100644 --- a/test/translation/lua/modulesClassExport.lua +++ b/test/translation/lua/modulesClassExport.lua @@ -1,12 +1,13 @@ -local exports = exports or {} -local TestClass = TestClass or {} -TestClass.__index = TestClass -function TestClass.new(construct, ...) - local self = setmetatable({}, TestClass) - if construct and TestClass.constructor then TestClass.constructor(self, ...) end - return self -end -function TestClass.constructor(self) -end -exports.TestClass = TestClass -return exports +local exports = exports or {}; +exports.TestClass = exports.TestClass or {}; +exports.TestClass.__index = exports.TestClass; +exports.TestClass.new = function(construct, ...) + local self = setmetatable({}, exports.TestClass); + if construct and exports.TestClass.constructor then + exports.TestClass.constructor(self, ...); + end + return self; +end; +exports.TestClass.constructor = function(self) +end; +return exports; diff --git a/test/translation/lua/modulesClassWithMemberExport.lua b/test/translation/lua/modulesClassWithMemberExport.lua index 4f09fd29c..655d142c8 100644 --- a/test/translation/lua/modulesClassWithMemberExport.lua +++ b/test/translation/lua/modulesClassWithMemberExport.lua @@ -1,14 +1,15 @@ -local exports = exports or {} -local TestClass = TestClass or {} -TestClass.__index = TestClass -function TestClass.new(construct, ...) - local self = setmetatable({}, TestClass) - if construct and TestClass.constructor then TestClass.constructor(self, ...) end - return self -end -function TestClass.constructor(self) -end -function TestClass.memberFunc(self) -end -exports.TestClass = TestClass -return exports +local exports = exports or {}; +exports.TestClass = exports.TestClass or {}; +exports.TestClass.__index = exports.TestClass; +exports.TestClass.new = function(construct, ...) + local self = setmetatable({}, exports.TestClass); + if construct and exports.TestClass.constructor then + exports.TestClass.constructor(self, ...); + end + return self; +end; +exports.TestClass.constructor = function(self) +end; +exports.TestClass.memberFunc = function(self) +end; +return exports; diff --git a/test/translation/lua/modulesFunctionExport.lua b/test/translation/lua/modulesFunctionExport.lua index 5b447e5b2..12e69553c 100644 --- a/test/translation/lua/modulesFunctionExport.lua +++ b/test/translation/lua/modulesFunctionExport.lua @@ -1,5 +1,4 @@ -local exports = exports or {} -local function publicFunc() -end -exports.publicFunc = publicFunc -return exports +local exports = exports or {}; +exports.publicFunc = function() +end; +return exports; diff --git a/test/translation/lua/modulesNamespaceExport.lua b/test/translation/lua/modulesNamespaceExport.lua index 768cf737b..122f64cf0 100644 --- a/test/translation/lua/modulesNamespaceExport.lua +++ b/test/translation/lua/modulesNamespaceExport.lua @@ -1,5 +1,6 @@ local exports = exports or {}; exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; do end -return exports; \ No newline at end of file +return exports; diff --git a/test/translation/lua/modulesNamespaceExportEnum.lua b/test/translation/lua/modulesNamespaceExportEnum.lua index 002807a03..938fdd56b 100644 --- a/test/translation/lua/modulesNamespaceExportEnum.lua +++ b/test/translation/lua/modulesNamespaceExportEnum.lua @@ -1,10 +1,9 @@ -local exports = exports or {} -local test = exports.test or test or {} +local exports = exports or {}; +exports.test = exports.test or {}; +local test = exports.test; do - local TestEnum={} - TestEnum.foo="foo" - TestEnum.bar="bar" - test.TestEnum = TestEnum + test.TestEnum = {}; + test.TestEnum.foo = "foo"; + test.TestEnum.bar = "bar"; end -exports.test = test -return exports +return exports; diff --git a/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua b/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua index 326a00294..44509f50d 100644 --- a/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua +++ b/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua @@ -1,13 +1,12 @@ -local exports = exports or {} -local TestSpace = exports.TestSpace or TestSpace or {} +local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; do - local TestNestedSpace = TestNestedSpace or {} + TestSpace.TestNestedSpace = TestSpace.TestNestedSpace or {}; + local TestNestedSpace = TestSpace.TestNestedSpace; do - local function innerFunc() - end - TestNestedSpace.innerFunc = innerFunc + TestNestedSpace.innerFunc = function() + end; end - TestSpace.TestNestedSpace = TestNestedSpace end -exports.TestSpace = TestSpace -return exports +return exports; diff --git a/test/translation/lua/modulesNamespaceWithMemberExport.lua b/test/translation/lua/modulesNamespaceWithMemberExport.lua index 7e9204160..020bcf4d5 100644 --- a/test/translation/lua/modulesNamespaceWithMemberExport.lua +++ b/test/translation/lua/modulesNamespaceWithMemberExport.lua @@ -1,9 +1,8 @@ -local exports = exports or {} -local TestSpace = exports.TestSpace or TestSpace or {} +local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; do - local function innerFunc() - end - TestSpace.innerFunc = innerFunc + TestSpace.innerFunc = function() + end; end -exports.TestSpace = TestSpace -return exports +return exports; diff --git a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua b/test/translation/lua/modulesNamespaceWithMemberNoExport.lua index 7a1ec050b..b0abeb433 100644 --- a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua +++ b/test/translation/lua/modulesNamespaceWithMemberNoExport.lua @@ -6,4 +6,4 @@ do innerFunc = function() end; end -return exports; \ No newline at end of file +return exports; diff --git a/test/translation/lua/namespace.lua b/test/translation/lua/namespace.lua index 8b4c78003..bdf6664fd 100644 --- a/test/translation/lua/namespace.lua +++ b/test/translation/lua/namespace.lua @@ -3,4 +3,4 @@ do local nsMember; nsMember = function() end; -end \ No newline at end of file +end diff --git a/test/translation/lua/namespaceMerge.lua b/test/translation/lua/namespaceMerge.lua index 4fa661f8a..e585c3c83 100644 --- a/test/translation/lua/namespaceMerge.lua +++ b/test/translation/lua/namespaceMerge.lua @@ -24,12 +24,11 @@ MergedClass.methodB = function(self) end; MergedClass = MergedClass or {}; do - local namespaceFunc; - namespaceFunc = function() + MergedClass.namespaceFunc = function() end; end local mergedClass = MergedClass.new(true); mergedClass:methodB(); mergedClass:propertyFunc(); MergedClass:staticMethodB(); -MergedClass.namespaceFunc(); \ No newline at end of file +MergedClass.namespaceFunc(); From 971a1786b7147ac6f80e5355c344dfe8a0d574eb Mon Sep 17 00:00:00 2001 From: Lolleko Date: Wed, 23 Jan 2019 13:08:10 +0100 Subject: [PATCH 08/12] Added export funcitonality to class transformation & cleaned up export code TODO fix tests --- src/LuaTransformer.ts | 217 +++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 120 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index d86d697c3..137ef0dd4 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -327,7 +327,9 @@ export class LuaTransformer { const value = this.transformExpression(f.initializer); // className["fieldName"] - const classField = tstl.createTableIndexExpression(className, fieldName); + const classField = tstl.createTableIndexExpression( + className, + fieldName); // className["fieldName"] = value; const assignClassField = tstl.createAssignmentStatement(classField, value); @@ -341,8 +343,11 @@ 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 fieldAssign = tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, fieldName), + classField, value ); @@ -354,23 +359,24 @@ export class LuaTransformer { .filter(n => ts.isConstructorDeclaration(n) && n.body)[0] as ts.ConstructorDeclaration; if (constructor) { // Add constructor plus initialization of instance fields - result.push(this.transformConstructor(constructor, className)); + result.push(this.transformConstructor(constructor, className, statement)); } else if (!isExtension && !extendsType) { // Generate a constructor if none was defined result.push(this.transformConstructor( ts.createConstructor([], [], [], ts.createBlock([], true)), - className + className, + statement )); } // Transform get accessors statement.members.filter(ts.isGetAccessor).forEach(getAccessor => { - result.push(this.transformGetAccessorDeclaration(getAccessor, className)); + result.push(this.transformGetAccessorDeclaration(getAccessor, className, statement)); }); // Transform set accessors statement.members.filter(ts.isSetAccessor).forEach(setAccessor => { - result.push(this.transformSetAccessorDeclaration(setAccessor, className)); + result.push(this.transformSetAccessorDeclaration(setAccessor, className, statement)); }); // Transform methods @@ -412,7 +418,7 @@ export class LuaTransformer { // (local) className = className or baseName.new() // (local) className = baseName.new() // exports.className = baseName.new() - const classVar = this.createLocalOrGlobalDeclaration(className, rhs, undefined, statement); + const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, rhs, undefined, statement); result.push(...classVar); } else { @@ -421,19 +427,24 @@ export class LuaTransformer { if (!noClassOr) { // className or {} - rhs = tstl.createBinaryExpression(className, rhs, tstl.SyntaxKind.OrOperator); + rhs = tstl.createBinaryExpression( + this.addExportToIdentifier(className, statement.name.text), + rhs, + tstl.SyntaxKind.OrOperator); } // (local) className = className or {} // (local) className = {} // exports.className = {} - const classVar = this.createLocalOrGlobalDeclaration(className, rhs, undefined, statement); + const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, rhs, undefined, statement); result.push(...classVar); } // className.__index - const classIndex = tstl.createTableIndexExpression(className, tstl.createStringLiteral("__index")); + const classIndex = tstl.createTableIndexExpression( + this.addExportToIdentifier(className, statement.name.text), + tstl.createStringLiteral("__index")); // className.__index = className const assignClassIndex = tstl.createAssignmentStatement(classIndex, className, undefined, statement); @@ -442,7 +453,9 @@ export class LuaTransformer { if (extendsType) { const baseName = tstl.createIdentifier(extendsType.symbol.escapedName as string); // className.__base = baseName - const classBase = tstl.createTableIndexExpression(className, tstl.createStringLiteral("__base")); + const classBase = tstl.createTableIndexExpression( + this.addExportToIdentifier(className, statement.name.text), + tstl.createStringLiteral("__base")); const assignClassBase = tstl.createAssignmentStatement(classBase, baseName, undefined, statement); @@ -501,8 +514,11 @@ export class LuaTransformer { newFuncStatements.push(returnSelf); // function className.new(construct, ...) ... end + // or function export.className.new(construct, ...) ... end const newFunc = tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, tstl.createStringLiteral("new")), + tstl.createTableIndexExpression( + this.addExportToIdentifier(className, statement.name.text), + tstl.createStringLiteral("new")), tstl.createFunctionExpression( tstl.createBlock(newFuncStatements), [tstl.createIdentifier("construct")], @@ -518,7 +534,8 @@ export class LuaTransformer { public transformConstructor( statement: ts.ConstructorDeclaration, - className: tstl.Identifier + className: tstl.Identifier, + classDeclaration: ts.ClassLikeDeclaration ): tstl.AssignmentStatement { // Don't transform methods without body (overload declarations) @@ -573,8 +590,11 @@ export class LuaTransformer { const body: tstl.Block = tstl.createBlock(bodyStatements); + const result = tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, tstl.createStringLiteral("constructor")), + tstl.createTableIndexExpression( + this.addExportToIdentifier(className, classDeclaration.name.text), + tstl.createStringLiteral("constructor")), tstl.createFunctionExpression(body, params, dotsLiteral, restParamName, undefined, undefined), undefined, statement); @@ -586,7 +606,8 @@ export class LuaTransformer { public transformGetAccessorDeclaration( getAccessor: ts.GetAccessorDeclaration, - className: tstl.Identifier + className: tstl.Identifier, + classDeclaration: ts.ClassLikeDeclaration ): tstl.AssignmentStatement { const name = this.transformIdentifier(getAccessor.name as ts.Identifier); @@ -597,14 +618,17 @@ export class LuaTransformer { ); return tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, tstl.createStringLiteral("get__" + name.text)), + tstl.createTableIndexExpression( + this.addExportToIdentifier(className, classDeclaration.name.text), + tstl.createStringLiteral("get__" + name.text)), accessorFunction ); } public transformSetAccessorDeclaration( setAccessor: ts.SetAccessorDeclaration, - className: tstl.Identifier + className: tstl.Identifier, + classDeclaration: ts.ClassLikeDeclaration ): tstl.AssignmentStatement { const name = this.transformIdentifier(setAccessor.name as ts.Identifier); @@ -619,7 +643,9 @@ export class LuaTransformer { ); return tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, tstl.createStringLiteral("set__" + name.text)), + tstl.createTableIndexExpression( + this.addExportToIdentifier(className, classDeclaration.name.text), + tstl.createStringLiteral("set__" + name.text)), accessorFunction ); } @@ -653,7 +679,9 @@ export class LuaTransformer { ); return tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, methodName), + tstl.createTableIndexExpression( + this.addExportToIdentifier(className, (node.parent as ts.ClassLikeDeclaration).name.text), + methodName), functionExpression, undefined, node @@ -789,7 +817,7 @@ export class LuaTransformer { } else { // local NS = NS or {} // TODO this is somewhat redundant since createLocalOrGlobalDeclaration also handles exports - const localDeclaration = this.createLocalOrGlobalDeclaration( + const localDeclaration = this.createLocalOrExportedOrGlobalDeclaration( this.transformIdentifier(statement.name as ts.Identifier), tstl.createBinaryExpression( this.transformIdentifier(statement.name as ts.Identifier), @@ -831,21 +859,21 @@ export class LuaTransformer { if (!membersOnly) { const name = this.transformIdentifier(enumDeclaration.name); const table = tstl.createTableExpression(); - result.push(...this.createLocalOrGlobalDeclaration(name, table, undefined, enumDeclaration)); + result.push(...this.createLocalOrExportedOrGlobalDeclaration(name, table, undefined, enumDeclaration)); } for (const enumMember of this.computeEnumMembers(enumDeclaration)) { const memberName = this.transformPropertyName(enumMember.name); if (membersOnly) { if (tstl.isIdentifier(memberName)) { - result.push(...this.createLocalOrGlobalDeclaration( + result.push(...this.createLocalOrExportedOrGlobalDeclaration( memberName, enumMember.value, undefined, enumDeclaration )); } else { - result.push(...this.createLocalOrGlobalDeclaration( + result.push(...this.createLocalOrExportedOrGlobalDeclaration( tstl.createIdentifier(enumMember.name.getText(), undefined, enumMember.name), enumMember.value, undefined, @@ -853,10 +881,8 @@ export class LuaTransformer { )); } } else { - let table: tstl.Identifier | tstl.TableIndexExpression = this.transformIdentifier(enumDeclaration.name); - if (this.isIdentifierExported(enumDeclaration.name.text)) { - table = this.createExportedIdentifier(table); - } + const table: tstl.IdentifierOrTableIndexExpression = + this.transformIdentifierExpression(enumDeclaration.name); const property = tstl.createTableIndexExpression(table, memberName, undefined); result.push(tstl.createAssignmentStatement(property, enumMember.value, undefined, enumMember.original)); } @@ -918,7 +944,7 @@ export class LuaTransformer { ); const functionExpression = tstl.createFunctionExpression(body, params, dotsLiteral, restParamName); - return this.createLocalOrGlobalDeclaration(name, functionExpression, undefined, functionDeclaration); + return this.createLocalOrExportedOrGlobalDeclaration(name, functionExpression, undefined, functionDeclaration); } public transformTypeAliasDeclaration(statement: ts.TypeAliasDeclaration): undefined { @@ -930,8 +956,7 @@ export class LuaTransformer { } public transformVariableDeclaration(statement: ts.VariableDeclaration) - : [tstl.AssignmentStatement | tstl.VariableDeclarationStatement] - | [tstl.VariableDeclarationStatement, tstl.AssignmentStatement] + : tstl.Statement[] { if (statement.initializer) { // Validate assignment @@ -941,55 +966,13 @@ export class LuaTransformer { } if (ts.isIdentifier(statement.name)) { - const isVariableExported = this.isIdentifierExported(statement.name.escapedText); // Find variable identifier const identifierName = this.transformIdentifier(statement.name); if (statement.initializer) { const value = this.transformExpression(statement.initializer); - if (ts.isFunctionExpression(statement.initializer) || ts.isArrowFunction(statement.initializer)) { - // Separate declaration and assignment for functions to allow recursion - - // local identifierName; identifierName = value; - if (isVariableExported) { - return [ - tstl.createVariableDeclarationStatement(identifierName), - tstl.createAssignmentStatement( - this.createExportedIdentifier(identifierName), - value), - ]; - } else { - return [ - tstl.createVariableDeclarationStatement(identifierName), - tstl.createAssignmentStatement( - identifierName, - value), - ]; - } - } else { - // local identifierName = value; - if (isVariableExported) { - return [ - tstl.createAssignmentStatement( - this.createExportedIdentifier(identifierName), - value), - ]; - } else { - return [tstl.createVariableDeclarationStatement(identifierName, value)]; - } - } + return this.createLocalOrExportedDeclaration(identifierName, value); } else { - // local identifierName = nil; - if (isVariableExported) { - return [ - tstl.createAssignmentStatement( - this.createExportedIdentifier(identifierName), tstl.createNilLiteral()), - ]; - } else { - return [ - tstl.createVariableDeclarationStatement( - identifierName, tstl.createNilLiteral()), - ]; - } + return this.createLocalOrExportedDeclaration(identifierName, tstl.createNilLiteral()); } } else if (ts.isArrayBindingPattern(statement.name)) { // Destructuring type @@ -1000,49 +983,21 @@ export class LuaTransformer { } const vars = statement.name.elements.map(e => this.transformArrayBindingElement(e)); - const isSomeVariableExported = vars.some(i => this.isIdentifierExported(i.text)); // Don't unpack TupleReturn decorated functions if (statement.initializer) { if (tsHelper.isTupleReturnCall(statement.initializer, this.checker)) { - // local vars = initializer; - if (isSomeVariableExported) { - return [tstl.createAssignmentStatement( - vars.map(i => this.createExportedIdentifier(i)), - this.transformExpression(statement.initializer) - )]; - } else { - return [tstl.createVariableDeclarationStatement( - vars, - this.transformExpression(statement.initializer) - )]; - } + return this.createLocalOrExportedDeclaration(vars, this.transformExpression(statement.initializer)); } else { // local vars = this.transpileDestructingAssignmentValue(node.initializer); const initializer = this.createUnpackCall( this.transformExpression(statement.initializer), statement.initializer ); - if (isSomeVariableExported) { - return [ - tstl.createAssignmentStatement( - vars.map(i => this.createExportedIdentifier(i)), - initializer), - ]; - } else { - return [tstl.createVariableDeclarationStatement(vars, initializer)]; - } + return this.createLocalOrExportedDeclaration(vars, initializer); } } else { - if (isSomeVariableExported) { - return [ - tstl.createAssignmentStatement( - vars.map(i => this.createExportedIdentifier(i)), - tstl.createNilLiteral()), - ]; - } else { - return [tstl.createVariableDeclarationStatement(vars)]; - } + return this.createLocalOrExportedDeclaration(vars, tstl.createNilLiteral()); } } else { throw TSTLErrors.UnsupportedKind("variable declaration", statement.name.kind, statement); @@ -3000,6 +2955,15 @@ 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)) { + return this.createExportedIdentifier(identifier); + } + return identifier; + } + public createExportedIdentifier(identifier: tstl.Identifier): tstl.TableIndexExpression { const exportTable = this.currentNamespace ? this.transformIdentifier(this.currentNamespace.name as ts.Identifier) @@ -3119,7 +3083,7 @@ export class LuaTransformer { return filePath.replace(new RegExp("\\\\|\/", "g"), "."); } - private createLocalOrGlobalDeclaration( + private createLocalOrExportedOrGlobalDeclaration( lhs: tstl.Identifier | tstl.Identifier[], rhs: tstl.Expression, parent?: tstl.Node, @@ -3127,24 +3091,37 @@ export class LuaTransformer { ): tstl.Statement[] { const statements: tstl.Statement[] = []; - if (this.isModule - || this.currentNamespace - || (tsOriginal && tsHelper.findFirstNodeAbove(tsOriginal, ts.isFunctionLike)) - ) { - if (!Array.isArray(lhs)) { - lhs = [lhs]; - } - const shouldExport = lhs.some(i => this.isIdentifierExported(i.text)); - if (shouldExport) { - statements.push( - tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), rhs, parent)); - } else { + if (this.isModule || this.currentNamespace) { + statements.push(...this.createLocalOrExportedDeclaration(lhs, rhs, parent ,tsOriginal)); + } else { + statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal)); + } + return statements; + } + + private createLocalOrExportedDeclaration( + 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]; + } + const shouldExport = lhs.some(i => this.isIdentifierExported(i.text)); + if (shouldExport) { + statements.push( + tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), rhs, parent)); + } else { + if (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)); + } else { + statements.push(tstl.createVariableDeclarationStatement(lhs, rhs, parent)); } - } else { - statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal)); } return statements; } From 5971e3a5d85aea9ec7b702113384fbc4ab97edaf Mon Sep 17 00:00:00 2001 From: Lolleko Date: Wed, 23 Jan 2019 17:48:34 +0100 Subject: [PATCH 09/12] Removed ts-node from test runner and fixed threaded runner --- package.json | 10 ++-- test/compiler/watchmode.spec.ts | 2 +- test/runner.ts | 2 +- test/test_thread.ts | 15 ++++-- test/threaded_runner.ts | 91 +++++++++++++++++++++------------ 5 files changed, 76 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 733ef7a83..737306100 100644 --- a/package.json +++ b/package.json @@ -14,16 +14,16 @@ "scripts": { "build": "tsc -p tsconfig.json && npm run build-lualib", "build-lualib": "ts-node ./build_lualib.ts", - "test": "npm run style-check && tslint -c ./tslint.json src/lualib/*.ts && npm run build-lualib && ts-node ./test/runner.ts", - "coverage": "nyc npm test && nyc report --reporter=text-lcov > coverage.lcov", - "coverage-html": "nyc npm test && nyc report --reporter=html", - "test-threaded": "style-check && npm run build && ts-node ./test/threaded_runner.ts", + "test": "npm run style-check && npm run build-lualib && tsc -p ./test/tsconfig.json && node ./test/runner.js", + "coverage": "nyc --source-map=true npm test && nyc report --reporter=text-lcov > coverage.lcov", + "coverage-html": "nyc --source-map=true npm test && nyc report --reporter=html", + "test-threaded": "npm run style-check && npm run build && node ./test/threaded_runner.js", "release-patch": "npm version patch", "release-minor": "npm version minor", "release-major": "npm version major", "preversion": "npm run build && npm test", "postversion": "git push && git push --tags", - "style-check": "tslint -p .", + "style-check": "tslint -p . && tslint -c ./tslint.json src/lualib/*.ts", "style-fix": "gts fix && tslint -p . --fix" }, "bin": { diff --git a/test/compiler/watchmode.spec.ts b/test/compiler/watchmode.spec.ts index c943b2779..7b838316b 100644 --- a/test/compiler/watchmode.spec.ts +++ b/test/compiler/watchmode.spec.ts @@ -15,7 +15,7 @@ export class CompilerWatchModeTest { fileToChange = fileToChange; const fileToChangeOut = fileToChange.replace(".ts", ".lua"); - const child = fork(path.join(__dirname, "watcher_proccess.ts")); + const child = fork(path.join(__dirname, "watcher_proccess.js")); child.send(args); await this.waitForFileExists(fileToChangeOut, 9000) diff --git a/test/runner.ts b/test/runner.ts index dbd52cdf1..b2dfbbf2b 100644 --- a/test/runner.ts +++ b/test/runner.ts @@ -7,7 +7,7 @@ import * as path from "path"; const testSet = TestSet.create(); // add your tests -testSet.addTestsFromFiles("./test/**/*.spec.ts"); +testSet.addTestsFromFiles("./test/**/*.spec.js"); // create a test runner const testRunner = new TestRunner(); diff --git a/test/test_thread.ts b/test/test_thread.ts index 784ac3323..ffde2316f 100644 --- a/test/test_thread.ts +++ b/test/test_thread.ts @@ -1,15 +1,18 @@ import { MatchError, TestRunner, TestSet, TestOutcome } from "alsatian"; import * as JSON from "circular-json"; -module.exports = function(input, done) { +module.exports = (input, done) => { const testSet = TestSet.create(); testSet.addTestsFromFiles(input.files); const testRunner = new TestRunner(); - testRunner.onTestComplete((result) => { + let testCount = 0; + let failedTestCount = 0; + + testRunner.onTestComplete(result => { if (result.outcome === TestOutcome.Fail) { if (result.error instanceof MatchError) { - console.log(`Test ${result.testFixture.description}, ${result.test.key}(${JSON.stringify(result.testCase.caseArguments)}) Failed!`) + console.log(`Test ${result.testFixture.description}, ${result.test.key}(${JSON.stringify(result.testCase.caseArguments)}) Failed!`); console.log(" ---\n" + ' message: "' + result.error.message + @@ -23,9 +26,11 @@ module.exports = function(input, done) { result.error.expected + "\n"); } + failedTestCount++; } - }) + testCount++; + }); testRunner.run(testSet) - .then((results) => done(results, input)) + .then(() => done(testCount, failedTestCount)); }; diff --git a/test/threaded_runner.ts b/test/threaded_runner.ts index 08a304e1a..ba8f42000 100644 --- a/test/threaded_runner.ts +++ b/test/threaded_runner.ts @@ -4,6 +4,20 @@ import * as os from "os"; import * as path from "path"; import {config, Pool} from "threads"; +function fileArrToString(fileArr: string[]): string { + return fileArr.map(val => path.basename(val).replace(".spec.js", "")).join(", "); +} + +function printTestStats(testCount: number, failedTestCount: number, header: string, footer: string): void { + console.log("-----------------"); + console.log(header); + console.log(`Total: ${testCount}`); + console.log(`Passed: ${testCount - failedTestCount}`); + console.log(`Failed: ${failedTestCount}`); + console.log(footer); + console.log("-----------------"); +} + config.set({ basepath: { node: __dirname, @@ -12,45 +26,58 @@ config.set({ let cpuCount = os.cpus().length + 1; if ("TRAVIS" in process.env && "CI" in process.env) { - // fixed thread count for CI - cpuCount = 8; + // fixed thread count for CI + cpuCount = 8; } -const testFiles: string[] = glob.sync("./test/**/*.spec.ts"); +const testFiles: string[] = glob.sync("./test/**/*.spec.js"); const pool = new Pool(cpuCount); let jobCounter = 0; - -const fileArrToString = (fileArr: string[]) => - fileArr.map(val => path.basename(val).replace(".spec.ts", "")).join(", "); +const testStartTime = new Date(); +const fileCount = testFiles.length; +let exitWithError = false; +let totalTestCount = 0; +let totalFailedTestCount = 0; console.log( `Running tests: ${fileArrToString(testFiles)} with ${cpuCount} threads`); -const filesPerThread = Math.floor(testFiles.length / cpuCount); -const threadsWithMoreWork = testFiles.length % cpuCount; - -for (let i = 1; i <= cpuCount; i++) { - let files: string[] = []; - if (i <= threadsWithMoreWork) { - files = testFiles.splice(0, filesPerThread + 1); - } else { - files = testFiles.splice(0, filesPerThread); - } - console.log(`Running tests: ${fileArrToString(files)} in thread ${i}`); - - pool.run("./test_thread") - .send({files: files}) - .on("done", - (results, input) => { - jobCounter++; - console.log(`Tests ${fileArrToString(files)} ${jobCounter}/${ - cpuCount} done.`); - }) - .on("error", error => { - console.log("Exception in test:", files, error); - }); -} +testFiles.forEach(file => { + pool.run("./test_thread") + .send({files: [file]}) + .on("done", + (testCount, failedTestCount) => { + if (failedTestCount !== 0) { + exitWithError = true; + } + totalTestCount += testCount; + totalFailedTestCount += failedTestCount; + jobCounter++; + printTestStats( + testCount, + failedTestCount, + `Tests ${file} results:`, + `Thread: ${jobCounter}/${fileCount} done.`); + }) + .on("error", error => { + console.log("Fatal non test related Exception in test file:", file, error); + }); +}); pool.on("finished", () => { - console.log("Everything done, shutting down the thread pool."); - pool.killAll(); + let footer = "All tests passed!"; + if (exitWithError) { + footer = "Exiting with Error: One or more tests failed!"; + } + printTestStats(totalTestCount, totalFailedTestCount, "Final Results:", footer); + + console.log("Everything done, shutting down the thread pool."); + const timeInMs = (new Date().valueOf() - testStartTime.valueOf()); + console.log(`Tests took: ${Math.floor(timeInMs / 1000 / 60)}:${Math.floor(timeInMs / 1000) % 60}`); + + pool.killAll(); + + if (exitWithError) { + process.exit(1); + } }); + From a292f710a57de9d772f314d81728ede93962df5e Mon Sep 17 00:00:00 2001 From: Lolleko Date: Wed, 23 Jan 2019 17:50:54 +0100 Subject: [PATCH 10/12] Fixed functions beeing declared as global --- src/LuaTransformer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 137ef0dd4..8148fb982 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -944,7 +944,7 @@ export class LuaTransformer { ); const functionExpression = tstl.createFunctionExpression(body, params, dotsLiteral, restParamName); - return this.createLocalOrExportedOrGlobalDeclaration(name, functionExpression, undefined, functionDeclaration); + return this.createLocalOrExportedDeclaration(name, functionExpression, undefined, functionDeclaration); } public transformTypeAliasDeclaration(statement: ts.TypeAliasDeclaration): undefined { From d01cdbf31617086854ffbb05769b24aae6bbd7fc Mon Sep 17 00:00:00 2001 From: Lolleko Date: Wed, 23 Jan 2019 18:09:52 +0100 Subject: [PATCH 11/12] Fixed recursive function declarations --- src/LuaTransformer.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 8148fb982..e1af58562 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -3115,7 +3115,9 @@ export class LuaTransformer { statements.push( tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), rhs, parent)); } else { - if (tsOriginal && tsHelper.findFirstNodeAbove(tsOriginal, ts.isFunctionLike)) { + // 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)); From 37d2bd7b0408fe97a909692262964669fd92f603 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Thu, 24 Jan 2019 12:56:59 -0700 Subject: [PATCH 12/12] =?UTF-8?q?fixed=20additional=20issues=20with=20expo?= =?UTF-8?q?rted=20classes=20and=20a=20few=20transform=20tes=E2=80=A6=20(#3?= =?UTF-8?q?55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed additional issues with exported classes and a few transform tests where functions are now declared local * local/global/export logic fix - function and var are global unless inside a module, namespace or function - everything else is local - functions and function expressions properly separate declaration from assignment for recursion now - transform tests updated - also fixed noHeader not being respected when building lualib --- src/CompilerOptions.ts | 4 +- src/LuaPrinter.ts | 2 +- src/LuaTransformer.ts | 140 ++++++++++++++----------- test/src/util.ts | 6 +- test/translation/ts/getSetAccessors.ts | 4 +- test/unit/assignments.spec.ts | 6 +- 6 files changed, 90 insertions(+), 72 deletions(-) diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index 1f8e49676..a69cce626 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; export interface CompilerOptions extends ts.CompilerOptions { - addHeader?: boolean; + noHeader?: boolean; luaTarget?: string; luaLibImport?: string; } @@ -18,4 +18,4 @@ export enum LuaTarget { Lua52 = "5.2", Lua53 = "5.3", LuaJIT = "jit", -} \ No newline at end of file +} diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 4777f7ca2..0f509c593 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -48,7 +48,7 @@ export class LuaPrinter { public print(block: tstl.Block, luaLibFeatures?: Set): 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`; } diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index e1af58562..5007250e5 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -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, @@ -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); @@ -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() @@ -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 {} @@ -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); @@ -469,7 +466,7 @@ export class LuaTransformer { this.selfIdentifier, tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [tstl.createTableExpression(), className] + [tstl.createTableExpression(), classNameWithExport] ) ); @@ -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()])), ])); @@ -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), @@ -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, @@ -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 ); @@ -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 ); @@ -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, @@ -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 { @@ -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 @@ -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); @@ -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; @@ -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 { diff --git a/test/src/util.ts b/test/src/util.ts index f488341a2..a4a90f0a0 100644 --- a/test/src/util.ts +++ b/test/src/util.ts @@ -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 { @@ -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 ); diff --git a/test/translation/ts/getSetAccessors.ts b/test/translation/ts/getSetAccessors.ts index 714be88a8..b721f0f0b 100644 --- a/test/translation/ts/getSetAccessors.ts +++ b/test/translation/ts/getSetAccessors.ts @@ -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; \ No newline at end of file +const c = (4 + instance.field)*3; diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index 814069201..badd03262 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -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};`); @@ -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;")