From 6778a8ae11eaade70f2f694413702c67251d9fe4 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Wed, 9 Jan 2019 21:04:49 +0100 Subject: [PATCH 1/3] Implemented DeleteExpression and NonNullExpression, fixed some broken tests --- src/LuaTransformer.ts | 18 ++++++++++++++++++ test/unit/array.spec.ts | 13 +++++++++++++ test/unit/curry.spec.ts | 16 +--------------- test/unit/expressions.spec.ts | 4 ++-- test/unit/functions.spec.ts | 2 +- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 63766e5dd..4fc988f32 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1280,6 +1280,8 @@ export class LuaTransformer { return this.transformArrayLiteral(expression as ts.ArrayLiteralExpression); case ts.SyntaxKind.ObjectLiteralExpression: return this.transformObjectLiteral(expression as ts.ObjectLiteralExpression); + case ts.SyntaxKind.DeleteExpression: + return this.transformDeleteExpression(expression as ts.DeleteExpression); case ts.SyntaxKind.FunctionExpression: return this.transformFunctionExpression(expression as ts.ArrowFunction, this.selfIdentifier); case ts.SyntaxKind.ArrowFunction: @@ -1300,6 +1302,10 @@ export class LuaTransformer { return this.transformAssertionExpression(expression as ts.AssertionExpression); case ts.SyntaxKind.TypeOfExpression: return this.transformTypeOfExpression(expression as ts.TypeOfExpression); + case ts.SyntaxKind.SpreadElement: + throw new Error("Not yet implemented"); + case ts.SyntaxKind.NonNullExpression: + return this.transformExpression((expression as ts.NonNullExpression).expression); case ts.SyntaxKind.EmptyStatement: // TODO move to extra function (consistency) return undefined; @@ -1677,6 +1683,18 @@ export class LuaTransformer { return tstl.createTableExpression(properties, undefined, node); } + public transformDeleteExpression(expression: ts.DeleteExpression): tstl.CallExpression { + const lhs = this.transformExpression(expression.expression) as tstl.IdentifierOrTableIndexExpression; + const assignment = tstl.createAssignmentStatement( + lhs, + tstl.createNilLiteral(), + undefined, + expression + ); + + return this.createImmediatelyInvokedFunctionExpression([assignment], []); + } + public transformFunctionExpression(node: ts.FunctionLikeDeclaration, context: tstl.Identifier | undefined): ExpressionVisitResult { const type = this.checker.getTypeAtLocation(node); const hasContext = tsHelper.getFunctionContextType(type, this.checker) !== ContextType.Void; diff --git a/test/unit/array.spec.ts b/test/unit/array.spec.ts index ce062fb8a..05da0f8b1 100644 --- a/test/unit/array.spec.ts +++ b/test/unit/array.spec.ts @@ -57,4 +57,17 @@ export class ArrayTests { const result = util.executeLua(lua); Expect(result).toBe(expected); } + + @Test("Array delete") + public arrayDelete(): void { + const lua = util.transpileString( + `const myarray = [1,2,3,4]; + delete myarray[2]; + return \`\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;` + ); + + const result = util.executeLua(lua); + + Expect(result).toBe("1,2,nil,4"); + } } diff --git a/test/unit/curry.spec.ts b/test/unit/curry.spec.ts index d9666c36c..c95e8172a 100644 --- a/test/unit/curry.spec.ts +++ b/test/unit/curry.spec.ts @@ -3,24 +3,10 @@ import * as util from "../src/util"; export class LuaCurryTests { - @Test("currying") - public currying() { - // Transpile - const lua = util.transpileString( - `(x: number) => (y: number) => x + y;` - ); - // Assert - Expect(lua).toBe(`function (x) - return function(y) - return x + y - end -end;`); - } - @Test("curryingAdd") @TestCase(2, 3) @TestCase(5, 4) - public curryingAdd(x: number, y: number) { + public curryingAdd(x: number, y: number): void { // Transpile const lua = util.transpileString( `let add = (x: number) => (y: number) => x + y; diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index ac603bf67..2b7274134 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -13,8 +13,8 @@ export class ExpressionTests { @TestCase("--i", "i = i - 1;") @TestCase("!a", "not a;") @TestCase("-a", "-a;") - @TestCase("delete tbl['test']", "tbl[\"test\"]=nil;") - @TestCase("delete tbl.test", "tbl.test=nil;") + @TestCase("delete tbl['test']", "(function ()\n tbl.test = nil;\n return ;\nend)();") + @TestCase("delete tbl.test", "(function ()\n tbl.test = nil;\n return ;\nend)();") @Test("Unary expressions basic") public unaryBasic(input: string, lua: string): void { Expect(util.transpileString(input)).toBe(lua); diff --git a/test/unit/functions.spec.ts b/test/unit/functions.spec.ts index 78857a797..de28f5102 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -1,4 +1,4 @@ -import { Expect, Test, TestCase } from "alsatian"; +import { Expect, Test, TestCase, FocusTest } from "alsatian"; import * as ts from "typescript"; import * as util from "../src/util"; From daf61a17d5afd91f3623435d86d9cf8a0dc3c0e8 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Thu, 10 Jan 2019 22:19:44 +0100 Subject: [PATCH 2/3] Return true from delete expression --- src/LuaAST.ts | 5 ++++- src/LuaTransformer.ts | 33 ++++++++++++++++++++++----------- test/unit/array.spec.ts | 26 ++++++++++++++++++++++++++ tslint.json | 1 + 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/LuaAST.ts b/src/LuaAST.ts index 5085b2865..6a806f844 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -76,7 +76,10 @@ export enum SyntaxKind { } // TODO maybe name this PrefixUnary? not sure it makes sense to do so, because all unary ops in Lua are prefix -export type UnaryOperator = SyntaxKind.NegationOperator | SyntaxKind.LengthOperator | SyntaxKind.NotOperator | SyntaxKind.BitwiseNotOperator; +export type UnaryOperator = SyntaxKind.NegationOperator + | SyntaxKind.LengthOperator + | SyntaxKind.NotOperator + | SyntaxKind.BitwiseNotOperator; export type BinaryOperator = SyntaxKind.AdditionOperator | SyntaxKind.SubractionOperator | SyntaxKind.MultiplicationOperator | SyntaxKind.DivisionOperator | diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 4fc988f32..6329dabfa 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1453,7 +1453,10 @@ export class LuaTransformer { tstl.createAssignmentStatement(left as tstl.IdentifierOrTableIndexExpression[], tmps), ]; return this.createImmediatelyInvokedFunctionExpression( - statements, tstl.createTableExpression(tmps.map(t => tstl.createTableFieldExpression(t)))); + statements, + tstl.createTableExpression(tmps.map(t => tstl.createTableFieldExpression(t))), + expression + ); } if (ts.isPropertyAccessExpression(expression.left) || ts.isElementAccessExpression(expression.left)) { @@ -1490,7 +1493,7 @@ export class LuaTransformer { // (function() ${left} = ${right}; return ${left} end)() const left = this.transformExpression(expression.left); const right = this.transformExpression(expression.right); - return this.createImmediatelyInvokedFunctionExpression([this.transformAssignment(expression.left, right)], left); + return this.createImmediatelyInvokedFunctionExpression([this.transformAssignment(expression.left, right)], left, expression); } } @@ -1539,7 +1542,11 @@ export class LuaTransformer { assignStatement = tstl.createAssignmentStatement(accessExpression, tmp); } // return ____TS_tmp - return this.createImmediatelyInvokedFunctionExpression([objAndIndexDeclaration, tmpDeclaration, assignStatement], tmp); + return this.createImmediatelyInvokedFunctionExpression( + [objAndIndexDeclaration, tmpDeclaration, assignStatement], + tmp, + lhs.parent + ); } else if (isPostfix) { // Postfix expressions need to cache original value in temp @@ -1550,7 +1557,7 @@ export class LuaTransformer { const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, left); const operatorExpression = tstl.createBinaryExpression(tmpIdentifier, right, replacementOperator); const assignStatement = this.transformAssignment(lhs, operatorExpression); - return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier); + return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier, lhs.parent); } else if (ts.isPropertyAccessExpression(lhs) || ts.isElementAccessExpression(lhs)) { // Simple property/element access expressions need to cache in temp to avoid double-evaluation @@ -1561,14 +1568,14 @@ export class LuaTransformer { const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, operatorExpression); const assignStatement = this.transformAssignment(lhs, tmpIdentifier); - return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier); + return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier, lhs.parent); } else { // Simple expressions // ${left} = ${right}; return ${right} const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); const assignStatement = this.transformAssignment(lhs, operatorExpression); - return this.createImmediatelyInvokedFunctionExpression([assignStatement], left); + return this.createImmediatelyInvokedFunctionExpression([assignStatement], left, lhs.parent); } } @@ -1692,7 +1699,7 @@ export class LuaTransformer { expression ); - return this.createImmediatelyInvokedFunctionExpression([assignment], []); + return this.createImmediatelyInvokedFunctionExpression([assignment], [tstl.createBooleanLiteral(true)], expression); } public transformFunctionExpression(node: ts.FunctionLikeDeclaration, context: tstl.Identifier | undefined): ExpressionVisitResult { @@ -1891,7 +1898,7 @@ export class LuaTransformer { const selfAssignment = this.createLocalOrGlobalDeclaration(selfIdentifier, context); const index = tstl.createTableIndexExpression(selfIdentifier, argument); const callExpression = tstl.createCallExpression(index, parameters); - return this.createImmediatelyInvokedFunctionExpression([selfAssignment], callExpression); + return this.createImmediatelyInvokedFunctionExpression([selfAssignment], callExpression, node); } else { return tstl.createCallExpression(this.transformExpression(node.expression), [context, ...parameters]); } @@ -2364,12 +2371,16 @@ export class LuaTransformer { this.luaLibFeatureSet.add(feature); } - public createImmediatelyInvokedFunctionExpression(statements: tstl.Statement[], result: tstl.Expression | tstl.Expression[]): - tstl.CallExpression { + public createImmediatelyInvokedFunctionExpression( + statements: tstl.Statement[], + result: tstl.Expression | tstl.Expression[], + tsOriginal: ts.Node + ): tstl.CallExpression + { const body = statements ? statements.slice(0) : []; body.push(tstl.createReturnStatement(Array.isArray(result) ? result : [result])); const iife = tstl.createFunctionExpression(tstl.createBlock(body)); - return tstl.createCallExpression(tstl.createParenthesizedExpression(iife)); + return tstl.createCallExpression(tstl.createParenthesizedExpression(iife), [], undefined, tsOriginal); } public createUnpackCall(expression: tstl.Expression): tstl.Expression { diff --git a/test/unit/array.spec.ts b/test/unit/array.spec.ts index 05da0f8b1..d72346314 100644 --- a/test/unit/array.spec.ts +++ b/test/unit/array.spec.ts @@ -70,4 +70,30 @@ export class ArrayTests { Expect(result).toBe("1,2,nil,4"); } + + @Test("Array delete return true") + public arrayDeleteReturnTrue(): void { + const lua = util.transpileString( + `const myarray = [1,2,3,4]; + const exists = delete myarray[2]; + return \`\${exists}:\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;` + ); + + const result = util.executeLua(lua); + + Expect(result).toBe("true:1,2,nil,4"); + } + + @Test("Array delete return false") + public arrayDeleteReturnFalse(): void { + const lua = util.transpileString( + `const myarray = [1,2,3,4]; + const exists = delete myarray[4]; + return \`\${exists}:\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;` + ); + + const result = util.executeLua(lua); + + Expect(result).toBe("true:1,2,3,4"); + } } diff --git a/tslint.json b/tslint.json index 02d094c1a..efe2e91ae 100644 --- a/tslint.json +++ b/tslint.json @@ -27,6 +27,7 @@ "jsdoc-format": true, "label-position": true, "max-classes-per-file": [true, 1], + "max-line-length": [true, 140], // TODO: Change this because Github does not handle 140 columns well "member-access": true, "new-parens": true, "no-angle-bracket-type-assertion": true, From 6fe7e86db3a8c635f92bb73af145d507b849c20b Mon Sep 17 00:00:00 2001 From: Perryvw Date: Fri, 11 Jan 2019 21:39:39 +0100 Subject: [PATCH 3/3] Delete statement shortcut --- src/LuaTransformer.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 2ae36e6a8..b6131715e 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1031,6 +1031,15 @@ export class LuaTransformer { ); } + else if (ts.isDeleteExpression(expression)) { + return tstl.createAssignmentStatement( + this.transformExpression(expression.expression) as tstl.IdentifierOrTableIndexExpression, + tstl.createNilLiteral(), + undefined, + expression + ); + } + return tstl.createExpressionStatement(this.transformExpression(expression)); }