From a0f8609d564519a1b816a002411a4483806eaa31 Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 2 Jan 2019 16:45:34 -0700 Subject: [PATCH 1/4] compound assignment expressions --- src/LuaPrinter.ts | 16 ++- src/LuaTransformer.ts | 247 ++++++++++++++++++++++++++++++++++++++++-- src/TSHelper.ts | 32 +++--- 3 files changed, 265 insertions(+), 30 deletions(-) diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 40d1ba4fa..dc536109f 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -1,5 +1,7 @@ import * as tstl from "./LuaAST"; +import {TSHelper as tsHelper} from "./TSHelper"; + export class LuaPrinter { /* tslint:disable:object-literal-sort-keys */ @@ -272,7 +274,7 @@ export class LuaPrinter { } private printFunctionExpression(expression: tstl.FunctionExpression): string { - const paramterArr: string[] = expression.params.map(i => this.printIdentifier(i)); + const paramterArr: string[] = expression.params ? expression.params.map(i => this.printIdentifier(i)) : []; if (expression.dots) { paramterArr.push(this.printDotsLiteral(expression.dots)); } @@ -290,7 +292,11 @@ export class LuaPrinter { const value = this.printExpression(expression.value); if (expression.key) { - return `[${this.printExpression(expression.key)}] = ${value}`; + if (tstl.isIdentifier(expression.key)) { + return `${this.printExpression(expression.key)} = ${value}`; + } else { + return `[${this.printExpression(expression.key)}] = ${value}`; + } } else { return value; } @@ -320,7 +326,7 @@ export class LuaPrinter { } private printCallExpression(expression: tstl.CallExpression): string { - const params = expression.params.map(e => this.printExpression(e)).join(", "); + const params = expression.params ? expression.params.map(e => this.printExpression(e)).join(", ") : ""; return `${this.printExpression(expression.expression)}(${params})`; } @@ -337,8 +343,8 @@ export class LuaPrinter { private printTableIndexExpression(expression: tstl.TableIndexExpression): string { const table = this.printExpression(expression.table); - if (tstl.isIdentifier(expression.index)) { - return `${table}.${this.printIdentifier(expression.index)}`; + if (tstl.isStringLiteral(expression.index) && tsHelper.isValidLuaIdentifier(expression.index.value)) { + return `${table}.${expression.index.value}`; } return `${table}[${this.printExpression(expression.index)}]`; } diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 1b2bb6c41..25daecf8a 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -171,10 +171,10 @@ export class LuaTransformer { statements: ts.Statement[] | ReadonlyArray): tstl.Statement[] { const tstlStatements = (statements as ts.Statement[]).map(statement => this.transformStatement(statement) as tstl.Statement); - + const flat = this.flat(tstlStatements); - // TODO this is somewhat hacky and not typesafe + // TODO this is somewhat hacky and not typesafe return flat; } @@ -928,6 +928,50 @@ export class LuaTransformer { } public transformExpressionStatement(statement: ts.ExpressionStatement): StatementVisitResult { + if (ts.isBinaryExpression(statement.expression)) { + // +=, -=, etc... + const [isCompound, replacementOperator] = tsHelper.isBinaryAssignmentToken( + statement.expression.operatorToken.kind + ); + if (isCompound) { + return this.transformCompoundAssignmentStatement( + statement.expression.left, + statement.expression.right, + replacementOperator, + false + ); + } + + } else if ( + ts.isPrefixUnaryExpression(statement.expression) + && ( + statement.expression.operator === ts.SyntaxKind.PlusPlusToken + || statement.expression.operator === ts.SyntaxKind.MinusMinusToken + ) + ) { + // ++i, --i + return this.transformCompoundAssignmentStatement( + statement.expression.operand, + ts.createLiteral(1), + statement.expression.operator === ts.SyntaxKind.PlusPlusToken + ? tstl.SyntaxKind.AdditionOperator + : tstl.SyntaxKind.SubractionOperator, + false + ); + } + + else if (ts.isPostfixUnaryExpression(statement.expression)) { + // i++, i-- + return this.transformCompoundAssignmentStatement( + statement.expression.operand, + ts.createLiteral(1), + statement.expression.operator === ts.SyntaxKind.PlusPlusToken + ? tstl.SyntaxKind.AdditionOperator + : tstl.SyntaxKind.SubractionOperator, + true + ); + } + return tstl.createExpressionStatement(this.transformExpression(statement.expression)); } @@ -1092,17 +1136,15 @@ export class LuaTransformer { public transformBinaryExpression(expression: ts.BinaryExpression): ExpressionVisitResult { // Check if this is an assignment token, then handle accordingly - // TODO NYI @tomb - /*const [isAssignment, operator] = tsHelper.isBinaryAssignmentToken(expression.operatorToken.kind); - if (isAssignment) { - return this.transpileAssignmentExpression( + const [isCompound, replacementOperator] = tsHelper.isBinaryAssignmentToken(expression.operatorToken.kind); + if (isCompound) { + return this.transformCompoundAssignmentExpression( expression.left, - operator, expression.right, - tsHelper.isExpressionStatement(expression), + replacementOperator, false ); - }*/ + } const lhs = this.transformExpression(expression.left); const rhs = this.transformExpression(expression.right); @@ -1174,6 +1216,143 @@ export class LuaTransformer { } } + public transformComplexCompoundAssignmentExpression( + objExpression: tstl.Expression, + indexExpression: tstl.Expression, + right: tstl.Expression, + replacementOperator: tstl.BinaryOperator, + isPostfix: boolean, + ): [tstl.Statement[], tstl.Expression] { + // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects + // local __TS_obj, __TS_index = ${objExpression}, ${indexExpression}; + const obj = tstl.createIdentifier("____TS_obj"); + const index = tstl.createIdentifier("____TS_index"); + const objAndIndexDeclaration = tstl.createVariableDeclarationStatement( + [obj, index], + [objExpression, indexExpression] + ); + const accessExpression = tstl.createTableIndexExpression(obj, index); + + const tmp = tstl.createIdentifier("____TS_tmp"); + right = tstl.createParenthesizedExpression(right); + let tmpDeclaration: tstl.VariableDeclarationStatement; + let assignStatement: tstl.VariableAssignmentStatement; + if (isPostfix) { + // local ____TS_tmp = ____TS_obj[____TS_index]; + // ____TS_obj[____TS_index] = ____TS_tmp ${replacementOperator} ____TS_obj[____TS_index]; + tmpDeclaration = tstl.createVariableDeclarationStatement(tmp, accessExpression); + const operatorExpression = tstl.createBinaryExpression(tmp, right, replacementOperator); + assignStatement = tstl.createVariableAssignmentStatement(accessExpression, operatorExpression); + } else { + // local ____TS_tmp = ____TS_obj[____TS_index] ${replacementOperator} ${right}; + // ____TS_obj[____TS_index] = ____TS_tmp; + const operatorExpression = tstl.createBinaryExpression(accessExpression, right, replacementOperator); + tmpDeclaration = tstl.createVariableDeclarationStatement(tmp, operatorExpression); + assignStatement = tstl.createVariableAssignmentStatement(accessExpression, tmp); + } + return [[objAndIndexDeclaration, tmpDeclaration, assignStatement], tmp]; + } + + public transformCompoundAssignmentExpression( + lhs: ts.Expression, + rhs: ts.Expression, + replacementOperator: tstl.BinaryOperator, + isPostfix: boolean + ): ExpressionVisitResult { + const left = this.transformExpression(lhs); + const right = this.transformExpression(rhs); + let statements: tstl.Statement[]; + let resultExpression: tstl.Expression; + + const [hasEffects, objExpression, indexExpression] = tsHelper.isAccessExpressionWithEvaluationEffects( + lhs, + this.checker + ); + if (hasEffects) { + [statements, resultExpression] = this.transformComplexCompoundAssignmentExpression( + this.transformExpression(objExpression), + this.transformExpression(indexExpression), + right, + replacementOperator, + isPostfix + ); + + } else if (isPostfix) { + // Postfix expressions need to cache original value in temp + // local ____TS_tmp = ${left}; + // ${left} = ____TS_tmp ${replacementOperator} ${right}; + // return ____TS_tmp + const tmpIdentifier = tstl.createIdentifier("____TS_tmp"); + const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, left); + const operatorExpression = tstl.createBinaryExpression(tmpIdentifier, right, replacementOperator); + const assignStatement = tstl.createBinaryExpression( + left, + operatorExpression, + tstl.SyntaxKind.AssignmentOperator + ); + statements = [tmpDeclaration, tstl.createExpressionStatement(assignStatement)]; + resultExpression = tmpIdentifier; + + } else if (ts.isPropertyAccessExpression(lhs) || ts.isElementAccessExpression(lhs)) { + // Simple property/element access expressions need to cache in temp to avoid double-evaluation + // local ____TS_tmp = ${left} ${replacementOperator} ${right}; + // ${left} = ____TS_tmp; + // return ____TS_tmp + const tmpIdentifier = tstl.createIdentifier("____TS_tmp"); + const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); + const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, operatorExpression); + const assignStatement = tstl.createBinaryExpression( + left, + tmpIdentifier, + tstl.SyntaxKind.AssignmentOperator + ); + statements = [tmpDeclaration, tstl.createExpressionStatement(assignStatement)]; + resultExpression = tmpIdentifier; + + } else { + // Simple statements/expressions + const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); + const assignStatement = tstl.createBinaryExpression(left, operatorExpression, tstl.SyntaxKind.AssignmentOperator); + statements = [tstl.createExpressionStatement(assignStatement)]; + resultExpression = left; + } + + statements.push(tstl.createReturnStatement([resultExpression])); + const lambda = tstl.createFunctionExpression(tstl.createBlock(statements)); + return tstl.createCallExpression(tstl.createParenthesizedExpression(lambda), []); + } + + public transformCompoundAssignmentStatement( + lhs: ts.Expression, + rhs: ts.Expression, + replacementOperator: tstl.BinaryOperator, + isPostfix: boolean + ): StatementVisitResult { + const left = this.transformExpression(lhs); + const right = this.transformExpression(rhs); + + const [hasEffects, objExpression, indexExpression] = tsHelper.isAccessExpressionWithEvaluationEffects( + lhs, + this.checker + ); + if (hasEffects) { + const [statements] = this.transformComplexCompoundAssignmentExpression( + this.transformExpression(objExpression), + this.transformExpression(indexExpression), + right, + replacementOperator, + isPostfix + ); + return tstl.createDoStatement(statements); + + } else { + // Simple statements + const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); + const assignStatement = tstl.createBinaryExpression(left, operatorExpression, tstl.SyntaxKind.AssignmentOperator); + return tstl.createExpressionStatement(assignStatement); + } + } + public transformBitOperation( node: ts.BinaryExpression, lhs: tstl.Expression, @@ -1194,11 +1373,55 @@ export class LuaTransformer { } public transformPostfixUnaryExpression(expression: ts.PostfixUnaryExpression): tstl.Expression { - throw new Error("Method not implemented."); + return this.transformCompoundAssignmentExpression( + expression.operand, + ts.createLiteral(1), + expression.operator === ts.SyntaxKind.PlusPlusToken + ? tstl.SyntaxKind.AdditionOperator + : tstl.SyntaxKind.SubractionOperator, + true + ); } public transformPrefixUnaryExpression(expression: ts.PrefixUnaryExpression): tstl.Expression { - throw new Error("Method not implemented."); + switch (expression.operator) { + case ts.SyntaxKind.PlusPlusToken: + return this.transformCompoundAssignmentExpression( + expression.operand, + ts.createLiteral(1), + tstl.SyntaxKind.AdditionOperator, + false + ); + + case ts.SyntaxKind.MinusMinusToken: + return this.transformCompoundAssignmentExpression( + expression.operand, + ts.createLiteral(1), + tstl.SyntaxKind.SubractionOperator, + false + ); + + case ts.SyntaxKind.PlusToken: + return this.transformExpression(expression.operand); + + case ts.SyntaxKind.MinusToken: + return tstl.createUnaryExpression( + this.transformExpression(expression.operand), + tstl.SyntaxKind.NegationOperator + ); + + case ts.SyntaxKind.ExclamationToken: + return tstl.createUnaryExpression( + this.transformExpression(expression.operand), + tstl.SyntaxKind.NotOperator + ); + + case ts.SyntaxKind.TildeToken: + return tstl.createUnaryExpression( + this.transformExpression(expression.operand), + tstl.SyntaxKind.BitwiseNotOperator + ); + } } public transformArrayLiteral(node: ts.ArrayLiteralExpression): ExpressionVisitResult { @@ -1596,7 +1819,7 @@ export class LuaTransformer { } const callPath = this.transformExpression(node.expression); - return tstl.createTableIndexExpression(callPath, tstl.createIdentifier(property), undefined, node); + return tstl.createTableIndexExpression(callPath, tstl.createStringLiteral(property), undefined, node); } public transformGetAccessor(node: ts.PropertyAccessExpression): ExpressionVisitResult { diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 8805b92e3..c265c7427 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -1,6 +1,7 @@ import * as ts from "typescript"; import { Decorator, DecoratorKind } from "./Decorator"; import { TSTLErrors } from "./Errors"; +import * as tstl from "./LuaAST"; export enum ContextType { None, @@ -269,32 +270,33 @@ export class TSHelper { return false; } - public static isBinaryAssignmentToken(token: ts.SyntaxKind): [boolean, ts.BinaryOperator] { + public static isBinaryAssignmentToken(token: ts.SyntaxKind): [boolean, tstl.BinaryOperator] { switch (token) { case ts.SyntaxKind.BarEqualsToken: - return [true, ts.SyntaxKind.BarToken]; + return [true, tstl.SyntaxKind.BitwiseOrOperator]; case ts.SyntaxKind.PlusEqualsToken: - return [true, ts.SyntaxKind.PlusToken]; + return [true, tstl.SyntaxKind.AdditionOperator]; case ts.SyntaxKind.CaretEqualsToken: - return [true, ts.SyntaxKind.CaretToken]; + return [true, tstl.SyntaxKind.BitwiseExclusiveOrOperator]; case ts.SyntaxKind.MinusEqualsToken: - return [true, ts.SyntaxKind.MinusToken]; + return [true, tstl.SyntaxKind.SubractionOperator]; case ts.SyntaxKind.SlashEqualsToken: - return [true, ts.SyntaxKind.SlashToken]; + return [true, tstl.SyntaxKind.DivisionOperator]; case ts.SyntaxKind.PercentEqualsToken: - return [true, ts.SyntaxKind.PercentToken]; + return [true, tstl.SyntaxKind.ModuloOperator]; case ts.SyntaxKind.AsteriskEqualsToken: - return [true, ts.SyntaxKind.AsteriskToken]; + return [true, tstl.SyntaxKind.MultiplicationOperator]; case ts.SyntaxKind.AmpersandEqualsToken: - return [true, ts.SyntaxKind.AmpersandToken]; + return [true, tstl.SyntaxKind.BitwiseAndOperator]; case ts.SyntaxKind.AsteriskAsteriskEqualsToken: - return [true, ts.SyntaxKind.AsteriskAsteriskToken]; + return [true, tstl.SyntaxKind.PowerOperator]; case ts.SyntaxKind.LessThanLessThanEqualsToken: - return [true, ts.SyntaxKind.LessThanLessThanToken]; + return [true, tstl.SyntaxKind.BitwiseLeftShiftOperator]; case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken: - return [true, ts.SyntaxKind.GreaterThanGreaterThanToken]; + return [true, tstl.SyntaxKind.BitwiseRightShiftOperator]; case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: - return [true, ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken]; + // return [true, ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken]; + throw new Error("Not yet implemented in lua AST"); //TODO } return [false, undefined]; @@ -496,4 +498,8 @@ export class TSHelper { } return text; } + + public static isValidLuaIdentifier(str: string): boolean { + return str.match(/[a-zA-Z_][a-zA-Z0-9_]*/) !== null; + } } From 120a486a7d74fe9aff090f61ffde6b73c1cf11fc Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 3 Jan 2019 14:22:24 -0700 Subject: [PATCH 2/4] assignment expressions and refactoring in compound assignments --- src/LuaAST.ts | 19 +-- src/LuaPrinter.ts | 7 +- src/LuaTransformer.ts | 332 ++++++++++++++++++++++++++---------------- 3 files changed, 218 insertions(+), 140 deletions(-) diff --git a/src/LuaAST.ts b/src/LuaAST.ts index 988270456..c57b45629 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -11,7 +11,7 @@ export enum SyntaxKind { // Statements DoStatement, VariableDeclarationStatement, - VariableAssignmentStatement, + AssignmentStatement, IfStatement, WhileStatement, RepeatStatement, @@ -40,8 +40,6 @@ export enum SyntaxKind { Identifier, TableIndexExpression, // Operators - AssignmentOperator, // TODO maybe remove this once we figure out the correct way to transform a assignment in a binary expression - // or maybe move change Assignment statement to contain a binaryExpression with an AssignmentOperator somehow? // Arithmetic AdditionOperator, // Maybe use abreviations for those add, sub, mul ... SubractionOperator, @@ -82,7 +80,6 @@ export type UnaryOperator = SyntaxKind.NegationOperator | SyntaxKind.LengthOpera SyntaxKind.NotOperator | SyntaxKind.BitwiseNotOperator; export type BinaryOperator = - SyntaxKind.AssignmentOperator | // TODO @see above // Arithmetic SyntaxKind.AdditionOperator | SyntaxKind.SubractionOperator | SyntaxKind.MultiplicationOperator | SyntaxKind.DivisionOperator | SyntaxKind.FloorDivisionOperator | @@ -214,24 +211,24 @@ export function createVariableDeclarationStatement( } // `test1, test2 = 12, 42` -export interface VariableAssignmentStatement extends Statement { - kind: SyntaxKind.VariableAssignmentStatement; +export interface AssignmentStatement extends Statement { + kind: SyntaxKind.AssignmentStatement; left: IdentifierOrTableIndexExpression[]; right: Expression[]; } -export function isVariableAssignmentStatement(node: Node): node is VariableAssignmentStatement { - return node.kind === SyntaxKind.VariableAssignmentStatement; +export function isAssignmentStatement(node: Node): node is AssignmentStatement { + return node.kind === SyntaxKind.AssignmentStatement; } -export function createVariableAssignmentStatement( +export function createAssignmentStatement( left: IdentifierOrTableIndexExpression | IdentifierOrTableIndexExpression[], right: Expression | Expression[], parent?: Node, - tsOriginal?: ts.Node): VariableAssignmentStatement { + tsOriginal?: ts.Node): AssignmentStatement { const statement = - createNode(SyntaxKind.VariableAssignmentStatement, parent, tsOriginal) as VariableAssignmentStatement; + createNode(SyntaxKind.AssignmentStatement, parent, tsOriginal) as AssignmentStatement; setParent(left, statement); if (Array.isArray(left)) { statement.left = left; diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index dc536109f..dd5bc3e6b 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -6,7 +6,6 @@ export class LuaPrinter { /* tslint:disable:object-literal-sort-keys */ private static operatorMap: {[key in tstl.Operator]: string} = { - [tstl.SyntaxKind.AssignmentOperator]: "=", [tstl.SyntaxKind.AdditionOperator]: "+", [tstl.SyntaxKind.SubractionOperator]: "-", [tstl.SyntaxKind.MultiplicationOperator]: "*", @@ -67,8 +66,8 @@ export class LuaPrinter { return this.printDoStatement(statement as tstl.DoStatement); case tstl.SyntaxKind.VariableDeclarationStatement: return this.printVariableDeclarationStatement(statement as tstl.VariableDeclarationStatement); - case tstl.SyntaxKind.VariableAssignmentStatement: - return this.printVariableAssignmentStatement(statement as tstl.VariableAssignmentStatement); + case tstl.SyntaxKind.AssignmentStatement: + return this.printVariableAssignmentStatement(statement as tstl.AssignmentStatement); case tstl.SyntaxKind.IfStatement: return this.printIfStatement(statement as tstl.IfStatement); case tstl.SyntaxKind.WhileStatement: @@ -111,7 +110,7 @@ export class LuaPrinter { } } - private printVariableAssignmentStatement(statement: tstl.VariableAssignmentStatement): string { + private printVariableAssignmentStatement(statement: tstl.AssignmentStatement): string { return this.indent(`${statement.left.map(e => this.printExpression(e)).join(", ")} = ` + `${statement.right.map(e => this.printExpression(e)).join(", ")};\n`); } diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 25daecf8a..b273d3cba 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -134,7 +134,7 @@ export class LuaTransformer { case ts.SyntaxKind.VariableStatement: return this.transformVariableStatement(node as ts.VariableStatement); case ts.SyntaxKind.ExpressionStatement: - return this.transformExpressionStatement(node as ts.ExpressionStatement); + return this.transformExpressionStatement((node as ts.ExpressionStatement).expression); case ts.SyntaxKind.ReturnStatement: return this.transformReturn(node as ts.ReturnStatement); case ts.SyntaxKind.IfStatement: @@ -339,7 +339,7 @@ export class LuaTransformer { const classField = tstl.createTableIndexExpression(className, fieldName); // className["fieldName"] = value; - const assignClassField = tstl.createVariableAssignmentStatement(classField, value); + const assignClassField = tstl.createAssignmentStatement(classField, value); result.push(assignClassField); } @@ -350,7 +350,7 @@ export class LuaTransformer { const fieldName = this.transformIdentifier(field.name as ts.Identifier); const value = this.transformExpression(field.initializer); - const fieldAssign = tstl.createVariableAssignmentStatement( + const fieldAssign = tstl.createAssignmentStatement( tstl.createTableIndexExpression(className, fieldName), value ); @@ -444,7 +444,7 @@ export class LuaTransformer { // className.__index const classIndex = tstl.createTableIndexExpression(className, tstl.createIdentifier("__index")); // className.__index = className - const assignClassIndex = tstl.createVariableAssignmentStatement(classIndex, className, undefined, statement); + const assignClassIndex = tstl.createAssignmentStatement(classIndex, className, undefined, statement); result.push(assignClassIndex); @@ -454,7 +454,7 @@ export class LuaTransformer { const classBase = tstl.createTableIndexExpression(className, tstl.createIdentifier("__base")); - const assignClassBase = tstl.createVariableAssignmentStatement(classBase, baseName, undefined, statement); + const assignClassBase = tstl.createAssignmentStatement(classBase, baseName, undefined, statement); result.push(assignClassBase); } @@ -483,7 +483,7 @@ export class LuaTransformer { const selfIndex = tstl.createTableIndexExpression(this.selfIdentifier, fieldName); // self[fieldName] = value - const assignClassField = tstl.createVariableAssignmentStatement(selfIndex, value); + const assignClassField = tstl.createAssignmentStatement(selfIndex, value); newFuncStatements.push(assignClassField); } @@ -517,7 +517,7 @@ export class LuaTransformer { newFuncStatements.push(returnSelf); // function className.new(construct, ...) ... end - const newFunc = tstl.createVariableAssignmentStatement( + const newFunc = tstl.createAssignmentStatement( tstl.createTableIndexExpression(className, tstl.createIdentifier("new")), tstl.createFunctionExpression( tstl.createBlock(newFuncStatements), @@ -535,7 +535,7 @@ export class LuaTransformer { } public transformConstructor( - statement: ts.ConstructorDeclaration, className: tstl.Identifier): tstl.VariableAssignmentStatement { + statement: ts.ConstructorDeclaration, className: tstl.Identifier): tstl.AssignmentStatement { // Don't transform methods without body (overload declarations) if (!statement.body) { @@ -556,7 +556,7 @@ export class LuaTransformer { if (declaration.initializer) { // self.declarationName = declarationName or initializer const assignement = - tstl.createVariableAssignmentStatement( + tstl.createAssignmentStatement( tstl.createTableIndexExpression( this.selfIdentifier, declarationName @@ -571,7 +571,7 @@ export class LuaTransformer { } else { // self.declarationName = declarationName const assignement = - tstl.createVariableAssignmentStatement( + tstl.createAssignmentStatement( tstl.createTableIndexExpression( this.selfIdentifier, declarationName @@ -592,7 +592,7 @@ export class LuaTransformer { const body: tstl.Block = tstl.createBlock(bodyStatements); const result = - tstl.createVariableAssignmentStatement( + tstl.createAssignmentStatement( tstl.createTableIndexExpression( className, tstl.createIdentifier("constructor") @@ -615,7 +615,7 @@ export class LuaTransformer { } public transformGetAccessorDeclaration( - getAccessor: ts.GetAccessorDeclaration, className: tstl.Identifier): tstl.VariableAssignmentStatement { + getAccessor: ts.GetAccessorDeclaration, className: tstl.Identifier): tstl.AssignmentStatement { const name = this.transformIdentifier(getAccessor.name as ts.Identifier); @@ -625,7 +625,7 @@ export class LuaTransformer { [this.selfIdentifier] ); - return tstl.createVariableAssignmentStatement( + return tstl.createAssignmentStatement( tstl.createTableIndexExpression(className, tstl.createIdentifier("get__" + name.text)), accessorFunction ); @@ -633,7 +633,7 @@ export class LuaTransformer { } public transformSetAccessorDeclaration( - setAccessor: ts.SetAccessorDeclaration, className: tstl.Identifier): tstl.VariableAssignmentStatement { + setAccessor: ts.SetAccessorDeclaration, className: tstl.Identifier): tstl.AssignmentStatement { const name = this.transformIdentifier(setAccessor.name as ts.Identifier); @@ -647,14 +647,14 @@ export class LuaTransformer { restParam ); - return tstl.createVariableAssignmentStatement( + return tstl.createAssignmentStatement( tstl.createTableIndexExpression(className, tstl.createIdentifier("set__" + name.text)), accessorFunction ); } public transformMethodDeclaration( - node: ts.MethodDeclaration, className: tstl.Identifier): tstl.VariableAssignmentStatement { + node: ts.MethodDeclaration, className: tstl.Identifier): tstl.AssignmentStatement { // Don't transform methods without body (overload declarations) if (!node.body) { @@ -679,7 +679,7 @@ export class LuaTransformer { restParamName ); - return tstl.createVariableAssignmentStatement( + return tstl.createAssignmentStatement( tstl.createTableIndexExpression(className, methodName), functionExpression ); @@ -751,7 +751,7 @@ export class LuaTransformer { const parameterName = this.transformIdentifier(declaration.name as ts.Identifier); const parameterValue = this.transformExpression(declaration.initializer); - const assignment = tstl.createVariableAssignmentStatement(parameterName, parameterValue); + const assignment = tstl.createAssignmentStatement(parameterName, parameterValue); const nilCondition = tstl.createBinaryExpression( parameterName, @@ -798,7 +798,7 @@ export class LuaTransformer { } else { const table = this.transformIdentifier(enumDeclaration.name); const property = tstl.createTableIndexExpression(table, enumMember.name, undefined); - result.push(tstl.createVariableAssignmentStatement( + result.push(tstl.createAssignmentStatement( property, enumMember.value, undefined, @@ -889,7 +889,7 @@ export class LuaTransformer { // Separate declaration and assignment for functions to allow recursion // local identifierName; identifierName = value; - return [tstl.createVariableDeclarationStatement(identifierName), tstl.createVariableAssignmentStatement(identifierName, value)]; + return [tstl.createVariableDeclarationStatement(identifierName), tstl.createAssignmentStatement(identifierName, value)]; } else { // local identifierName = value; return tstl.createVariableDeclarationStatement(identifierName, value); @@ -914,7 +914,7 @@ export class LuaTransformer { return tstl.createVariableDeclarationStatement(vars, this.transformExpression(statement.initializer)); } else { // local vars = this.transpileDestructingAssignmentValue(node.initializer); - return tstl.createVariableDeclarationStatement(vars, this.createDestructingDestructingAssignmentValue(statement.initializer)); + return tstl.createVariableDeclarationStatement(vars, this.createUnpackCall(statement.initializer)); } } else { throw TSTLErrors.UnsupportedKind("variable declaration", statement.name.kind, statement); @@ -927,52 +927,53 @@ export class LuaTransformer { ); } - public transformExpressionStatement(statement: ts.ExpressionStatement): StatementVisitResult { - if (ts.isBinaryExpression(statement.expression)) { - // +=, -=, etc... + public transformExpressionStatement(expression: ts.Expression): StatementVisitResult { + if (ts.isBinaryExpression(expression)) { const [isCompound, replacementOperator] = tsHelper.isBinaryAssignmentToken( - statement.expression.operatorToken.kind + expression.operatorToken.kind ); if (isCompound) { + // +=, -=, etc... return this.transformCompoundAssignmentStatement( - statement.expression.left, - statement.expression.right, - replacementOperator, - false + expression.left, + expression.right, + replacementOperator ); + + } else if (expression.operatorToken.kind === ts.SyntaxKind.EqualsToken) { + // = assignment + return this.transformAssignmentStatement(expression); } } else if ( - ts.isPrefixUnaryExpression(statement.expression) + ts.isPrefixUnaryExpression(expression) && ( - statement.expression.operator === ts.SyntaxKind.PlusPlusToken - || statement.expression.operator === ts.SyntaxKind.MinusMinusToken + expression.operator === ts.SyntaxKind.PlusPlusToken + || expression.operator === ts.SyntaxKind.MinusMinusToken ) ) { // ++i, --i return this.transformCompoundAssignmentStatement( - statement.expression.operand, + expression.operand, ts.createLiteral(1), - statement.expression.operator === ts.SyntaxKind.PlusPlusToken + expression.operator === ts.SyntaxKind.PlusPlusToken ? tstl.SyntaxKind.AdditionOperator - : tstl.SyntaxKind.SubractionOperator, - false + : tstl.SyntaxKind.SubractionOperator ); } - else if (ts.isPostfixUnaryExpression(statement.expression)) { + else if (ts.isPostfixUnaryExpression(expression)) { // i++, i-- return this.transformCompoundAssignmentStatement( - statement.expression.operand, + expression.operand, ts.createLiteral(1), - statement.expression.operator === ts.SyntaxKind.PlusPlusToken + expression.operator === ts.SyntaxKind.PlusPlusToken ? tstl.SyntaxKind.AdditionOperator - : tstl.SyntaxKind.SubractionOperator, - true + : tstl.SyntaxKind.SubractionOperator ); } - return tstl.createExpressionStatement(this.transformExpression(statement.expression)); + return tstl.createExpressionStatement(this.transformExpression(expression)); } public transformReturn(statement: ts.ReturnStatement): StatementVisitResult { @@ -989,7 +990,7 @@ export class LuaTransformer { return tstl.createReturnStatement(statement.expression.elements.map(elem => this.transformExpression(elem))); } else if (!tsHelper.isTupleReturnCall(statement.expression, this.checker)) { // If return expression is not another TupleReturn call, unpack it - return tstl.createReturnStatement([this.createDestructingDestructingAssignmentValue(statement.expression)]); + return tstl.createReturnStatement([this.createUnpackCall(statement.expression)]); } } return tstl.createReturnStatement([this.transformExpression(statement.expression)]); @@ -1012,6 +1013,8 @@ export class LuaTransformer { } public transformForStatement(arg0: ts.ForStatement): StatementVisitResult { + // NOTE : When implementing, make sure incrementor is transformed with transformExpressionStatement + // to ensure it is not wrapped in an iife. throw new Error("Method not implemented."); } @@ -1194,8 +1197,7 @@ export class LuaTransformer { case ts.SyntaxKind.LessThanEqualsToken: return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.LessEqualOperator); case ts.SyntaxKind.EqualsToken: - // TODO rework this @see tstl.SyntaxKind.AssignmentOperator declaration - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.AssignmentOperator); + return this.transformAssignmentExpression(expression); case ts.SyntaxKind.EqualsEqualsToken: case ts.SyntaxKind.EqualsEqualsEqualsToken: return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.EqualityOperator); @@ -1216,41 +1218,94 @@ export class LuaTransformer { } } - public transformComplexCompoundAssignmentExpression( - objExpression: tstl.Expression, - indexExpression: tstl.Expression, - right: tstl.Expression, - replacementOperator: tstl.BinaryOperator, - isPostfix: boolean, - ): [tstl.Statement[], tstl.Expression] { - // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects - // local __TS_obj, __TS_index = ${objExpression}, ${indexExpression}; - const obj = tstl.createIdentifier("____TS_obj"); - const index = tstl.createIdentifier("____TS_index"); - const objAndIndexDeclaration = tstl.createVariableDeclarationStatement( - [obj, index], - [objExpression, indexExpression] - ); - const accessExpression = tstl.createTableIndexExpression(obj, index); - - const tmp = tstl.createIdentifier("____TS_tmp"); - right = tstl.createParenthesizedExpression(right); - let tmpDeclaration: tstl.VariableDeclarationStatement; - let assignStatement: tstl.VariableAssignmentStatement; - if (isPostfix) { - // local ____TS_tmp = ____TS_obj[____TS_index]; - // ____TS_obj[____TS_index] = ____TS_tmp ${replacementOperator} ____TS_obj[____TS_index]; - tmpDeclaration = tstl.createVariableDeclarationStatement(tmp, accessExpression); - const operatorExpression = tstl.createBinaryExpression(tmp, right, replacementOperator); - assignStatement = tstl.createVariableAssignmentStatement(accessExpression, operatorExpression); + public transformAssignmentStatement(expression: ts.BinaryExpression): tstl.Statement { + if (ts.isArrayLiteralExpression(expression.left)) { + // Destructuring assignment + const left = expression.left.elements.map(e => this.transformExpression(e)); + let right: tstl.Expression[]; + if (ts.isArrayLiteralExpression(expression.right)) { + right = expression.right.elements.map(e => this.transformExpression(e)); + } else if (tsHelper.isTupleReturnCall(expression.right, this.checker)) { + right = [this.transformExpression(expression.right)]; + } else { + right = [this.createUnpackCall(expression.right)]; + } + return tstl.createAssignmentStatement(left as tstl.IdentifierOrTableIndexExpression[], right); + } else { + // Simple assignment + return tstl.createAssignmentStatement( + this.transformExpression(expression.left) as tstl.IdentifierOrTableIndexExpression, + this.transformExpression(expression.right) + ); + } + } + + public transformAssignmentExpression(expression: ts.BinaryExpression): ExpressionVisitResult { + if (ts.isArrayLiteralExpression(expression.left)) { + // Destructuring assignment + // (function() local ${tmps} = ${right}; ${left} = ${tmps}; return {${tmps}} end)() + const left = expression.left.elements.map(e => this.transformExpression(e)); + let right: tstl.Expression[]; + if (ts.isArrayLiteralExpression(expression.right)) { + right = expression.right.elements.map(e => this.transformExpression(e)); + } else if (tsHelper.isTupleReturnCall(expression.right, this.checker)) { + right = [this.transformExpression(expression.right)]; + } else { + right = [this.createUnpackCall(expression.right)]; + } + const tmps = expression.left.elements.map((_, i) => tstl.createIdentifier(`____TS_tmp${i}`)); + const statements: tstl.Statement[] = [ + tstl.createVariableDeclarationStatement(tmps, right), + tstl.createAssignmentStatement(left as tstl.IdentifierOrTableIndexExpression[], tmps), + ]; + return this.createImmediatelyInvokedFunctionExpression( + statements, + tstl.createTableExpression(tmps.map(t => tstl.createTableFieldExpression(t))) + ); + } + + if (ts.isPropertyAccessExpression(expression.left) || ts.isElementAccessExpression(expression.left)) { + // Left is property/element access: cache result while maintaining order of evaluation + // (function(o, i, v) o[i] = v; return v end)(${objExpression}, ${indexExpression}, ${right}) + const objParameter = tstl.createIdentifier("o"); + const indexParameter = tstl.createIdentifier("i"); + const valueParameter = tstl.createIdentifier("v"); + const indexStatement = tstl.createTableIndexExpression(objParameter, indexParameter); + const statements: tstl.Statement[] = [ + tstl.createAssignmentStatement(indexStatement, valueParameter), + tstl.createReturnStatement([valueParameter]), + ]; + const iife = tstl.createFunctionExpression( + tstl.createBlock(statements), + [objParameter, indexParameter, valueParameter] + ); + const objExpression = this.transformExpression(expression.left.expression); + let indexExpression: tstl.Expression; + if (ts.isPropertyAccessExpression(expression.left)) { + // Property access + indexExpression = tstl.createStringLiteral(expression.left.name.text); + } else { + // Element access + indexExpression = this.transformExpression(expression.left.argumentExpression); + const argType = this.checker.getTypeAtLocation(expression.left.expression); + if (tsHelper.isArrayType(argType, this.checker)) { + // Array access needs a +1 + indexExpression = this.expressionPlusOne(indexExpression); + } + } + const args = [objExpression, indexExpression, this.transformExpression(expression.right)]; + return tstl.createCallExpression(tstl.createParenthesizedExpression(iife), args); + } else { - // local ____TS_tmp = ____TS_obj[____TS_index] ${replacementOperator} ${right}; - // ____TS_obj[____TS_index] = ____TS_tmp; - const operatorExpression = tstl.createBinaryExpression(accessExpression, right, replacementOperator); - tmpDeclaration = tstl.createVariableDeclarationStatement(tmp, operatorExpression); - assignStatement = tstl.createVariableAssignmentStatement(accessExpression, tmp); + // Simple assignment + // (function() ${left} = ${right}; return ${left} end)() + const left = this.transformExpression(expression.left); + const right = this.transformExpression(expression.right); + return this.createImmediatelyInvokedFunctionExpression( + [tstl.createAssignmentStatement(left as tstl.IdentifierOrTableIndexExpression, right)], + left + ); } - return [[objAndIndexDeclaration, tmpDeclaration, assignStatement], tmp]; } public transformCompoundAssignmentExpression( @@ -1259,22 +1314,45 @@ export class LuaTransformer { replacementOperator: tstl.BinaryOperator, isPostfix: boolean ): ExpressionVisitResult { - const left = this.transformExpression(lhs); - const right = this.transformExpression(rhs); - let statements: tstl.Statement[]; - let resultExpression: tstl.Expression; + const left = this.transformExpression(lhs) as tstl.IdentifierOrTableIndexExpression; + let right = this.transformExpression(rhs); const [hasEffects, objExpression, indexExpression] = tsHelper.isAccessExpressionWithEvaluationEffects( lhs, this.checker ); if (hasEffects) { - [statements, resultExpression] = this.transformComplexCompoundAssignmentExpression( - this.transformExpression(objExpression), - this.transformExpression(indexExpression), - right, - replacementOperator, - isPostfix + // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects + // local __TS_obj, __TS_index = ${objExpression}, ${indexExpression}; + const obj = tstl.createIdentifier("____TS_obj"); + const index = tstl.createIdentifier("____TS_index"); + const objAndIndexDeclaration = tstl.createVariableDeclarationStatement( + [obj, index], + [this.transformExpression(objExpression), this.transformExpression(indexExpression)] + ); + const accessExpression = tstl.createTableIndexExpression(obj, index); + + const tmp = tstl.createIdentifier("____TS_tmp"); + right = tstl.createParenthesizedExpression(right); + let tmpDeclaration: tstl.VariableDeclarationStatement; + let assignStatement: tstl.AssignmentStatement; + if (isPostfix) { + // local ____TS_tmp = ____TS_obj[____TS_index]; + // ____TS_obj[____TS_index] = ____TS_tmp ${replacementOperator} ${right}; + tmpDeclaration = tstl.createVariableDeclarationStatement(tmp, accessExpression); + const operatorExpression = tstl.createBinaryExpression(tmp, right, replacementOperator); + assignStatement = tstl.createAssignmentStatement(accessExpression, operatorExpression); + } else { + // local ____TS_tmp = ____TS_obj[____TS_index] ${replacementOperator} ${right}; + // ____TS_obj[____TS_index] = ____TS_tmp; + const operatorExpression = tstl.createBinaryExpression(accessExpression, right, replacementOperator); + tmpDeclaration = tstl.createVariableDeclarationStatement(tmp, operatorExpression); + assignStatement = tstl.createAssignmentStatement(accessExpression, tmp); + } + // return ____TS_tmp + return this.createImmediatelyInvokedFunctionExpression( + [objAndIndexDeclaration, tmpDeclaration, assignStatement], + tmp ); } else if (isPostfix) { @@ -1285,13 +1363,8 @@ export class LuaTransformer { const tmpIdentifier = tstl.createIdentifier("____TS_tmp"); const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, left); const operatorExpression = tstl.createBinaryExpression(tmpIdentifier, right, replacementOperator); - const assignStatement = tstl.createBinaryExpression( - left, - operatorExpression, - tstl.SyntaxKind.AssignmentOperator - ); - statements = [tmpDeclaration, tstl.createExpressionStatement(assignStatement)]; - resultExpression = tmpIdentifier; + const assignStatement = tstl.createAssignmentStatement(left, operatorExpression); + return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier); } else if (ts.isPropertyAccessExpression(lhs) || ts.isElementAccessExpression(lhs)) { // Simple property/element access expressions need to cache in temp to avoid double-evaluation @@ -1301,34 +1374,24 @@ export class LuaTransformer { const tmpIdentifier = tstl.createIdentifier("____TS_tmp"); const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, operatorExpression); - const assignStatement = tstl.createBinaryExpression( - left, - tmpIdentifier, - tstl.SyntaxKind.AssignmentOperator - ); - statements = [tmpDeclaration, tstl.createExpressionStatement(assignStatement)]; - resultExpression = tmpIdentifier; + const assignStatement = tstl.createAssignmentStatement(left, tmpIdentifier); + return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier); } else { - // Simple statements/expressions + // Simple expressions + // ${left} = ${right}; return ${right} const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); - const assignStatement = tstl.createBinaryExpression(left, operatorExpression, tstl.SyntaxKind.AssignmentOperator); - statements = [tstl.createExpressionStatement(assignStatement)]; - resultExpression = left; + const assignStatement = tstl.createAssignmentStatement(left, operatorExpression); + return this.createImmediatelyInvokedFunctionExpression([assignStatement], left); } - - statements.push(tstl.createReturnStatement([resultExpression])); - const lambda = tstl.createFunctionExpression(tstl.createBlock(statements)); - return tstl.createCallExpression(tstl.createParenthesizedExpression(lambda), []); } public transformCompoundAssignmentStatement( lhs: ts.Expression, rhs: ts.Expression, - replacementOperator: tstl.BinaryOperator, - isPostfix: boolean + replacementOperator: tstl.BinaryOperator ): StatementVisitResult { - const left = this.transformExpression(lhs); + const left = this.transformExpression(lhs) as tstl.IdentifierOrTableIndexExpression; const right = this.transformExpression(rhs); const [hasEffects, objExpression, indexExpression] = tsHelper.isAccessExpressionWithEvaluationEffects( @@ -1336,20 +1399,29 @@ export class LuaTransformer { this.checker ); if (hasEffects) { - const [statements] = this.transformComplexCompoundAssignmentExpression( - this.transformExpression(objExpression), - this.transformExpression(indexExpression), - right, - replacementOperator, - isPostfix + // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects + // local __TS_obj, __TS_index = ${objExpression}, ${indexExpression}; + // ____TS_obj[____TS_index] = ____TS_obj[____TS_index] ${replacementOperator} ${right}; + const obj = tstl.createIdentifier("____TS_obj"); + const index = tstl.createIdentifier("____TS_index"); + const objAndIndexDeclaration = tstl.createVariableDeclarationStatement( + [obj, index], + [this.transformExpression(objExpression), this.transformExpression(indexExpression)] + ); + const accessExpression = tstl.createTableIndexExpression(obj, index); + const operatorExpression = tstl.createBinaryExpression( + accessExpression, + tstl.createParenthesizedExpression(right), + replacementOperator ); - return tstl.createDoStatement(statements); + const assignStatement = tstl.createAssignmentStatement(accessExpression, operatorExpression); + return tstl.createDoStatement([objAndIndexDeclaration, assignStatement]); } else { // Simple statements + // ${left} = ${left} ${replacementOperator} ${right} const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); - const assignStatement = tstl.createBinaryExpression(left, operatorExpression, tstl.SyntaxKind.AssignmentOperator); - return tstl.createExpressionStatement(assignStatement); + return tstl.createAssignmentStatement(left, operatorExpression); } } @@ -2165,11 +2237,21 @@ export class LuaTransformer { this.luaLibFeatureSet.add(feature); } - public createDestructingDestructingAssignmentValue(expression: ts.Expression): tstl.Expression { + public createImmediatelyInvokedFunctionExpression( + statements: tstl.Statement[], + result: tstl.Expression | tstl.Expression[] + ): 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)); + } + + public createUnpackCall(expression: ts.Expression): tstl.Expression { return tstl.createCallExpression( tstl.createTableIndexExpression( tstl.createIdentifier("table"), - tstl.createIdentifier("unpack") + tstl.createStringLiteral("unpack") ), [this.transformExpression(expression)] ); @@ -2206,7 +2288,7 @@ export class LuaTransformer { if (this.isModule || this.currentNamespace) { return tstl.createVariableDeclarationStatement(lhs, rhs, parent, tsOriginal); } else { - return tstl.createVariableAssignmentStatement(lhs, rhs, parent, tsOriginal); + return tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal); } } From 1ea074f478dad039a548cd3cb688b6e487d2afda Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 3 Jan 2019 15:55:37 -0700 Subject: [PATCH 3/4] fixed table index expressions that were being given identifiers instead of string literals --- src/LuaTransformer.ts | 44 ++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 0aeeda021..ca907926d 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -198,15 +198,17 @@ export class LuaTransformer { filteredElements.forEach(importSpecifier => { if (importSpecifier.propertyName) { - const propertyName = this.transformIdentifier(importSpecifier.propertyName); + const propertyIdentifier = this.transformIdentifier(importSpecifier.propertyName); + const propertyName = tstl.createStringLiteral(propertyIdentifier.text); const renamedImport = tstl.createVariableDeclarationStatement( this.transformIdentifier(importSpecifier.name), tstl.createTableIndexExpression(importUniqueName, propertyName), undefined, importSpecifier); result.push(renamedImport); } else { - const name = this.transformIdentifier(importSpecifier.name); + const nameIdentifier = this.transformIdentifier(importSpecifier.name); + const name = tstl.createStringLiteral(nameIdentifier.text); const namedImport = tstl.createVariableDeclarationStatement( - name, + nameIdentifier, tstl.createTableIndexExpression(importUniqueName, name), undefined, importSpecifier); result.push(namedImport); } @@ -265,8 +267,8 @@ export class LuaTransformer { throw TSTLErrors.MissingMetaExtension(statement); } - const extendsName = tstl.createIdentifier(extendsType.symbol.escapedName as string); - className = tstl.createIdentifier("__meta__" + extendsName.text); + const extendsName = tstl.createStringLiteral(extendsType.symbol.escapedName as string); + className = tstl.createIdentifier("__meta__" + extendsName.value); // local className = debug.getregistry()["extendsName"] const assignDebugCallIndex = @@ -276,7 +278,7 @@ export class LuaTransformer { tstl.createCallExpression( tstl.createTableIndexExpression( tstl.createIdentifier("debug"), - tstl.createIdentifier("getregistry") + tstl.createStringLiteral("getregistry") ), [] ), @@ -381,7 +383,7 @@ export class LuaTransformer { // baseName.new const newIndex = - tstl.createTableIndexExpression(baseName, tstl.createIdentifier("new")); + tstl.createTableIndexExpression(baseName, tstl.createStringLiteral("new")); // baseName.new() let rhs: tstl.Expression = tstl.createCallExpression(newIndex, []); @@ -415,7 +417,7 @@ export class LuaTransformer { } // className.__index - const classIndex = tstl.createTableIndexExpression(className, tstl.createIdentifier("__index")); + const classIndex = tstl.createTableIndexExpression(className, tstl.createStringLiteral("__index")); // className.__index = className const assignClassIndex = tstl.createAssignmentStatement(classIndex, className, undefined, statement); @@ -425,7 +427,7 @@ export class LuaTransformer { const baseName = tstl.createIdentifier(extendsType.symbol.escapedName as string); // className.__base = baseName const classBase = - tstl.createTableIndexExpression(className, tstl.createIdentifier("__base")); + tstl.createTableIndexExpression(className, tstl.createStringLiteral("__base")); const assignClassBase = tstl.createAssignmentStatement(classBase, baseName, undefined, statement); @@ -468,13 +470,13 @@ export class LuaTransformer { const ifConstructor = tstl.createIfStatement( tstl.createBinaryExpression( tstl.createIdentifier("construct"), - tstl.createTableIndexExpression(className, tstl.createIdentifier("constructor")), + tstl.createTableIndexExpression(className, tstl.createStringLiteral("constructor")), tstl.SyntaxKind.AndOperator ), tstl.createBlock([ tstl.createExpressionStatement( tstl.createCallExpression( - tstl.createTableIndexExpression(className, tstl.createIdentifier("constructor")), + tstl.createTableIndexExpression(className, tstl.createStringLiteral("constructor")), [this.selfIdentifier, tstl.createDotsLiteral()] ) ), @@ -490,7 +492,7 @@ export class LuaTransformer { // function className.new(construct, ...) ... end const newFunc = tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, tstl.createIdentifier("new")), + tstl.createTableIndexExpression(className, tstl.createStringLiteral("new")), tstl.createFunctionExpression( tstl.createBlock(newFuncStatements), [tstl.createIdentifier("construct")], @@ -531,7 +533,7 @@ export class LuaTransformer { tstl.createAssignmentStatement( tstl.createTableIndexExpression( this.selfIdentifier, - declarationName + tstl.createStringLiteral(declarationName.text) ), tstl.createBinaryExpression( declarationName, @@ -546,7 +548,7 @@ export class LuaTransformer { tstl.createAssignmentStatement( tstl.createTableIndexExpression( this.selfIdentifier, - declarationName + tstl.createStringLiteral(declarationName.text) ), declarationName ); @@ -567,7 +569,7 @@ export class LuaTransformer { tstl.createAssignmentStatement( tstl.createTableIndexExpression( className, - tstl.createIdentifier("constructor") + tstl.createStringLiteral("constructor") ), tstl.createFunctionExpression( body, @@ -598,7 +600,7 @@ export class LuaTransformer { ); return tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, tstl.createIdentifier("get__" + name.text)), + tstl.createTableIndexExpression(className, tstl.createStringLiteral("get__" + name.text)), accessorFunction ); @@ -620,7 +622,7 @@ export class LuaTransformer { ); return tstl.createAssignmentStatement( - tstl.createTableIndexExpression(className, tstl.createIdentifier("set__" + name.text)), + tstl.createTableIndexExpression(className, tstl.createStringLiteral("set__" + name.text)), accessorFunction ); } @@ -1702,8 +1704,8 @@ export class LuaTransformer { 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.createIdentifier("__base"); - const constructorIdentifier = tstl.createIdentifier("constructor"); + const baseIdentifier = tstl.createStringLiteral("__base"); + const constructorIdentifier = tstl.createStringLiteral("constructor"); return tstl.createCallExpression( tstl.createTableIndexExpression( @@ -2012,7 +2014,7 @@ export class LuaTransformer { }; if (translation[identifier.escapedText as string]) { - const property = tstl.createIdentifier(translation[identifier.escapedText as string]); + const property = tstl.createStringLiteral(translation[identifier.escapedText as string]); const math = tstl.createIdentifier("math"); return tstl.createTableIndexExpression(math, property, undefined, identifier); } else { @@ -2288,7 +2290,7 @@ export class LuaTransformer { const value = +propertyName.text; return tstl.createNumericLiteral(value, undefined, propertyName); } else { - return this.transformIdentifier(propertyName); + return tstl.createStringLiteral(this.transformIdentifier(propertyName).text); } } From 4885011df74b6b374909f9445f67897638d23bab Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 4 Jan 2019 06:23:23 -0700 Subject: [PATCH 4/4] moved ternaries out of parameters and changed transformExpressionStatement to take a ts.ExpressionStatement|ts.Expression --- src/LuaTransformer.ts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index ca907926d..f32a61b71 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -109,7 +109,7 @@ export class LuaTransformer { case ts.SyntaxKind.VariableStatement: return this.transformVariableStatement(node as ts.VariableStatement); case ts.SyntaxKind.ExpressionStatement: - return this.transformExpressionStatement((node as ts.ExpressionStatement).expression); + return this.transformExpressionStatement(node as ts.ExpressionStatement); case ts.SyntaxKind.ReturnStatement: return this.transformReturn(node as ts.ReturnStatement); case ts.SyntaxKind.IfStatement: @@ -913,7 +913,8 @@ export class LuaTransformer { ); } - public transformExpressionStatement(expression: ts.Expression): StatementVisitResult { + public transformExpressionStatement(statement: ts.ExpressionStatement | ts.Expression): StatementVisitResult { + const expression = ts.isExpressionStatement(statement) ? statement.expression : statement; if (ts.isBinaryExpression(expression)) { const [isCompound, replacementOperator] = tsHelper.isBinaryAssignmentToken( expression.operatorToken.kind @@ -939,23 +940,25 @@ export class LuaTransformer { ) ) { // ++i, --i + const replacementOperator = expression.operator === ts.SyntaxKind.PlusPlusToken + ? tstl.SyntaxKind.AdditionOperator + : tstl.SyntaxKind.SubractionOperator; return this.transformCompoundAssignmentStatement( expression.operand, ts.createLiteral(1), - expression.operator === ts.SyntaxKind.PlusPlusToken - ? tstl.SyntaxKind.AdditionOperator - : tstl.SyntaxKind.SubractionOperator + replacementOperator ); } else if (ts.isPostfixUnaryExpression(expression)) { // i++, i-- + const replacementOperator = expression.operator === ts.SyntaxKind.PlusPlusToken + ? tstl.SyntaxKind.AdditionOperator + : tstl.SyntaxKind.SubractionOperator; return this.transformCompoundAssignmentStatement( expression.operand, ts.createLiteral(1), - expression.operator === ts.SyntaxKind.PlusPlusToken - ? tstl.SyntaxKind.AdditionOperator - : tstl.SyntaxKind.SubractionOperator + replacementOperator ); } @@ -1520,12 +1523,13 @@ export class LuaTransformer { } public transformPostfixUnaryExpression(expression: ts.PostfixUnaryExpression): tstl.Expression { + const replacementOperator = expression.operator === ts.SyntaxKind.PlusPlusToken + ? tstl.SyntaxKind.AdditionOperator + : tstl.SyntaxKind.SubractionOperator; return this.transformCompoundAssignmentExpression( expression.operand, ts.createLiteral(1), - expression.operator === ts.SyntaxKind.PlusPlusToken - ? tstl.SyntaxKind.AdditionOperator - : tstl.SyntaxKind.SubractionOperator, + replacementOperator, true ); }