UNPKG

typescript-to-lua

Version:

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

207 lines 11.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.transformCallExpression = void 0; exports.validateArguments = validateArguments; exports.transformArguments = transformArguments; exports.transformCallAndArguments = transformCallAndArguments; exports.transformContextualCallExpression = transformContextualCallExpression; exports.getCalledExpression = getCalledExpression; const ts = require("typescript"); const lua = require("../../LuaAST"); const builtins_1 = require("../builtins"); const assignment_validation_1 = require("../utils/assignment-validation"); const function_context_1 = require("../utils/function-context"); const lua_ast_1 = require("../utils/lua-ast"); const safe_names_1 = require("../utils/safe-names"); const typescript_1 = require("../utils/typescript"); const access_1 = require("./access"); const multi_1 = require("./language-extensions/multi"); const diagnostics_1 = require("../utils/diagnostics"); const expression_list_1 = require("./expression-list"); const preceding_statements_1 = require("../utils/preceding-statements"); const optional_chaining_1 = require("./optional-chaining"); const import_1 = require("./modules/import"); const call_extension_1 = require("./language-extensions/call-extension"); const identifier_1 = require("./identifier"); function validateArguments(context, params, signature) { if (!signature || signature.parameters.length < params.length) { return; } for (const [index, param] of params.entries()) { const signatureParameter = signature.parameters[index]; if (signatureParameter.valueDeclaration !== undefined) { const signatureType = context.checker.getTypeAtLocation(signatureParameter.valueDeclaration); const paramType = context.checker.getTypeAtLocation(param); (0, assignment_validation_1.validateAssignment)(context, param, paramType, signatureType, signatureParameter.name); } } } function transformArguments(context, params, signature, callContext) { validateArguments(context, params, signature); return (0, expression_list_1.transformExpressionList)(context, callContext ? [callContext, ...params] : params); } function transformCallWithArguments(context, callExpression, transformedArguments, argPrecedingStatements, callContext) { let call = context.transformExpression(callExpression); let transformedContext; if (callContext) { transformedContext = context.transformExpression(callContext); } if (argPrecedingStatements.length > 0) { if (transformedContext) { transformedContext = (0, expression_list_1.moveToPrecedingTemp)(context, transformedContext, callContext); } call = (0, expression_list_1.moveToPrecedingTemp)(context, call, callExpression); context.addPrecedingStatements(argPrecedingStatements); } if (transformedContext) { transformedArguments.unshift(transformedContext); } return [call, transformedArguments]; } function transformCallAndArguments(context, callExpression, params, signature, callContext) { const { precedingStatements: argPrecedingStatements, result: transformedArguments } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => transformArguments(context, params, signature, callContext)); return transformCallWithArguments(context, callExpression, transformedArguments, argPrecedingStatements); } function transformElementAccessCall(context, left, transformedArguments, argPrecedingStatements) { // Cache left-side if it has effects // local ____self = context; return ____self[argument](parameters); const selfIdentifier = lua.createIdentifier(context.createTempName("self")); const callContext = context.transformExpression(left.expression); const selfAssignment = lua.createVariableDeclarationStatement(selfIdentifier, callContext); context.addPrecedingStatements(selfAssignment); const argument = ts.isElementAccessExpression(left) ? (0, access_1.transformElementAccessArgument)(context, left) : lua.createStringLiteral(left.name.text); let index = lua.createTableIndexExpression(selfIdentifier, argument); if (argPrecedingStatements.length > 0) { // Cache index in temp if args had preceding statements index = (0, expression_list_1.moveToPrecedingTemp)(context, index); context.addPrecedingStatements(argPrecedingStatements); } return lua.createCallExpression(index, [selfIdentifier, ...transformedArguments]); } function transformContextualCallExpression(context, node, args) { if (ts.isOptionalChain(node)) { return (0, optional_chaining_1.transformOptionalChain)(context, node); } const left = ts.isCallExpression(node) ? getCalledExpression(node) : node.tag; let { precedingStatements: argPrecedingStatements, result: transformedArguments } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => transformArguments(context, args)); if (ts.isPropertyAccessExpression(left) && ts.isIdentifier(left.name) && (0, safe_names_1.isValidLuaIdentifier)(left.name.text, context.options) && argPrecedingStatements.length === 0) { // table:name() const table = context.transformExpression(left.expression); let name = left.name.text; const symbol = context.checker.getSymbolAtLocation(left); const customName = (0, identifier_1.getCustomNameFromSymbol)(context, symbol); if (customName) { name = customName; } return lua.createMethodCallExpression(table, lua.createIdentifier(name, left.name), transformedArguments, node); } else if (ts.isElementAccessExpression(left) || ts.isPropertyAccessExpression(left)) { if ((0, typescript_1.isExpressionWithEvaluationEffect)(left.expression)) { return transformElementAccessCall(context, left, transformedArguments, argPrecedingStatements); } else { let expression; [expression, transformedArguments] = transformCallWithArguments(context, left, transformedArguments, argPrecedingStatements, left.expression); return lua.createCallExpression(expression, transformedArguments, node); } } else if (ts.isIdentifier(left) || ts.isCallExpression(left)) { const callContext = context.isStrict ? ts.factory.createNull() : ts.factory.createIdentifier("_G"); let expression; [expression, transformedArguments] = transformCallWithArguments(context, left, transformedArguments, argPrecedingStatements, callContext); return lua.createCallExpression(expression, transformedArguments, node); } else { throw new Error(`Unsupported LeftHandSideExpression kind: ${ts.SyntaxKind[left.kind]}`); } } function transformPropertyCall(context, node, calledMethod) { const signature = context.checker.getResolvedSignature(node); if (calledMethod.expression.kind === ts.SyntaxKind.SuperKeyword) { // Super calls take the format of super.call(self,...) const parameters = transformArguments(context, node.arguments, signature, ts.factory.createThis()); return lua.createCallExpression(context.transformExpression(node.expression), parameters, node); } if ((0, function_context_1.getCallContextType)(context, node) !== function_context_1.ContextType.Void) { // table:name() return transformContextualCallExpression(context, node, node.arguments); } else { // table.name() const [callPath, parameters] = transformCallAndArguments(context, node.expression, node.arguments, signature); return lua.createCallExpression(callPath, parameters, node); } } function transformElementCall(context, node) { if ((0, function_context_1.getCallContextType)(context, node) !== function_context_1.ContextType.Void) { // A contextual parameter must be given to this call expression return transformContextualCallExpression(context, node, node.arguments); } else { // No context const [expression, parameters] = transformCallAndArguments(context, node.expression, node.arguments); return lua.createCallExpression(expression, parameters, node); } } const transformCallExpression = (node, context) => { var _a; const calledExpression = getCalledExpression(node); if (calledExpression.kind === ts.SyntaxKind.ImportKeyword) { return (0, import_1.transformImportExpression)(node, context); } if (ts.isOptionalChain(node)) { return (0, optional_chaining_1.transformOptionalChain)(context, node); } const optionalContinuation = ts.isIdentifier(calledExpression) ? (0, optional_chaining_1.getOptionalContinuationData)(calledExpression) : undefined; const wrapResultInTable = (0, multi_1.isMultiReturnCall)(context, node) && (0, multi_1.shouldMultiReturnCallBeWrapped)(context, node); const builtinOrExtensionResult = (_a = (0, builtins_1.transformBuiltinCallExpression)(context, node)) !== null && _a !== void 0 ? _a : (0, call_extension_1.transformLanguageExtensionCallExpression)(context, node); if (builtinOrExtensionResult) { if (optionalContinuation !== undefined) { context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node)); } return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(builtinOrExtensionResult) : builtinOrExtensionResult; } if (ts.isPropertyAccessExpression(calledExpression)) { const result = transformPropertyCall(context, node, calledExpression); return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(result) : result; } if (ts.isElementAccessExpression(calledExpression)) { const result = transformElementCall(context, node); return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(result) : result; } const signature = context.checker.getResolvedSignature(node); // Handle super calls properly if (calledExpression.kind === ts.SyntaxKind.SuperKeyword) { const parameters = transformArguments(context, node.arguments, signature, ts.factory.createThis()); return lua.createCallExpression(lua.createTableIndexExpression(context.transformExpression(ts.factory.createSuper()), lua.createStringLiteral("____constructor")), parameters, node); } let callPath; let parameters; const isContextualCall = (0, function_context_1.getCallContextType)(context, node) !== function_context_1.ContextType.Void; if (!isContextualCall) { [callPath, parameters] = transformCallAndArguments(context, calledExpression, node.arguments, signature); } else { // if is optionalContinuation, context will be handled by transformOptionalChain. const useGlobalContext = !context.isStrict && optionalContinuation === undefined; const callContext = useGlobalContext ? ts.factory.createIdentifier("_G") : ts.factory.createNull(); [callPath, parameters] = transformCallAndArguments(context, calledExpression, node.arguments, signature, callContext); } const callExpression = lua.createCallExpression(callPath, parameters, node); if (optionalContinuation && isContextualCall) { optionalContinuation.contextualCall = callExpression; } return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(callExpression) : callExpression; }; exports.transformCallExpression = transformCallExpression; function getCalledExpression(node) { return ts.skipOuterExpressions(node.expression); } //# sourceMappingURL=call.js.map