UNPKG

roblox-ts

Version:

<div align="center"><img width=25% src="https://i.imgur.com/yCjHmng.png"></div> <h1 align="center"><a href="https://roblox-ts.github.io/">roblox-ts</a></h1> <div align="center">A TypeScript-to-Lua Compiler for Roblox</div> <br> <div align="center"> <a hr

325 lines 13.2 kB
"use strict"; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const ts = __importStar(require("ts-morph")); const _1 = require("."); const CompilerError_1 = require("../errors/CompilerError"); const typeUtilities_1 = require("../typeUtilities"); const utility_1 = require("../utility"); exports.nodeHasParameters = (ancestor) => ts.TypeGuards.isFunctionExpression(ancestor) || ts.TypeGuards.isArrowFunction(ancestor) || ts.TypeGuards.isFunctionDeclaration(ancestor) || ts.TypeGuards.isConstructorDeclaration(ancestor) || ts.TypeGuards.isMethodDeclaration(ancestor); function getReturnStrFromExpression(state, exp, func) { exp = utility_1.skipNodesDownwards(exp); if (func && typeUtilities_1.isTupleType(func.getReturnType())) { if (ts.TypeGuards.isArrayLiteralExpression(exp)) { let expStr = _1.compileExpression(state, exp); expStr = expStr.substr(2, expStr.length - 4); return `return ${expStr};`; } else if (ts.TypeGuards.isCallExpression(exp) && typeUtilities_1.isTupleType(exp.getReturnType())) { const expStr = _1.compileCallExpression(state, exp, true); return `return ${expStr};`; } else { const expStr = _1.compileExpression(state, exp); return `return unpack(${expStr});`; } } { state.declarationContext.set(exp, { isIdentifier: false, set: "return", }); const expStr = _1.compileExpression(state, exp); return state.declarationContext.delete(exp) && `return ${expStr};`; } } function compileReturnStatement(state, node) { const exp = utility_1.skipNodesDownwards(node.getExpression()); if (exp) { state.enterPrecedingStatementContext(); const funcNode = node.getFirstAncestor(exports.nodeHasParameters); const returnStr = getReturnStrFromExpression(state, exp, funcNode); return state.exitPrecedingStatementContextAndJoin() + (returnStr ? state.indent + returnStr + "\n" : ""); } else { return state.indent + `return nil;\n`; } } exports.compileReturnStatement = compileReturnStatement; function isFunctionExpressionMethod(node) { const parent = utility_1.skipNodesUpwards(node.getParent()); return ts.TypeGuards.isPropertyAssignment(parent) && ts.TypeGuards.isObjectLiteralExpression(parent.getParent()); } exports.isFunctionExpressionMethod = isFunctionExpressionMethod; function isMethodDeclaration(node) { return (ts.TypeGuards.isMethodDeclaration(node) || (ts.TypeGuards.isFunctionExpression(node) && isFunctionExpressionMethod(node))); } exports.isMethodDeclaration = isMethodDeclaration; function compileFunctionBody(state, body, node, initializers) { const isBlock = ts.TypeGuards.isBlock(body); const isExpression = ts.TypeGuards.isExpression(body); let result = ""; if (isBlock || isExpression) { result += "\n"; state.pushIndent(); initializers.forEach(initializer => (result += state.indent + initializer + "\n")); if (isBlock) { result += _1.compileBlock(state, body); } else { state.enterPrecedingStatementContext(); const returnStr = getReturnStrFromExpression(state, body, node); result += state.exitPrecedingStatementContextAndJoin() + (returnStr ? state.indent + returnStr + "\n" : ""); } state.popIndent(); result += state.indent; } else { /* istanbul ignore next */ throw new CompilerError_1.CompilerError(`Unexpected function body ( ${body.getKindName()} ) in compileFunctionBody`, node, CompilerError_1.CompilerErrorType.BadFunctionBody, true); } return result; } function canSugaryCompileFunction(node) { if (node.getSourceFile().getExtension() === "tsx") { return false; } else if (ts.TypeGuards.isConstructorDeclaration(node)) { return true; } else if (ts.TypeGuards.isFunctionDeclaration(node) || ts.TypeGuards.isMethodDeclaration(node)) { const nameNode = node.getNameNode(); if (nameNode && ts.TypeGuards.isIdentifier(nameNode)) { return true; } } return false; } function compileFunction(state, node, name, body, namePrefix = "") { state.pushIdStack(); const paramNames = new Array(); const initializers = new Array(); _1.getParameterData(state, paramNames, initializers, node); _1.checkReturnsNonAny(node); let result; let frontWrap = ""; let backWrap = ""; let prefix = ""; if (ts.TypeGuards.isFunctionDeclaration(node)) { const nameNode = node.getNameNode(); if (nameNode && typeUtilities_1.shouldHoist(node, nameNode)) { state.pushHoistStack(name); } else { prefix = "local "; } } let isGenerator = false; if (!ts.TypeGuards.isConstructorDeclaration(node)) { /* istanbul ignore next */ if (node.isAsync()) { state.usesTSLibrary = true; frontWrap = "TS.async("; backWrap = ")" + backWrap; } isGenerator = !ts.TypeGuards.isArrowFunction(node) && node.isGenerator(); } const sugarcoat = name !== "" && frontWrap === "" && canSugaryCompileFunction(node); let namePrefixEndsInColon = namePrefix.endsWith(":"); if (name) { if (sugarcoat) { result = state.indent + prefix; } else { if (namePrefix && namePrefixEndsInColon) { namePrefix = namePrefix.slice(0, -1) + "."; namePrefixEndsInColon = false; } result = state.indent + prefix + namePrefix + name + " = "; } backWrap += ";\n"; } else { result = ""; } if (isMethodDeclaration(node) && !namePrefixEndsInColon) { giveInitialSelfParameter(node, paramNames); } result += frontWrap + "function" + (sugarcoat ? " " + namePrefix + name : "") + "(" + paramNames.join(", ") + ")"; if (isGenerator) { // will error if IterableIterator is nullable typeUtilities_1.isIterableIterator(node.getReturnType(), node); result += "\n"; state.pushIndent(); result += state.indent + `return {\n`; state.pushIndent(); result += state.indent + `next = coroutine.wrap(function()`; result += compileFunctionBody(state, body, node, initializers); result += `\twhile true do coroutine.yield({ done = true }) end;\n`; result += state.indent + `end);\n`; state.popIndent(); result += state.indent + `};\n`; state.popIndent(); result += state.indent; } else { result += compileFunctionBody(state, body, node, initializers); } state.popIdStack(); return result + "end" + backWrap; } function giveInitialSelfParameter(node, paramNames) { const parameters = node.getParameters(); let replacedThis = false; if (parameters.length > 0) { const child = parameters[0].getFirstChildByKind(ts.SyntaxKind.Identifier); const classParent = node.getFirstAncestor((ancestor) => ts.TypeGuards.isClassDeclaration(ancestor) || ts.TypeGuards.isClassExpression(ancestor)); if (classParent && child && child.getText() === "this" && (typeUtilities_1.getType(child).getText() === "this" || typeUtilities_1.getType(child) === typeUtilities_1.getType(classParent))) { paramNames[0] = "self"; replacedThis = true; } } if (!replacedThis) { const thisParam = node.getParameter("this"); if (!thisParam || typeUtilities_1.getType(thisParam).getText() !== "void") { paramNames.unshift("self"); } } } function compileFunctionDeclaration(state, node) { const body = node.getBody(); let name = node.getName(); if (name) { _1.checkReserved(name, node, true); } else { name = state.getNewId(); } if (body) { state.pushExport(name, node); return compileFunction(state, node, name, body); } else { return ""; } } exports.compileFunctionDeclaration = compileFunctionDeclaration; function compileMethodDeclaration(state, node, namePrefix) { const nameNode = node.getNameNode(); let name; if (ts.TypeGuards.isComputedPropertyName(nameNode)) { namePrefix = namePrefix.slice(0, -1); name = `[${_1.compileExpression(state, utility_1.skipNodesDownwards(nameNode.getExpression()))}]`; } else { name = _1.compileExpression(state, nameNode); _1.checkReserved(name, node); } return compileFunction(state, node, name, node.getBodyOrThrow(), namePrefix); } exports.compileMethodDeclaration = compileMethodDeclaration; function containsSuperExpression(child) { if (child && ts.TypeGuards.isExpressionStatement(child)) { const exp = utility_1.skipNodesDownwards(child.getExpression()); if (ts.TypeGuards.isCallExpression(exp)) { const superExp = utility_1.skipNodesDownwards(exp.getExpression()); if (ts.TypeGuards.isSuperExpression(superExp)) { return true; } } } return false; } function compileConstructorDeclaration(state, classExp, className, node, extraInitializers, hasSuper, isRoact) { if (isRoact && !node) { return ""; } const paramNames = new Array(); const initializers = new Array(); const defaults = new Array(); const inheritsFromArray = typeUtilities_1.classDeclarationInheritsFromArray(classExp, false); state.pushIdStack(); if (node) { _1.getParameterData(state, paramNames, initializers, node, defaults); } else if (!inheritsFromArray) { paramNames.push("..."); } const paramStr = paramNames.join(", "); const methodName = isRoact ? "init" : "constructor"; let result = ""; result += state.indent + `function ${className}:${methodName}(${paramStr})\n`; state.pushIndent(); if (node) { const body = node.getBodyOrThrow(); if (ts.TypeGuards.isBlock(body)) { defaults.forEach(initializer => (result += state.indent + initializer + "\n")); const bodyStatements = body.getStatements(); let k = 0; if (containsSuperExpression(bodyStatements[k])) { result += _1.compileStatement(state, bodyStatements[k++]); } initializers.forEach(initializer => (result += state.indent + initializer + "\n")); if (extraInitializers) { extraInitializers.forEach(initializer => (result += initializer)); } for (; k < bodyStatements.length; ++k) { result += _1.compileStatement(state, bodyStatements[k]); } const returnStatement = node.getStatementByKind(ts.SyntaxKind.ReturnStatement); if (returnStatement) { throw new CompilerError_1.CompilerError(`Cannot use return statement in constructor for ${className}`, returnStatement, CompilerError_1.CompilerErrorType.NoConstructorReturn); } } } else { if (hasSuper && !inheritsFromArray) { result += state.indent + `super.constructor(self, ...);\n`; } if (extraInitializers) { extraInitializers.forEach(initializer => (result += initializer)); } } state.popIndent(); state.popIdStack(); result += state.indent + "end;\n"; return result; } exports.compileConstructorDeclaration = compileConstructorDeclaration; function compileFunctionExpression(state, node) { const potentialNameNode = node.getChildAtIndex(1); if (ts.TypeGuards.isFunctionExpression(node) && ts.TypeGuards.isIdentifier(potentialNameNode) && potentialNameNode.findReferences()[0].getReferences().length > 1) { const name = _1.compileExpression(state, potentialNameNode); const id = state.pushPrecedingStatementToNewId(node, ""); state.pushPrecedingStatements(node, state.indent + `do\n`); state.pushIndent(); state.pushPrecedingStatements(node, state.indent + `local ${name};\n`); state.pushPrecedingStatements(node, compileFunction(state, node, `${name}`, node.getBody())); state.pushPrecedingStatements(node, state.indent + `${id} = ${name};\n`); state.popIndent(); state.pushPrecedingStatements(node, state.indent + `end;\n`); // this should not be classified as isPushed. return id; } else { return compileFunction(state, node, "", node.getBody()); } } exports.compileFunctionExpression = compileFunctionExpression; //# sourceMappingURL=function.js.map