UNPKG

roblox-ts

Version:

A TypeScript-to-Luau Compiler for Roblox

726 lines 38.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PROPERTY_CALL_MACROS = void 0; const luau_ast_1 = __importDefault(require("@roblox-ts/luau-ast")); const assert_1 = require("../../Shared/util/assert"); const convertToIndexableExpression_1 = require("../util/convertToIndexableExpression"); const isUsedAsStatement_1 = require("../util/isUsedAsStatement"); const offset_1 = require("../util/offset"); const types_1 = require("../util/types"); const valueToIdStr_1 = require("../util/valueToIdStr"); const typescript_1 = __importDefault(require("typescript")); function makeMathMethod(operator) { return (state, node, expression, args) => { let rhs = args[0]; if (!luau_ast_1.default.isSimple(rhs)) { rhs = luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ParenthesizedExpression, { expression: rhs }); } return luau_ast_1.default.binary(expression, operator, rhs); }; } const OPERATOR_TO_NAME_MAP = new Map([ ["+", "add"], ["-", "sub"], ["*", "mul"], ["/", "div"], ["//", "idiv"], ]); function makeMathSet(...operators) { const result = {}; for (const operator of operators) { const methodName = OPERATOR_TO_NAME_MAP.get(operator); (0, assert_1.assert)(methodName); result[methodName] = makeMathMethod(operator); } return result; } function makeStringCallback(strCallback) { return (state, node, expression, args) => { return luau_ast_1.default.call(strCallback, [expression, ...args]); }; } const STRING_CALLBACKS = { size: (state, node, expression) => luau_ast_1.default.unary("#", expression), byte: makeStringCallback(luau_ast_1.default.globals.string.byte), find: makeStringCallback(luau_ast_1.default.globals.string.find), format: makeStringCallback(luau_ast_1.default.globals.string.format), gmatch: makeStringCallback(luau_ast_1.default.globals.string.gmatch), gsub: makeStringCallback(luau_ast_1.default.globals.string.gsub), lower: makeStringCallback(luau_ast_1.default.globals.string.lower), match: makeStringCallback(luau_ast_1.default.globals.string.match), rep: makeStringCallback(luau_ast_1.default.globals.string.rep), reverse: makeStringCallback(luau_ast_1.default.globals.string.reverse), split: makeStringCallback(luau_ast_1.default.globals.string.split), sub: makeStringCallback(luau_ast_1.default.globals.string.sub), upper: makeStringCallback(luau_ast_1.default.globals.string.upper), }; function makeEveryOrSomeMethod(callbackArgsListMaker, initialState) { return (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const resultId = state.pushToVar(luau_ast_1.default.bool(initialState), "result"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const keyId = luau_ast_1.default.tempId("k"); const valueId = luau_ast_1.default.tempId("v"); const callCallback = luau_ast_1.default.call(callbackId, callbackArgsListMaker(keyId, valueId, expression)); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(keyId, valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: initialState ? luau_ast_1.default.unary("not", callCallback) : callCallback, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: resultId, operator: "=", right: luau_ast_1.default.bool(!initialState), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BreakStatement, {})), elseBody: luau_ast_1.default.list.make(), })), })); return resultId; }; } function makeEveryMethod(callbackArgsListMaker) { return makeEveryOrSomeMethod(callbackArgsListMaker, true); } function makeSomeMethod(callbackArgsListMaker) { return makeEveryOrSomeMethod(callbackArgsListMaker, false); } function argumentsWithDefaults(state, args, defaults) { for (let i = 0; i < args.length; i++) { if (!luau_ast_1.default.isSimplePrimitive(args[i])) { args[i] = state.pushToVar(args[i], (0, valueToIdStr_1.valueToIdStr)(args[i]) || `arg${i}`); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.binary(args[i], "==", luau_ast_1.default.nil()), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: args[i], operator: "=", right: defaults[i], })), elseBody: luau_ast_1.default.list.make(), })); } } for (let j = args.length; j < defaults.length; j++) { args[j] = defaults[j]; } return args; } const ARRAY_LIKE_METHODS = { size: (state, node, expression) => luau_ast_1.default.unary("#", expression), }; const READONLY_ARRAY_METHODS = { isEmpty: (state, node, expression) => luau_ast_1.default.binary(luau_ast_1.default.unary("#", expression), "==", luau_ast_1.default.number(0)), join: (state, node, expression, args) => { args = argumentsWithDefaults(state, args, [luau_ast_1.default.strings[", "]]); const indexType = state.typeChecker.getIndexTypeOfType(state.getType(node.expression.expression), typescript_1.default.IndexKind.Number); if (indexType && !(0, types_1.isDefinitelyType)(indexType, types_1.isStringType, types_1.isNumberType)) { expression = state.pushToVarIfComplex(expression, "exp"); const id = state.pushToVar(luau_ast_1.default.call(luau_ast_1.default.globals.table.create, [luau_ast_1.default.unary("#", expression)]), "result"); const keyId = luau_ast_1.default.tempId("k"); const valueId = luau_ast_1.default.tempId("v"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(keyId, valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: id, index: keyId, }), operator: "=", right: luau_ast_1.default.call(luau_ast_1.default.globals.tostring, [valueId]), })), })); expression = id; } return luau_ast_1.default.call(luau_ast_1.default.globals.table.concat, [expression, args[0]]); }, move: (state, node, expression, args) => { const moveArgs = [expression, (0, offset_1.offset)(args[0], 1), (0, offset_1.offset)(args[1], 1), (0, offset_1.offset)(args[2], 1)]; if (args[3]) { moveArgs.push(args[3]); } return luau_ast_1.default.call(luau_ast_1.default.globals.table.move, moveArgs); }, includes: (state, node, expression, args) => { const callArgs = [expression, args[0]]; if (args[1]) { callArgs.push((0, offset_1.offset)(args[1], 1)); } return luau_ast_1.default.binary(luau_ast_1.default.call(luau_ast_1.default.globals.table.find, callArgs), "~=", luau_ast_1.default.nil()); }, indexOf: (state, node, expression, args) => { const findArgs = [expression, args[0]]; if (args.length > 1) { findArgs.push((0, offset_1.offset)(args[1], 1)); } return (0, offset_1.offset)(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BinaryExpression, { left: luau_ast_1.default.call(luau_ast_1.default.globals.table.find, findArgs), operator: "or", right: luau_ast_1.default.number(0), }), -1); }, every: makeEveryMethod((keyId, valueId, expression) => [valueId, (0, offset_1.offset)(keyId, -1), expression]), some: makeSomeMethod((keyId, valueId, expression) => [valueId, (0, offset_1.offset)(keyId, -1), expression]), forEach: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const keyId = luau_ast_1.default.tempId("k"); const valueId = luau_ast_1.default.tempId("v"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(keyId, valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(callbackId, [valueId, (0, offset_1.offset)(keyId, -1), expression]), })), })); return !(0, isUsedAsStatement_1.isUsedAsStatement)(node) ? luau_ast_1.default.nil() : luau_ast_1.default.none(); }, map: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const newValueId = state.pushToVar(luau_ast_1.default.call(luau_ast_1.default.globals.table.create, [luau_ast_1.default.unary("#", expression)]), "newValue"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const keyId = luau_ast_1.default.tempId("k"); const valueId = luau_ast_1.default.tempId("v"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(keyId, valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: newValueId, index: keyId, }), operator: "=", right: luau_ast_1.default.call(callbackId, [valueId, (0, offset_1.offset)(keyId, -1), expression]), })), })); return newValueId; }, mapFiltered: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const newValueId = state.pushToVar(luau_ast_1.default.array(), "newValue"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const lengthId = state.pushToVar(luau_ast_1.default.number(0), "length"); const keyId = luau_ast_1.default.tempId("k"); const valueId = luau_ast_1.default.tempId("v"); const resultId = luau_ast_1.default.tempId("result"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(keyId, valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.VariableDeclaration, { left: resultId, right: luau_ast_1.default.call(callbackId, [valueId, (0, offset_1.offset)(keyId, -1), expression]), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.binary(resultId, "~=", luau_ast_1.default.nil()), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: lengthId, operator: "+=", right: luau_ast_1.default.number(1), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: newValueId, index: lengthId, }), operator: "=", right: resultId, })), elseBody: luau_ast_1.default.list.make(), })), })); return newValueId; }, filterUndefined: (state, node, expression) => { expression = state.pushToVarIfComplex(expression, "exp"); const lengthId = state.pushToVar(luau_ast_1.default.number(0), "length"); const indexId1 = luau_ast_1.default.tempId("i"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(indexId1), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.binary(indexId1, ">", lengthId), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: lengthId, operator: "=", right: indexId1, })), elseBody: luau_ast_1.default.list.make(), })), })); const resultId = state.pushToVar(luau_ast_1.default.array(), "result"); const resultLengthId = state.pushToVar(luau_ast_1.default.number(0), "resultLength"); const indexId2 = luau_ast_1.default.tempId("i"); const valueId = luau_ast_1.default.tempId("v"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.NumericForStatement, { id: indexId2, start: luau_ast_1.default.number(1), end: lengthId, step: undefined, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.VariableDeclaration, { left: valueId, right: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: indexId2, }), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.binary(valueId, "~=", luau_ast_1.default.nil()), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: resultLengthId, operator: "+=", right: luau_ast_1.default.number(1), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: resultId, index: resultLengthId, }), operator: "=", right: valueId, })), elseBody: luau_ast_1.default.list.make(), })), })); return resultId; }, filter: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const newValueId = state.pushToVar(luau_ast_1.default.array(), "newValue"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const lengthId = state.pushToVar(luau_ast_1.default.number(0), "length"); const keyId = luau_ast_1.default.tempId("k"); const valueId = luau_ast_1.default.tempId("v"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(keyId, valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BinaryExpression, { left: luau_ast_1.default.call(callbackId, [valueId, (0, offset_1.offset)(keyId, -1), expression]), operator: "==", right: luau_ast_1.default.bool(true), }), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: lengthId, operator: "+=", right: luau_ast_1.default.number(1), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: newValueId, index: lengthId, }), operator: "=", right: valueId, })), elseBody: luau_ast_1.default.list.make(), })), })); return newValueId; }, reduce: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); let start = luau_ast_1.default.number(1); const end = luau_ast_1.default.unary("#", expression); const step = 1; const lengthExp = luau_ast_1.default.unary("#", expression); let resultId; if (args.length < 2) { state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.binary(lengthExp, "==", luau_ast_1.default.number(0)), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(luau_ast_1.default.globals.error, [ luau_ast_1.default.string("Attempted to call `ReadonlyArray.reduce()` on an empty array without an initialValue."), ]), })), elseBody: luau_ast_1.default.list.make(), })); resultId = state.pushToVar(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: start, }), "result"); start = (0, offset_1.offset)(start, step); } else { resultId = state.pushToVar(args[1], "result"); } const callbackId = state.pushToVar(args[0], "callback"); const iteratorId = luau_ast_1.default.tempId("i"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.NumericForStatement, { id: iteratorId, start, end, step: step === 1 ? undefined : luau_ast_1.default.number(step), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: resultId, operator: "=", right: luau_ast_1.default.call(callbackId, [ resultId, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: iteratorId, }), (0, offset_1.offset)(iteratorId, -1), expression, ]), })), })); return resultId; }, find: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const loopId = luau_ast_1.default.tempId("i"); const valueId = luau_ast_1.default.tempId("v"); const resultId = state.pushToVar(undefined, "result"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { expression, ids: luau_ast_1.default.list.make(loopId, valueId), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BinaryExpression, { left: luau_ast_1.default.call(callbackId, [valueId, (0, offset_1.offset)(loopId, -1), expression]), operator: "==", right: luau_ast_1.default.bool(true), }), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: resultId, operator: "=", right: valueId, }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BreakStatement, {})), elseBody: luau_ast_1.default.list.make(), })), })); return resultId; }, findIndex: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const loopId = luau_ast_1.default.tempId("i"); const valueId = luau_ast_1.default.tempId("v"); const resultId = state.pushToVar(luau_ast_1.default.number(-1), "result"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { expression, ids: luau_ast_1.default.list.make(loopId, valueId), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BinaryExpression, { left: luau_ast_1.default.call(callbackId, [valueId, (0, offset_1.offset)(loopId, -1), expression]), operator: "==", right: luau_ast_1.default.bool(true), }), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: resultId, operator: "=", right: (0, offset_1.offset)(loopId, -1), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BreakStatement, {})), elseBody: luau_ast_1.default.list.make(), })), })); return resultId; }, }; const ARRAY_METHODS = { push: (state, node, expression, args) => { if (args.length === 0) { return luau_ast_1.default.unary("#", expression); } expression = state.pushToVarIfComplex(expression, "exp"); for (let i = 0; i < args.length; i++) { state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(luau_ast_1.default.globals.table.insert, [expression, args[i]]), })); } return !(0, isUsedAsStatement_1.isUsedAsStatement)(node) ? luau_ast_1.default.unary("#", expression) : luau_ast_1.default.none(); }, pop: (state, node, expression) => { expression = state.pushToVarIfComplex(expression, "exp"); let lengthExp = luau_ast_1.default.unary("#", expression); const returnValueIsUsed = !(0, isUsedAsStatement_1.isUsedAsStatement)(node); let retValue; if (returnValueIsUsed) { lengthExp = state.pushToVar(lengthExp, "length"); retValue = state.pushToVar(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: lengthExp, }), "result"); } state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: lengthExp, }), operator: "=", right: luau_ast_1.default.nil(), })); return returnValueIsUsed ? retValue : luau_ast_1.default.none(); }, shift: (state, node, expression) => luau_ast_1.default.call(luau_ast_1.default.globals.table.remove, [expression, luau_ast_1.default.number(1)]), unshift: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); for (let i = args.length - 1; i >= 0; i--) { const arg = args[i]; state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(luau_ast_1.default.globals.table.insert, [expression, luau_ast_1.default.number(1), arg]), })); } return !(0, isUsedAsStatement_1.isUsedAsStatement)(node) ? luau_ast_1.default.unary("#", expression) : luau_ast_1.default.none(); }, insert: (state, node, expression, args) => { return luau_ast_1.default.call(luau_ast_1.default.globals.table.insert, [expression, (0, offset_1.offset)(args[0], 1), args[1]]); }, remove: (state, node, expression, args) => luau_ast_1.default.call(luau_ast_1.default.globals.table.remove, [expression, (0, offset_1.offset)(args[0], 1)]), unorderedRemove: (state, node, expression, args) => { const indexExp = state.pushToVarIfComplex((0, offset_1.offset)(args[0], 1), "index"); expression = state.pushToVarIfComplex(expression, "exp"); const lengthId = state.pushToVar(luau_ast_1.default.unary("#", expression), "length"); const valueIsUsed = !(0, isUsedAsStatement_1.isUsedAsStatement)(node); const valueId = state.pushToVar(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: indexExp, }), "value"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.IfStatement, { condition: luau_ast_1.default.binary(valueId, "~=", luau_ast_1.default.nil()), statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: indexExp, }), operator: "=", right: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: lengthId, }), }), luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: lengthId, }), operator: "=", right: luau_ast_1.default.nil(), })), elseBody: luau_ast_1.default.list.make(), })); return valueIsUsed ? valueId : luau_ast_1.default.none(); }, sort: (state, node, expression, args) => { const valueIsUsed = !(0, isUsedAsStatement_1.isUsedAsStatement)(node); if (valueIsUsed) { expression = state.pushToVarIfComplex(expression, "exp"); } args.unshift(expression); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(luau_ast_1.default.globals.table.sort, args), })); return valueIsUsed ? expression : luau_ast_1.default.none(); }, clear: (state, node, expression) => { state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(luau_ast_1.default.globals.table.clear, [expression]), })); return !(0, isUsedAsStatement_1.isUsedAsStatement)(node) ? luau_ast_1.default.nil() : luau_ast_1.default.none(); }, }; const READONLY_SET_MAP_SHARED_METHODS = { isEmpty: (state, node, expression) => luau_ast_1.default.binary(luau_ast_1.default.call(luau_ast_1.default.globals.next, [expression]), "==", luau_ast_1.default.nil()), size: (state, node, expression) => { const sizeId = state.pushToVar(luau_ast_1.default.number(0), "size"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(luau_ast_1.default.tempId()), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: sizeId, operator: "+=", right: luau_ast_1.default.number(1), })), })); return sizeId; }, has: (state, node, expression, args) => { const left = luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: args[0], }); return luau_ast_1.default.binary(left, "~=", luau_ast_1.default.nil()); }, }; const SET_MAP_SHARED_METHODS = { delete: (state, node, expression, args) => { const arg = state.pushToVarIfComplex(args[0], "value"); const valueIsUsed = !(0, isUsedAsStatement_1.isUsedAsStatement)(node); let valueExistedId; if (valueIsUsed) { expression = state.pushToVarIfNonId(expression, "exp"); valueExistedId = state.pushToVar(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.BinaryExpression, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression, index: arg, }), operator: "~=", right: luau_ast_1.default.nil(), }), "valueExisted"); } state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: arg, }), operator: "=", right: luau_ast_1.default.nil(), })); return valueIsUsed ? valueExistedId : luau_ast_1.default.none(); }, clear: (state, node, expression) => { state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(luau_ast_1.default.globals.table.clear, [expression]), })); return !(0, isUsedAsStatement_1.isUsedAsStatement)(node) ? luau_ast_1.default.nil() : luau_ast_1.default.none(); }, }; const READONLY_SET_METHODS = { ...READONLY_SET_MAP_SHARED_METHODS, forEach: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const valueId = luau_ast_1.default.tempId("v"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(callbackId, [valueId, valueId, expression]), })), })); return !(0, isUsedAsStatement_1.isUsedAsStatement)(node) ? luau_ast_1.default.nil() : luau_ast_1.default.none(); }, }; const SET_METHODS = { ...SET_MAP_SHARED_METHODS, add: (state, node, expression, args) => { const valueIsUsed = !(0, isUsedAsStatement_1.isUsedAsStatement)(node); if (valueIsUsed) { expression = state.pushToVarIfComplex(expression, "exp"); } state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: args[0], }), operator: "=", right: luau_ast_1.default.bool(true), })); return valueIsUsed ? expression : luau_ast_1.default.none(); }, }; const READONLY_MAP_METHODS = { ...READONLY_SET_MAP_SHARED_METHODS, forEach: (state, node, expression, args) => { expression = state.pushToVarIfComplex(expression, "exp"); const callbackId = state.pushToVarIfNonId(args[0], "callback"); const keyId = luau_ast_1.default.tempId("k"); const valueId = luau_ast_1.default.tempId("v"); state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ForStatement, { ids: luau_ast_1.default.list.make(keyId, valueId), expression, statements: luau_ast_1.default.list.make(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.CallStatement, { expression: luau_ast_1.default.call(callbackId, [valueId, keyId, expression]), })), })); return !(0, isUsedAsStatement_1.isUsedAsStatement)(node) ? luau_ast_1.default.nil() : luau_ast_1.default.none(); }, get: (state, node, expression, args) => luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: args[0], }), }; const MAP_METHODS = { ...SET_MAP_SHARED_METHODS, set: (state, node, expression, args) => { const [keyExp, valueExp] = args; const valueIsUsed = !(0, isUsedAsStatement_1.isUsedAsStatement)(node); if (valueIsUsed) { expression = state.pushToVarIfComplex(expression, "exp"); } state.prereq(luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ComputedIndexExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), index: keyExp, }), operator: "=", right: valueExp, })); return valueIsUsed ? expression : luau_ast_1.default.none(); }, }; const PROMISE_METHODS = { then: (state, node, expression, args) => luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.MethodCallExpression, { expression: (0, convertToIndexableExpression_1.convertToIndexableExpression)(expression), name: "andThen", args: luau_ast_1.default.list.make(...args), }), }; exports.PROPERTY_CALL_MACROS = { CFrame: makeMathSet("+", "-", "*"), UDim: makeMathSet("+", "-"), UDim2: makeMathSet("+", "-"), Vector2: makeMathSet("+", "-", "*", "/", "//"), Vector2int16: makeMathSet("+", "-", "*", "/"), Vector3: makeMathSet("+", "-", "*", "/", "//"), Vector3int16: makeMathSet("+", "-", "*", "/"), Number: makeMathSet("//"), String: STRING_CALLBACKS, ArrayLike: ARRAY_LIKE_METHODS, ReadonlyArray: READONLY_ARRAY_METHODS, Array: ARRAY_METHODS, ReadonlySet: READONLY_SET_METHODS, Set: SET_METHODS, ReadonlyMap: READONLY_MAP_METHODS, Map: MAP_METHODS, Promise: PROMISE_METHODS, }; function header(text) { return luau_ast_1.default.comment(` ▼ ${text} ▼`); } function footer(text) { return luau_ast_1.default.comment(` ▲ ${text} ▲`); } function wasExpressionPushed(statements, expression) { if (luau_ast_1.default.list.isNonEmpty(statements)) { const firstStatement = statements.head.value; if (luau_ast_1.default.isVariableDeclaration(firstStatement)) { if (!luau_ast_1.default.list.isList(firstStatement.left) && luau_ast_1.default.isTemporaryIdentifier(firstStatement.left)) { if (firstStatement.right === expression) { return true; } } } } return false; } function wrapComments(methodName, callback) { return (state, callNode, callExp, args) => { const [expression, prereqs] = state.capture(() => callback(state, callNode, callExp, args)); let size = luau_ast_1.default.list.size(prereqs); if (size > 0) { const wasPushed = wasExpressionPushed(prereqs, callExp); let pushStatement; if (wasPushed) { pushStatement = luau_ast_1.default.list.shift(prereqs); size--; } if (size > 1) { luau_ast_1.default.list.unshift(prereqs, header(methodName)); if (wasPushed && pushStatement) { luau_ast_1.default.list.unshift(prereqs, pushStatement); } luau_ast_1.default.list.push(prereqs, footer(methodName)); } else { if (wasPushed && pushStatement) { luau_ast_1.default.list.unshift(prereqs, pushStatement); } } } state.prereqList(prereqs); return expression; }; } for (const [className, macroList] of Object.entries(exports.PROPERTY_CALL_MACROS)) { for (const [methodName, macro] of Object.entries(macroList)) { macroList[methodName] = wrapComments(`${className}.${methodName}`, macro); } } //# sourceMappingURL=propertyCallMacros.js.map