From 1d24912729426bf81b8c3b386f10c61d1aecb829 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Sun, 7 Apr 2019 09:46:17 -0600 Subject: [PATCH 1/4] exports, classes and modules no longer use X = X or {} --- src/Decorator.ts | 3 - src/LuaTransformer.ts | 128 ++++++++++++++++++------------------------ src/TSHelper.ts | 16 ++++++ 3 files changed, 72 insertions(+), 75 deletions(-) diff --git a/src/Decorator.ts b/src/Decorator.ts index c18ab4dc3..73ac39ea7 100644 --- a/src/Decorator.ts +++ b/src/Decorator.ts @@ -21,8 +21,6 @@ export class Decorator { return DecoratorKind.Phantom; case "tuplereturn": return DecoratorKind.TupleReturn; - case "noclassor": - return DecoratorKind.NoClassOr; case "luaiterator": return DecoratorKind.LuaIterator; case "noself": @@ -52,7 +50,6 @@ export enum DecoratorKind { PureAbstract = "PureAbstract", Phantom = "Phantom", TupleReturn = "TupleReturn", - NoClassOr = "NoClassOr", LuaIterator = "LuaIterator", NoSelf = "NoSelf", NoSelfInFile = "NoSelfInFile", diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 86f680583..d4464d1d7 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -118,18 +118,20 @@ export class LuaTransformer { this.popScope(); if (this.isModule) { + // local exports = {} statements.unshift( tstl.createVariableDeclarationStatement( tstl.createIdentifier("exports"), - tstl.createBinaryExpression( - tstl.createIdentifier("exports"), - tstl.createTableExpression(), - tstl.SyntaxKind.OrOperator - ))); + tstl.createTableExpression() + ) + ); + + // return exports statements.push( tstl.createReturnStatement( [tstl.createIdentifier("exports")] - )); + ) + ); } } @@ -593,24 +595,10 @@ export class LuaTransformer { extendsType: ts.Type ): tstl.Statement[] { - let noClassOr = false; - if (extendsType) { - const decorators = tsHelper.getCustomDecorators(extendsType, this.checker); - noClassOr = decorators.has(DecoratorKind.NoClassOr); - } - const result: tstl.Statement[] = []; - // className = className or {} - let classTable: tstl.Expression = tstl.createTableExpression([], statement); - if (!noClassOr) { - classTable = tstl.createBinaryExpression( - this.addExportToIdentifier(className), // Use original identifier node in declaration - classTable, - tstl.SyntaxKind.OrOperator, - statement - ); - } + // className = {} + const classTable: tstl.Expression = tstl.createTableExpression([], statement); const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, classTable, statement); result.push(...classVar); @@ -659,20 +647,13 @@ export class LuaTransformer { this.importLuaLibFeature(LuaLibFeature.ClassNewIndex); } - // className.prototype = className.prototype or {} + // className.prototype = {} const createClassPrototype = () => tstl.createTableIndexExpression( createClassNameWithExport(), tstl.createStringLiteral("prototype"), statement ); - const classPrototypeTable = noClassOr - ? tstl.createTableExpression([], statement) - : tstl.createBinaryExpression( - createClassPrototype(), - tstl.createTableExpression(), - tstl.SyntaxKind.OrOperator, - statement - ); + const classPrototypeTable = tstl.createTableExpression(); const assignClassPrototype = tstl.createAssignmentStatement(createClassPrototype(), classPrototypeTable); result.push(assignClassPrototype); @@ -1302,60 +1283,63 @@ export class LuaTransformer { const result: tstl.Statement[] = []; - if (this.currentNamespace) { - // outerNS.innerNS = outerNS.innerNS or {} - const namespaceDeclaration = tstl.createAssignmentStatement( - tstl.createTableIndexExpression( - this.transformIdentifier(this.currentNamespace.name as ts.Identifier), - tstl.createStringLiteral(this.transformIdentifier(statement.name as ts.Identifier).text)), - tstl.createBinaryExpression( + const symbol = this.checker.getSymbolAtLocation(statement.name); + const hasExports = symbol !== undefined && this.checker.getExportsOfModule(symbol).length > 0; + const isFirstDeclaration = symbol !== undefined + && symbol.declarations[0] === statement + // TS allows an empty namespace before a class of the same name + && symbol.declarations.findIndex(d => ts.isClassLike(d)) === -1; + if (isFirstDeclaration) { + const isExported = (ts.getCombinedModifierFlags(statement) & ts.ModifierFlags.Export) !== 0; + if (isExported && this.currentNamespace) { + // outerNS.innerNS = {} + const namespaceDeclaration = tstl.createAssignmentStatement( tstl.createTableIndexExpression( this.transformIdentifier(this.currentNamespace.name as ts.Identifier), tstl.createStringLiteral(this.transformIdentifier(statement.name as ts.Identifier).text)), - tstl.createTableExpression(), - tstl.SyntaxKind.OrOperator)); + tstl.createTableExpression() + ); - result.push(namespaceDeclaration); + result.push(namespaceDeclaration); - // local innerNS = outerNS.innerNS - const localDeclaration = this.createHoistableVariableDeclarationStatement( - statement.name as ts.Identifier, - tstl.createTableIndexExpression( - this.transformIdentifier(this.currentNamespace.name as ts.Identifier), - tstl.createStringLiteral(this.transformIdentifier(statement.name as ts.Identifier).text))); + if (hasExports && tsHelper.moduleHasEmittedBody(statement)) { + // local innerNS = outerNS.innerNS + const localDeclaration = this.createHoistableVariableDeclarationStatement( + statement.name as ts.Identifier, + tstl.createTableIndexExpression( + this.transformIdentifier(this.currentNamespace.name as ts.Identifier), + tstl.createStringLiteral(this.transformIdentifier(statement.name as ts.Identifier).text))); - result.push(localDeclaration); + result.push(localDeclaration); + } - } else if (this.isModule && (ts.getCombinedModifierFlags(statement) & ts.ModifierFlags.Export)) { - // exports.NS = exports.NS or {} - const namespaceDeclaration = tstl.createAssignmentStatement( - this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier)), - tstl.createBinaryExpression( + } else if (isExported && !this.currentNamespace && this.isModule) { + // exports.NS = {} + const namespaceDeclaration = tstl.createAssignmentStatement( this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier)), - tstl.createTableExpression(), - tstl.SyntaxKind.OrOperator)); + tstl.createTableExpression() + ); - result.push(namespaceDeclaration); + result.push(namespaceDeclaration); - // local NS = exports.NS - const localDeclaration = this.createHoistableVariableDeclarationStatement( - statement.name as ts.Identifier, - this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier))); + if (hasExports && tsHelper.moduleHasEmittedBody(statement)) { + // local NS = exports.NS + const localDeclaration = this.createHoistableVariableDeclarationStatement( + statement.name as ts.Identifier, + this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier))); - result.push(localDeclaration); + result.push(localDeclaration); + } - } else { - // local NS = NS or {} - const localDeclaration = this.createLocalOrExportedOrGlobalDeclaration( - this.transformIdentifier(statement.name as ts.Identifier), - tstl.createBinaryExpression( + } else { + // local NS = {} + const localDeclaration = this.createLocalOrExportedOrGlobalDeclaration( this.transformIdentifier(statement.name as ts.Identifier), - tstl.createTableExpression(), - tstl.SyntaxKind.OrOperator - ) - ); + tstl.createTableExpression() + ); - result.push(...localDeclaration); + result.push(...localDeclaration); + } } // Set current namespace for nested NS @@ -1364,7 +1348,7 @@ export class LuaTransformer { this.currentNamespace = statement; // Transform moduleblock to block and visit it - if (statement.body && (ts.isModuleBlock(statement.body) || ts.isModuleDeclaration(statement.body))) { + if (tsHelper.moduleHasEmittedBody(statement)) { this.pushScope(ScopeType.Block, statement); let statements = ts.isModuleBlock(statement.body) ? this.transformStatements(statement.body.statements) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index d9ec50f2e..521b06f22 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -736,4 +736,20 @@ export class TSHelper { return [false, undefined]; } } + + public static moduleHasEmittedBody(statement: ts.ModuleDeclaration) + : statement is ts.ModuleDeclaration & {body: ts.ModuleBlock | ts.ModuleDeclaration} + { + if (statement.body) { + if (ts.isModuleBlock(statement.body)) { + // Ignore if body has no emitted statements + return statement.body.statements.findIndex( + s => !ts.isInterfaceDeclaration(s) && !ts.isTypeAliasDeclaration(s) + ) !== -1; + } else if (ts.isModuleDeclaration(statement.body)) { + return true; + } + } + return false; + } } From f116725b34d6a1792a2a8522ec533e0c740fa18e Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Sun, 7 Apr 2019 13:55:26 -0600 Subject: [PATCH 2/4] fixed translation tests --- .../__snapshots__/transformation.spec.ts.snap | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/test/translation/__snapshots__/transformation.spec.ts.snap b/test/translation/__snapshots__/transformation.spec.ts.snap index 346836118..03a021790 100644 --- a/test/translation/__snapshots__/transformation.spec.ts.snap +++ b/test/translation/__snapshots__/transformation.spec.ts.snap @@ -42,9 +42,9 @@ end" `; exports[`Transformation (classPureAbstract) 1`] = ` -"ClassB = ClassB or {} +"ClassB = {} ClassB.__index = ClassB -ClassB.prototype = ClassB.prototype or {} +ClassB.prototype = {} ClassB.prototype.__index = ClassB.prototype ClassB.prototype.constructor = ClassB function ClassB.new(...) @@ -192,7 +192,7 @@ TestEnum.baz = \\"val3\\"" `; exports[`Transformation (exportStatement) 1`] = ` -"local exports = exports or {} +"local exports = {} local xyz = 4 exports.xyz = xyz exports.uwv = xyz @@ -262,9 +262,9 @@ end" exports[`Transformation (getSetAccessors) 1`] = ` "require(\\"lualib_bundle\\"); -MyClass = MyClass or {} +MyClass = {} MyClass.__index = MyClass -MyClass.prototype = MyClass.prototype or {} +MyClass.prototype = {} MyClass.prototype.____getters = {} MyClass.prototype.__index = __TS__Index(MyClass.prototype) MyClass.prototype.____setters = {} @@ -295,9 +295,9 @@ a.abc = \\"def\\"" `; exports[`Transformation (methodRestArguments) 1`] = ` -"MyClass = MyClass or {} +"MyClass = {} MyClass.__index = MyClass -MyClass.prototype = MyClass.prototype or {} +MyClass.prototype = {} MyClass.prototype.__index = MyClass.prototype MyClass.prototype.constructor = MyClass function MyClass.new(...) @@ -313,16 +313,16 @@ end" `; exports[`Transformation (modulesChangedVariableExport) 1`] = ` -"local exports = exports or {} +"local exports = {} exports.foo = 1 return exports" `; exports[`Transformation (modulesClassExport) 1`] = ` -"local exports = exports or {} -exports.TestClass = exports.TestClass or {} +"local exports = {} +exports.TestClass = {} exports.TestClass.__index = exports.TestClass -exports.TestClass.prototype = exports.TestClass.prototype or {} +exports.TestClass.prototype = {} exports.TestClass.prototype.__index = exports.TestClass.prototype exports.TestClass.prototype.constructor = exports.TestClass function exports.TestClass.new(...) @@ -336,10 +336,10 @@ return exports" `; exports[`Transformation (modulesClassWithMemberExport) 1`] = ` -"local exports = exports or {} -exports.TestClass = exports.TestClass or {} +"local exports = {} +exports.TestClass = {} exports.TestClass.__index = exports.TestClass -exports.TestClass.prototype = exports.TestClass.prototype or {} +exports.TestClass.prototype = {} exports.TestClass.prototype.__index = exports.TestClass.prototype exports.TestClass.prototype.constructor = exports.TestClass function exports.TestClass.new(...) @@ -355,7 +355,7 @@ return exports" `; exports[`Transformation (modulesFunctionExport) 1`] = ` -"local exports = exports or {} +"local exports = {} function exports.publicFunc(self) end return exports" @@ -407,15 +407,14 @@ local RenamedClass = __TSTL_space_module.TestClass" exports[`Transformation (modulesImportWithoutFromClause) 1`] = `"require(\\"test\\")"`; exports[`Transformation (modulesNamespaceExport) 1`] = ` -"local exports = exports or {} -exports.TestSpace = exports.TestSpace or {} -local TestSpace = exports.TestSpace +"local exports = {} +exports.TestSpace = {} return exports" `; exports[`Transformation (modulesNamespaceExportEnum) 1`] = ` -"local exports = exports or {} -exports.test = exports.test or {} +"local exports = {} +exports.test = {} local test = exports.test do test.TestEnum = {} @@ -428,11 +427,11 @@ return exports" `; exports[`Transformation (modulesNamespaceNestedWithMemberExport) 1`] = ` -"local exports = exports or {} -exports.TestSpace = exports.TestSpace or {} +"local exports = {} +exports.TestSpace = {} local TestSpace = exports.TestSpace do - TestSpace.TestNestedSpace = TestSpace.TestNestedSpace or {} + TestSpace.TestNestedSpace = {} local TestNestedSpace = TestSpace.TestNestedSpace do function TestNestedSpace.innerFunc(self) @@ -442,11 +441,11 @@ end return exports" `; -exports[`Transformation (modulesNamespaceNoExport) 1`] = `"TestSpace = TestSpace or {}"`; +exports[`Transformation (modulesNamespaceNoExport) 1`] = `"TestSpace = {}"`; exports[`Transformation (modulesNamespaceWithMemberExport) 1`] = ` -"local exports = exports or {} -exports.TestSpace = exports.TestSpace or {} +"local exports = {} +exports.TestSpace = {} local TestSpace = exports.TestSpace do function TestSpace.innerFunc(self) @@ -456,9 +455,8 @@ return exports" `; exports[`Transformation (modulesNamespaceWithMemberNoExport) 1`] = ` -"local exports = exports or {} -exports.TestSpace = exports.TestSpace or {} -local TestSpace = exports.TestSpace +"local exports = {} +exports.TestSpace = {} do local function innerFunc(self) end @@ -467,7 +465,7 @@ return exports" `; exports[`Transformation (modulesVariableExport) 1`] = ` -"local exports = exports or {} +"local exports = {} exports.foo = \\"bar\\" return exports" `; @@ -475,7 +473,7 @@ return exports" exports[`Transformation (modulesVariableNoExport) 1`] = `"local foo = \\"bar\\""`; exports[`Transformation (namespace) 1`] = ` -"myNamespace = myNamespace or {} +"myNamespace = {} do local function nsMember(self) end @@ -483,9 +481,9 @@ end" `; exports[`Transformation (namespaceMerge) 1`] = ` -"MergedClass = MergedClass or {} +"MergedClass = {} MergedClass.__index = MergedClass -MergedClass.prototype = MergedClass.prototype or {} +MergedClass.prototype = {} MergedClass.prototype.__index = MergedClass.prototype MergedClass.prototype.constructor = MergedClass function MergedClass.new(...) @@ -508,7 +506,6 @@ function MergedClass.prototype.methodB(self) self:methodA() self:propertyFunc() end -MergedClass = MergedClass or {} do function MergedClass.namespaceFunc(self) end @@ -521,10 +518,9 @@ MergedClass:namespaceFunc()" `; exports[`Transformation (namespaceNested) 1`] = ` -"myNamespace = myNamespace or {} +"myNamespace = {} do - myNamespace.myNestedNamespace = myNamespace.myNestedNamespace or {} - local myNestedNamespace = myNamespace.myNestedNamespace + local myNestedNamespace = {} do local function nsMember(self) end From e79f34e6930d16801255105cbdce87491a72ee12 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Mon, 8 Apr 2019 05:49:20 -0600 Subject: [PATCH 3/4] changed 'exports' to '____exports' --- src/LuaTransformer.ts | 12 +- .../__snapshots__/transformation.spec.ts.snap | 112 +++++++++--------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index d4464d1d7..ba231c30c 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -121,7 +121,7 @@ export class LuaTransformer { // local exports = {} statements.unshift( tstl.createVariableDeclarationStatement( - tstl.createIdentifier("exports"), + this.createExportsIdentifier(), tstl.createTableExpression() ) ); @@ -129,7 +129,7 @@ export class LuaTransformer { // return exports statements.push( tstl.createReturnStatement( - [tstl.createIdentifier("exports")] + [this.createExportsIdentifier()] ) ); } @@ -291,7 +291,7 @@ export class LuaTransformer { const body = tstl.createBlock( [tstl.createAssignmentStatement( tstl.createTableIndexExpression( - tstl.createIdentifier("exports"), + this.createExportsIdentifier(), forKey ), forValue @@ -4179,7 +4179,7 @@ export class LuaTransformer { public createExportedIdentifier(identifier: tstl.Identifier): tstl.TableIndexExpression { const exportTable = this.currentNamespace ? this.transformIdentifier(this.currentNamespace.name as ts.Identifier) - : tstl.createIdentifier("exports"); + : this.createExportsIdentifier(); return tstl.createTableIndexExpression( exportTable, @@ -4304,6 +4304,10 @@ export class LuaTransformer { return tstl.createIdentifier("self", tsOriginal); } + private createExportsIdentifier(): tstl.Identifier { + return tstl.createIdentifier("____exports"); + } + private createLocalOrExportedOrGlobalDeclaration( lhs: tstl.Identifier | tstl.Identifier[], rhs?: tstl.Expression, diff --git a/test/translation/__snapshots__/transformation.spec.ts.snap b/test/translation/__snapshots__/transformation.spec.ts.snap index 03a021790..a6acc3492 100644 --- a/test/translation/__snapshots__/transformation.spec.ts.snap +++ b/test/translation/__snapshots__/transformation.spec.ts.snap @@ -192,29 +192,29 @@ TestEnum.baz = \\"val3\\"" `; exports[`Transformation (exportStatement) 1`] = ` -"local exports = {} +"local ____exports = {} local xyz = 4 -exports.xyz = xyz -exports.uwv = xyz +____exports.xyz = xyz +____exports.uwv = xyz do local __TSTL_export = require(\\"xyz\\") for ____exportKey, ____exportValue in pairs(__TSTL_export) do - exports[____exportKey] = ____exportValue + ____exports[____exportKey] = ____exportValue end end do local __TSTL_xyz = require(\\"xyz\\") local abc = __TSTL_xyz.abc local def = __TSTL_xyz.def - exports.abc = abc - exports.def = def + ____exports.abc = abc + ____exports.def = def end do local __TSTL_xyz = require(\\"xyz\\") local def = __TSTL_xyz.abc - exports.def = def + ____exports.def = def end -return exports" +return ____exports" `; exports[`Transformation (for) 1`] = ` @@ -313,52 +313,52 @@ end" `; exports[`Transformation (modulesChangedVariableExport) 1`] = ` -"local exports = {} -exports.foo = 1 -return exports" +"local ____exports = {} +____exports.foo = 1 +return ____exports" `; exports[`Transformation (modulesClassExport) 1`] = ` -"local exports = {} -exports.TestClass = {} -exports.TestClass.__index = exports.TestClass -exports.TestClass.prototype = {} -exports.TestClass.prototype.__index = exports.TestClass.prototype -exports.TestClass.prototype.constructor = exports.TestClass -function exports.TestClass.new(...) - local self = setmetatable({}, exports.TestClass.prototype) +"local ____exports = {} +____exports.TestClass = {} +____exports.TestClass.__index = ____exports.TestClass +____exports.TestClass.prototype = {} +____exports.TestClass.prototype.__index = ____exports.TestClass.prototype +____exports.TestClass.prototype.constructor = ____exports.TestClass +function ____exports.TestClass.new(...) + local self = setmetatable({}, ____exports.TestClass.prototype) self:____constructor(...) return self end -function exports.TestClass.prototype.____constructor(self) +function ____exports.TestClass.prototype.____constructor(self) end -return exports" +return ____exports" `; exports[`Transformation (modulesClassWithMemberExport) 1`] = ` -"local exports = {} -exports.TestClass = {} -exports.TestClass.__index = exports.TestClass -exports.TestClass.prototype = {} -exports.TestClass.prototype.__index = exports.TestClass.prototype -exports.TestClass.prototype.constructor = exports.TestClass -function exports.TestClass.new(...) - local self = setmetatable({}, exports.TestClass.prototype) +"local ____exports = {} +____exports.TestClass = {} +____exports.TestClass.__index = ____exports.TestClass +____exports.TestClass.prototype = {} +____exports.TestClass.prototype.__index = ____exports.TestClass.prototype +____exports.TestClass.prototype.constructor = ____exports.TestClass +function ____exports.TestClass.new(...) + local self = setmetatable({}, ____exports.TestClass.prototype) self:____constructor(...) return self end -function exports.TestClass.prototype.____constructor(self) +function ____exports.TestClass.prototype.____constructor(self) end -function exports.TestClass.prototype.memberFunc(self) +function ____exports.TestClass.prototype.memberFunc(self) end -return exports" +return ____exports" `; exports[`Transformation (modulesFunctionExport) 1`] = ` -"local exports = {} -function exports.publicFunc(self) +"local ____exports = {} +function ____exports.publicFunc(self) end -return exports" +return ____exports" `; exports[`Transformation (modulesFunctionNoExport) 1`] = ` @@ -407,15 +407,15 @@ local RenamedClass = __TSTL_space_module.TestClass" exports[`Transformation (modulesImportWithoutFromClause) 1`] = `"require(\\"test\\")"`; exports[`Transformation (modulesNamespaceExport) 1`] = ` -"local exports = {} -exports.TestSpace = {} -return exports" +"local ____exports = {} +____exports.TestSpace = {} +return ____exports" `; exports[`Transformation (modulesNamespaceExportEnum) 1`] = ` -"local exports = {} -exports.test = {} -local test = exports.test +"local ____exports = {} +____exports.test = {} +local test = ____exports.test do test.TestEnum = {} test.TestEnum.foo = \\"foo\\" @@ -423,13 +423,13 @@ do test.TestEnum.bar = \\"bar\\" test.TestEnum.bar = \\"bar\\" end -return exports" +return ____exports" `; exports[`Transformation (modulesNamespaceNestedWithMemberExport) 1`] = ` -"local exports = {} -exports.TestSpace = {} -local TestSpace = exports.TestSpace +"local ____exports = {} +____exports.TestSpace = {} +local TestSpace = ____exports.TestSpace do TestSpace.TestNestedSpace = {} local TestNestedSpace = TestSpace.TestNestedSpace @@ -438,36 +438,36 @@ do end end end -return exports" +return ____exports" `; exports[`Transformation (modulesNamespaceNoExport) 1`] = `"TestSpace = {}"`; exports[`Transformation (modulesNamespaceWithMemberExport) 1`] = ` -"local exports = {} -exports.TestSpace = {} -local TestSpace = exports.TestSpace +"local ____exports = {} +____exports.TestSpace = {} +local TestSpace = ____exports.TestSpace do function TestSpace.innerFunc(self) end end -return exports" +return ____exports" `; exports[`Transformation (modulesNamespaceWithMemberNoExport) 1`] = ` -"local exports = {} -exports.TestSpace = {} +"local ____exports = {} +____exports.TestSpace = {} do local function innerFunc(self) end end -return exports" +return ____exports" `; exports[`Transformation (modulesVariableExport) 1`] = ` -"local exports = {} -exports.foo = \\"bar\\" -return exports" +"local ____exports = {} +____exports.foo = \\"bar\\" +return ____exports" `; exports[`Transformation (modulesVariableNoExport) 1`] = `"local foo = \\"bar\\""`; From b3d5807379da4cf025eee914ba496bd993661cd6 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Mon, 8 Apr 2019 06:24:43 -0600 Subject: [PATCH 4/4] caching classes in local when exported --- src/LuaTransformer.ts | 61 +++++++++++-------- .../__snapshots__/transformation.spec.ts.snap | 32 +++++----- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index ba231c30c..4357414fa 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -572,7 +572,7 @@ export class LuaTransformer { const value = this.transformExpression(field.initializer); const classField = tstl.createTableIndexExpression( - this.addExportToIdentifier(tstl.cloneIdentifier(className)), + tstl.cloneIdentifier(className), fieldName ); @@ -597,18 +597,26 @@ export class LuaTransformer { { const result: tstl.Statement[] = []; - // className = {} + // [____exports.]className = {} const classTable: tstl.Expression = tstl.createTableExpression([], statement); const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, classTable, statement); result.push(...classVar); - const createClassNameWithExport = () => this.addExportToIdentifier(tstl.cloneIdentifier(className)); + if (this.isIdentifierExported(className)) { + // local className = ____exports.className + result.push( + tstl.createVariableDeclarationStatement( + tstl.cloneIdentifier(className), + this.addExportToIdentifier(tstl.cloneIdentifier(className)) + ) + ); + } // className.____getters = {} if (statement.members.some(m => ts.isGetAccessor(m) && tsHelper.isStatic(m))) { const classGetters = tstl.createTableIndexExpression( - createClassNameWithExport(), + tstl.cloneIdentifier(className), tstl.createStringLiteral("____getters"), statement ); @@ -624,17 +632,17 @@ export class LuaTransformer { // className.__index = className const classIndex = tstl.createTableIndexExpression( - createClassNameWithExport(), + tstl.cloneIdentifier(className), tstl.createStringLiteral("__index"), statement ); - const assignClassIndex = tstl.createAssignmentStatement(classIndex, createClassNameWithExport(), statement); + const assignClassIndex = tstl.createAssignmentStatement(classIndex, tstl.cloneIdentifier(className), statement); result.push(assignClassIndex); // className.____setters = {} if (statement.members.some(m => ts.isSetAccessor(m) && tsHelper.isStatic(m))) { const classSetters = tstl.createTableIndexExpression( - createClassNameWithExport(), + tstl.cloneIdentifier(className), tstl.createStringLiteral("____setters") ); const assignClassSetters = tstl.createAssignmentStatement( @@ -649,7 +657,7 @@ export class LuaTransformer { // className.prototype = {} const createClassPrototype = () => tstl.createTableIndexExpression( - createClassNameWithExport(), + tstl.cloneIdentifier(className), tstl.createStringLiteral("prototype"), statement ); @@ -730,7 +738,7 @@ export class LuaTransformer { ); const assignClassPrototypeConstructor = tstl.createAssignmentStatement( classPrototypeConstructor, - createClassNameWithExport(), + tstl.cloneIdentifier(className), statement ); result.push(assignClassPrototypeConstructor); @@ -740,11 +748,13 @@ export class LuaTransformer { if (extendsType) { const extendedTypeNode = tsHelper.getExtendedTypeNode(statement, this.checker); - const baseName = this.transformExpression(extendedTypeNode.expression); + const baseName = ts.isIdentifier(extendedTypeNode.expression) + ? this.transformIdentifier(extendedTypeNode.expression) // Skip adding '____exports' + : this.transformExpression(extendedTypeNode.expression); // className.____super = baseName const createClassBase = () => tstl.createTableIndexExpression( - createClassNameWithExport(), + tstl.cloneIdentifier(className), tstl.createStringLiteral("____super"), statement ); @@ -781,7 +791,7 @@ export class LuaTransformer { const setClassMetatable = tstl.createExpressionStatement( tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [createClassNameWithExport(), tstl.createTableExpression(metatableFields)] + [tstl.cloneIdentifier(className), tstl.createTableExpression(metatableFields)] ) ); result.push(setClassMetatable); @@ -791,7 +801,7 @@ export class LuaTransformer { const setClassMetatable = tstl.createExpressionStatement( tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [createClassNameWithExport(), createClassBase()] + [tstl.cloneIdentifier(className), createClassBase()] ) ); result.push(setClassMetatable); @@ -837,7 +847,7 @@ export class LuaTransformer { const setClassMetatable = tstl.createExpressionStatement( tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [createClassNameWithExport(), tstl.createTableExpression(metatableFields)] + [tstl.cloneIdentifier(className), tstl.createTableExpression(metatableFields)] ) ); result.push(setClassMetatable); @@ -875,7 +885,7 @@ export class LuaTransformer { // or function export.className.new(construct, ...) ... end const newFunc = tstl.createAssignmentStatement( tstl.createTableIndexExpression( - createClassNameWithExport(), + tstl.cloneIdentifier(className), tstl.createStringLiteral("new")), tstl.createFunctionExpression( tstl.createBlock(newFuncStatements), @@ -933,7 +943,7 @@ export class LuaTransformer { public createConstructorName(className: tstl.Identifier): tstl.TableIndexExpression { return tstl.createTableIndexExpression( tstl.createTableIndexExpression( - this.addExportToIdentifier(tstl.cloneIdentifier(className)), + tstl.cloneIdentifier(className), tstl.createStringLiteral("prototype") ), tstl.createStringLiteral("____constructor") @@ -1029,10 +1039,9 @@ export class LuaTransformer { tstl.FunctionExpressionFlags.Declaration ); - const classNameWithExport = this.addExportToIdentifier(tstl.cloneIdentifier(className)); const methodTable = tsHelper.isStatic(getAccessor) - ? classNameWithExport - : tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("prototype")); + ? tstl.cloneIdentifier(className) + : tstl.createTableIndexExpression(tstl.cloneIdentifier(className), tstl.createStringLiteral("prototype")); const classGetters = tstl.createTableIndexExpression( methodTable, @@ -1065,10 +1074,9 @@ export class LuaTransformer { tstl.FunctionExpressionFlags.Declaration ); - const classNameWithExport = this.addExportToIdentifier(tstl.cloneIdentifier(className)); const methodTable = tsHelper.isStatic(setAccessor) - ? classNameWithExport - : tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("prototype")); + ? tstl.cloneIdentifier(className) + : tstl.createTableIndexExpression(tstl.cloneIdentifier(className), tstl.createStringLiteral("prototype")); const classSetters = tstl.createTableIndexExpression( methodTable, @@ -1114,10 +1122,9 @@ export class LuaTransformer { node.body ); - const classNameWithExport = this.addExportToIdentifier(tstl.cloneIdentifier(className)); const methodTable = tsHelper.isStatic(node) || noPrototype - ? classNameWithExport - : tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("prototype")); + ? tstl.cloneIdentifier(className) + : tstl.createTableIndexExpression(tstl.cloneIdentifier(className), tstl.createStringLiteral("prototype")); return tstl.createAssignmentStatement( tstl.createTableIndexExpression( @@ -3141,11 +3148,11 @@ export class LuaTransformer { let baseClassName: tstl.IdentifierOrTableIndexExpression; if (ts.isIdentifier(extendsExpression)) { // Use "baseClassName" if base is a simple identifier - baseClassName = this.addExportToIdentifier(this.transformIdentifier(extendsExpression)); + baseClassName = this.transformIdentifier(extendsExpression); } else { // Use "className.____super" if the base is not a simple identifier baseClassName = tstl.createTableIndexExpression( - this.addExportToIdentifier(this.transformIdentifier(classDeclaration.name)), + this.transformIdentifier(classDeclaration.name), tstl.createStringLiteral("____super"), expression ); diff --git a/test/translation/__snapshots__/transformation.spec.ts.snap b/test/translation/__snapshots__/transformation.spec.ts.snap index a6acc3492..d6c1a3abb 100644 --- a/test/translation/__snapshots__/transformation.spec.ts.snap +++ b/test/translation/__snapshots__/transformation.spec.ts.snap @@ -321,16 +321,17 @@ return ____exports" exports[`Transformation (modulesClassExport) 1`] = ` "local ____exports = {} ____exports.TestClass = {} -____exports.TestClass.__index = ____exports.TestClass -____exports.TestClass.prototype = {} -____exports.TestClass.prototype.__index = ____exports.TestClass.prototype -____exports.TestClass.prototype.constructor = ____exports.TestClass -function ____exports.TestClass.new(...) - local self = setmetatable({}, ____exports.TestClass.prototype) +local TestClass = ____exports.TestClass +TestClass.__index = TestClass +TestClass.prototype = {} +TestClass.prototype.__index = TestClass.prototype +TestClass.prototype.constructor = TestClass +function TestClass.new(...) + local self = setmetatable({}, TestClass.prototype) self:____constructor(...) return self end -function ____exports.TestClass.prototype.____constructor(self) +function TestClass.prototype.____constructor(self) end return ____exports" `; @@ -338,18 +339,19 @@ return ____exports" exports[`Transformation (modulesClassWithMemberExport) 1`] = ` "local ____exports = {} ____exports.TestClass = {} -____exports.TestClass.__index = ____exports.TestClass -____exports.TestClass.prototype = {} -____exports.TestClass.prototype.__index = ____exports.TestClass.prototype -____exports.TestClass.prototype.constructor = ____exports.TestClass -function ____exports.TestClass.new(...) - local self = setmetatable({}, ____exports.TestClass.prototype) +local TestClass = ____exports.TestClass +TestClass.__index = TestClass +TestClass.prototype = {} +TestClass.prototype.__index = TestClass.prototype +TestClass.prototype.constructor = TestClass +function TestClass.new(...) + local self = setmetatable({}, TestClass.prototype) self:____constructor(...) return self end -function ____exports.TestClass.prototype.____constructor(self) +function TestClass.prototype.____constructor(self) end -function ____exports.TestClass.prototype.memberFunc(self) +function TestClass.prototype.memberFunc(self) end return ____exports" `;