UNPKG

typescript-to-lua

Version:

A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!

165 lines 9.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.transformQualifiedName = exports.transformPropertyAccessExpression = exports.transformElementAccessExpression = void 0; exports.transformElementAccessArgument = transformElementAccessArgument; exports.transformElementAccessExpressionWithCapture = transformElementAccessExpressionWithCapture; exports.transformPropertyAccessExpressionWithCapture = transformPropertyAccessExpressionWithCapture; const ts = require("typescript"); const lua = require("../../LuaAST"); const builtins_1 = require("../builtins"); const annotations_1 = require("../utils/annotations"); const diagnostics_1 = require("../utils/diagnostics"); const language_extensions_1 = require("../utils/language-extensions"); const lua_ast_1 = require("../utils/lua-ast"); const lualib_1 = require("../utils/lualib"); const typescript_1 = require("../utils/typescript"); const enum_1 = require("./enum"); const expression_list_1 = require("./expression-list"); const call_extension_1 = require("./language-extensions/call-extension"); const multi_1 = require("./language-extensions/multi"); const optional_chaining_1 = require("./optional-chaining"); const typescript_2 = require("typescript"); const identifier_1 = require("./identifier"); const export_1 = require("../utils/export"); function addOneToArrayAccessArgument(context, node, index) { const type = context.checker.getTypeAtLocation(node.expression); const argumentType = context.checker.getTypeAtLocation(node.argumentExpression); if ((0, typescript_1.isArrayType)(context, type) && (0, typescript_1.isNumberType)(context, argumentType)) { return (0, lua_ast_1.addToNumericExpression)(index, 1); } return index; } function transformElementAccessArgument(context, node) { const index = context.transformExpression(node.argumentExpression); return addOneToArrayAccessArgument(context, node, index); } const transformElementAccessExpression = (node, context) => transformElementAccessExpressionWithCapture(context, node, undefined).expression; exports.transformElementAccessExpression = transformElementAccessExpression; function transformElementAccessExpressionWithCapture(context, node, thisValueCapture) { const constEnumValue = (0, enum_1.tryGetConstEnumValue)(context, node); if (constEnumValue) { return { expression: constEnumValue }; } if (ts.isOptionalChain(node)) { return (0, optional_chaining_1.transformOptionalChainWithCapture)(context, node, thisValueCapture); } const [table, accessExpression] = (0, expression_list_1.transformOrderedExpressions)(context, [node.expression, node.argumentExpression]); const type = context.checker.getTypeAtLocation(node.expression); const argumentType = context.checker.getTypeAtLocation(node.argumentExpression); if ((0, typescript_1.isStringType)(context, type) && (0, typescript_1.isNumberType)(context, argumentType)) { // strings are not callable, so ignore thisValueCapture return { expression: (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.StringAccess, node, table, accessExpression), }; } const updatedAccessExpression = addOneToArrayAccessArgument(context, node, accessExpression); if ((0, multi_1.isMultiReturnCall)(context, node.expression)) { const accessType = context.checker.getTypeAtLocation(node.argumentExpression); if (!(0, typescript_1.isNumberType)(context, accessType)) { context.diagnostics.push((0, diagnostics_1.invalidMultiReturnAccess)(node)); } const canOmitSelect = ts.isNumericLiteral(node.argumentExpression) && node.argumentExpression.text === "0"; if (canOmitSelect) { // wrapping in parenthesis ensures only the first return value is used // https://www.lua.org/manual/5.1/manual.html#2.5 return { expression: lua.createParenthesizedExpression(table) }; } const selectIdentifier = lua.createIdentifier("select"); return { expression: lua.createCallExpression(selectIdentifier, [updatedAccessExpression, table]) }; } if (thisValueCapture) { const thisValue = (0, optional_chaining_1.captureThisValue)(context, table, thisValueCapture, node.expression); return { expression: lua.createTableIndexExpression(thisValue, updatedAccessExpression, node), thisValue, }; } return { expression: lua.createTableIndexExpression(table, updatedAccessExpression, node) }; } const transformPropertyAccessExpression = (node, context) => transformPropertyAccessExpressionWithCapture(context, node, undefined).expression; exports.transformPropertyAccessExpression = transformPropertyAccessExpression; function transformPropertyAccessExpressionWithCapture(context, node, thisValueCapture) { const type = context.checker.getTypeAtLocation(node.expression); const isOptionalLeft = (0, optional_chaining_1.isOptionalContinuation)(node.expression); let property = node.name.text; const symbol = context.checker.getSymbolAtLocation(node.name); const customName = (0, identifier_1.getCustomNameFromSymbol)(context, symbol); if (customName) { property = customName; } const constEnumValue = (0, enum_1.tryGetConstEnumValue)(context, node); if (constEnumValue) { return { expression: constEnumValue }; } if (ts.isCallExpression(node.expression) && (0, multi_1.returnsMultiType)(context, node.expression)) { context.diagnostics.push((0, diagnostics_1.invalidMultiReturnAccess)(node)); } if (ts.isOptionalChain(node)) { return (0, optional_chaining_1.transformOptionalChainWithCapture)(context, node, thisValueCapture); } // Do not output path for member only enums const annotations = (0, annotations_1.getTypeAnnotations)(type); if (annotations.has(annotations_1.AnnotationKind.CompileMembersOnly)) { if (isOptionalLeft) { context.diagnostics.push((0, diagnostics_1.unsupportedOptionalCompileMembersOnly)(node)); } if (ts.isPropertyAccessExpression(node.expression)) { // in case of ...x.enum.y transform to ...x.y const expression = lua.createTableIndexExpression(context.transformExpression(node.expression.expression), lua.createStringLiteral(property), node); return { expression }; } else { // Check if we need to account for enum being exported int his file if ((0, export_1.isSymbolExported)(context, type.symbol) && (0, export_1.getSymbolExportScope)(context, type.symbol) === node.expression.getSourceFile()) { return { expression: lua.createTableIndexExpression((0, lua_ast_1.createExportsIdentifier)(), lua.createStringLiteral(property), node), }; } else { return { expression: lua.createIdentifier(property, node) }; } } } const builtinResult = (0, builtins_1.transformBuiltinPropertyAccessExpression)(context, node); if (builtinResult) { // Ignore thisValueCapture. // This assumes that nothing returned by builtin property accesses are callable. // If this assumption is no longer true, this may need to be updated. return { expression: builtinResult }; } if (ts.isIdentifier(node.expression) && node.parent && (!ts.isCallExpression(node.parent) || node.parent.expression !== node)) { // Check if this is a method call extension that is not used as a call const extensionType = (0, language_extensions_1.getExtensionKindForNode)(context, node); if (extensionType && call_extension_1.callExtensions.has(extensionType)) { context.diagnostics.push((0, diagnostics_1.invalidCallExtensionUse)(node)); } } const table = context.transformExpression(node.expression); if (thisValueCapture) { const thisValue = (0, optional_chaining_1.captureThisValue)(context, table, thisValueCapture, node.expression); const expression = lua.createTableIndexExpression(thisValue, lua.createStringLiteral(property), node); return { expression, thisValue, }; } if (node.expression.kind === typescript_2.SyntaxKind.SuperKeyword) { const symbol = context.checker.getSymbolAtLocation(node); if (symbol && symbol.flags & ts.SymbolFlags.GetAccessor) { return { expression: (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.DescriptorGet, node, lua.createIdentifier("self"), table, lua.createStringLiteral(property)), }; } } return { expression: lua.createTableIndexExpression(table, lua.createStringLiteral(property), node) }; } const transformQualifiedName = (node, context) => { const right = lua.createStringLiteral(node.right.text, node.right); const left = context.transformExpression(node.left); return lua.createTableIndexExpression(left, right, node); }; exports.transformQualifiedName = transformQualifiedName; //# sourceMappingURL=access.js.map