From 920e11cc8fb158a0d38b7a32f312d2d4ad46c1d0 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Fri, 8 Feb 2019 06:47:58 -0700 Subject: [PATCH 1/5] update to class transpilation - classes separated into static and instance tables - fixed issues with super calls - renamed new and constructor to avoid name collisions - added errors for extensions being used in inappropriate ways --- src/LuaTransformer.ts | 349 +++++++++++------- src/TSTLErrors.ts | 13 +- src/lualib/InstanceOf.ts | 20 +- 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 | 13 +- test/translation/lua/getSetAccessors.lua | 19 +- test/translation/lua/methodRestArguments.lua | 15 +- test/translation/lua/modulesClassExport.lua | 13 +- .../lua/modulesClassWithMemberExport.lua | 15 +- test/translation/lua/namespaceMerge.lua | 23 +- test/unit/assignments.spec.ts | 2 +- test/unit/class.spec.ts | 133 ++++++- .../compiler/configuration/options.spec.ts | 2 +- test/unit/decoratorMetaExtension.spec.ts | 2 +- test/unit/typechecking.spec.ts | 17 + 18 files changed, 452 insertions(+), 194 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 038cea273..3ce87dc19 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -53,7 +53,7 @@ export class LuaTransformer { private currentSourceFile?: ts.SourceFile; private currentNamespace: ts.ModuleDeclaration; - private classStack: tstl.Identifier[]; + private classStack: ts.ClassLikeDeclaration[]; private scopeStack: Scope[]; private genVarCounter: number; @@ -279,6 +279,8 @@ export class LuaTransformer { nameOverride?: tstl.Identifier ): tstl.Statement[] { + this.classStack.push(statement); + let className = statement.name ? this.transformIdentifier(statement.name) : nameOverride; if (!className) { throw TSTLErrors.MissingClassName(statement); @@ -295,9 +297,22 @@ export class LuaTransformer { throw TSTLErrors.InvalidExtensionMetaExtension(statement); } + if ((isExtension || isMetaExtension) && this.isIdentifierExported(className.text)) { + // Cannot export extension classes + throw TSTLErrors.InvalidExportsExtension(statement); + } + // Get type that is extended const extendsType = tsHelper.getExtendedType(statement, this.checker); + if (!(isExtension || isMetaExtension) && extendsType) { + // Non-extensions cannot extend extension classes + const extendsDecorators = tsHelper.getCustomDecorators(extendsType, this.checker); + if (extendsDecorators.has(DecoratorKind.Extension) || extendsDecorators.has(DecoratorKind.MetaExtension)) { + throw TSTLErrors.InvalidExtendsExtension(statement); + } + } + // Get all properties with value const properties = statement.members.filter(ts.isPropertyDeclaration).filter(member => member.initializer); @@ -347,7 +362,6 @@ export class LuaTransformer { const classCreationMethods = this.createClassCreationMethods( statement, className, - instanceFields, extendsType ); result.push(...classCreationMethods); @@ -388,18 +402,47 @@ export class LuaTransformer { } // Find first constructor with body - const constructor = statement.members - .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, statement)); - } else if (!isExtension && !extendsType) { - // Generate a constructor if none was defined - result.push(this.transformConstructor( - ts.createConstructor([], [], [], ts.createBlock([], true)), - className, - statement - )); + if (!isExtension && !isMetaExtension) { + const constructor = statement.members + .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, instanceFields, statement)); + } else if (!extendsType) { + // Generate a constructor if none was defined in a base class + result.push(this.transformConstructor( + ts.createConstructor([], [], [], ts.createBlock([], true)), + className, + instanceFields, + statement + )); + } else if (instanceFields.length > 0) { + // Generate a constructor if none was defined in a class with instance fields that need initialization + // className.prototype.____constructor = function(self, ...) + // baseClassName.prototype.____constructor(self, ...) + // ... + const constructorBody = this.transformClassInstanceFields(instanceFields); + const superCall = tstl.createExpressionStatement( + tstl.createCallExpression( + tstl.createTableIndexExpression( + this.transformSuperKeyword(ts.createSuper()), + tstl.createStringLiteral("____constructor") + ), + [this.createSelfIdentifier(), tstl.createDotsLiteral()] + ) + ); + constructorBody.unshift(superCall); + const constructorFunction = tstl.createFunctionExpression( + tstl.createBlock(constructorBody), + [this.createSelfIdentifier()], + tstl.createDotsLiteral() + ); + result.push(tstl.createAssignmentStatement( + this.createConstructorName(className), + constructorFunction, + statement + )); + } } // Transform get accessors @@ -417,14 +460,17 @@ export class LuaTransformer { result.push(this.transformMethodDeclaration(method, className)); }); + this.classStack.pop(); + return result; } public createClassCreationMethods( statement: ts.ClassLikeDeclarationBase, className: tstl.Identifier, - instanceFields: ts.PropertyDeclaration[], - extendsType: ts.Type): tstl.Statement[] { + extendsType: ts.Type + ): tstl.Statement[] + { let noClassOr = false; if (extendsType) { const decorators = tsHelper.getCustomDecorators(extendsType, this.checker); @@ -435,138 +481,163 @@ export class LuaTransformer { const classNameWithExport = this.addExportToIdentifier(className); - // Write class declaration - if (extendsType) { - const extendedTypeNode = tsHelper.getExtendedTypeNode(statement, this.checker); - const baseName = this.transformExpression(extendedTypeNode.expression); - - // baseName.new - const newIndex = tstl.createTableIndexExpression(baseName, tstl.createStringLiteral("new")); - - // baseName.new() - let rhs: tstl.Expression = tstl.createCallExpression(newIndex, []); - - if (!noClassOr) { - // className or baseName.new() - rhs = tstl.createBinaryExpression(classNameWithExport, rhs, tstl.SyntaxKind.OrOperator); - } - - // (local) className = className or baseName.new() - // (local) className = baseName.new() - // exports.className = baseName.new() - const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, rhs, statement); - - result.push(...classVar); - } else { - // {} - let rhs: tstl.Expression = tstl.createTableExpression(); - - if (!noClassOr) { - // className or {} - rhs = tstl.createBinaryExpression(classNameWithExport, rhs, tstl.SyntaxKind.OrOperator); - } - - // (local) className = className or {} - // (local) className = {} - // exports.className = {} - const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, rhs, statement); - - result.push(...classVar); + // className = className or {} + let classTable: tstl.Expression = tstl.createTableExpression(); + if (!noClassOr) { + classTable = tstl.createBinaryExpression(classNameWithExport, classTable, tstl.SyntaxKind.OrOperator); } - // className.__index - const classIndex = tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("__index")); + const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, classTable, statement); + result.push(...classVar); + // className.__index = className + const classIndex = tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("__index")); const assignClassIndex = tstl.createAssignmentStatement(classIndex, classNameWithExport, statement); - result.push(assignClassIndex); + // className.prototype = className.prototype or {} + const classPrototype = tstl.createTableIndexExpression( + classNameWithExport, + tstl.createStringLiteral("prototype") + ); + const classPrototypeTable = noClassOr + ? tstl.createTableExpression() + : tstl.createBinaryExpression(classPrototype, tstl.createTableExpression(), tstl.SyntaxKind.OrOperator); + const assignClassPrototype = tstl.createAssignmentStatement(classPrototype, classPrototypeTable); + result.push(assignClassPrototype); + + // className.prototype.__index = className.prototype + const classPrototypeIndex = tstl.createTableIndexExpression( + classPrototype, + tstl.createStringLiteral("__index") + ); + const assignClassPrototypeIndex = tstl.createAssignmentStatement(classPrototypeIndex, classPrototype); + result.push(assignClassPrototypeIndex); + + // className.prototype.constructor = className + const classPrototypeConstructor = tstl.createTableIndexExpression( + classPrototype, + tstl.createStringLiteral("constructor") + ); + const assignClassPrototypeConstructor = tstl.createAssignmentStatement( + classPrototypeConstructor, + className, + statement + ); + result.push(assignClassPrototypeConstructor); + if (extendsType) { const extendedTypeNode = tsHelper.getExtendedTypeNode(statement, this.checker); const baseName = this.transformExpression(extendedTypeNode.expression); - // className.__base = baseName - const classBase = tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("__base")); - + // className.____super = baseName + const classBase = tstl.createTableIndexExpression( + classNameWithExport, + tstl.createStringLiteral("____super") + ); const assignClassBase = tstl.createAssignmentStatement(classBase, baseName, statement); - result.push(assignClassBase); + + // setmetatable(className, className.____super) + const setClassMetatable = tstl.createExpressionStatement( + tstl.createCallExpression( + tstl.createIdentifier("setmetatable"), + [classNameWithExport, classBase] + ) + ); + result.push(setClassMetatable); + + // setmetatable(className.prototype, className.____super.prototype) + const basePrototype = tstl.createTableIndexExpression(classBase, tstl.createStringLiteral("prototype")); + const setClassPrototypeMetatable = tstl.createExpressionStatement( + tstl.createCallExpression( + tstl.createIdentifier("setmetatable"), + [classPrototype, basePrototype] + ) + ); + result.push(setClassPrototypeMetatable); } const newFuncStatements: tstl.Statement[] = []; - // local self = setmetatable({}, className) + // local self = setmetatable({}, className.prototype) const assignSelf = tstl.createVariableDeclarationStatement( this.createSelfIdentifier(), tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [tstl.createTableExpression(), classNameWithExport] + [tstl.createTableExpression(), classPrototype] ) ); - newFuncStatements.push(assignSelf); - for (const f of instanceFields) { - // Get identifier - const fieldName = this.transformPropertyName(f.name); - - const value = this.transformExpression(f.initializer); - - // self[fieldName] - const selfIndex = tstl.createTableIndexExpression(this.createSelfIdentifier(), fieldName); - - // self[fieldName] = value - const assignClassField = tstl.createAssignmentStatement(selfIndex, value); - - newFuncStatements.push(assignClassField); - } - - /* - if construct and className.constructor then - className.constructor(self, ...) - end - */ - const ifConstructor = tstl.createIfStatement( - tstl.createBinaryExpression( - tstl.createIdentifier("construct"), - tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("constructor")), - tstl.SyntaxKind.AndOperator), - tstl.createBlock([ - tstl.createExpressionStatement(tstl.createCallExpression( - tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("constructor")), - [this.createSelfIdentifier(), tstl.createDotsLiteral()])), - ])); - - newFuncStatements.push(ifConstructor); + // self:____constructor(...) + const callConstructor = tstl.createExpressionStatement( + tstl.createMethodCallExpression( + this.createSelfIdentifier(), + tstl.createIdentifier("____constructor"), + [tstl.createDotsLiteral()] + ) + ); + newFuncStatements.push(callConstructor); // return self const returnSelf = tstl.createReturnStatement([this.createSelfIdentifier()]); - newFuncStatements.push(returnSelf); - // function className.new(construct, ...) ... end - // or function export.className.new(construct, ...) ... end + // function className.____new(construct, ...) ... end + // or function export.className.____new(construct, ...) ... end const newFunc = tstl.createAssignmentStatement( tstl.createTableIndexExpression( classNameWithExport, - tstl.createStringLiteral("new")), + tstl.createStringLiteral("____new")), tstl.createFunctionExpression( tstl.createBlock(newFuncStatements), - [tstl.createIdentifier("construct")], + undefined, tstl.createDotsLiteral(), undefined, statement ) ); - result.push(newFunc); return result; } + public transformClassInstanceFields(instanceFields: ts.PropertyDeclaration[]): tstl.Statement[] { + const statements: tstl.Statement[] = []; + + for (const f of instanceFields) { + // Get identifier + const fieldName = this.transformPropertyName(f.name); + + const value = this.transformExpression(f.initializer); + + // self[fieldName] + const selfIndex = tstl.createTableIndexExpression(this.createSelfIdentifier(), fieldName); + + // self[fieldName] = value + const assignClassField = tstl.createAssignmentStatement(selfIndex, value); + + statements.push(assignClassField); + } + + return statements; + } + + public createConstructorName(className: tstl.Identifier): tstl.TableIndexExpression { + return tstl.createTableIndexExpression( + tstl.createTableIndexExpression( + this.addExportToIdentifier(className), + tstl.createStringLiteral("prototype") + ), + tstl.createStringLiteral("____constructor") + ); + } + public transformConstructor( statement: ts.ConstructorDeclaration, className: tstl.Identifier, + instanceFields: ts.PropertyDeclaration[], classDeclaration: ts.ClassLikeDeclaration ): tstl.AssignmentStatement { @@ -575,14 +646,11 @@ export class LuaTransformer { return undefined; } + const bodyStatements: tstl.Statement[] = this.transformClassInstanceFields(instanceFields); + // Check for field declarations in constructor const constructorFieldsDeclarations = statement.parameters.filter(p => p.modifiers !== undefined); - // Transform constructor body - this.classStack.push(className); - - const bodyStatements: tstl.Statement[] = []; - // Add in instance field declarations for (const declaration of constructorFieldsDeclarations) { const declarationName = this.transformIdentifier(declaration.name as ts.Identifier); @@ -611,7 +679,7 @@ export class LuaTransformer { } } - // function className.constructor(params) ... end + // function className.constructor(self, params) ... end const [params, dotsLiteral, restParamName] = this.transformParameters( statement.parameters, @@ -624,13 +692,10 @@ export class LuaTransformer { const block: tstl.Block = tstl.createBlock(bodyStatements); const result = tstl.createAssignmentStatement( - tstl.createTableIndexExpression( - this.addExportToIdentifier(className), - tstl.createStringLiteral("constructor")), + this.createConstructorName(className), tstl.createFunctionExpression(block, params, dotsLiteral, restParamName, undefined, undefined), - statement); - - this.classStack.pop(); + statement + ); return result; } @@ -651,7 +716,10 @@ export class LuaTransformer { return tstl.createAssignmentStatement( tstl.createTableIndexExpression( - this.addExportToIdentifier(className), + tstl.createTableIndexExpression( + this.addExportToIdentifier(className), + tstl.createStringLiteral("prototype") + ), tstl.createStringLiteral("get__" + name.text)), accessorFunction ); @@ -677,7 +745,10 @@ export class LuaTransformer { return tstl.createAssignmentStatement( tstl.createTableIndexExpression( - this.addExportToIdentifier(className), + tstl.createTableIndexExpression( + this.addExportToIdentifier(className), + tstl.createStringLiteral("prototype") + ), tstl.createStringLiteral("set__" + name.text)), accessorFunction ); @@ -712,10 +783,15 @@ export class LuaTransformer { restParamName ); - const parent = node.parent as ts.ClassLikeDeclaration; + const isStatic = node.modifiers && node.modifiers.some(m => m.kind === ts.SyntaxKind.StaticKeyword); + const classNameWithExport = this.addExportToIdentifier(className); + const methodTable = isStatic + ? classNameWithExport + : tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("prototype")); + return tstl.createAssignmentStatement( tstl.createTableIndexExpression( - this.addExportToIdentifier(className), + methodTable, methodName), functionExpression, node @@ -1846,6 +1922,14 @@ export class LuaTransformer { ); case ts.SyntaxKind.InstanceOfKeyword: + const decorators = tsHelper.getCustomDecorators( + this.checker.getTypeAtLocation(expression.right), + this.checker + ); + if (decorators.has(DecoratorKind.Extension) || decorators.has(DecoratorKind.MetaExtension)) { + // Cannot use instanceof on extension classes + throw TSTLErrors.InvalidInstanceOfExtension(expression); + } return this.transformLuaLibFunction(LuaLibFeature.InstanceOf, lhs, rhs); case ts.SyntaxKind.CommaToken: @@ -2429,7 +2513,7 @@ export class LuaTransformer { const name = this.transformExpression(node.expression); const sig = this.checker.getResolvedSignature(node); const params = node.arguments - ? this.transformArguments(node.arguments, sig, ts.createTrue()) + ? this.transformArguments(node.arguments, sig) : [tstl.createBooleanLiteral(true)]; const type = this.checker.getTypeAtLocation(node); @@ -2454,7 +2538,7 @@ export class LuaTransformer { } return tstl.createCallExpression( - tstl.createTableIndexExpression(name, tstl.createStringLiteral("new")), + tstl.createTableIndexExpression(name, tstl.createStringLiteral("____new")), params, node ); @@ -2468,11 +2552,21 @@ export class LuaTransformer { } public transformSuperKeyword(expression: ts.SuperExpression): tstl.Expression { - return tstl.createTableIndexExpression( - this.createSelfIdentifier(), - tstl.createStringLiteral("__base"), - expression - ); + const classDeclaration = this.classStack[this.classStack.length - 1]; + const extendsExpression = tsHelper.getExtendedTypeNode(classDeclaration, this.checker).expression; + let baseClassName: tstl.IdentifierOrTableIndexExpression; + if (ts.isIdentifier(extendsExpression)) { + // Use "baseClassName" if base is a simple identifier + baseClassName = this.addExportToIdentifier(this.transformIdentifier(extendsExpression)); + } else { + // Use "className.____super" if the base is not a simple identifier + baseClassName = tstl.createTableIndexExpression( + this.addExportToIdentifier(this.transformIdentifier(classDeclaration.name)), + tstl.createStringLiteral("____super"), + expression + ); + } + return tstl.createTableIndexExpression(baseClassName, tstl.createStringLiteral("prototype")); } public transformCallExpression(node: ts.CallExpression): tstl.Expression { @@ -2503,14 +2597,11 @@ export class LuaTransformer { // Handle super calls properly if (node.expression.kind === ts.SyntaxKind.SuperKeyword) { parameters = this.transformArguments(node.arguments, signature, ts.createThis()); - const classIdentifier = this.classStack[this.classStack.length - 1]; - const baseIdentifier = tstl.createStringLiteral("__base"); - const constructorIdentifier = tstl.createStringLiteral("constructor"); return tstl.createCallExpression( tstl.createTableIndexExpression( - tstl.createTableIndexExpression(this.addExportToIdentifier(classIdentifier), baseIdentifier), - constructorIdentifier + this.transformSuperKeyword(ts.createSuper()), + tstl.createStringLiteral("____constructor") ), parameters ); diff --git a/src/TSTLErrors.ts b/src/TSTLErrors.ts index b5719bc90..5adc79b03 100644 --- a/src/TSTLErrors.ts +++ b/src/TSTLErrors.ts @@ -25,10 +25,19 @@ export class TSTLErrors { new TranspileError(`${name} expects ${expected} argument(s) but got ${got}.`, node); public static InvalidExtensionMetaExtension = (node: ts.Node) => - new TranspileError(`Cannot use both '!Extension' and '!MetaExtension' decorators on the same class.`, node); + new TranspileError(`Cannot use both '@extension' and '@metaExtension' decorators on the same class.`, node); public static InvalidNewExpressionOnExtension = (node: ts.Node) => - new TranspileError(`Cannot construct classes with decorator '!Extension' or '!MetaExtension'.`, node); + new TranspileError(`Cannot construct classes with decorator '@extension' or '@metaExtension'.`, node); + + public static InvalidExtendsExtension = (node: ts.Node) => + new TranspileError(`Cannot extend classes with decorator '@extension' or '@metaExtension'.`, node); + + public static InvalidExportsExtension = (node: ts.Node) => + new TranspileError(`Cannot export classes with decorator '@extension' or '@metaExtension'.`, node); + + public static InvalidInstanceOfExtension = (node: ts.Node) => + new TranspileError(`Cannot use instanceof on classes with decorator '@extension' or '@metaExtension'.`, node); public static InvalidPropertyCall = (node: ts.Node) => new TranspileError(`Tried to transpile a non-property call as property call.`, node); diff --git a/src/lualib/InstanceOf.ts b/src/lualib/InstanceOf.ts index 3b6a12dab..c23c3604a 100644 --- a/src/lualib/InstanceOf.ts +++ b/src/lualib/InstanceOf.ts @@ -1,14 +1,20 @@ interface LuaClass { - __index: LuaClass; - __base: LuaClass; + ____super?: LuaClass; } -function __TS__InstanceOf(obj: LuaClass, classTbl: LuaClass): boolean { - while (obj !== undefined) { - if (obj.__index === classTbl) { - return true; +interface LuaObject { + constructor: LuaClass; +} + +function __TS__InstanceOf(obj: LuaObject, classTbl: LuaClass): boolean { + if (obj !== undefined) { + let luaClass = obj.constructor; + while (luaClass !== undefined) { + if (luaClass === classTbl) { + return true; + } + luaClass = luaClass.____super; } - obj = obj.__base; } return false; } diff --git a/test/translation/lua/classExtension1.lua b/test/translation/lua/classExtension1.lua index ff9e5bb5d..6f9f350b2 100644 --- a/test/translation/lua/classExtension1.lua +++ b/test/translation/lua/classExtension1.lua @@ -1,2 +1,2 @@ -MyClass.myFunction = function(self) +MyClass.prototype.myFunction = function(self) end; diff --git a/test/translation/lua/classExtension2.lua b/test/translation/lua/classExtension2.lua index 94e8f655f..cc6622932 100644 --- a/test/translation/lua/classExtension2.lua +++ b/test/translation/lua/classExtension2.lua @@ -1,2 +1,2 @@ -TestClass.myFunction = function(self) +TestClass.prototype.myFunction = function(self) end; diff --git a/test/translation/lua/classExtension3.lua b/test/translation/lua/classExtension3.lua index 008d45956..2a476b215 100644 --- a/test/translation/lua/classExtension3.lua +++ b/test/translation/lua/classExtension3.lua @@ -1,4 +1,4 @@ -RenamedTestClass.myFunction = function(self) +RenamedTestClass.prototype.myFunction = function(self) end; -RenamedMyClass.myFunction = function(self) +RenamedMyClass.prototype.myFunction = function(self) end; diff --git a/test/translation/lua/classExtension4.lua b/test/translation/lua/classExtension4.lua index 8fcb73124..07317d0f0 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.prototype.myFunction = function(self) end; diff --git a/test/translation/lua/classPureAbstract.lua b/test/translation/lua/classPureAbstract.lua index 63d61f0db..ba55394c6 100644 --- a/test/translation/lua/classPureAbstract.lua +++ b/test/translation/lua/classPureAbstract.lua @@ -1,11 +1,12 @@ ClassB = ClassB or {}; ClassB.__index = ClassB; -ClassB.new = function(construct, ...) - local self = setmetatable({}, ClassB); - if construct and ClassB.constructor then - ClassB.constructor(self, ...); - end +ClassB.prototype = ClassB.prototype or {}; +ClassB.prototype.__index = ClassB.prototype; +ClassB.prototype.constructor = ClassB; +ClassB.____new = function(...) + local self = setmetatable({}, ClassB.prototype); + self:____constructor(...); return self; end; -ClassB.constructor = function(self) +ClassB.prototype.____constructor = function(self) end; diff --git a/test/translation/lua/getSetAccessors.lua b/test/translation/lua/getSetAccessors.lua index 9fe62bbb6..c9f230815 100644 --- a/test/translation/lua/getSetAccessors.lua +++ b/test/translation/lua/getSetAccessors.lua @@ -1,21 +1,22 @@ MyClass = MyClass or {}; MyClass.__index = MyClass; -MyClass.new = function(construct, ...) - local self = setmetatable({}, MyClass); - if construct and MyClass.constructor then - MyClass.constructor(self, ...); - end +MyClass.prototype = MyClass.prototype or {}; +MyClass.prototype.__index = MyClass.prototype; +MyClass.prototype.constructor = MyClass; +MyClass.____new = function(...) + local self = setmetatable({}, MyClass.prototype); + self:____constructor(...); return self; end; -MyClass.constructor = function(self) +MyClass.prototype.____constructor = function(self) end; -MyClass.get__field = function(self) +MyClass.prototype.get__field = function(self) return self._field + 4; end; -MyClass.set__field = function(self, v) +MyClass.prototype.set__field = function(self, v) self._field = v * 2; end; -local instance = MyClass.new(true); +local instance = MyClass.____new(); instance:set__field(4); local b = instance:get__field(); local c = (4 + instance:get__field()) * 3; diff --git a/test/translation/lua/methodRestArguments.lua b/test/translation/lua/methodRestArguments.lua index 236560407..6ec0c10a4 100644 --- a/test/translation/lua/methodRestArguments.lua +++ b/test/translation/lua/methodRestArguments.lua @@ -1,14 +1,15 @@ MyClass = MyClass or {}; MyClass.__index = MyClass; -MyClass.new = function(construct, ...) - local self = setmetatable({}, MyClass); - if construct and MyClass.constructor then - MyClass.constructor(self, ...); - end +MyClass.prototype = MyClass.prototype or {}; +MyClass.prototype.__index = MyClass.prototype; +MyClass.prototype.constructor = MyClass; +MyClass.____new = function(...) + local self = setmetatable({}, MyClass.prototype); + self:____constructor(...); return self; end; -MyClass.constructor = function(self) +MyClass.prototype.____constructor = function(self) end; -MyClass.varargsFunction = function(self, a, ...) +MyClass.prototype.varargsFunction = function(self, a, ...) local b = ({...}); end; diff --git a/test/translation/lua/modulesClassExport.lua b/test/translation/lua/modulesClassExport.lua index a339f9482..7494e59fc 100644 --- a/test/translation/lua/modulesClassExport.lua +++ b/test/translation/lua/modulesClassExport.lua @@ -1,13 +1,14 @@ 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 +exports.TestClass.prototype = exports.TestClass.prototype or {}; +exports.TestClass.prototype.__index = exports.TestClass.prototype; +exports.TestClass.prototype.constructor = TestClass; +exports.TestClass.____new = function(...) + local self = setmetatable({}, exports.TestClass.prototype); + self:____constructor(...); return self; end; -exports.TestClass.constructor = function(self) +exports.TestClass.prototype.____constructor = function(self) end; return exports; diff --git a/test/translation/lua/modulesClassWithMemberExport.lua b/test/translation/lua/modulesClassWithMemberExport.lua index 655d142c8..9a91514fc 100644 --- a/test/translation/lua/modulesClassWithMemberExport.lua +++ b/test/translation/lua/modulesClassWithMemberExport.lua @@ -1,15 +1,16 @@ 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 +exports.TestClass.prototype = exports.TestClass.prototype or {}; +exports.TestClass.prototype.__index = exports.TestClass.prototype; +exports.TestClass.prototype.constructor = TestClass; +exports.TestClass.____new = function(...) + local self = setmetatable({}, exports.TestClass.prototype); + self:____constructor(...); return self; end; -exports.TestClass.constructor = function(self) +exports.TestClass.prototype.____constructor = function(self) end; -exports.TestClass.memberFunc = function(self) +exports.TestClass.prototype.memberFunc = function(self) end; return exports; diff --git a/test/translation/lua/namespaceMerge.lua b/test/translation/lua/namespaceMerge.lua index e585c3c83..f99928ead 100644 --- a/test/translation/lua/namespaceMerge.lua +++ b/test/translation/lua/namespaceMerge.lua @@ -1,24 +1,25 @@ 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 +MergedClass.prototype = MergedClass.prototype or {}; +MergedClass.prototype.__index = MergedClass.prototype; +MergedClass.prototype.constructor = MergedClass; +MergedClass.____new = function(...) + local self = setmetatable({}, MergedClass.prototype); + self:____constructor(...); return self; end; -MergedClass.constructor = function(self) +MergedClass.prototype.____constructor = function(self) + self.propertyFunc = function(____) + end; end; MergedClass.staticMethodA = function(self) end; MergedClass.staticMethodB = function(self) self:staticMethodA(); end; -MergedClass.methodA = function(self) +MergedClass.prototype.methodA = function(self) end; -MergedClass.methodB = function(self) +MergedClass.prototype.methodB = function(self) self:methodA(); self:propertyFunc(); end; @@ -27,7 +28,7 @@ do MergedClass.namespaceFunc = function() end; end -local mergedClass = MergedClass.new(true); +local mergedClass = MergedClass.____new(); mergedClass:methodB(); mergedClass:propertyFunc(); MergedClass:staticMethodB(); diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index eb1a13a29..714abff3d 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -152,7 +152,7 @@ export class AssignmentTests { + `let [a,b] = jkl.abc();`; const lua = util.transpileString(code); - Expect(lua).toBe("local jkl = def.new(true);\nlocal a, b = jkl:abc();"); + Expect(lua).toBe("local jkl = def.____new();\nlocal a, b = jkl:abc();"); } @Test("TupleReturn functional") diff --git a/test/unit/class.spec.ts b/test/unit/class.spec.ts index 384d12fdd..5592933e9 100644 --- a/test/unit/class.spec.ts +++ b/test/unit/class.spec.ts @@ -1,7 +1,8 @@ -import { Expect, Test } from "alsatian"; +import { Expect, Test, TestCase } from "alsatian"; import * as ts from "typescript"; import * as util from "../src/util"; +import { TranspileError } from "../../src/TranspileError"; export class ClassTests { @@ -277,6 +278,29 @@ export class ClassTests { Expect(result).toBe(10); } + @Test("classSuperSkip") + public classSuperSkip(): void { + const result = util.transpileAndExecute( + `class a { + public field: number = 4; + constructor(n: number) { + this.field = n; + } + } + class b extends a { + } + class c extends b { + constructor() { + super(5); + } + } + return new c().field;` + ); + + // Assert + Expect(result).toBe(5); + } + @Test("renamedClassExtends") public renamedClassExtends(): void { @@ -603,6 +627,68 @@ export class ClassTests { Expect(result).toBe(10); } + @Test("CallSuperExpressionMethod") + public callSuperExpressionMethod(): void { + const result = util.transpileAndExecute( + `let i = 0; + function make() { + const j = i++; + return class { + constructor() {} + method() {} + }; + } + class B extends make() { + constructor() { super(); } + method() { super.method(); } + } + const inst = new B(); + inst.method(); + inst.method(); + inst.method(); + return i;` + ); + + // Assert + Expect(result).toBe(1); + } + + @Test("CallSuperSuperMethod") + public callSuperSuperMethod(): void { + const result = util.transpileAndExecute( + `class a { + a: number + constructor(n: number) { + this.a = n; + } + public method() { + return this.a; + } + } + class b extends a { + constructor(n: number) { + super(n); + } + public method() { + return super.method(); + } + } + class c extends b { + constructor(n: number) { + super(n); + } + public method() { + return super.method(); + } + } + let inst = new c(6); + return inst.method();` + ); + + // Assert + Expect(result).toBe(6); + } + @Test("classExpression") public classExpression(): void { const result = util.transpileAndExecute( @@ -662,7 +748,7 @@ export class ClassTests { } @Test("Exported class super call") - public exportedClassSupercAll(): void { + public exportedClassSuperCall(): void { const code = `export class Foo { prop: string; @@ -676,4 +762,47 @@ export class ClassTests { export const baz = (new Bar()).prop;`; Expect(util.transpileExecuteAndReturnExport(code, "baz")).toBe("bar"); } + + @TestCase("(new Foo())", "foo") + @TestCase("Foo", "bar") + @Test("Class method name collision") + public classMethodNameCollisiom(input: string, expectResult: string): void { + const code = + `class Foo { + public method() { return "foo"; } + public static method() { return "bar"; } + } + return ${input}.method();`; + Expect(util.transpileAndExecute(code)).toBe(expectResult); + } + + @TestCase("extension") + @TestCase("metaExtension") + @Test("Class extends extension") + public classExtendsExtension(extensionType: string): void { + const code = + `declare class A {} + /** @${extensionType} **/ + class B extends A {} + class C extends B {}`; + Expect(() => util.transpileString(code)).toThrowError( + TranspileError, + "Cannot extend classes with decorator '@extension' or '@metaExtension'." + ); + } + + @TestCase("extension") + @TestCase("metaExtension") + @Test("Class construct extension") + public classConstructExtension(extensionType: string): void { + const code = + `declare class A {} + /** @${extensionType} **/ + class B extends A {} + const b = new B();`; + Expect(() => util.transpileString(code)).toThrowError( + TranspileError, + "Cannot construct classes with decorator '@extension' or '@metaExtension'." + ); + } } diff --git a/test/unit/compiler/configuration/options.spec.ts b/test/unit/compiler/configuration/options.spec.ts index 262b80085..9d150b61c 100644 --- a/test/unit/compiler/configuration/options.spec.ts +++ b/test/unit/compiler/configuration/options.spec.ts @@ -24,6 +24,6 @@ export class ObjectLiteralTests const options = {LuaLibImportKind: importKind}; const result = util.transpileString("const a = new Map();", options); - Expect(result).toBe("local a = Map.new(true);"); + Expect(result).toBe("local a = Map.____new();"); } } diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index c58fde638..f0a5eabdc 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -57,6 +57,6 @@ export class DecoratorMetaExtension { ` ); }).toThrowError(TranspileError, - "Cannot construct classes with decorator '!Extension' or '!MetaExtension'."); + "Cannot construct classes with decorator '@extension' or '@metaExtension'."); } } diff --git a/test/unit/typechecking.spec.ts b/test/unit/typechecking.spec.ts index 095b87afd..a08740cad 100644 --- a/test/unit/typechecking.spec.ts +++ b/test/unit/typechecking.spec.ts @@ -1,6 +1,7 @@ import { Expect, Test, TestCase } from "alsatian"; import * as util from "../src/util"; +import { TranspileError } from "../../src/TranspileError"; export class TypeCheckingTests { @TestCase("0") @@ -116,4 +117,20 @@ export class TypeCheckingTests { Expect(result).toBe(false); } + + @TestCase("extension") + @TestCase("metaExtension") + @Test("instanceof extension") + public instanceOfExtension(extensionType: string): void { + const code = + `declare class A {} + /** @${extensionType} **/ + class B extends A {} + declare const foo: any; + const result = foo instanceof B;`; + Expect(() => util.transpileString(code)).toThrowError( + TranspileError, + "Cannot use instanceof on classes with decorator '@extension' or '@metaExtension'." + ); + } } From f2c9d52e5a643268d434d4488ea910631c41c870 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Fri, 8 Feb 2019 07:55:34 -0700 Subject: [PATCH 2/5] added cloneIdentifier ...and using it to prevent the same nodes being referenced from different places in the lua ast --- src/LuaAST.ts | 4 +++ src/LuaTransformer.ts | 66 ++++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/LuaAST.ts b/src/LuaAST.ts index 424d09057..401e7047b 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -813,6 +813,10 @@ export function createIdentifier( return expression; } +export function cloneIdentifier(identifier: Identifier): Identifier { + return createIdentifier(identifier.text, undefined, identifier.symbolId); +} + export interface TableIndexExpression extends Expression { kind: SyntaxKind.TableIndexExpression; table: Expression; diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 3ce87dc19..80445c950 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -373,7 +373,7 @@ export class LuaTransformer { // className["fieldName"] const classField = tstl.createTableIndexExpression( - className, + tstl.cloneIdentifier(className), fieldName); // className["fieldName"] = value; @@ -389,7 +389,7 @@ export class LuaTransformer { const value = this.transformExpression(field.initializer); const classField = tstl.createTableIndexExpression( - this.addExportToIdentifier(className), + this.addExportToIdentifier(tstl.cloneIdentifier(className)), fieldName ); @@ -479,44 +479,55 @@ export class LuaTransformer { const result: tstl.Statement[] = []; - const classNameWithExport = this.addExportToIdentifier(className); - // className = className or {} let classTable: tstl.Expression = tstl.createTableExpression(); if (!noClassOr) { - classTable = tstl.createBinaryExpression(classNameWithExport, classTable, tstl.SyntaxKind.OrOperator); + classTable = tstl.createBinaryExpression( + this.addExportToIdentifier(className), // Use original identifier node in declaration + classTable, + tstl.SyntaxKind.OrOperator + ); } const classVar = this.createLocalOrExportedOrGlobalDeclaration(className, classTable, statement); result.push(...classVar); + const createClassNameWithExport = () => this.addExportToIdentifier(tstl.cloneIdentifier(className)); + // className.__index = className - const classIndex = tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("__index")); - const assignClassIndex = tstl.createAssignmentStatement(classIndex, classNameWithExport, statement); + const classIndex = tstl.createTableIndexExpression( + createClassNameWithExport(), + tstl.createStringLiteral("__index") + ); + const assignClassIndex = tstl.createAssignmentStatement(classIndex, createClassNameWithExport(), statement); result.push(assignClassIndex); // className.prototype = className.prototype or {} - const classPrototype = tstl.createTableIndexExpression( - classNameWithExport, + const createClassPrototype = () => tstl.createTableIndexExpression( + createClassNameWithExport(), tstl.createStringLiteral("prototype") ); const classPrototypeTable = noClassOr ? tstl.createTableExpression() - : tstl.createBinaryExpression(classPrototype, tstl.createTableExpression(), tstl.SyntaxKind.OrOperator); - const assignClassPrototype = tstl.createAssignmentStatement(classPrototype, classPrototypeTable); + : tstl.createBinaryExpression( + createClassPrototype(), + tstl.createTableExpression(), + tstl.SyntaxKind.OrOperator + ); + const assignClassPrototype = tstl.createAssignmentStatement(createClassPrototype(), classPrototypeTable); result.push(assignClassPrototype); // className.prototype.__index = className.prototype const classPrototypeIndex = tstl.createTableIndexExpression( - classPrototype, + createClassPrototype(), tstl.createStringLiteral("__index") ); - const assignClassPrototypeIndex = tstl.createAssignmentStatement(classPrototypeIndex, classPrototype); + const assignClassPrototypeIndex = tstl.createAssignmentStatement(classPrototypeIndex, createClassPrototype()); result.push(assignClassPrototypeIndex); // className.prototype.constructor = className const classPrototypeConstructor = tstl.createTableIndexExpression( - classPrototype, + createClassPrototype(), tstl.createStringLiteral("constructor") ); const assignClassPrototypeConstructor = tstl.createAssignmentStatement( @@ -531,28 +542,31 @@ export class LuaTransformer { const baseName = this.transformExpression(extendedTypeNode.expression); // className.____super = baseName - const classBase = tstl.createTableIndexExpression( - classNameWithExport, + const createClassBase = () => tstl.createTableIndexExpression( + createClassNameWithExport(), tstl.createStringLiteral("____super") ); - const assignClassBase = tstl.createAssignmentStatement(classBase, baseName, statement); + const assignClassBase = tstl.createAssignmentStatement(createClassBase(), baseName, statement); result.push(assignClassBase); // setmetatable(className, className.____super) const setClassMetatable = tstl.createExpressionStatement( tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [classNameWithExport, classBase] + [createClassNameWithExport(), createClassBase()] ) ); result.push(setClassMetatable); // setmetatable(className.prototype, className.____super.prototype) - const basePrototype = tstl.createTableIndexExpression(classBase, tstl.createStringLiteral("prototype")); + const basePrototype = tstl.createTableIndexExpression( + createClassBase(), + tstl.createStringLiteral("prototype") + ); const setClassPrototypeMetatable = tstl.createExpressionStatement( tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [classPrototype, basePrototype] + [createClassPrototype(), basePrototype] ) ); result.push(setClassPrototypeMetatable); @@ -565,7 +579,7 @@ export class LuaTransformer { this.createSelfIdentifier(), tstl.createCallExpression( tstl.createIdentifier("setmetatable"), - [tstl.createTableExpression(), classPrototype] + [tstl.createTableExpression(), createClassPrototype()] ) ); newFuncStatements.push(assignSelf); @@ -588,7 +602,7 @@ export class LuaTransformer { // or function export.className.____new(construct, ...) ... end const newFunc = tstl.createAssignmentStatement( tstl.createTableIndexExpression( - classNameWithExport, + createClassNameWithExport(), tstl.createStringLiteral("____new")), tstl.createFunctionExpression( tstl.createBlock(newFuncStatements), @@ -627,7 +641,7 @@ export class LuaTransformer { public createConstructorName(className: tstl.Identifier): tstl.TableIndexExpression { return tstl.createTableIndexExpression( tstl.createTableIndexExpression( - this.addExportToIdentifier(className), + this.addExportToIdentifier(tstl.cloneIdentifier(className)), tstl.createStringLiteral("prototype") ), tstl.createStringLiteral("____constructor") @@ -717,7 +731,7 @@ export class LuaTransformer { return tstl.createAssignmentStatement( tstl.createTableIndexExpression( tstl.createTableIndexExpression( - this.addExportToIdentifier(className), + this.addExportToIdentifier(tstl.cloneIdentifier(className)), tstl.createStringLiteral("prototype") ), tstl.createStringLiteral("get__" + name.text)), @@ -746,7 +760,7 @@ export class LuaTransformer { return tstl.createAssignmentStatement( tstl.createTableIndexExpression( tstl.createTableIndexExpression( - this.addExportToIdentifier(className), + this.addExportToIdentifier(tstl.cloneIdentifier(className)), tstl.createStringLiteral("prototype") ), tstl.createStringLiteral("set__" + name.text)), @@ -784,7 +798,7 @@ export class LuaTransformer { ); const isStatic = node.modifiers && node.modifiers.some(m => m.kind === ts.SyntaxKind.StaticKeyword); - const classNameWithExport = this.addExportToIdentifier(className); + const classNameWithExport = this.addExportToIdentifier(tstl.cloneIdentifier(className)); const methodTable = isStatic ? classNameWithExport : tstl.createTableIndexExpression(classNameWithExport, tstl.createStringLiteral("prototype")); From ffa6a363d437373a93ee3a3415c843f805b7e387 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Sat, 9 Feb 2019 07:17:27 -0700 Subject: [PATCH 3/5] reverted ____new back to new and added new and self to banned identifier list --- src/LuaTransformer.ts | 13 +++++++------ test/translation/lua/classPureAbstract.lua | 2 +- test/translation/lua/getSetAccessors.lua | 4 ++-- test/translation/lua/methodRestArguments.lua | 2 +- test/translation/lua/modulesClassExport.lua | 2 +- .../lua/modulesClassWithMemberExport.lua | 2 +- test/translation/lua/namespaceMerge.lua | 4 ++-- test/unit/assignments.spec.ts | 2 +- test/unit/compiler/configuration/options.spec.ts | 2 +- 9 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 80445c950..014e86a9e 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -40,8 +40,9 @@ interface Scope { export class LuaTransformer { public luaKeywords: Set = new Set([ - "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", - "in", "local", "nil", "not", "or", "repeat", "return", "then", "until", "while", + "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", + "in", "local", "new", "nil", "not", "or", "repeat", "return", "self", "then", "until", + "while", ]); private isStrict = true; @@ -598,12 +599,12 @@ export class LuaTransformer { const returnSelf = tstl.createReturnStatement([this.createSelfIdentifier()]); newFuncStatements.push(returnSelf); - // function className.____new(construct, ...) ... end - // or function export.className.____new(construct, ...) ... end + // function className.new(construct, ...) ... end + // or function export.className.new(construct, ...) ... end const newFunc = tstl.createAssignmentStatement( tstl.createTableIndexExpression( createClassNameWithExport(), - tstl.createStringLiteral("____new")), + tstl.createStringLiteral("new")), tstl.createFunctionExpression( tstl.createBlock(newFuncStatements), undefined, @@ -2552,7 +2553,7 @@ export class LuaTransformer { } return tstl.createCallExpression( - tstl.createTableIndexExpression(name, tstl.createStringLiteral("____new")), + tstl.createTableIndexExpression(name, tstl.createStringLiteral("new")), params, node ); diff --git a/test/translation/lua/classPureAbstract.lua b/test/translation/lua/classPureAbstract.lua index ba55394c6..70ba4efb3 100644 --- a/test/translation/lua/classPureAbstract.lua +++ b/test/translation/lua/classPureAbstract.lua @@ -3,7 +3,7 @@ ClassB.__index = ClassB; ClassB.prototype = ClassB.prototype or {}; ClassB.prototype.__index = ClassB.prototype; ClassB.prototype.constructor = ClassB; -ClassB.____new = function(...) +ClassB.new = function(...) local self = setmetatable({}, ClassB.prototype); self:____constructor(...); return self; diff --git a/test/translation/lua/getSetAccessors.lua b/test/translation/lua/getSetAccessors.lua index c9f230815..c1c16ff51 100644 --- a/test/translation/lua/getSetAccessors.lua +++ b/test/translation/lua/getSetAccessors.lua @@ -3,7 +3,7 @@ MyClass.__index = MyClass; MyClass.prototype = MyClass.prototype or {}; MyClass.prototype.__index = MyClass.prototype; MyClass.prototype.constructor = MyClass; -MyClass.____new = function(...) +MyClass.new = function(...) local self = setmetatable({}, MyClass.prototype); self:____constructor(...); return self; @@ -16,7 +16,7 @@ end; MyClass.prototype.set__field = function(self, v) self._field = v * 2; end; -local instance = MyClass.____new(); +local instance = MyClass.new(); instance:set__field(4); local b = instance:get__field(); local c = (4 + instance:get__field()) * 3; diff --git a/test/translation/lua/methodRestArguments.lua b/test/translation/lua/methodRestArguments.lua index 6ec0c10a4..0f2ba1555 100644 --- a/test/translation/lua/methodRestArguments.lua +++ b/test/translation/lua/methodRestArguments.lua @@ -3,7 +3,7 @@ MyClass.__index = MyClass; MyClass.prototype = MyClass.prototype or {}; MyClass.prototype.__index = MyClass.prototype; MyClass.prototype.constructor = MyClass; -MyClass.____new = function(...) +MyClass.new = function(...) local self = setmetatable({}, MyClass.prototype); self:____constructor(...); return self; diff --git a/test/translation/lua/modulesClassExport.lua b/test/translation/lua/modulesClassExport.lua index 7494e59fc..4f145ed02 100644 --- a/test/translation/lua/modulesClassExport.lua +++ b/test/translation/lua/modulesClassExport.lua @@ -4,7 +4,7 @@ exports.TestClass.__index = exports.TestClass; exports.TestClass.prototype = exports.TestClass.prototype or {}; exports.TestClass.prototype.__index = exports.TestClass.prototype; exports.TestClass.prototype.constructor = TestClass; -exports.TestClass.____new = function(...) +exports.TestClass.new = function(...) local self = setmetatable({}, exports.TestClass.prototype); self:____constructor(...); return self; diff --git a/test/translation/lua/modulesClassWithMemberExport.lua b/test/translation/lua/modulesClassWithMemberExport.lua index 9a91514fc..40a5d8539 100644 --- a/test/translation/lua/modulesClassWithMemberExport.lua +++ b/test/translation/lua/modulesClassWithMemberExport.lua @@ -4,7 +4,7 @@ exports.TestClass.__index = exports.TestClass; exports.TestClass.prototype = exports.TestClass.prototype or {}; exports.TestClass.prototype.__index = exports.TestClass.prototype; exports.TestClass.prototype.constructor = TestClass; -exports.TestClass.____new = function(...) +exports.TestClass.new = function(...) local self = setmetatable({}, exports.TestClass.prototype); self:____constructor(...); return self; diff --git a/test/translation/lua/namespaceMerge.lua b/test/translation/lua/namespaceMerge.lua index f99928ead..3c515447c 100644 --- a/test/translation/lua/namespaceMerge.lua +++ b/test/translation/lua/namespaceMerge.lua @@ -3,7 +3,7 @@ MergedClass.__index = MergedClass; MergedClass.prototype = MergedClass.prototype or {}; MergedClass.prototype.__index = MergedClass.prototype; MergedClass.prototype.constructor = MergedClass; -MergedClass.____new = function(...) +MergedClass.new = function(...) local self = setmetatable({}, MergedClass.prototype); self:____constructor(...); return self; @@ -28,7 +28,7 @@ do MergedClass.namespaceFunc = function() end; end -local mergedClass = MergedClass.____new(); +local mergedClass = MergedClass.new(); mergedClass:methodB(); mergedClass:propertyFunc(); MergedClass:staticMethodB(); diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index 714abff3d..dda85cc20 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -152,7 +152,7 @@ export class AssignmentTests { + `let [a,b] = jkl.abc();`; const lua = util.transpileString(code); - Expect(lua).toBe("local jkl = def.____new();\nlocal a, b = jkl:abc();"); + Expect(lua).toBe("local jkl = def.new();\nlocal a, b = jkl:abc();"); } @Test("TupleReturn functional") diff --git a/test/unit/compiler/configuration/options.spec.ts b/test/unit/compiler/configuration/options.spec.ts index 9d150b61c..28324c10a 100644 --- a/test/unit/compiler/configuration/options.spec.ts +++ b/test/unit/compiler/configuration/options.spec.ts @@ -24,6 +24,6 @@ export class ObjectLiteralTests const options = {LuaLibImportKind: importKind}; const result = util.transpileString("const a = new Map();", options); - Expect(result).toBe("local a = Map.____new();"); + Expect(result).toBe("local a = Map.new();"); } } From ccc3b62ecc3388e9532221fddf391fbe5ec0177a Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Sat, 9 Feb 2019 09:39:50 -0700 Subject: [PATCH 4/5] spacing sanity --- src/LuaTransformer.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 014e86a9e..e74b0f664 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -40,9 +40,8 @@ interface Scope { export class LuaTransformer { public luaKeywords: Set = new Set([ - "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", - "in", "local", "new", "nil", "not", "or", "repeat", "return", "self", "then", "until", - "while", + "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "new", "nil", + "not", "or", "repeat", "return", "self", "then", "until", "while", ]); private isStrict = true; From c0b061313f6fcb41fe1516a65721714114d70369 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Sun, 10 Feb 2019 08:13:21 -0700 Subject: [PATCH 5/5] fixed bug introduced in merge --- src/LuaTransformer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 1d000f319..cbcccbe42 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -296,7 +296,7 @@ export class LuaTransformer { throw TSTLErrors.InvalidExtensionMetaExtension(statement); } - if ((isExtension || isMetaExtension) && this.isIdentifierExported(className.text)) { + if ((isExtension || isMetaExtension) && this.isIdentifierExported(className)) { // Cannot export extension classes throw TSTLErrors.InvalidExportsExtension(statement); }