UNPKG

typescript-to-lua

Version:

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

240 lines 13.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); 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 = __importStar(require("typescript")); const lua = __importStar(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