|
| 1 | +import * as ts from "typescript"; |
| 2 | +import * as lua from "../../../LuaAST"; |
| 3 | +import { TransformationContext } from "../../context"; |
| 4 | +import * as extensions from "../../utils/language-extensions"; |
| 5 | +import { assert } from "../../../utils"; |
| 6 | +import { findFirstNodeAbove } from "../../utils/typescript"; |
| 7 | +import { LuaTarget } from "../../../CompilerOptions"; |
| 8 | +import { unsupportedForTarget } from "../../utils/diagnostics"; |
| 9 | + |
| 10 | +const binaryOperatorMappings = new Map<extensions.ExtensionKind, lua.BinaryOperator>([ |
| 11 | + [extensions.ExtensionKind.AdditionOperatorType, lua.SyntaxKind.AdditionOperator], |
| 12 | + [extensions.ExtensionKind.AdditionOperatorMethodType, lua.SyntaxKind.AdditionOperator], |
| 13 | + [extensions.ExtensionKind.SubtractionOperatorType, lua.SyntaxKind.SubtractionOperator], |
| 14 | + [extensions.ExtensionKind.SubtractionOperatorMethodType, lua.SyntaxKind.SubtractionOperator], |
| 15 | + [extensions.ExtensionKind.MultiplicationOperatorType, lua.SyntaxKind.MultiplicationOperator], |
| 16 | + [extensions.ExtensionKind.MultiplicationOperatorMethodType, lua.SyntaxKind.MultiplicationOperator], |
| 17 | + [extensions.ExtensionKind.DivisionOperatorType, lua.SyntaxKind.DivisionOperator], |
| 18 | + [extensions.ExtensionKind.DivisionOperatorMethodType, lua.SyntaxKind.DivisionOperator], |
| 19 | + [extensions.ExtensionKind.ModuloOperatorType, lua.SyntaxKind.ModuloOperator], |
| 20 | + [extensions.ExtensionKind.ModuloOperatorMethodType, lua.SyntaxKind.ModuloOperator], |
| 21 | + [extensions.ExtensionKind.PowerOperatorType, lua.SyntaxKind.PowerOperator], |
| 22 | + [extensions.ExtensionKind.PowerOperatorMethodType, lua.SyntaxKind.PowerOperator], |
| 23 | + [extensions.ExtensionKind.FloorDivisionOperatorType, lua.SyntaxKind.FloorDivisionOperator], |
| 24 | + [extensions.ExtensionKind.FloorDivisionOperatorMethodType, lua.SyntaxKind.FloorDivisionOperator], |
| 25 | + [extensions.ExtensionKind.BitwiseAndOperatorType, lua.SyntaxKind.BitwiseAndOperator], |
| 26 | + [extensions.ExtensionKind.BitwiseAndOperatorMethodType, lua.SyntaxKind.BitwiseAndOperator], |
| 27 | + [extensions.ExtensionKind.BitwiseOrOperatorType, lua.SyntaxKind.BitwiseOrOperator], |
| 28 | + [extensions.ExtensionKind.BitwiseOrOperatorMethodType, lua.SyntaxKind.BitwiseOrOperator], |
| 29 | + [extensions.ExtensionKind.BitwiseExclusiveOrOperatorType, lua.SyntaxKind.BitwiseExclusiveOrOperator], |
| 30 | + [extensions.ExtensionKind.BitwiseExclusiveOrOperatorMethodType, lua.SyntaxKind.BitwiseExclusiveOrOperator], |
| 31 | + [extensions.ExtensionKind.BitwiseLeftShiftOperatorType, lua.SyntaxKind.BitwiseLeftShiftOperator], |
| 32 | + [extensions.ExtensionKind.BitwiseLeftShiftOperatorMethodType, lua.SyntaxKind.BitwiseLeftShiftOperator], |
| 33 | + [extensions.ExtensionKind.BitwiseRightShiftOperatorType, lua.SyntaxKind.BitwiseRightShiftOperator], |
| 34 | + [extensions.ExtensionKind.BitwiseRightShiftOperatorMethodType, lua.SyntaxKind.BitwiseRightShiftOperator], |
| 35 | + [extensions.ExtensionKind.ConcatOperatorType, lua.SyntaxKind.ConcatOperator], |
| 36 | + [extensions.ExtensionKind.ConcatOperatorMethodType, lua.SyntaxKind.ConcatOperator], |
| 37 | + [extensions.ExtensionKind.LessThanOperatorType, lua.SyntaxKind.LessThanOperator], |
| 38 | + [extensions.ExtensionKind.LessThanOperatorMethodType, lua.SyntaxKind.LessThanOperator], |
| 39 | + [extensions.ExtensionKind.GreaterThanOperatorType, lua.SyntaxKind.GreaterThanOperator], |
| 40 | + [extensions.ExtensionKind.GreaterThanOperatorMethodType, lua.SyntaxKind.GreaterThanOperator], |
| 41 | +]); |
| 42 | + |
| 43 | +const unaryOperatorMappings = new Map<extensions.ExtensionKind, lua.UnaryOperator>([ |
| 44 | + [extensions.ExtensionKind.NegationOperatorType, lua.SyntaxKind.NegationOperator], |
| 45 | + [extensions.ExtensionKind.NegationOperatorMethodType, lua.SyntaxKind.NegationOperator], |
| 46 | + [extensions.ExtensionKind.BitwiseNotOperatorType, lua.SyntaxKind.BitwiseNotOperator], |
| 47 | + [extensions.ExtensionKind.BitwiseNotOperatorMethodType, lua.SyntaxKind.BitwiseNotOperator], |
| 48 | + [extensions.ExtensionKind.LengthOperatorType, lua.SyntaxKind.LengthOperator], |
| 49 | + [extensions.ExtensionKind.LengthOperatorMethodType, lua.SyntaxKind.LengthOperator], |
| 50 | +]); |
| 51 | + |
| 52 | +const operatorMapExtensions = new Set<extensions.ExtensionKind>([ |
| 53 | + ...binaryOperatorMappings.keys(), |
| 54 | + ...unaryOperatorMappings.keys(), |
| 55 | +]); |
| 56 | + |
| 57 | +const bitwiseOperatorMapExtensions = new Set<extensions.ExtensionKind>([ |
| 58 | + extensions.ExtensionKind.BitwiseAndOperatorType, |
| 59 | + extensions.ExtensionKind.BitwiseAndOperatorMethodType, |
| 60 | + extensions.ExtensionKind.BitwiseOrOperatorType, |
| 61 | + extensions.ExtensionKind.BitwiseOrOperatorMethodType, |
| 62 | + extensions.ExtensionKind.BitwiseExclusiveOrOperatorType, |
| 63 | + extensions.ExtensionKind.BitwiseExclusiveOrOperatorMethodType, |
| 64 | + extensions.ExtensionKind.BitwiseLeftShiftOperatorType, |
| 65 | + extensions.ExtensionKind.BitwiseLeftShiftOperatorMethodType, |
| 66 | + extensions.ExtensionKind.BitwiseRightShiftOperatorType, |
| 67 | + extensions.ExtensionKind.BitwiseRightShiftOperatorMethodType, |
| 68 | + extensions.ExtensionKind.BitwiseNotOperatorType, |
| 69 | + extensions.ExtensionKind.BitwiseNotOperatorMethodType, |
| 70 | +]); |
| 71 | + |
| 72 | +function getTypeDeclaration(declaration: ts.Declaration) { |
| 73 | + return ts.isTypeAliasDeclaration(declaration) |
| 74 | + ? declaration |
| 75 | + : findFirstNodeAbove(declaration, ts.isTypeAliasDeclaration); |
| 76 | +} |
| 77 | + |
| 78 | +function getOperatorMapExtensionKindForCall(context: TransformationContext, node: ts.CallExpression) { |
| 79 | + const signature = context.checker.getResolvedSignature(node); |
| 80 | + if (!signature || !signature.declaration) { |
| 81 | + return; |
| 82 | + } |
| 83 | + const typeDeclaration = getTypeDeclaration(signature.declaration); |
| 84 | + if (!typeDeclaration) { |
| 85 | + return; |
| 86 | + } |
| 87 | + const mapping = extensions.getExtensionKind(typeDeclaration); |
| 88 | + if (mapping !== undefined && operatorMapExtensions.has(mapping)) { |
| 89 | + return mapping; |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +function isOperatorMapDeclaration(declaration: ts.Declaration) { |
| 94 | + const typeDeclaration = getTypeDeclaration(declaration); |
| 95 | + if (typeDeclaration) { |
| 96 | + const extensionKind = extensions.getExtensionKind(typeDeclaration); |
| 97 | + return extensionKind !== undefined ? operatorMapExtensions.has(extensionKind) : false; |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +function isOperatorMapType(context: TransformationContext, type: ts.Type): boolean { |
| 102 | + if (type.isUnionOrIntersection()) { |
| 103 | + return type.types.some(t => isOperatorMapType(context, t)); |
| 104 | + } else { |
| 105 | + return type.symbol?.declarations?.some(isOperatorMapDeclaration); |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +function isOperatorMapIdentifier(context: TransformationContext, node: ts.Identifier) { |
| 110 | + const type = context.checker.getTypeAtLocation(node); |
| 111 | + return isOperatorMapType(context, type); |
| 112 | +} |
| 113 | + |
| 114 | +export function isOperatorMapping(context: TransformationContext, node: ts.CallExpression | ts.Identifier) { |
| 115 | + if (ts.isCallExpression(node)) { |
| 116 | + return getOperatorMapExtensionKindForCall(context, node) !== undefined; |
| 117 | + } else { |
| 118 | + return isOperatorMapIdentifier(context, node); |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +export function transformOperatorMappingExpression( |
| 123 | + context: TransformationContext, |
| 124 | + node: ts.CallExpression |
| 125 | +): lua.Expression { |
| 126 | + const extensionKind = getOperatorMapExtensionKindForCall(context, node); |
| 127 | + assert(extensionKind); |
| 128 | + |
| 129 | + const isBefore53 = |
| 130 | + context.luaTarget === LuaTarget.Lua51 || |
| 131 | + context.luaTarget === LuaTarget.Lua52 || |
| 132 | + context.luaTarget === LuaTarget.LuaJIT || |
| 133 | + context.luaTarget === LuaTarget.Universal; |
| 134 | + if (isBefore53) { |
| 135 | + const luaTarget = context.luaTarget === LuaTarget.Universal ? LuaTarget.Lua51 : context.luaTarget; |
| 136 | + if (bitwiseOperatorMapExtensions.has(extensionKind)) { |
| 137 | + context.diagnostics.push(unsupportedForTarget(node, "Native bitwise operations", luaTarget)); |
| 138 | + } else if ( |
| 139 | + extensionKind === extensions.ExtensionKind.FloorDivisionOperatorType || |
| 140 | + extensionKind === extensions.ExtensionKind.FloorDivisionOperatorMethodType |
| 141 | + ) { |
| 142 | + context.diagnostics.push(unsupportedForTarget(node, "Floor division operator", luaTarget)); |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + const args = node.arguments.slice(); |
| 147 | + if (binaryOperatorMappings.has(extensionKind)) { |
| 148 | + if ( |
| 149 | + args.length === 1 && |
| 150 | + (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) |
| 151 | + ) { |
| 152 | + args.unshift(node.expression.expression); |
| 153 | + } |
| 154 | + |
| 155 | + const luaOperator = binaryOperatorMappings.get(extensionKind); |
| 156 | + assert(luaOperator); |
| 157 | + return lua.createBinaryExpression( |
| 158 | + context.transformExpression(args[0]), |
| 159 | + context.transformExpression(args[1]), |
| 160 | + luaOperator |
| 161 | + ); |
| 162 | + } else { |
| 163 | + let arg: ts.Expression; |
| 164 | + if ( |
| 165 | + args.length === 0 && |
| 166 | + (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) |
| 167 | + ) { |
| 168 | + arg = node.expression.expression; |
| 169 | + } else { |
| 170 | + arg = args[0]; |
| 171 | + } |
| 172 | + |
| 173 | + const luaOperator = unaryOperatorMappings.get(extensionKind); |
| 174 | + assert(luaOperator); |
| 175 | + return lua.createUnaryExpression(context.transformExpression(arg), luaOperator); |
| 176 | + } |
| 177 | +} |
0 commit comments