From 2b8851260a9f116784437c8488910707b1969554 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sat, 7 Dec 2019 19:52:01 +0000 Subject: [PATCH 1/6] Move `new` utility to lualib --- src/LuaLib.ts | 1 + src/lualib/New.ts | 5 +++ src/transformation/utils/errors.ts | 3 -- src/transformation/visitors/class/index.ts | 9 ----- src/transformation/visitors/class/new.ts | 4 +- src/transformation/visitors/class/setup.ts | 47 +--------------------- test/unit/classes/classes.spec.ts | 42 ------------------- 7 files changed, 9 insertions(+), 102 deletions(-) create mode 100644 src/lualib/New.ts diff --git a/src/LuaLib.ts b/src/LuaLib.ts index b50ab1e75..da2530118 100644 --- a/src/LuaLib.ts +++ b/src/LuaLib.ts @@ -36,6 +36,7 @@ export enum LuaLibFeature { InstanceOfObject = "InstanceOfObject", Iterator = "Iterator", Map = "Map", + New = "New", NewIndex = "NewIndex", Number = "Number", NumberIsFinite = "NumberIsFinite", diff --git a/src/lualib/New.ts b/src/lualib/New.ts new file mode 100644 index 000000000..47e25694d --- /dev/null +++ b/src/lualib/New.ts @@ -0,0 +1,5 @@ +function __TS__New(this: void, target: LuaClass, ...args: Vararg): any { + const instance: any = setmetatable({}, target.prototype); + instance.____constructor(...args); + return instance; +} diff --git a/src/transformation/utils/errors.ts b/src/transformation/utils/errors.ts index ea741e967..bb3f3ce79 100644 --- a/src/transformation/utils/errors.ts +++ b/src/transformation/utils/errors.ts @@ -51,9 +51,6 @@ export const InvalidInstanceOfExtension = (node: ts.Node) => export const InvalidJsonFileContent = (node: ts.Node) => new TranspileError("Invalid JSON file content", node); -export const ForbiddenStaticClassPropertyName = (node: ts.Node, name: string) => - new TranspileError(`Cannot use "${name}" as a static class property or method name.`, node); - export const MissingClassName = (node: ts.Node) => new TranspileError(`Class declarations must have a name.`, node); export const MissingForOfVariables = (node: ts.Node) => diff --git a/src/transformation/visitors/class/index.ts b/src/transformation/visitors/class/index.ts index 6f4192182..b2d2ee774 100644 --- a/src/transformation/visitors/class/index.ts +++ b/src/transformation/visitors/class/index.ts @@ -5,7 +5,6 @@ import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; import { ForbiddenLuaTableNonDeclaration, - ForbiddenStaticClassPropertyName, InvalidExportsExtension, InvalidExtendsExtension, InvalidExtendsLuaTable, @@ -136,14 +135,6 @@ export function transformClassDeclaration( throw ForbiddenLuaTableNonDeclaration(classDeclaration); } - for (const member of classDeclaration.members) { - if (member.name && (ts.isStringLiteral(member.name) || ts.isIdentifier(member.name))) { - if (isStaticNode(member) && member.name.text === "new") { - throw ForbiddenStaticClassPropertyName(member, member.name.text); - } - } - } - // Get all properties with value const properties = classDeclaration.members.filter(ts.isPropertyDeclaration).filter(member => member.initializer); diff --git a/src/transformation/visitors/class/new.ts b/src/transformation/visitors/class/new.ts index a35cad983..19797b48e 100644 --- a/src/transformation/visitors/class/new.ts +++ b/src/transformation/visitors/class/new.ts @@ -3,7 +3,7 @@ import * as lua from "../../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; import { InvalidAnnotationArgumentNumber, InvalidNewExpressionOnExtension } from "../../utils/errors"; -import { importLuaLibFeature, LuaLibFeature } from "../../utils/lualib"; +import { importLuaLibFeature, LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { transformArguments } from "../call"; import { transformLuaTableNewExpression } from "../lua-table"; @@ -82,5 +82,5 @@ export const transformNewExpression: FunctionVisitor = (node, ); } - return lua.createCallExpression(lua.createTableIndexExpression(name, lua.createStringLiteral("new")), params, node); + return transformLuaLibFunction(context, LuaLibFeature.New, node, name, ...params); }; diff --git a/src/transformation/visitors/class/setup.ts b/src/transformation/visitors/class/setup.ts index 5c136d756..efd6ef411 100644 --- a/src/transformation/visitors/class/setup.ts +++ b/src/transformation/visitors/class/setup.ts @@ -8,11 +8,7 @@ import { getIdentifierExportScope, hasDefaultExportModifier, } from "../../utils/export"; -import { - createExportsIdentifier, - createLocalOrExportedOrGlobalDeclaration, - createSelfIdentifier, -} from "../../utils/lua-ast"; +import { createExportsIdentifier, createLocalOrExportedOrGlobalDeclaration } from "../../utils/lua-ast"; import { importLuaLibFeature, LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { hasMemberInClassOrAncestor } from "./members/accessors"; import { getExtendedTypeNode, isStaticNode } from "./utils"; @@ -303,46 +299,5 @@ export function createClassSetup( result.push(setClassMetatable); } - const newFuncStatements: lua.Statement[] = []; - - // local self = setmetatable({}, localClassName.prototype) - const assignSelf = lua.createVariableDeclarationStatement( - createSelfIdentifier(), - lua.createCallExpression(lua.createIdentifier("setmetatable"), [ - lua.createTableExpression(), - createClassPrototype(), - ]), - statement - ); - newFuncStatements.push(assignSelf); - - // self:____constructor(...) - const callConstructor = lua.createExpressionStatement( - lua.createMethodCallExpression(createSelfIdentifier(), lua.createIdentifier("____constructor"), [ - lua.createDotsLiteral(), - ]), - statement - ); - newFuncStatements.push(callConstructor); - - // return self - const returnSelf = lua.createReturnStatement([createSelfIdentifier()], statement); - newFuncStatements.push(returnSelf); - - // function localClassName.new(construct, ...) ... end - // or function export.localClassName.new(construct, ...) ... end - const newFunc = lua.createAssignmentStatement( - lua.createTableIndexExpression(lua.cloneIdentifier(localClassName), lua.createStringLiteral("new")), - lua.createFunctionExpression( - lua.createBlock(newFuncStatements), - undefined, - lua.createDotsLiteral(), - undefined, - lua.FunctionExpressionFlags.Declaration - ), - statement - ); - result.push(newFunc); - return result; } diff --git a/test/unit/classes/classes.spec.ts b/test/unit/classes/classes.spec.ts index cfb1451aa..7516cceaf 100644 --- a/test/unit/classes/classes.spec.ts +++ b/test/unit/classes/classes.spec.ts @@ -1,5 +1,3 @@ -import * as ts from "typescript"; -import { ForbiddenStaticClassPropertyName } from "../../../src/transformation/utils/errors"; import * as util from "../../util"; test("ClassFieldInitializer", () => { @@ -831,43 +829,3 @@ test("Class field override in subclass with constructors", () => { return (new Foo()).field + (new Bar()).field;`; expect(util.transpileAndExecute(code)).toBe("foobar"); }); - -test("Class cannot have static new method", () => { - const code = ` - class Foo { - static new() {} - }`; - expect(() => util.transpileAndExecute(code)).toThrow( - ForbiddenStaticClassPropertyName(ts.createEmptyStatement(), "new").message - ); -}); - -test("Class cannot have static new property", () => { - const code = ` - class Foo { - static new = "foobar"; - }`; - expect(() => util.transpileAndExecute(code)).toThrow( - ForbiddenStaticClassPropertyName(ts.createEmptyStatement(), "new").message - ); -}); - -test("Class cannot have static new get accessor", () => { - const code = ` - class Foo { - static get new() { return "foobar" } - }`; - expect(() => util.transpileAndExecute(code)).toThrow( - ForbiddenStaticClassPropertyName(ts.createEmptyStatement(), "new").message - ); -}); - -test("Class cannot have static new set accessor", () => { - const code = ` - class Foo { - static set new(value: string) {} - }`; - expect(() => util.transpileAndExecute(code)).toThrow( - ForbiddenStaticClassPropertyName(ts.createEmptyStatement(), "new").message - ); -}); From 18feb63942d8dbd2f0f5d41eea772fc7ee505018 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sat, 7 Dec 2019 20:22:15 +0000 Subject: [PATCH 2/6] Move some class setup boilerplate to lualib --- src/LuaLib.ts | 1 + src/lualib/Class.ts | 7 ++++ src/lualib/declarations/tstl.d.ts | 2 + src/transformation/utils/lualib.ts | 2 +- src/transformation/visitors/class/index.ts | 15 +++----- src/transformation/visitors/class/setup.ts | 44 +++++----------------- 6 files changed, 27 insertions(+), 44 deletions(-) create mode 100644 src/lualib/Class.ts diff --git a/src/LuaLib.ts b/src/LuaLib.ts index da2530118..a7c2e9a2d 100644 --- a/src/LuaLib.ts +++ b/src/LuaLib.ts @@ -24,6 +24,7 @@ export enum LuaLibFeature { ArrayFlat = "ArrayFlat", ArrayFlatMap = "ArrayFlatMap", ArraySetLength = "ArraySetLength", + Class = "Class", ClassIndex = "ClassIndex", ClassNewIndex = "ClassNewIndex", Decorate = "Decorate", diff --git a/src/lualib/Class.ts b/src/lualib/Class.ts new file mode 100644 index 000000000..26d184602 --- /dev/null +++ b/src/lualib/Class.ts @@ -0,0 +1,7 @@ +function __TS__Class(): LuaClass { + const c = {} as LuaClass; + c.__index = c; + c.prototype = {}; + c.prototype.constructor = c; + return c; +} diff --git a/src/lualib/declarations/tstl.d.ts b/src/lualib/declarations/tstl.d.ts index 7a7a8bf4f..9216870f2 100644 --- a/src/lualib/declarations/tstl.d.ts +++ b/src/lualib/declarations/tstl.d.ts @@ -11,10 +11,12 @@ interface LuaClass { ____super?: LuaClass; ____getters?: { [key: string]: (self: LuaClass) => any }; ____setters?: { [key: string]: (self: LuaClass, val: any) => void }; + __index?: any; } interface LuaObject { constructor: LuaClass; ____getters?: { [key: string]: (self: LuaObject) => any }; ____setters?: { [key: string]: (self: LuaObject, val: any) => void }; + __index?: any; } diff --git a/src/transformation/utils/lualib.ts b/src/transformation/utils/lualib.ts index 583887c7a..3c2d0ec1b 100644 --- a/src/transformation/utils/lualib.ts +++ b/src/transformation/utils/lualib.ts @@ -18,7 +18,7 @@ export function importLuaLibFeature(context: TransformationContext, feature: Lua export function transformLuaLibFunction( context: TransformationContext, feature: LuaLibFeature, - tsParent?: ts.Expression, + tsParent?: ts.Node, ...params: lua.Expression[] ): lua.CallExpression { importLuaLibFeature(context, feature); diff --git a/src/transformation/visitors/class/index.ts b/src/transformation/visitors/class/index.ts index b2d2ee774..e9c8c108c 100644 --- a/src/transformation/visitors/class/index.ts +++ b/src/transformation/visitors/class/index.ts @@ -79,16 +79,13 @@ export function transformClassDeclaration( } else if (classDeclaration.name !== undefined) { className = transformIdentifier(context, classDeclaration.name); classNameText = classDeclaration.name.text; + } else if (hasDefaultExportModifier(classDeclaration)) { + const left = createExportedIdentifier(context, createDefaultExportIdentifier(classDeclaration)); + const right = transformClassAsExpression(classDeclaration, context, true); + + return lua.createAssignmentStatement(left, right, classDeclaration); } else { - const isDefaultExport = hasDefaultExportModifier(classDeclaration); - if (isDefaultExport) { - const left = createExportedIdentifier(context, createDefaultExportIdentifier(classDeclaration)); - const right = transformClassAsExpression(classDeclaration, context, true); - - return lua.createAssignmentStatement(left, right, classDeclaration); - } else { - throw MissingClassName(classDeclaration); - } + throw MissingClassName(classDeclaration); } const annotations = getTypeAnnotations(context, context.checker.getTypeAtLocation(classDeclaration)); diff --git a/src/transformation/visitors/class/setup.ts b/src/transformation/visitors/class/setup.ts index efd6ef411..75fe620bd 100644 --- a/src/transformation/visitors/class/setup.ts +++ b/src/transformation/visitors/class/setup.ts @@ -23,20 +23,19 @@ export function createClassSetup( ): lua.Statement[] { const result: lua.Statement[] = []; - // [____exports.]className = {} - const classTable: lua.Expression = lua.createTableExpression(); + // __TS__Class() + const classInitializer = transformLuaLibFunction(context, LuaLibFeature.Class, statement); - const isDefaultExport = hasDefaultExportModifier(statement); - - const defaultExportLeftHandSide = isDefaultExport + const defaultExportLeftHandSide = hasDefaultExportModifier(statement) ? lua.createTableIndexExpression(createExportsIdentifier(), createDefaultExportStringLiteral(statement)) : undefined; - const classVar = defaultExportLeftHandSide - ? [lua.createAssignmentStatement(defaultExportLeftHandSide, classTable, statement)] - : createLocalOrExportedOrGlobalDeclaration(context, className, classTable, statement); - - result.push(...classVar); + // [____exports.]className = __TS__Class() + if (defaultExportLeftHandSide) { + result.push(lua.createAssignmentStatement(defaultExportLeftHandSide, classInitializer, statement)); + } else { + result.push(...createLocalOrExportedOrGlobalDeclaration(context, className, classInitializer, statement)); + } if (defaultExportLeftHandSide) { // local localClassName = ____exports.default @@ -75,14 +74,6 @@ export function createClassSetup( importLuaLibFeature(context, LuaLibFeature.ClassIndex); } - // localClassName.__index = localClassName - const classIndex = lua.createTableIndexExpression( - lua.cloneIdentifier(localClassName), - lua.createStringLiteral("__index") - ); - const assignClassIndex = lua.createAssignmentStatement(classIndex, lua.cloneIdentifier(localClassName), statement); - result.push(assignClassIndex); - // localClassName.____setters = {} if (statement.members.some(m => ts.isSetAccessor(m) && isStaticNode(m))) { const classSetters = lua.createTableIndexExpression( @@ -95,12 +86,9 @@ export function createClassSetup( importLuaLibFeature(context, LuaLibFeature.ClassNewIndex); } - // localClassName.prototype = {} + // localClassName.prototype const createClassPrototype = () => lua.createTableIndexExpression(lua.cloneIdentifier(localClassName), lua.createStringLiteral("prototype")); - const classPrototypeTable = lua.createTableExpression(); - const assignClassPrototype = lua.createAssignmentStatement(createClassPrototype(), classPrototypeTable, statement); - result.push(assignClassPrototype); // localClassName.prototype.____getters = {} if (statement.members.some(m => ts.isGetAccessor(m) && !isStaticNode(m))) { @@ -166,18 +154,6 @@ export function createClassSetup( result.push(assignClassPrototypeIndex); } - // localClassName.prototype.constructor = localClassName - const classPrototypeConstructor = lua.createTableIndexExpression( - createClassPrototype(), - lua.createStringLiteral("constructor") - ); - const assignClassPrototypeConstructor = lua.createAssignmentStatement( - classPrototypeConstructor, - lua.cloneIdentifier(localClassName), - statement - ); - result.push(assignClassPrototypeConstructor); - const hasStaticGetters = hasMemberInClassOrAncestor( context, statement, From 9670b88b831da84b89bf76d1ec1212cc6658bd4c Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sat, 7 Dec 2019 21:15:25 +0000 Subject: [PATCH 3/6] Fix failing tests --- src/LuaLib.ts | 2 +- .../__snapshots__/transformation.spec.ts.snap | 48 ++++--------------- test/unit/decorators/tupleReturn.spec.ts | 4 +- test/unit/printer/sourcemaps.spec.ts | 6 +-- 4 files changed, 14 insertions(+), 46 deletions(-) diff --git a/src/LuaLib.ts b/src/LuaLib.ts index a7c2e9a2d..b7e8c2a6b 100644 --- a/src/LuaLib.ts +++ b/src/LuaLib.ts @@ -69,7 +69,7 @@ export enum LuaLibFeature { const luaLibDependencies: { [lib in LuaLibFeature]?: LuaLibFeature[] } = { ArrayFlat: [LuaLibFeature.ArrayConcat], ArrayFlatMap: [LuaLibFeature.ArrayConcat], - Error: [LuaLibFeature.FunctionCall], + Error: [LuaLibFeature.New, LuaLibFeature.FunctionCall], InstanceOf: [LuaLibFeature.Symbol], Iterator: [LuaLibFeature.Symbol], ObjectFromEntries: [LuaLibFeature.Iterator, LuaLibFeature.Symbol], diff --git a/test/translation/__snapshots__/transformation.spec.ts.snap b/test/translation/__snapshots__/transformation.spec.ts.snap index 45f7a2d4a..7e9405256 100644 --- a/test/translation/__snapshots__/transformation.spec.ts.snap +++ b/test/translation/__snapshots__/transformation.spec.ts.snap @@ -40,17 +40,10 @@ end" `; exports[`Transformation (classPureAbstract) 1`] = ` -"ClassB = {} +"require(\\"lualib_bundle\\"); +ClassB = __TS__Class() ClassB.name = \\"ClassB\\" -ClassB.__index = ClassB -ClassB.prototype = {} ClassB.prototype.__index = ClassB.prototype -ClassB.prototype.constructor = ClassB -function ClassB.new(...) - local self = setmetatable({}, ClassB.prototype) - self:____constructor(...) - return self -end function ClassB.prototype.____constructor(self) end" `; @@ -82,17 +75,10 @@ return ____exports" `; exports[`Transformation (methodRestArguments) 1`] = ` -"MyClass = {} +"require(\\"lualib_bundle\\"); +MyClass = __TS__Class() MyClass.name = \\"MyClass\\" -MyClass.__index = MyClass -MyClass.prototype = {} MyClass.prototype.__index = MyClass.prototype -MyClass.prototype.constructor = MyClass -function MyClass.new(...) - local self = setmetatable({}, MyClass.prototype) - self:____constructor(...) - return self -end function MyClass.prototype.____constructor(self) end function MyClass.prototype.varargsFunction(self, a, ...) @@ -106,38 +92,24 @@ return ____exports" `; exports[`Transformation (modulesClassExport) 1`] = ` -"local ____exports = {} -____exports.TestClass = {} +"require(\\"lualib_bundle\\"); +local ____exports = {} +____exports.TestClass = __TS__Class() local TestClass = ____exports.TestClass TestClass.name = \\"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 TestClass.prototype.____constructor(self) end return ____exports" `; exports[`Transformation (modulesClassWithMemberExport) 1`] = ` -"local ____exports = {} -____exports.TestClass = {} +"require(\\"lualib_bundle\\"); +local ____exports = {} +____exports.TestClass = __TS__Class() local TestClass = ____exports.TestClass TestClass.name = \\"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 TestClass.prototype.____constructor(self) end function TestClass.prototype.memberFunc(self) diff --git a/test/unit/decorators/tupleReturn.spec.ts b/test/unit/decorators/tupleReturn.spec.ts index 66df74aba..289428a4f 100644 --- a/test/unit/decorators/tupleReturn.spec.ts +++ b/test/unit/decorators/tupleReturn.spec.ts @@ -404,7 +404,7 @@ test("TupleReturn method assignment", () => { `; const lua = util.transpileString(code); - expect(lua).toBe("local jkl = def.new()\nlocal a, b = jkl:abc()"); + expect(lua).toBe('require("lualib_bundle");\nlocal jkl = __TS__New(def)\nlocal a, b = jkl:abc()'); }); test("TupleReturn functional", () => { @@ -504,7 +504,7 @@ test("TupleReturn method assignment", () => { `; const lua = util.transpileString(code); - expect(lua).toBe("local jkl = def.new()\nlocal a, b = jkl:abc()"); + expect(lua).toBe('require("lualib_bundle");\nlocal jkl = __TS__New(def)\nlocal a, b = jkl:abc()'); }); test("TupleReturn functional", () => { diff --git a/test/unit/printer/sourcemaps.spec.ts b/test/unit/printer/sourcemaps.spec.ts index 4023dad19..9a6deb74a 100644 --- a/test/unit/printer/sourcemaps.spec.ts +++ b/test/unit/printer/sourcemaps.spec.ts @@ -84,16 +84,12 @@ test.each([ `, assertPatterns: [ - { luaPattern: "Bar = {}", typeScriptPattern: "class Bar" }, + { luaPattern: "Bar =", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.name =", typeScriptPattern: "class Bar" }, - { luaPattern: "Bar.__index =", typeScriptPattern: "class Bar" }, - { luaPattern: "Bar.prototype =", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.prototype.__index =", typeScriptPattern: "class Bar" }, - { luaPattern: "Bar.prototype.constructor =", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.____super = Foo", typeScriptPattern: "Foo {" }, { luaPattern: "setmetatable(Bar,", typeScriptPattern: "Foo {" }, { luaPattern: "setmetatable(Bar.prototype,", typeScriptPattern: "Foo {" }, - { luaPattern: "function Bar.new", typeScriptPattern: "class Bar" }, { luaPattern: "function Bar.prototype.____constructor", typeScriptPattern: "constructor" }, ], }, From 2cecda13f9c644ddf6a5327957e03f7574b36f3a Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sat, 7 Dec 2019 21:21:36 +0000 Subject: [PATCH 4/6] Remove duplicated `@tupleReturn` tests --- test/unit/decorators/tupleReturn.spec.ts | 100 ----------------------- 1 file changed, 100 deletions(-) diff --git a/test/unit/decorators/tupleReturn.spec.ts b/test/unit/decorators/tupleReturn.spec.ts index 289428a4f..803acad4a 100644 --- a/test/unit/decorators/tupleReturn.spec.ts +++ b/test/unit/decorators/tupleReturn.spec.ts @@ -444,103 +444,3 @@ test("TupleReturn in expression", () => { expect(result).toBe("a3"); }); - -test("TupleReturn assignment", () => { - const code = ` - /** @tupleReturn */ - declare function abc(this: void): number[] - let [a,b] = abc(); - `; - - const lua = util.transpileString(code); - expect(lua).toBe("local a, b = abc()"); -}); - -test("TupleReturn Single assignment", () => { - const code = ` - /** @tupleReturn */ - declare function abc(this: void): [number, string]; - let a = abc(); - a = abc(); - `; - - const lua = util.transpileString(code); - expect(lua).toBe("local a = ({\n abc()\n})\na = ({\n abc()\n})"); -}); - -test("TupleReturn interface assignment", () => { - const code = ` - interface def { - /** @tupleReturn */ - abc(); - } declare const jkl : def; - let [a,b] = jkl.abc(); - `; - - const lua = util.transpileString(code); - expect(lua).toBe("local a, b = jkl:abc()"); -}); - -test("TupleReturn namespace assignment", () => { - const code = ` - declare namespace def { - /** @tupleReturn */ - function abc(this: void) {} - } - let [a,b] = def.abc(); - `; - - const lua = util.transpileString(code); - expect(lua).toBe("local a, b = def.abc()"); -}); - -test("TupleReturn method assignment", () => { - const code = ` - declare class def { - /** @tupleReturn */ - abc() { return [1,2,3]; } - } const jkl = new def(); - let [a,b] = jkl.abc(); - `; - - const lua = util.transpileString(code); - expect(lua).toBe('require("lualib_bundle");\nlocal jkl = __TS__New(def)\nlocal a, b = jkl:abc()'); -}); - -test("TupleReturn functional", () => { - const code = ` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const [a, b] = abc(); - return b + a; - `; - - const result = util.transpileAndExecute(code); - - expect(result).toBe("a3"); -}); - -test("TupleReturn single", () => { - const code = ` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const res = abc(); - return res.length - `; - - const result = util.transpileAndExecute(code); - - expect(result).toBe(2); -}); - -test("TupleReturn in expression", () => { - const code = ` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - return abc()[1] + abc()[0]; - `; - - const result = util.transpileAndExecute(code); - - expect(result).toBe("a3"); -}); From 07b084def8426a02f79029d056528f630944ebe4 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 8 Dec 2019 15:07:33 +0000 Subject: [PATCH 5/6] Move `Class.prototype.__index = Class.prototype` to helper --- src/lualib/Class.ts | 1 + src/transformation/visitors/class/setup.ts | 16 ++++------------ .../__snapshots__/transformation.spec.ts.snap | 4 ---- test/unit/printer/sourcemaps.spec.ts | 1 - 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/lualib/Class.ts b/src/lualib/Class.ts index 26d184602..14aa98587 100644 --- a/src/lualib/Class.ts +++ b/src/lualib/Class.ts @@ -2,6 +2,7 @@ function __TS__Class(): LuaClass { const c = {} as LuaClass; c.__index = c; c.prototype = {}; + c.prototype.__index = c.prototype; c.prototype.constructor = c; return c; } diff --git a/src/transformation/visitors/class/setup.ts b/src/transformation/visitors/class/setup.ts index 75fe620bd..2a4a1c8d0 100644 --- a/src/transformation/visitors/class/setup.ts +++ b/src/transformation/visitors/class/setup.ts @@ -104,23 +104,15 @@ export function createClassSetup( result.push(assignClassPrototypeGetters); } - const classPrototypeIndex = lua.createTableIndexExpression( - createClassPrototype(), - lua.createStringLiteral("__index") - ); if (hasMemberInClassOrAncestor(context, statement, m => ts.isGetAccessor(m) && !isStaticNode(m))) { // localClassName.prototype.__index = __TS__Index(localClassName.prototype) - const assignClassPrototypeIndex = lua.createAssignmentStatement( - classPrototypeIndex, - transformLuaLibFunction(context, LuaLibFeature.Index, undefined, createClassPrototype()), - statement + const classPrototypeIndex = lua.createTableIndexExpression( + createClassPrototype(), + lua.createStringLiteral("__index") ); - result.push(assignClassPrototypeIndex); - } else { - // localClassName.prototype.__index = localClassName.prototype const assignClassPrototypeIndex = lua.createAssignmentStatement( classPrototypeIndex, - createClassPrototype(), + transformLuaLibFunction(context, LuaLibFeature.Index, undefined, createClassPrototype()), statement ); result.push(assignClassPrototypeIndex); diff --git a/test/translation/__snapshots__/transformation.spec.ts.snap b/test/translation/__snapshots__/transformation.spec.ts.snap index 7e9405256..55ad7a99c 100644 --- a/test/translation/__snapshots__/transformation.spec.ts.snap +++ b/test/translation/__snapshots__/transformation.spec.ts.snap @@ -43,7 +43,6 @@ exports[`Transformation (classPureAbstract) 1`] = ` "require(\\"lualib_bundle\\"); ClassB = __TS__Class() ClassB.name = \\"ClassB\\" -ClassB.prototype.__index = ClassB.prototype function ClassB.prototype.____constructor(self) end" `; @@ -78,7 +77,6 @@ exports[`Transformation (methodRestArguments) 1`] = ` "require(\\"lualib_bundle\\"); MyClass = __TS__Class() MyClass.name = \\"MyClass\\" -MyClass.prototype.__index = MyClass.prototype function MyClass.prototype.____constructor(self) end function MyClass.prototype.varargsFunction(self, a, ...) @@ -97,7 +95,6 @@ local ____exports = {} ____exports.TestClass = __TS__Class() local TestClass = ____exports.TestClass TestClass.name = \\"TestClass\\" -TestClass.prototype.__index = TestClass.prototype function TestClass.prototype.____constructor(self) end return ____exports" @@ -109,7 +106,6 @@ local ____exports = {} ____exports.TestClass = __TS__Class() local TestClass = ____exports.TestClass TestClass.name = \\"TestClass\\" -TestClass.prototype.__index = TestClass.prototype function TestClass.prototype.____constructor(self) end function TestClass.prototype.memberFunc(self) diff --git a/test/unit/printer/sourcemaps.spec.ts b/test/unit/printer/sourcemaps.spec.ts index 9a6deb74a..8f3acb42a 100644 --- a/test/unit/printer/sourcemaps.spec.ts +++ b/test/unit/printer/sourcemaps.spec.ts @@ -86,7 +86,6 @@ test.each([ assertPatterns: [ { luaPattern: "Bar =", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.name =", typeScriptPattern: "class Bar" }, - { luaPattern: "Bar.prototype.__index =", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.____super = Foo", typeScriptPattern: "Foo {" }, { luaPattern: "setmetatable(Bar,", typeScriptPattern: "Foo {" }, { luaPattern: "setmetatable(Bar.prototype,", typeScriptPattern: "Foo {" }, From bc078d52b82c4cda5a1d5d95eba12e5615195ea9 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 8 Dec 2019 15:08:06 +0000 Subject: [PATCH 6/6] Add helper call to sourcemap tests --- test/unit/printer/sourcemaps.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/printer/sourcemaps.spec.ts b/test/unit/printer/sourcemaps.spec.ts index 8f3acb42a..918d430d1 100644 --- a/test/unit/printer/sourcemaps.spec.ts +++ b/test/unit/printer/sourcemaps.spec.ts @@ -84,7 +84,7 @@ test.each([ `, assertPatterns: [ - { luaPattern: "Bar =", typeScriptPattern: "class Bar" }, + { luaPattern: "Bar = __TS__Class()", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.name =", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.____super = Foo", typeScriptPattern: "Foo {" }, { luaPattern: "setmetatable(Bar,", typeScriptPattern: "Foo {" },