From 76b6c22f6a06210d4f5638fcab4ebbe628c50892 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Thu, 10 Jan 2019 07:19:29 -0700 Subject: [PATCH 1/4] properly handling bitwise operators and passing original nodes in some places it wasn't being passed --- src/LuaAST.ts | 12 ++- src/LuaPrinter.ts | 146 ++++++++++++++++++++------- src/LuaTransformer.ts | 162 +++++++++++++++++++++--------- src/TSHelper.ts | 3 +- src/targets/LuaTransformer.52.ts | 47 ++++----- src/targets/LuaTransformer.53.ts | 44 +++----- src/targets/LuaTransformer.JIT.ts | 20 ---- test/unit/expressions.spec.ts | 58 +++++------ 8 files changed, 291 insertions(+), 201 deletions(-) diff --git a/src/LuaAST.ts b/src/LuaAST.ts index 5085b2865..de823e9eb 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -71,20 +71,26 @@ export enum SyntaxKind { BitwiseOrOperator, BitwiseExclusiveOrOperator, BitwiseRightShiftOperator, + BitwiseArithmaticRightShift, BitwiseLeftShiftOperator, BitwiseNotOperator, // Unary } // 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 UnaryBitwiseOperator = SyntaxKind.BitwiseNotOperator; + +export type UnaryOperator = SyntaxKind.NegationOperator | SyntaxKind.LengthOperator | SyntaxKind.NotOperator | UnaryBitwiseOperator; + +export type BinaryBitwiseOperator = + SyntaxKind.BitwiseAndOperator | SyntaxKind.BitwiseOrOperator | SyntaxKind.BitwiseExclusiveOrOperator | + SyntaxKind.BitwiseRightShiftOperator | SyntaxKind.BitwiseArithmaticRightShift | SyntaxKind.BitwiseLeftShiftOperator; export type BinaryOperator = SyntaxKind.AdditionOperator | SyntaxKind.SubractionOperator | SyntaxKind.MultiplicationOperator | SyntaxKind.DivisionOperator | SyntaxKind.FloorDivisionOperator | SyntaxKind.ModuloOperator | SyntaxKind.PowerOperator | SyntaxKind.ConcatOperator | SyntaxKind.EqualityOperator | SyntaxKind.InequalityOperator | SyntaxKind.LessThanOperator | SyntaxKind.LessEqualOperator | SyntaxKind.GreaterThanOperator | SyntaxKind.GreaterEqualOperator | SyntaxKind.AndOperator | SyntaxKind.OrOperator | - SyntaxKind.BitwiseAndOperator | SyntaxKind.BitwiseOrOperator | SyntaxKind.BitwiseExclusiveOrOperator | - SyntaxKind.BitwiseRightShiftOperator | SyntaxKind.BitwiseLeftShiftOperator | SyntaxKind.BitwiseNotOperator; + BinaryBitwiseOperator; export type Operator = UnaryOperator | BinaryOperator; diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 5e7734828..491be1d2f 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -2,40 +2,10 @@ import * as tstl from "./LuaAST"; import { TSHelper as tsHelper } from "./TSHelper"; import { LuaLibFeature, LuaLib } from "./LuaLib"; -import { CompilerOptions } from "./CompilerOptions"; +import { CompilerOptions, LuaTarget } from "./CompilerOptions"; import { LuaLibImportKind } from "./CompilerOptions"; export class LuaPrinter { - /* tslint:disable:object-literal-sort-keys */ - private static operatorMap: {[key in tstl.Operator]: string} = { - [tstl.SyntaxKind.AdditionOperator]: "+", - [tstl.SyntaxKind.SubractionOperator]: "-", - [tstl.SyntaxKind.MultiplicationOperator]: "*", - [tstl.SyntaxKind.DivisionOperator]: "/", - [tstl.SyntaxKind.FloorDivisionOperator]: "//", - [tstl.SyntaxKind.ModuloOperator]: "%", - [tstl.SyntaxKind.PowerOperator]: "^", - [tstl.SyntaxKind.NegationOperator]: "-", - [tstl.SyntaxKind.ConcatOperator]: "..", - [tstl.SyntaxKind.LengthOperator]: "#", - [tstl.SyntaxKind.EqualityOperator]: "==", - [tstl.SyntaxKind.InequalityOperator]: "~=", - [tstl.SyntaxKind.LessThanOperator]: "<", - [tstl.SyntaxKind.LessEqualOperator]: "<=", - [tstl.SyntaxKind.GreaterThanOperator]: ">", - [tstl.SyntaxKind.GreaterEqualOperator]: ">=", - [tstl.SyntaxKind.AndOperator]: "and", - [tstl.SyntaxKind.OrOperator]: "or", - [tstl.SyntaxKind.NotOperator]: "not ", - [tstl.SyntaxKind.BitwiseAndOperator]: "&", - [tstl.SyntaxKind.BitwiseOrOperator]: "|", - [tstl.SyntaxKind.BitwiseExclusiveOrOperator]: "~", - [tstl.SyntaxKind.BitwiseRightShiftOperator]: ">>", - [tstl.SyntaxKind.BitwiseLeftShiftOperator]: "<<", - [tstl.SyntaxKind.BitwiseNotOperator]: "~", - }; - /* tslint:enable:object-literal-sort-keys */ - private options: CompilerOptions; private currentIndent: string; @@ -57,7 +27,7 @@ export class LuaPrinter { || this.options.luaLibImport === LuaLibImportKind.Always) { header += `require("lualib_bundle");\n`; - } + } // Inline lualib features else if (this.options.luaLibImport === LuaLibImportKind.Inline && luaLibFeatures.size > 0) { @@ -342,7 +312,26 @@ export class LuaPrinter { const operand = this.needsParentheses(expression.operand) ? `(${this.printExpression(expression.operand)})` : this.printExpression(expression.operand); - return `${this.printOperator(expression.operator)}${operand}`; + + switch (expression.operator) { + case tstl.SyntaxKind.NegationOperator: + return `-${operand}`; + case tstl.SyntaxKind.LengthOperator: + return `#${operand}`; + case tstl.SyntaxKind.NotOperator: + return `not ${operand}`; + case tstl.SyntaxKind.BitwiseNotOperator: + switch (this.options.luaTarget) { + case LuaTarget.Lua52: + return `bit32.bnot(${operand})`; + case LuaTarget.LuaJIT: + return `bit.bnot(${operand})`; + default: + return `~${operand}`; + } + default: + return operand; + } } private printBinaryExpression(expression: tstl.BinaryExpression): string { @@ -354,8 +343,91 @@ export class LuaPrinter { ? `(${this.printExpression(expression.right)})` : this.printExpression(expression.right); - const operator = this.printOperator(expression.operator); - return `${left} ${operator} ${right}`; + switch (expression.operator) { + case tstl.SyntaxKind.AdditionOperator: + return `${left} + ${right}`; + case tstl.SyntaxKind.SubractionOperator: + return `${left} - ${right}`; + case tstl.SyntaxKind.MultiplicationOperator: + return `${left} * ${right}`; + case tstl.SyntaxKind.DivisionOperator: + return `${left} / ${right}`; + case tstl.SyntaxKind.FloorDivisionOperator: + return `${left} // ${right}`; + case tstl.SyntaxKind.ModuloOperator: + return `${left} % ${right}`; + case tstl.SyntaxKind.PowerOperator: + return `${left} ^ ${right}`; + case tstl.SyntaxKind.ConcatOperator: + return `${left} .. ${right}`; + case tstl.SyntaxKind.EqualityOperator: + return `${left} == ${right}`; + case tstl.SyntaxKind.InequalityOperator: + return `${left} ~= ${right}`; + case tstl.SyntaxKind.LessThanOperator: + return `${left} < ${right}`; + case tstl.SyntaxKind.LessEqualOperator: + return `${left} <= ${right}`; + case tstl.SyntaxKind.GreaterThanOperator: + return `${left} > ${right}`; + case tstl.SyntaxKind.GreaterEqualOperator: + return `${left} >= ${right}`; + case tstl.SyntaxKind.AndOperator: + return `${left} and ${right}`; + case tstl.SyntaxKind.OrOperator: + return `${left} or ${right}`; + case tstl.SyntaxKind.BitwiseAndOperator: + switch (this.options.luaTarget) { + case LuaTarget.Lua52: + return `bit32.band(${left}, ${right})`; + case LuaTarget.LuaJIT: + return `bit.band(${left}, ${right})`; + default: + return `${left} & ${right}`; + } + case tstl.SyntaxKind.BitwiseOrOperator: + switch (this.options.luaTarget) { + case LuaTarget.Lua52: + return `bit32.bor(${left}, ${right})`; + case LuaTarget.LuaJIT: + return `bit.bor(${left}, ${right})`; + default: + return `${left} | ${right}`; + } + case tstl.SyntaxKind.BitwiseExclusiveOrOperator: + switch (this.options.luaTarget) { + case LuaTarget.Lua52: + return `bit32.bxor(${left}, ${right})`; + case LuaTarget.LuaJIT: + return `bit.bxor(${left}, ${right})`; + default: + return `${left} ~ ${right}`; + } + case tstl.SyntaxKind.BitwiseRightShiftOperator: + switch (this.options.luaTarget) { + case LuaTarget.Lua52: + return `bit32.rshift(${left}, ${right})`; + case LuaTarget.LuaJIT: + return `bit.rshift(${left}, ${right})`; + default: + return `${left} >> ${right}`; + } + case tstl.SyntaxKind.BitwiseArithmaticRightShift: + if (this.options.luaTarget === LuaTarget.LuaJIT) { + return `bit.arshift(${left}, ${right})`; + } else { + return `bit32.arshift(${left}, ${right})`; + } + case tstl.SyntaxKind.BitwiseLeftShiftOperator: + switch (this.options.luaTarget) { + case LuaTarget.Lua52: + return `bit32.lshift(${left}, ${right})`; + case LuaTarget.LuaJIT: + return `bit.lshift(${left}, ${right})`; + default: + return `${left} << ${right}`; + } + } } private needsParentheses(expression: tstl.Expression): boolean { @@ -390,10 +462,6 @@ export class LuaPrinter { return `${table}[${this.printExpression(expression.index)}]`; } - private printOperator(kind: tstl.Operator): string { - return LuaPrinter.operatorMap[kind]; - } - private ignoreDeadStatements(statements: tstl.Statement[]): tstl.Statement[] { const aliveStatements = []; for (const statement of statements) { diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 269c8142b..7fb6b9e83 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -33,7 +33,7 @@ export class LuaTransformer { private isStrict = true; private checker: ts.TypeChecker; - private options: CompilerOptions; + protected options: CompilerOptions; private isModule: boolean; private currentSourceFile?: ts.SourceFile; @@ -878,7 +878,7 @@ export class LuaTransformer { const [isCompound, replacementOperator] = tsHelper.isBinaryAssignmentToken(expression.operatorToken.kind); if (isCompound) { // +=, -=, etc... - return this.transformCompoundAssignmentStatement(expression.left, expression.right, replacementOperator); + return this.transformCompoundAssignmentStatement(expression, expression.left, expression.right, replacementOperator); } else if (expression.operatorToken.kind === ts.SyntaxKind.EqualsToken) { // = assignment @@ -891,14 +891,14 @@ 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), replacementOperator); + return this.transformCompoundAssignmentStatement(expression, expression.operand, ts.createLiteral(1), 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), replacementOperator); + return this.transformCompoundAssignmentStatement(expression, expression.operand, ts.createLiteral(1), replacementOperator); } return tstl.createExpressionStatement(this.transformExpression(expression)); @@ -1297,71 +1297,97 @@ export class LuaTransformer { } } + public transformBinaryOperation( + node: ts.Node, + left: tstl.Expression, + right: tstl.Expression, + operator: tstl.BinaryOperator + ): tstl.Expression { + switch (operator) { + case tstl.SyntaxKind.BitwiseAndOperator: + case tstl.SyntaxKind.BitwiseOrOperator: + case tstl.SyntaxKind.BitwiseExclusiveOrOperator: + case tstl.SyntaxKind.BitwiseLeftShiftOperator: + case tstl.SyntaxKind.BitwiseRightShiftOperator: + case tstl.SyntaxKind.BitwiseArithmaticRightShift: + return this.transformBinaryBitOperation(node, left, right, operator); + default: + return tstl.createBinaryExpression(left, right, operator, undefined, node); + } + } + public transformBinaryExpression(expression: ts.BinaryExpression): tstl.Expression { // Check if this is an assignment token, then handle accordingly const [isCompound, replacementOperator] = tsHelper.isBinaryAssignmentToken(expression.operatorToken.kind); if (isCompound) { - return this.transformCompoundAssignmentExpression(expression.left, expression.right, replacementOperator, false); + return this.transformCompoundAssignmentExpression(expression, expression.left, expression.right, replacementOperator, false); } const lhs = this.transformExpression(expression.left); const rhs = this.transformExpression(expression.right); - // Transpile Bitops + // Transpile operators switch (expression.operatorToken.kind) { case ts.SyntaxKind.AmpersandToken: + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseAndOperator); case ts.SyntaxKind.BarToken: + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseOrOperator); case ts.SyntaxKind.CaretToken: + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseExclusiveOrOperator); case ts.SyntaxKind.LessThanLessThanToken: + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseLeftShiftOperator); case ts.SyntaxKind.GreaterThanGreaterThanToken: + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseRightShiftOperator); case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - return this.transformBitOperation(expression, lhs, rhs); - } - - // Transpile operators - switch (expression.operatorToken.kind) { + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseArithmaticRightShift); case ts.SyntaxKind.AmpersandAmpersandToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.AndOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.AndOperator); case ts.SyntaxKind.BarBarToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.OrOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.OrOperator); case ts.SyntaxKind.PlusToken: // Replace string + with .. const typeLeft = this.checker.getTypeAtLocation(expression.left); const typeRight = this.checker.getTypeAtLocation(expression.right); if (tsHelper.isStringType(typeLeft) || tsHelper.isStringType(typeRight)) { - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.ConcatOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.ConcatOperator); } - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.AdditionOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.AdditionOperator); case ts.SyntaxKind.MinusToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.SubractionOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.SubractionOperator); case ts.SyntaxKind.AsteriskToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.MultiplicationOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.MultiplicationOperator); case ts.SyntaxKind.AsteriskAsteriskToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.PowerOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.PowerOperator); case ts.SyntaxKind.SlashToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.DivisionOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.DivisionOperator); case ts.SyntaxKind.PercentToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.ModuloOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.ModuloOperator); case ts.SyntaxKind.GreaterThanToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.GreaterThanOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.GreaterThanOperator); case ts.SyntaxKind.GreaterThanEqualsToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.GreaterEqualOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.GreaterEqualOperator); case ts.SyntaxKind.LessThanToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.LessThanOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.LessThanOperator); case ts.SyntaxKind.LessThanEqualsToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.LessEqualOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.LessEqualOperator); case ts.SyntaxKind.EqualsToken: return this.transformAssignmentExpression(expression); case ts.SyntaxKind.EqualsEqualsToken: case ts.SyntaxKind.EqualsEqualsEqualsToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.EqualityOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.EqualityOperator); case ts.SyntaxKind.ExclamationEqualsToken: case ts.SyntaxKind.ExclamationEqualsEqualsToken: - return tstl.createBinaryExpression(lhs, rhs, tstl.SyntaxKind.InequalityOperator); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.InequalityOperator); case ts.SyntaxKind.InKeyword: const indexExpression = tstl.createTableIndexExpression(rhs, lhs); - return tstl.createBinaryExpression(indexExpression, tstl.createNilLiteral(), tstl.SyntaxKind.InequalityOperator); + return tstl.createBinaryExpression( + indexExpression, + tstl.createNilLiteral(), + tstl.SyntaxKind.InequalityOperator, + undefined, + expression + ); case ts.SyntaxKind.InstanceOfKeyword: return this.transformLuaLibFunction(LuaLibFeature.InstanceOf, lhs, rhs); default: @@ -1371,9 +1397,14 @@ export class LuaTransformer { public transformAssignment(lhs: ts.Expression, right: tstl.Expression): tstl.Statement { if (ts.isPropertyAccessExpression(lhs) && tsHelper.hasSetAccessor(lhs, this.checker)) { - return tstl.createExpressionStatement(this.transformSetAccessor(lhs, right)); + return tstl.createExpressionStatement(this.transformSetAccessor(lhs, right), undefined, lhs.parent); } else { - return tstl.createAssignmentStatement(this.transformExpression(lhs) as tstl.IdentifierOrTableIndexExpression, right); + return tstl.createAssignmentStatement( + this.transformExpression(lhs) as tstl.IdentifierOrTableIndexExpression, + right, + undefined, + lhs.parent + ); } } @@ -1383,11 +1414,6 @@ export class LuaTransformer { const leftType = this.checker.getTypeAtLocation(expression.left); this.validateFunctionAssignment(expression.right, rightType, leftType); - if (ts.isPropertyAccessExpression(expression.left) && tsHelper.hasSetAccessor(expression.left, this.checker)) { - const right = this.transformExpression(expression.right); - return tstl.createExpressionStatement(this.transformSetAccessor(expression.left, right)); - } - if (ts.isArrayLiteralExpression(expression.left)) { // Destructuring assignment const left = expression.left.elements.map(e => this.transformExpression(e)); @@ -1399,7 +1425,7 @@ export class LuaTransformer { } else { right = [this.createUnpackCall(this.transformExpression(expression.right))]; } - return tstl.createAssignmentStatement(left as tstl.IdentifierOrTableIndexExpression[], right); + return tstl.createAssignmentStatement(left as tstl.IdentifierOrTableIndexExpression[], right, undefined, expression); } else { // Simple assignment return this.transformAssignment(expression.left, this.transformExpression(expression.right)); @@ -1472,6 +1498,7 @@ export class LuaTransformer { } public transformCompoundAssignmentExpression( + expression: ts.Expression, lhs: ts.Expression, rhs: ts.Expression, replacementOperator: tstl.BinaryOperator, @@ -1506,12 +1533,12 @@ export class LuaTransformer { // 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); + const operatorExpression = this.transformBinaryOperation(expression, 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); + const operatorExpression = this.transformBinaryOperation(expression, accessExpression, right, replacementOperator); tmpDeclaration = tstl.createVariableDeclarationStatement(tmp, operatorExpression); assignStatement = tstl.createAssignmentStatement(accessExpression, tmp); } @@ -1525,7 +1552,7 @@ export class LuaTransformer { // return ____TS_tmp const tmpIdentifier = tstl.createIdentifier("____TS_tmp"); const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, left); - const operatorExpression = tstl.createBinaryExpression(tmpIdentifier, right, replacementOperator); + const operatorExpression = this.transformBinaryOperation(expression, tmpIdentifier, right, replacementOperator); const assignStatement = this.transformAssignment(lhs, operatorExpression); return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier); @@ -1535,7 +1562,7 @@ export class LuaTransformer { // ${left} = ____TS_tmp; // return ____TS_tmp const tmpIdentifier = tstl.createIdentifier("____TS_tmp"); - const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); + const operatorExpression = this.transformBinaryOperation(lhs.parent, left, right, replacementOperator); const tmpDeclaration = tstl.createVariableDeclarationStatement(tmpIdentifier, operatorExpression); const assignStatement = this.transformAssignment(lhs, tmpIdentifier); return this.createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier); @@ -1543,14 +1570,18 @@ export class LuaTransformer { } else { // Simple expressions // ${left} = ${right}; return ${right} - const operatorExpression = tstl.createBinaryExpression(left, right, replacementOperator); + const operatorExpression = this.transformBinaryOperation(lhs.parent, left, right, replacementOperator); const assignStatement = this.transformAssignment(lhs, operatorExpression); return this.createImmediatelyInvokedFunctionExpression([assignStatement], left); } } - public transformCompoundAssignmentStatement(lhs: ts.Expression, rhs: ts.Expression, replacementOperator: tstl.BinaryOperator): - tstl.Statement { + public transformCompoundAssignmentStatement( + node: ts.Node, + lhs: ts.Expression, + rhs: ts.Expression, + replacementOperator: tstl.BinaryOperator + ): tstl.Statement { if (replacementOperator === tstl.SyntaxKind.AdditionOperator) { // Check is we need to use string concat operator const typeLeft = this.checker.getTypeAtLocation(lhs); @@ -1573,20 +1604,37 @@ export class LuaTransformer { 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); + const operatorExpression = this.transformBinaryOperation( + node, + accessExpression, + tstl.createParenthesizedExpression(right), + replacementOperator + ); 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 operatorExpression = this.transformBinaryOperation(node, left, right, replacementOperator); return this.transformAssignment(lhs, operatorExpression); } } - public transformBitOperation(node: ts.BinaryExpression, lhs: tstl.Expression, rhs: tstl.Expression): ExpressionVisitResult { + public transformUnaryBitOperation( + node: ts.Node, + expression: tstl.Expression, + operator: tstl.UnaryBitwiseOperator + ): ExpressionVisitResult { + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); + } + + public transformBinaryBitOperation( + node: ts.Node, + lhs: tstl.Expression, + rhs: tstl.Expression, + operator: tstl.BinaryBitwiseOperator + ): ExpressionVisitResult { throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); } @@ -1601,18 +1649,28 @@ 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), replacementOperator, true); + return this.transformCompoundAssignmentExpression(expression, expression.operand, ts.createLiteral(1), replacementOperator, true); } public transformPrefixUnaryExpression(expression: ts.PrefixUnaryExpression): tstl.Expression { switch (expression.operator) { case ts.SyntaxKind.PlusPlusToken: return this.transformCompoundAssignmentExpression( - expression.operand, ts.createLiteral(1), tstl.SyntaxKind.AdditionOperator, false); + expression, + 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); + expression, + expression.operand, + ts.createLiteral(1), + tstl.SyntaxKind.SubractionOperator, + false + ); case ts.SyntaxKind.PlusToken: return this.transformExpression(expression.operand); @@ -1624,7 +1682,11 @@ export class LuaTransformer { return tstl.createUnaryExpression(this.transformExpression(expression.operand), tstl.SyntaxKind.NotOperator); case ts.SyntaxKind.TildeToken: - return tstl.createUnaryExpression(this.transformExpression(expression.operand), tstl.SyntaxKind.BitwiseNotOperator); + return this.transformUnaryBitOperation( + expression, + this.transformExpression(expression.operand), + tstl.SyntaxKind.BitwiseNotOperator + ); } } diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 6c1922f70..04512415d 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -293,8 +293,7 @@ export class TSHelper { case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken: return [true, tstl.SyntaxKind.BitwiseRightShiftOperator]; case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: - // return [true, ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken]; - throw new Error("Not yet implemented in lua AST"); // TODO + return [true, tstl.SyntaxKind.BitwiseArithmaticRightShift]; } return [false, undefined]; diff --git a/src/targets/LuaTransformer.52.ts b/src/targets/LuaTransformer.52.ts index 8a6a1560d..e76e8936f 100644 --- a/src/targets/LuaTransformer.52.ts +++ b/src/targets/LuaTransformer.52.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as tstl from "../LuaAST"; -import {LuaTransformer, StatementVisitResult, ScopeType} from "../LuaTransformer"; +import {ExpressionVisitResult, StatementVisitResult, ScopeType} from "../LuaTransformer"; import {TSHelper as tsHelper} from "../TSHelper"; import { LuaTransformer51 } from "./LuaTransformer.51"; @@ -49,35 +49,24 @@ export class LuaTransformer52 extends LuaTransformer51 // } // } - // /** @override */ - // public transpileUnaryBitOperation(node: ts.PrefixUnaryExpression, operand: string): string { - // switch (node.operator) { - // case ts.SyntaxKind.TildeToken: - // return `bit32.bnot(${operand})`; - // default: - // throw TSTLErrors.UnsupportedKind("bitwise operator", node.operator, node); - // } - // } + /** @override */ + public transformUnaryBitOperation( + node: ts.Node, + expression: tstl.Expression, + operator: tstl.UnaryBitwiseOperator + ): ExpressionVisitResult { + return tstl.createUnaryExpression(expression, operator, undefined, node); + } - // /** @override */ - // public transpileBitOperation(node: ts.BinaryExpression, lhs: string, rhs: string): string { - // switch (node.operatorToken.kind) { - // case ts.SyntaxKind.AmpersandToken: - // return `bit32.band(${lhs},${rhs})`; - // case ts.SyntaxKind.BarToken: - // return `bit32.bor(${lhs},${rhs})`; - // case ts.SyntaxKind.CaretToken: - // return `bit32.bxor(${lhs},${rhs})`; - // case ts.SyntaxKind.LessThanLessThanToken: - // return `bit32.lshift(${lhs},${rhs})`; - // case ts.SyntaxKind.GreaterThanGreaterThanToken: - // return `bit32.rshift(${lhs},${rhs})`; - // case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - // return `bit32.arshift(${lhs},${rhs})`; - // default: - // throw TSTLErrors.UnsupportedKind("bitwise operator", node.operatorToken.kind, node); - // } - // } + /** @override */ + public transformBinaryBitOperation( + node: ts.Node, + left: tstl.Expression, + right: tstl.Expression, + operator: tstl.BinaryBitwiseOperator + ): ExpressionVisitResult { + return tstl.createBinaryExpression(left, right, operator, undefined, node); + } // /** @override */ // public transpileSwitch(node: ts.SwitchStatement): string { diff --git a/src/targets/LuaTransformer.53.ts b/src/targets/LuaTransformer.53.ts index 1d88c639e..544efc0bf 100644 --- a/src/targets/LuaTransformer.53.ts +++ b/src/targets/LuaTransformer.53.ts @@ -1,40 +1,26 @@ import * as ts from "typescript"; -import {LuaTransformer} from "../LuaTransformer"; +import * as tstl from "../LuaAST"; +import {ExpressionVisitResult} from "../LuaTransformer"; import {TSHelper as tsHelper} from "../TSHelper"; import { LuaTransformer52 } from "./LuaTransformer.52"; +import {TSTLErrors} from "../TSTLErrors"; export class LuaTransformer53 extends LuaTransformer52 { // TODO - // /** @override */ - // public transpileUnaryBitOperation(node: ts.PrefixUnaryExpression, operand: string): string { - // switch (node.operator) { - // case ts.SyntaxKind.TildeToken: - // return `~${operand}`; - // default: - // throw TSTLErrors.UnsupportedKind("bitwise operator", node.operator, node); - // } - // } - // /** @override */ - // public transpileBitOperation(node: ts.BinaryExpression, lhs: string, rhs: string): string { - // switch (node.operatorToken.kind) { - // case ts.SyntaxKind.AmpersandToken: - // return `${lhs} & ${rhs}`; - // case ts.SyntaxKind.BarToken: - // return `${lhs} | ${rhs}`; - // case ts.SyntaxKind.CaretToken: - // return `${lhs} ~ ${rhs}`; - // case ts.SyntaxKind.LessThanLessThanToken: - // return `${lhs} << ${rhs}`; - // case ts.SyntaxKind.GreaterThanGreaterThanToken: - // return `${lhs} >> ${rhs}`; - // case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - // throw TSTLErrors.UnsupportedForTarget("Bitwise >>> operator", this.options.luaTarget, node); - // default: - // throw TSTLErrors.UnsupportedKind("bitwise operator", node.operatorToken.kind, node); - // } - // } + /** @override */ + public transformBinaryBitOperation( + expression: ts.Node, + left: tstl.Expression, + right: tstl.Expression, + operator: tstl.BinaryBitwiseOperator + ): ExpressionVisitResult { + if (operator === tstl.SyntaxKind.BitwiseArithmaticRightShift) { + throw TSTLErrors.UnsupportedForTarget("Bitwise >>> operator", this.options.luaTarget, expression); + } + return tstl.createBinaryExpression(left, right, operator, undefined, expression); + } // /** @override */ // public getValidStringProperties(): { [js: string]: string } { diff --git a/src/targets/LuaTransformer.JIT.ts b/src/targets/LuaTransformer.JIT.ts index 44f0fbc11..e3ec7a45d 100644 --- a/src/targets/LuaTransformer.JIT.ts +++ b/src/targets/LuaTransformer.JIT.ts @@ -22,26 +22,6 @@ export class LuaTransformerJIT extends LuaTransformer52 { // } // } - // /** @override */ - // public transpileBitOperation(node: ts.BinaryExpression, lhs: string, rhs: string): string { - // switch (node.operatorToken.kind) { - // case ts.SyntaxKind.AmpersandToken: - // return `bit.band(${lhs},${rhs})`; - // case ts.SyntaxKind.BarToken: - // return `bit.bor(${lhs},${rhs})`; - // case ts.SyntaxKind.CaretToken: - // return `bit.bxor(${lhs},${rhs})`; - // case ts.SyntaxKind.LessThanLessThanToken: - // return `bit.lshift(${lhs},${rhs})`; - // case ts.SyntaxKind.GreaterThanGreaterThanToken: - // return `bit.rshift(${lhs},${rhs})`; - // case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - // return `bit.arshift(${lhs},${rhs})`; - // default: - // throw TSTLErrors.UnsupportedKind("bitwise operator", node.operatorToken.kind, node); - // } - // } - // /** @override */ // public transpileDestructingAssignmentValue(node: ts.Expression): string { // return `unpack(${this.transpileExpression(node)})`; diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index ac603bf67..045591858 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -113,36 +113,36 @@ export class ExpressionTests { } @TestCase("~a", "bit.bnot(a);") - @TestCase("a&b", "bit.band(a,b);") - @TestCase("a&=b", "a = (bit.band(a,b));") - @TestCase("a|b", "bit.bor(a,b);") - @TestCase("a|=b", "a = (bit.bor(a,b));") - @TestCase("a^b", "bit.bxor(a,b);") - @TestCase("a^=b", "a = (bit.bxor(a,b));") - @TestCase("a<>b", "bit.rshift(a,b);") - @TestCase("a>>=b", "a = (bit.rshift(a,b));") - @TestCase("a>>>b", "bit.arshift(a,b);") - @TestCase("a>>>=b", "a = (bit.arshift(a,b));") + @TestCase("a&b", "bit.band(a, b);") + @TestCase("a&=b", "a = bit.band(a, b);") + @TestCase("a|b", "bit.bor(a, b);") + @TestCase("a|=b", "a = bit.bor(a, b);") + @TestCase("a^b", "bit.bxor(a, b);") + @TestCase("a^=b", "a = bit.bxor(a, b);") + @TestCase("a<>b", "bit.rshift(a, b);") + @TestCase("a>>=b", "a = bit.rshift(a, b);") + @TestCase("a>>>b", "bit.arshift(a, b);") + @TestCase("a>>>=b", "a = bit.arshift(a, b);") @Test("Bitop [JIT]") public bitOperatorOverrideJIT(input: string, lua: string): void { Expect(util.transpileString(input, { luaTarget: LuaTarget.LuaJIT, luaLibImport: "none" })).toBe(lua); } @TestCase("~a", "bit32.bnot(a);") - @TestCase("a&b", "bit32.band(a,b);") - @TestCase("a&=b", "a = (bit32.band(a,b));") - @TestCase("a|b", "bit32.bor(a,b);") - @TestCase("a|=b", "a = (bit32.bor(a,b));") - @TestCase("a^b", "bit32.bxor(a,b);") - @TestCase("a^=b", "a = (bit32.bxor(a,b));") - @TestCase("a<>b", "bit32.rshift(a,b);") - @TestCase("a>>=b", "a = (bit32.rshift(a,b));") - @TestCase("a>>>b", "bit32.arshift(a,b);") - @TestCase("a>>>=b", "a = (bit32.arshift(a,b));") + @TestCase("a&b", "bit32.band(a, b);") + @TestCase("a&=b", "a = bit32.band(a, b);") + @TestCase("a|b", "bit32.bor(a, b);") + @TestCase("a|=b", "a = bit32.bor(a, b);") + @TestCase("a^b", "bit32.bxor(a, b);") + @TestCase("a^=b", "a = bit32.bxor(a, b);") + @TestCase("a<>b", "bit32.rshift(a, b);") + @TestCase("a>>=b", "a = bit32.rshift(a, b);") + @TestCase("a>>>b", "bit32.arshift(a, b);") + @TestCase("a>>>=b", "a = bit32.arshift(a, b);") @Test("Bitop [5.2]") public bitOperatorOverride52(input: string, lua: string): void { Expect(util.transpileString(input, { luaTarget: LuaTarget.Lua52, luaLibImport: "none" })).toBe(lua); @@ -150,15 +150,15 @@ export class ExpressionTests { @TestCase("~a", "~a;") @TestCase("a&b", "a & b;") - @TestCase("a&=b", "a = (a & b);") + @TestCase("a&=b", "a = a & b;") @TestCase("a|b", "a | b;") - @TestCase("a|=b", "a = (a | b);") + @TestCase("a|=b", "a = a | b;") @TestCase("a^b", "a ~ b;") - @TestCase("a^=b", "a = (a ~ b);") + @TestCase("a^=b", "a = a ~ b;") @TestCase("a<>b", "a >> b;") - @TestCase("a>>=b", "a = (a >> b);") + @TestCase("a>>=b", "a = a >> b;") @Test("Bitop [5.3]") public bitOperatorOverride53(input: string, lua: string): void { Expect(util.transpileString(input, { luaTarget: LuaTarget.Lua53, luaLibImport: "none" })).toBe(lua); From e5af7dda915bf4cd95be12f24bde4776a0a0d515 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Thu, 10 Jan 2019 15:16:32 -0700 Subject: [PATCH 2/4] Fixes and cleanup - Changed Arithmatic to Arithmetic - Throwing errors in printer in case something slips through from transformer - Throwing errors for unknown prefix/postifx unary ops - Move target-specific logic from subclasses to base transformer for bitops and unpack - Removed some unused helpers --- src/LuaAST.ts | 4 +- src/LuaPrinter.ts | 28 +++++++++--- src/LuaTransformer.ts | 72 ++++++++++++++++++++++++++----- src/TSHelper.ts | 19 +------- src/targets/LuaTransformer.52.ts | 26 ----------- src/targets/LuaTransformer.53.ts | 13 ------ src/targets/LuaTransformer.JIT.ts | 5 --- 7 files changed, 88 insertions(+), 79 deletions(-) diff --git a/src/LuaAST.ts b/src/LuaAST.ts index de823e9eb..47323a7aa 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -71,7 +71,7 @@ export enum SyntaxKind { BitwiseOrOperator, BitwiseExclusiveOrOperator, BitwiseRightShiftOperator, - BitwiseArithmaticRightShift, + BitwiseArithmeticRightShift, BitwiseLeftShiftOperator, BitwiseNotOperator, // Unary } @@ -83,7 +83,7 @@ export type UnaryOperator = SyntaxKind.NegationOperator | SyntaxKind.LengthOpera export type BinaryBitwiseOperator = SyntaxKind.BitwiseAndOperator | SyntaxKind.BitwiseOrOperator | SyntaxKind.BitwiseExclusiveOrOperator | - SyntaxKind.BitwiseRightShiftOperator | SyntaxKind.BitwiseArithmaticRightShift | SyntaxKind.BitwiseLeftShiftOperator; + SyntaxKind.BitwiseRightShiftOperator | SyntaxKind.BitwiseArithmeticRightShift | SyntaxKind.BitwiseLeftShiftOperator; export type BinaryOperator = SyntaxKind.AdditionOperator | SyntaxKind.SubractionOperator | SyntaxKind.MultiplicationOperator | SyntaxKind.DivisionOperator | diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 491be1d2f..992cee811 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -4,6 +4,7 @@ import { TSHelper as tsHelper } from "./TSHelper"; import { LuaLibFeature, LuaLib } from "./LuaLib"; import { CompilerOptions, LuaTarget } from "./CompilerOptions"; import { LuaLibImportKind } from "./CompilerOptions"; +import { TSTLErrors } from "./TSTLErrors"; export class LuaPrinter { private options: CompilerOptions; @@ -322,6 +323,8 @@ export class LuaPrinter { return `not ${operand}`; case tstl.SyntaxKind.BitwiseNotOperator: switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); case LuaTarget.Lua52: return `bit32.bnot(${operand})`; case LuaTarget.LuaJIT: @@ -378,6 +381,8 @@ export class LuaPrinter { return `${left} or ${right}`; case tstl.SyntaxKind.BitwiseAndOperator: switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); case LuaTarget.Lua52: return `bit32.band(${left}, ${right})`; case LuaTarget.LuaJIT: @@ -387,6 +392,8 @@ export class LuaPrinter { } case tstl.SyntaxKind.BitwiseOrOperator: switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); case LuaTarget.Lua52: return `bit32.bor(${left}, ${right})`; case LuaTarget.LuaJIT: @@ -396,6 +403,8 @@ export class LuaPrinter { } case tstl.SyntaxKind.BitwiseExclusiveOrOperator: switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); case LuaTarget.Lua52: return `bit32.bxor(${left}, ${right})`; case LuaTarget.LuaJIT: @@ -405,6 +414,8 @@ export class LuaPrinter { } case tstl.SyntaxKind.BitwiseRightShiftOperator: switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); case LuaTarget.Lua52: return `bit32.rshift(${left}, ${right})`; case LuaTarget.LuaJIT: @@ -412,14 +423,21 @@ export class LuaPrinter { default: return `${left} >> ${right}`; } - case tstl.SyntaxKind.BitwiseArithmaticRightShift: - if (this.options.luaTarget === LuaTarget.LuaJIT) { - return `bit.arshift(${left}, ${right})`; - } else { - return `bit32.arshift(${left}, ${right})`; + case tstl.SyntaxKind.BitwiseArithmeticRightShift: + switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); + case LuaTarget.Lua52: + return `bit32.arshift(${left}, ${right})`; + case LuaTarget.LuaJIT: + return `bit.arshift(${left}, ${right})`; + default: + throw TSTLErrors.UnsupportedForTarget("Bitwise >>> operator", this.options.luaTarget, undefined); } case tstl.SyntaxKind.BitwiseLeftShiftOperator: switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); case LuaTarget.Lua52: return `bit32.lshift(${left}, ${right})`; case LuaTarget.LuaJIT: diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 7fb6b9e83..6786c3472 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1309,7 +1309,7 @@ export class LuaTransformer { case tstl.SyntaxKind.BitwiseExclusiveOrOperator: case tstl.SyntaxKind.BitwiseLeftShiftOperator: case tstl.SyntaxKind.BitwiseRightShiftOperator: - case tstl.SyntaxKind.BitwiseArithmaticRightShift: + case tstl.SyntaxKind.BitwiseArithmeticRightShift: return this.transformBinaryBitOperation(node, left, right, operator); default: return tstl.createBinaryExpression(left, right, operator, undefined, node); @@ -1340,7 +1340,7 @@ export class LuaTransformer { case ts.SyntaxKind.GreaterThanGreaterThanToken: return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseRightShiftOperator); case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseArithmaticRightShift); + return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.BitwiseArithmeticRightShift); case ts.SyntaxKind.AmpersandAmpersandToken: return this.transformBinaryOperation(expression, lhs, rhs, tstl.SyntaxKind.AndOperator); case ts.SyntaxKind.BarBarToken: @@ -1626,16 +1626,34 @@ export class LuaTransformer { expression: tstl.Expression, operator: tstl.UnaryBitwiseOperator ): ExpressionVisitResult { - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); + switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); + case LuaTarget.Lua52: + case LuaTarget.LuaJIT: + default: + return tstl.createUnaryExpression(expression, operator, undefined, node); + } } public transformBinaryBitOperation( node: ts.Node, - lhs: tstl.Expression, - rhs: tstl.Expression, + left: tstl.Expression, + right: tstl.Expression, operator: tstl.BinaryBitwiseOperator ): ExpressionVisitResult { - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); + switch (this.options.luaTarget) { + case LuaTarget.Lua51: + throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); + case LuaTarget.Lua52: + case LuaTarget.LuaJIT: + return tstl.createBinaryExpression(left, right, operator, undefined, node); + default: + if (operator === tstl.SyntaxKind.BitwiseArithmeticRightShift) { + throw TSTLErrors.UnsupportedForTarget("Bitwise >>> operator", this.options.luaTarget, node); + } + return tstl.createBinaryExpression(left, right, operator, undefined, node); + } } public transformConditionalExpression(node: ts.ConditionalExpression, brackets?: boolean): tstl.CallExpression { @@ -1647,9 +1665,28 @@ 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, expression.operand, ts.createLiteral(1), replacementOperator, true); + switch (expression.operator) { + case ts.SyntaxKind.PlusPlusToken: + return this.transformCompoundAssignmentExpression( + expression, + expression.operand, + ts.createLiteral(1), + tstl.SyntaxKind.AdditionOperator, + true + ); + + case ts.SyntaxKind.MinusMinusToken: + return this.transformCompoundAssignmentExpression( + expression, + expression.operand, + ts.createLiteral(1), + tstl.SyntaxKind.SubractionOperator, + true + ); + + default: + throw TSTLErrors.UnsupportedKind("unary postfix operator", expression.operator, expression); + } } public transformPrefixUnaryExpression(expression: ts.PrefixUnaryExpression): tstl.Expression { @@ -1687,6 +1724,9 @@ export class LuaTransformer { this.transformExpression(expression.operand), tstl.SyntaxKind.BitwiseNotOperator ); + + default: + throw TSTLErrors.UnsupportedKind("unary prefix operator", expression.operator, expression); } } @@ -2400,7 +2440,19 @@ export class LuaTransformer { } public createUnpackCall(expression: tstl.Expression): tstl.Expression { - return tstl.createCallExpression(tstl.createIdentifier("unpack"), [expression]); + switch (this.options.luaTarget) { + case LuaTarget.Lua51: + case LuaTarget.LuaJIT: + return tstl.createCallExpression(tstl.createIdentifier("unpack"), [expression]); + + case LuaTarget.Lua52: + case LuaTarget.Lua53: + default: + return tstl.createCallExpression( + tstl.createTableIndexExpression(tstl.createIdentifier("table"), tstl.createStringLiteral("unpack")), + [expression] + ); + } } private getAbsoluteImportPath(relativePath: string): string { diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 04512415d..5c8b6fa3b 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -293,29 +293,12 @@ export class TSHelper { case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken: return [true, tstl.SyntaxKind.BitwiseRightShiftOperator]; case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: - return [true, tstl.SyntaxKind.BitwiseArithmaticRightShift]; + return [true, tstl.SyntaxKind.BitwiseArithmeticRightShift]; } return [false, undefined]; } - public static isCompoundPrefixUnaryOperator(node: ts.PrefixUnaryExpression): boolean { - return node.operator !== ts.SyntaxKind.ExclamationToken && node.operator !== ts.SyntaxKind.MinusToken && - node.operator !== ts.SyntaxKind.PlusToken && node.operator !== ts.SyntaxKind.TildeToken; - } - - public static getUnaryCompoundAssignmentOperator(node: ts.PrefixUnaryExpression | ts.PostfixUnaryExpression): ts.BinaryOperator { - switch (node.operator) { - case ts.SyntaxKind.PlusPlusToken: - return ts.SyntaxKind.PlusToken; - case ts.SyntaxKind.MinusMinusToken: - return ts.SyntaxKind.MinusToken; - default: - throw TSTLErrors.UnsupportedKind( - `unary ${ts.isPrefixUnaryExpression(node) ? "prefix" : "postfix"} operator`, node.operator, node); - } - } - public static isExpressionStatement(node: ts.Expression): boolean { return node.parent === undefined || ts.isExpressionStatement(node.parent) || ts.isForStatement(node.parent); } diff --git a/src/targets/LuaTransformer.52.ts b/src/targets/LuaTransformer.52.ts index e76e8936f..5be693c57 100644 --- a/src/targets/LuaTransformer.52.ts +++ b/src/targets/LuaTransformer.52.ts @@ -31,13 +31,6 @@ export class LuaTransformer52 extends LuaTransformer51 ); } - /** @override */ - public createUnpackCall(expression: tstl.Expression): tstl.Expression { - return tstl.createCallExpression( - tstl.createTableIndexExpression(tstl.createIdentifier("table"), tstl.createStringLiteral("unpack")), - [expression]); - } - // /** @override */ // public transpileBreak(node: ts.BreakStatement): string { // const topScope = this.peekSpecialScope(); @@ -49,25 +42,6 @@ export class LuaTransformer52 extends LuaTransformer51 // } // } - /** @override */ - public transformUnaryBitOperation( - node: ts.Node, - expression: tstl.Expression, - operator: tstl.UnaryBitwiseOperator - ): ExpressionVisitResult { - return tstl.createUnaryExpression(expression, operator, undefined, node); - } - - /** @override */ - public transformBinaryBitOperation( - node: ts.Node, - left: tstl.Expression, - right: tstl.Expression, - operator: tstl.BinaryBitwiseOperator - ): ExpressionVisitResult { - return tstl.createBinaryExpression(left, right, operator, undefined, node); - } - // /** @override */ // public transpileSwitch(node: ts.SwitchStatement): string { // const expression = this.transpileExpression(node.expression, true); diff --git a/src/targets/LuaTransformer.53.ts b/src/targets/LuaTransformer.53.ts index 544efc0bf..0564a8692 100644 --- a/src/targets/LuaTransformer.53.ts +++ b/src/targets/LuaTransformer.53.ts @@ -9,19 +9,6 @@ import {TSTLErrors} from "../TSTLErrors"; export class LuaTransformer53 extends LuaTransformer52 { // TODO - /** @override */ - public transformBinaryBitOperation( - expression: ts.Node, - left: tstl.Expression, - right: tstl.Expression, - operator: tstl.BinaryBitwiseOperator - ): ExpressionVisitResult { - if (operator === tstl.SyntaxKind.BitwiseArithmaticRightShift) { - throw TSTLErrors.UnsupportedForTarget("Bitwise >>> operator", this.options.luaTarget, expression); - } - return tstl.createBinaryExpression(left, right, operator, undefined, expression); - } - // /** @override */ // public getValidStringProperties(): { [js: string]: string } { // return { diff --git a/src/targets/LuaTransformer.JIT.ts b/src/targets/LuaTransformer.JIT.ts index e3ec7a45d..c0ec9191e 100644 --- a/src/targets/LuaTransformer.JIT.ts +++ b/src/targets/LuaTransformer.JIT.ts @@ -6,11 +6,6 @@ import {TSHelper as tsHelper} from "../TSHelper"; import { LuaTransformer52 } from "./LuaTransformer.52"; export class LuaTransformerJIT extends LuaTransformer52 { - /** @override */ - public createUnpackCall(expression: tstl.Expression): tstl.Expression { - return tstl.createCallExpression(tstl.createIdentifier("unpack"), [expression]); - } - // TODO // /** @override */ // public transpileUnaryBitOperation(node: ts.PrefixUnaryExpression, operand: string): string { From cdff2e07a2275e48d3eceb304d469204587e4b45 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Fri, 11 Jan 2019 07:15:48 -0700 Subject: [PATCH 3/4] moved bitop handling properly into transformer --- src/LuaPrinter.ts | 163 ++++++++++-------------------------------- src/LuaTransformer.ts | 53 +++++++++++++- 2 files changed, 91 insertions(+), 125 deletions(-) diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 992cee811..7c59f47e0 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -2,11 +2,41 @@ import * as tstl from "./LuaAST"; import { TSHelper as tsHelper } from "./TSHelper"; import { LuaLibFeature, LuaLib } from "./LuaLib"; -import { CompilerOptions, LuaTarget } from "./CompilerOptions"; +import { CompilerOptions } from "./CompilerOptions"; import { LuaLibImportKind } from "./CompilerOptions"; -import { TSTLErrors } from "./TSTLErrors"; export class LuaPrinter { + /* tslint:disable:object-literal-sort-keys */ + private static operatorMap: {[key in tstl.Operator]: string} = { + [tstl.SyntaxKind.AdditionOperator]: "+", + [tstl.SyntaxKind.SubractionOperator]: "-", + [tstl.SyntaxKind.MultiplicationOperator]: "*", + [tstl.SyntaxKind.DivisionOperator]: "/", + [tstl.SyntaxKind.FloorDivisionOperator]: "//", + [tstl.SyntaxKind.ModuloOperator]: "%", + [tstl.SyntaxKind.PowerOperator]: "^", + [tstl.SyntaxKind.NegationOperator]: "-", + [tstl.SyntaxKind.ConcatOperator]: "..", + [tstl.SyntaxKind.LengthOperator]: "#", + [tstl.SyntaxKind.EqualityOperator]: "==", + [tstl.SyntaxKind.InequalityOperator]: "~=", + [tstl.SyntaxKind.LessThanOperator]: "<", + [tstl.SyntaxKind.LessEqualOperator]: "<=", + [tstl.SyntaxKind.GreaterThanOperator]: ">", + [tstl.SyntaxKind.GreaterEqualOperator]: ">=", + [tstl.SyntaxKind.AndOperator]: "and", + [tstl.SyntaxKind.OrOperator]: "or", + [tstl.SyntaxKind.NotOperator]: "not ", + [tstl.SyntaxKind.BitwiseAndOperator]: "&", + [tstl.SyntaxKind.BitwiseOrOperator]: "|", + [tstl.SyntaxKind.BitwiseExclusiveOrOperator]: "~", + [tstl.SyntaxKind.BitwiseRightShiftOperator]: ">>", + [tstl.SyntaxKind.BitwiseArithmeticRightShift]: ">>>", + [tstl.SyntaxKind.BitwiseLeftShiftOperator]: "<<", + [tstl.SyntaxKind.BitwiseNotOperator]: "~", + }; + /* tslint:enable:object-literal-sort-keys */ + private options: CompilerOptions; private currentIndent: string; @@ -313,28 +343,7 @@ export class LuaPrinter { const operand = this.needsParentheses(expression.operand) ? `(${this.printExpression(expression.operand)})` : this.printExpression(expression.operand); - - switch (expression.operator) { - case tstl.SyntaxKind.NegationOperator: - return `-${operand}`; - case tstl.SyntaxKind.LengthOperator: - return `#${operand}`; - case tstl.SyntaxKind.NotOperator: - return `not ${operand}`; - case tstl.SyntaxKind.BitwiseNotOperator: - switch (this.options.luaTarget) { - case LuaTarget.Lua51: - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); - case LuaTarget.Lua52: - return `bit32.bnot(${operand})`; - case LuaTarget.LuaJIT: - return `bit.bnot(${operand})`; - default: - return `~${operand}`; - } - default: - return operand; - } + return `${this.printOperator(expression.operator)}${operand}`; } private printBinaryExpression(expression: tstl.BinaryExpression): string { @@ -346,106 +355,8 @@ export class LuaPrinter { ? `(${this.printExpression(expression.right)})` : this.printExpression(expression.right); - switch (expression.operator) { - case tstl.SyntaxKind.AdditionOperator: - return `${left} + ${right}`; - case tstl.SyntaxKind.SubractionOperator: - return `${left} - ${right}`; - case tstl.SyntaxKind.MultiplicationOperator: - return `${left} * ${right}`; - case tstl.SyntaxKind.DivisionOperator: - return `${left} / ${right}`; - case tstl.SyntaxKind.FloorDivisionOperator: - return `${left} // ${right}`; - case tstl.SyntaxKind.ModuloOperator: - return `${left} % ${right}`; - case tstl.SyntaxKind.PowerOperator: - return `${left} ^ ${right}`; - case tstl.SyntaxKind.ConcatOperator: - return `${left} .. ${right}`; - case tstl.SyntaxKind.EqualityOperator: - return `${left} == ${right}`; - case tstl.SyntaxKind.InequalityOperator: - return `${left} ~= ${right}`; - case tstl.SyntaxKind.LessThanOperator: - return `${left} < ${right}`; - case tstl.SyntaxKind.LessEqualOperator: - return `${left} <= ${right}`; - case tstl.SyntaxKind.GreaterThanOperator: - return `${left} > ${right}`; - case tstl.SyntaxKind.GreaterEqualOperator: - return `${left} >= ${right}`; - case tstl.SyntaxKind.AndOperator: - return `${left} and ${right}`; - case tstl.SyntaxKind.OrOperator: - return `${left} or ${right}`; - case tstl.SyntaxKind.BitwiseAndOperator: - switch (this.options.luaTarget) { - case LuaTarget.Lua51: - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); - case LuaTarget.Lua52: - return `bit32.band(${left}, ${right})`; - case LuaTarget.LuaJIT: - return `bit.band(${left}, ${right})`; - default: - return `${left} & ${right}`; - } - case tstl.SyntaxKind.BitwiseOrOperator: - switch (this.options.luaTarget) { - case LuaTarget.Lua51: - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); - case LuaTarget.Lua52: - return `bit32.bor(${left}, ${right})`; - case LuaTarget.LuaJIT: - return `bit.bor(${left}, ${right})`; - default: - return `${left} | ${right}`; - } - case tstl.SyntaxKind.BitwiseExclusiveOrOperator: - switch (this.options.luaTarget) { - case LuaTarget.Lua51: - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); - case LuaTarget.Lua52: - return `bit32.bxor(${left}, ${right})`; - case LuaTarget.LuaJIT: - return `bit.bxor(${left}, ${right})`; - default: - return `${left} ~ ${right}`; - } - case tstl.SyntaxKind.BitwiseRightShiftOperator: - switch (this.options.luaTarget) { - case LuaTarget.Lua51: - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); - case LuaTarget.Lua52: - return `bit32.rshift(${left}, ${right})`; - case LuaTarget.LuaJIT: - return `bit.rshift(${left}, ${right})`; - default: - return `${left} >> ${right}`; - } - case tstl.SyntaxKind.BitwiseArithmeticRightShift: - switch (this.options.luaTarget) { - case LuaTarget.Lua51: - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); - case LuaTarget.Lua52: - return `bit32.arshift(${left}, ${right})`; - case LuaTarget.LuaJIT: - return `bit.arshift(${left}, ${right})`; - default: - throw TSTLErrors.UnsupportedForTarget("Bitwise >>> operator", this.options.luaTarget, undefined); - } - case tstl.SyntaxKind.BitwiseLeftShiftOperator: - switch (this.options.luaTarget) { - case LuaTarget.Lua51: - throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, undefined); - case LuaTarget.Lua52: - return `bit32.lshift(${left}, ${right})`; - case LuaTarget.LuaJIT: - return `bit.lshift(${left}, ${right})`; - default: - return `${left} << ${right}`; - } - } + const operator = this.printOperator(expression.operator); + return `${left} ${operator} ${right}`; } private needsParentheses(expression: tstl.Expression): boolean { @@ -480,6 +391,10 @@ export class LuaPrinter { return `${table}[${this.printExpression(expression.index)}]`; } + private printOperator(kind: tstl.Operator): string { + return LuaPrinter.operatorMap[kind]; + } + private ignoreDeadStatements(statements: tstl.Statement[]): tstl.Statement[] { const aliveStatements = []; for (const statement of statements) { diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 6786c3472..318835730 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1311,6 +1311,7 @@ export class LuaTransformer { case tstl.SyntaxKind.BitwiseRightShiftOperator: case tstl.SyntaxKind.BitwiseArithmeticRightShift: return this.transformBinaryBitOperation(node, left, right, operator); + default: return tstl.createBinaryExpression(left, right, operator, undefined, node); } @@ -1388,8 +1389,10 @@ export class LuaTransformer { undefined, expression ); + case ts.SyntaxKind.InstanceOfKeyword: return this.transformLuaLibFunction(LuaLibFeature.InstanceOf, lhs, rhs); + default: throw TSTLErrors.UnsupportedKind("binary operator", expression.operatorToken.kind, expression); } @@ -1629,8 +1632,25 @@ export class LuaTransformer { switch (this.options.luaTarget) { case LuaTarget.Lua51: throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); + case LuaTarget.Lua52: case LuaTarget.LuaJIT: + const bitTable = tstl.createIdentifier(this.options.luaTarget === LuaTarget.LuaJIT ? "bit" : "bit32"); + let bitFunction: string; + switch (operator) { + case tstl.SyntaxKind.BitwiseNotOperator: + bitFunction = "bnot"; + break; + default: + throw TSTLErrors.UnsupportedKind("unary bitwise operator", operator, node); + } + return tstl.createCallExpression( + tstl.createTableIndexExpression(bitTable, tstl.createStringLiteral(bitFunction)), + [expression], + undefined, + node + ); + default: return tstl.createUnaryExpression(expression, operator, undefined, node); } @@ -1645,9 +1665,40 @@ export class LuaTransformer { switch (this.options.luaTarget) { case LuaTarget.Lua51: throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); + case LuaTarget.Lua52: case LuaTarget.LuaJIT: - return tstl.createBinaryExpression(left, right, operator, undefined, node); + const bitTable = tstl.createIdentifier(this.options.luaTarget === LuaTarget.LuaJIT ? "bit" : "bit32"); + let bitFunction: string; + switch (operator) { + case tstl.SyntaxKind.BitwiseAndOperator: + bitFunction = "band"; + break; + case tstl.SyntaxKind.BitwiseOrOperator: + bitFunction = "bor"; + break; + case tstl.SyntaxKind.BitwiseExclusiveOrOperator: + bitFunction = "bxor"; + break; + case tstl.SyntaxKind.BitwiseLeftShiftOperator: + bitFunction = "lshift"; + break; + case tstl.SyntaxKind.BitwiseRightShiftOperator: + bitFunction = "rshift"; + break; + case tstl.SyntaxKind.BitwiseArithmeticRightShift: + bitFunction = "arshift"; + break; + default: + throw TSTLErrors.UnsupportedKind("binary bitwise operator", operator, node); + } + return tstl.createCallExpression( + tstl.createTableIndexExpression(bitTable, tstl.createStringLiteral(bitFunction)), + [left, right], + undefined, + node + ); + default: if (operator === tstl.SyntaxKind.BitwiseArithmeticRightShift) { throw TSTLErrors.UnsupportedForTarget("Bitwise >>> operator", this.options.luaTarget, node); From 762c0eeab11fb790195af2fcdb2a16d4462f094f Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Fri, 11 Jan 2019 12:56:43 -0700 Subject: [PATCH 4/4] broke lua52/luajit bitops out to their own functions --- src/LuaTransformer.ts | 111 +++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 318835730..32bbeca72 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1624,6 +1624,28 @@ export class LuaTransformer { } } + public transformUnaryBitLibOperation( + node: ts.Node, + expression: tstl.Expression, + operator: tstl.UnaryBitwiseOperator, + lib: string + ): ExpressionVisitResult { + let bitFunction: string; + switch (operator) { + case tstl.SyntaxKind.BitwiseNotOperator: + bitFunction = "bnot"; + break; + default: + throw TSTLErrors.UnsupportedKind("unary bitwise operator", operator, node); + } + return tstl.createCallExpression( + tstl.createTableIndexExpression(tstl.createIdentifier(lib), tstl.createStringLiteral(bitFunction)), + [expression], + undefined, + node + ); + } + public transformUnaryBitOperation( node: ts.Node, expression: tstl.Expression, @@ -1634,28 +1656,54 @@ export class LuaTransformer { throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); case LuaTarget.Lua52: + return this.transformUnaryBitLibOperation(node, expression, operator, "bit32"); + case LuaTarget.LuaJIT: - const bitTable = tstl.createIdentifier(this.options.luaTarget === LuaTarget.LuaJIT ? "bit" : "bit32"); - let bitFunction: string; - switch (operator) { - case tstl.SyntaxKind.BitwiseNotOperator: - bitFunction = "bnot"; - break; - default: - throw TSTLErrors.UnsupportedKind("unary bitwise operator", operator, node); - } - return tstl.createCallExpression( - tstl.createTableIndexExpression(bitTable, tstl.createStringLiteral(bitFunction)), - [expression], - undefined, - node - ); + return this.transformUnaryBitLibOperation(node, expression, operator, "bit"); default: return tstl.createUnaryExpression(expression, operator, undefined, node); } } + public transformBinaryBitLibOperation( + node: ts.Node, + left: tstl.Expression, + right: tstl.Expression, + operator: tstl.BinaryBitwiseOperator, + lib: string + ): ExpressionVisitResult { + let bitFunction: string; + switch (operator) { + case tstl.SyntaxKind.BitwiseAndOperator: + bitFunction = "band"; + break; + case tstl.SyntaxKind.BitwiseOrOperator: + bitFunction = "bor"; + break; + case tstl.SyntaxKind.BitwiseExclusiveOrOperator: + bitFunction = "bxor"; + break; + case tstl.SyntaxKind.BitwiseLeftShiftOperator: + bitFunction = "lshift"; + break; + case tstl.SyntaxKind.BitwiseRightShiftOperator: + bitFunction = "rshift"; + break; + case tstl.SyntaxKind.BitwiseArithmeticRightShift: + bitFunction = "arshift"; + break; + default: + throw TSTLErrors.UnsupportedKind("binary bitwise operator", operator, node); + } + return tstl.createCallExpression( + tstl.createTableIndexExpression(tstl.createIdentifier(lib), tstl.createStringLiteral(bitFunction)), + [left, right], + undefined, + node + ); + } + public transformBinaryBitOperation( node: ts.Node, left: tstl.Expression, @@ -1667,37 +1715,10 @@ export class LuaTransformer { throw TSTLErrors.UnsupportedForTarget("Bitwise operations", this.options.luaTarget, node); case LuaTarget.Lua52: + return this.transformBinaryBitLibOperation(node, left, right, operator, "bit32"); + case LuaTarget.LuaJIT: - const bitTable = tstl.createIdentifier(this.options.luaTarget === LuaTarget.LuaJIT ? "bit" : "bit32"); - let bitFunction: string; - switch (operator) { - case tstl.SyntaxKind.BitwiseAndOperator: - bitFunction = "band"; - break; - case tstl.SyntaxKind.BitwiseOrOperator: - bitFunction = "bor"; - break; - case tstl.SyntaxKind.BitwiseExclusiveOrOperator: - bitFunction = "bxor"; - break; - case tstl.SyntaxKind.BitwiseLeftShiftOperator: - bitFunction = "lshift"; - break; - case tstl.SyntaxKind.BitwiseRightShiftOperator: - bitFunction = "rshift"; - break; - case tstl.SyntaxKind.BitwiseArithmeticRightShift: - bitFunction = "arshift"; - break; - default: - throw TSTLErrors.UnsupportedKind("binary bitwise operator", operator, node); - } - return tstl.createCallExpression( - tstl.createTableIndexExpression(bitTable, tstl.createStringLiteral(bitFunction)), - [left, right], - undefined, - node - ); + return this.transformBinaryBitLibOperation(node, left, right, operator, "bit"); default: if (operator === tstl.SyntaxKind.BitwiseArithmeticRightShift) {