roblox-ts
Version:
A TypeScript-to-Luau Compiler for Roblox
191 lines • 11.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformCallExpressionInner = transformCallExpressionInner;
exports.transformPropertyCallExpressionInner = transformPropertyCallExpressionInner;
exports.transformElementCallExpressionInner = transformElementCallExpressionInner;
exports.transformCallExpression = transformCallExpression;
const luau_ast_1 = __importDefault(require("@roblox-ts/luau-ast"));
const diagnostics_1 = require("../../../Shared/diagnostics");
const assert_1 = require("../../../Shared/util/assert");
const DiagnosticService_1 = require("../../classes/DiagnosticService");
const transformExpression_1 = require("./transformExpression");
const transformImportExpression_1 = require("./transformImportExpression");
const transformOptionalChain_1 = require("../transformOptionalChain");
const addOneIfArrayType_1 = require("../../util/addOneIfArrayType");
const convertToIndexableExpression_1 = require("../../util/convertToIndexableExpression");
const ensureTransformOrder_1 = require("../../util/ensureTransformOrder");
const expressionMightMutate_1 = require("../../util/expressionMightMutate");
const isMethod_1 = require("../../util/isMethod");
const types_1 = require("../../util/types");
const validateNotAny_1 = require("../../util/validateNotAny");
const valueToIdStr_1 = require("../../util/valueToIdStr");
const wrapReturnIfLuaTuple_1 = require("../../util/wrapReturnIfLuaTuple");
const typescript_1 = __importDefault(require("typescript"));
function runCallMacro(macro, state, node, expression, nodeArguments) {
let args;
const prereqs = state.capturePrereqs(() => {
args = (0, ensureTransformOrder_1.ensureTransformOrder)(state, nodeArguments);
const lastArg = nodeArguments[nodeArguments.length - 1];
if (lastArg && typescript_1.default.isSpreadElement(lastArg)) {
const signature = state.typeChecker.getSignaturesOfType(state.getType(node.expression), typescript_1.default.SignatureKind.Call)[0];
const lastParameter = signature.parameters[signature.parameters.length - 1].valueDeclaration;
if (lastParameter && typescript_1.default.isParameter(lastParameter) && lastParameter.dotDotDotToken) {
DiagnosticService_1.DiagnosticService.addDiagnostic(diagnostics_1.errors.noVarArgsMacroSpread(lastArg));
return;
}
const tupleArgType = state.getType(lastArg.expression);
(0, assert_1.assert)(state.typeChecker.isTupleType(tupleArgType));
const argumentCount = tupleArgType.target.elementFlags.length;
const spread = args.pop();
const tempIds = luau_ast_1.default.list.make();
for (let i = args.length; i < argumentCount; i++) {
const tempId = luau_ast_1.default.tempId(`spread${i}`);
args.push(tempId);
luau_ast_1.default.list.push(tempIds, tempId);
}
state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.VariableDeclaration, {
left: tempIds,
right: spread,
}));
}
for (let i = 0; i < args.length; i++) {
if ((0, expressionMightMutate_1.expressionMightMutate)(state, args[i], nodeArguments[i])) {
args[i] = state.pushToVar(args[i], (0, valueToIdStr_1.valueToIdStr)(args[i]) || `arg${i}`);
}
}
});
let nodeExpression = node.expression;
if (typescript_1.default.isPropertyAccessExpression(nodeExpression) || typescript_1.default.isElementAccessExpression(nodeExpression)) {
nodeExpression = nodeExpression.expression;
}
if (!luau_ast_1.default.list.isEmpty(prereqs) && (0, expressionMightMutate_1.expressionMightMutate)(state, expression, nodeExpression)) {
expression = state.pushToVar(expression, (0, valueToIdStr_1.valueToIdStr)(expression) || "exp");
}
state.prereqList(prereqs);
return (0, wrapReturnIfLuaTuple_1.wrapReturnIfLuaTuple)(state, node, macro(state, node, expression, args));
}
function fixVoidArgumentsForRobloxFunctions(state, type, args, nodeArguments) {
if ((0, types_1.isPossiblyType)(type, (0, types_1.isRobloxType)(state))) {
for (let i = 0; i < args.length; i++) {
const arg = args[i];
const nodeArg = nodeArguments[i];
if (typescript_1.default.isCallExpression(nodeArg) && (0, types_1.isPossiblyType)(state.getType(nodeArg), types_1.isUndefinedType)) {
args[i] = luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ParenthesizedExpression, {
expression: arg,
});
}
}
}
}
function transformCallExpressionInner(state, node, expression, nodeArguments) {
if (typescript_1.default.isImportCall(node)) {
return (0, transformImportExpression_1.transformImportExpression)(state, node);
}
(0, validateNotAny_1.validateNotAnyType)(state, node.expression);
if (typescript_1.default.isSuperCall(node)) {
return luau_ast_1.default.call(luau_ast_1.default.property((0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), "constructor"), [
luau_ast_1.default.globals.self,
...(0, ensureTransformOrder_1.ensureTransformOrder)(state, node.arguments),
]);
}
const expType = state.typeChecker.getNonOptionalType(state.getType(node.expression));
const symbol = (0, types_1.getFirstDefinedSymbol)(state, expType);
if (symbol) {
const macro = state.services.macroManager.getCallMacro(symbol);
if (macro) {
return runCallMacro(macro, state, node, expression, nodeArguments);
}
}
const [args, prereqs] = state.capture(() => (0, ensureTransformOrder_1.ensureTransformOrder)(state, nodeArguments));
fixVoidArgumentsForRobloxFunctions(state, expType, args, nodeArguments);
if (!luau_ast_1.default.list.isEmpty(prereqs) && (0, expressionMightMutate_1.expressionMightMutate)(state, expression, node.expression)) {
expression = state.pushToVar(expression, "fn");
}
state.prereqList(prereqs);
const exp = luau_ast_1.default.call((0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), args);
return (0, wrapReturnIfLuaTuple_1.wrapReturnIfLuaTuple)(state, node, exp);
}
function transformPropertyCallExpressionInner(state, node, expression, baseExpression, name, nodeArguments) {
(0, validateNotAny_1.validateNotAnyType)(state, expression.expression);
(0, validateNotAny_1.validateNotAnyType)(state, node.expression);
if (typescript_1.default.isSuperProperty(expression)) {
return luau_ast_1.default.call(luau_ast_1.default.property((0, convertToIndexableExpression_1.convertToIndexableExpression)(baseExpression), expression.name.text), [
luau_ast_1.default.globals.self,
...(0, ensureTransformOrder_1.ensureTransformOrder)(state, node.arguments),
]);
}
const expType = state.typeChecker.getNonOptionalType(state.getType(node.expression));
const symbol = (0, types_1.getFirstDefinedSymbol)(state, expType);
if (symbol) {
const macro = state.services.macroManager.getPropertyCallMacro(symbol);
if (macro) {
return runCallMacro(macro, state, node, baseExpression, nodeArguments);
}
}
const [args, prereqs] = state.capture(() => (0, ensureTransformOrder_1.ensureTransformOrder)(state, nodeArguments));
fixVoidArgumentsForRobloxFunctions(state, expType, args, nodeArguments);
if (!luau_ast_1.default.list.isEmpty(prereqs) && (0, expressionMightMutate_1.expressionMightMutate)(state, baseExpression, expression.expression)) {
baseExpression = state.pushToVar(baseExpression);
}
state.prereqList(prereqs);
let exp;
if ((0, isMethod_1.isMethod)(state, expression)) {
if (luau_ast_1.default.isValidIdentifier(name)) {
exp = luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.MethodCallExpression, {
name,
expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(baseExpression),
args: luau_ast_1.default.list.make(...args),
});
}
else {
baseExpression = state.pushToVarIfComplex(baseExpression);
args.unshift(baseExpression);
exp = luau_ast_1.default.call(luau_ast_1.default.property((0, convertToIndexableExpression_1.convertToIndexableExpression)(baseExpression), name), args);
}
}
else {
exp = luau_ast_1.default.call(luau_ast_1.default.property((0, convertToIndexableExpression_1.convertToIndexableExpression)(baseExpression), name), args);
}
return (0, wrapReturnIfLuaTuple_1.wrapReturnIfLuaTuple)(state, node, exp);
}
function transformElementCallExpressionInner(state, node, expression, baseExpression, argumentExpression, nodeArguments) {
(0, validateNotAny_1.validateNotAnyType)(state, expression.expression);
(0, validateNotAny_1.validateNotAnyType)(state, expression.argumentExpression);
(0, validateNotAny_1.validateNotAnyType)(state, node.expression);
if (typescript_1.default.isSuperProperty(expression)) {
return luau_ast_1.default.call(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, {
expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(baseExpression),
index: (0, transformExpression_1.transformExpression)(state, expression.argumentExpression),
}), [luau_ast_1.default.globals.self, ...(0, ensureTransformOrder_1.ensureTransformOrder)(state, node.arguments)]);
}
const expType = state.typeChecker.getNonOptionalType(state.getType(node.expression));
const symbol = (0, types_1.getFirstDefinedSymbol)(state, expType);
if (symbol) {
const macro = state.services.macroManager.getPropertyCallMacro(symbol);
if (macro) {
return runCallMacro(macro, state, node, baseExpression, nodeArguments);
}
}
const [[argumentExp, ...args], prereqs] = state.capture(() => (0, ensureTransformOrder_1.ensureTransformOrder)(state, [argumentExpression, ...nodeArguments]));
fixVoidArgumentsForRobloxFunctions(state, expType, args, nodeArguments);
if (!luau_ast_1.default.list.isEmpty(prereqs) && (0, expressionMightMutate_1.expressionMightMutate)(state, baseExpression, expression.expression)) {
baseExpression = state.pushToVar(baseExpression);
}
state.prereqList(prereqs);
if ((0, isMethod_1.isMethod)(state, expression)) {
baseExpression = state.pushToVarIfComplex(baseExpression);
args.unshift(baseExpression);
}
const exp = luau_ast_1.default.call(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, {
expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(baseExpression),
index: (0, addOneIfArrayType_1.addOneIfArrayType)(state, state.typeChecker.getNonOptionalType(state.getType(expression.expression)), argumentExp),
}), args);
return (0, wrapReturnIfLuaTuple_1.wrapReturnIfLuaTuple)(state, node, exp);
}
function transformCallExpression(state, node) {
return (0, transformOptionalChain_1.transformOptionalChain)(state, node);
}
//# sourceMappingURL=transformCallExpression.js.map