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

203 lines 10.5 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 utility_1 = require("../utility"); function fallThroughConditionsRequireIfStatement(fallThroughConditions, fallThroughVar) { return (fallThroughConditions.length > 0 && (fallThroughConditions.length !== 1 || fallThroughConditions[0] !== fallThroughVar)); } function compileRemainingConditions(state, result, fallThroughConditions, anyFallThrough, previousCaseFallsThrough, fallThroughVar) { if (fallThroughVar && previousCaseFallsThrough && fallThroughConditions[0] !== fallThroughVar) { fallThroughConditions.unshift(fallThroughVar); } if (anyFallThrough) { return result + state.indent + `${fallThroughVar} = ${fallThroughConditions.join(" or ")};\n`; } else { return result + state.indent + `if ${fallThroughConditions.join(" or ")} then\n${state.indent}end;\n`; } } function compileSwitchStatement(state, node) { let preResult = ""; let expStr; const expression = utility_1.skipNodesDownwards(node.getExpression()); state.enterPrecedingStatementContext(); const rawExpStr = _1.compileExpression(state, expression); const expressionContext = state.exitPrecedingStatementContext(); const hasPrecedingStatements = expressionContext.length > 0; if (hasPrecedingStatements) { preResult += expressionContext.join(""); } if ((hasPrecedingStatements && expressionContext.isPushed) || (ts.TypeGuards.isIdentifier(expression) && _1.isIdentifierDefinedInConst(expression))) { expStr = rawExpStr; } else { expStr = state.getNewId(); preResult += state.indent + `local ${expStr} = ${rawExpStr};\n`; } preResult += state.indent + `repeat\n`; state.pushIndent(); state.pushIdStack(); state.hoistStack.push(new Set()); let fallThroughVar; const clauses = node.getCaseBlock().getClauses(); let anyFallThrough = false; let result = ""; let previousCaseFallsThrough = false; const lastClauseIndex = clauses.length - 1; const lastClause = clauses[lastClauseIndex]; const lastNonDefaultClauseIndex = clauses.length - 1 - [...clauses].reverse().findIndex(clause => ts.TypeGuards.isCaseClause(clause)); if (lastClause) { const hasDefault = !ts.TypeGuards.isCaseClause(lastClause); let fallThroughConditions = new Array(); for (let i = 0; i < clauses.length; i++) { const clause = clauses[i]; const statements = clause.getStatements(); let writeThatWeFellThrough = true; let lastStatement = statements[statements.length - 1]; let blockStatements = statements; while (lastStatement && ts.TypeGuards.isBlock(lastStatement)) { blockStatements = lastStatement.getStatements(); lastStatement = blockStatements[blockStatements.length - 1]; } // Returns/Breaks are not always the last statement. Unreachable code is valid TS const endsInReturnOrBreakStatement = blockStatements.find(statement => ts.TypeGuards.isBreakStatement(statement) || ts.TypeGuards.isReturnStatement(statement)); const hasStatements = statements.length > 0; const currentCaseFallsThrough = !endsInReturnOrBreakStatement && (hasDefault ? lastClauseIndex - 1 : lastClauseIndex) > i; const shouldPushFallThroughVar = currentCaseFallsThrough && hasStatements && i !== lastNonDefaultClauseIndex; // add if statement if the clause is non-default let isNonDefault = false; if (ts.TypeGuards.isCaseClause(clause)) { isNonDefault = true; state.enterPrecedingStatementContext(); const clauseExp = clause.getExpression(); let clauseExpStr = _1.compileExpression(state, clauseExp); if (_1.shouldWrapExpression(clauseExp, false)) { clauseExpStr = `(${clauseExpStr})`; } let context = state.exitPrecedingStatementContext(); const hasContext = context.length > 0; let condition = `${expStr} == ${clauseExpStr}`; const fellThroughFirstHere = !anyFallThrough; let wroteFallThrough = false; /* God, grant me the serenity to accept the things I cannot change, The courage to change the things I can, And wisdom to know the difference. */ if (!anyFallThrough && (((!hasStatements || previousCaseFallsThrough) && hasContext) || (hasStatements && currentCaseFallsThrough && i !== lastNonDefaultClauseIndex))) { fallThroughVar = state.getNewId(); anyFallThrough = true; if (hasStatements || (hasContext && (fallThroughConditionsRequireIfStatement(fallThroughConditions, fallThroughVar) || previousCaseFallsThrough))) { result += state.indent + `local ${fallThroughVar} = false;\n`; wroteFallThrough = true; } } if (!hasStatements || previousCaseFallsThrough) { if (fallThroughVar && hasContext) { let indent = 1; if (fallThroughConditionsRequireIfStatement(fallThroughConditions, fallThroughVar)) { if (fallThroughVar && !wroteFallThrough && previousCaseFallsThrough && fallThroughVar !== condition && fallThroughConditions[0] !== fallThroughVar) { fallThroughConditions.unshift(fallThroughVar); } result += state.indent + `if ${fallThroughConditions.join(" or ")} then\n`; result += state.indent + `\t${fallThroughVar} = true;\n`; result += state.indent + "else\n"; state.pushIndent(); } else if (previousCaseFallsThrough) { result += state.indent + `if not ${fallThroughVar} then\n`; state.pushIndent(); } else { indent = 0; } result += utility_1.joinIndentedLines(context, indent); result += state.indent + `${fellThroughFirstHere && !wroteFallThrough ? "local " : ""}${fallThroughVar} = ${condition};\n`; if (indent === 1) { state.popIndent(); result += state.indent + `end;\n`; } condition = fallThroughVar; fallThroughConditions = []; context = undefined; } } fallThroughConditions.push(condition); if (hasStatements) { if (fallThroughVar && !wroteFallThrough && previousCaseFallsThrough && fallThroughVar !== condition && fallThroughConditions[0] !== fallThroughVar) { fallThroughConditions.unshift(fallThroughVar); } if (context) { result += utility_1.joinIndentedLines(context, 0); } if (fallThroughConditions.length === 1 && fallThroughConditions[0] === fallThroughVar) { writeThatWeFellThrough = false; } result += state.indent + `if ${fallThroughConditions.join(" or ")} then\n`; state.pushIndent(); fallThroughConditions = new Array(); } else { previousCaseFallsThrough = true; continue; } } else if (i !== lastClauseIndex) { throw new CompilerError_1.CompilerError("Default case must be the last case in a switch statement!", clause, CompilerError_1.CompilerErrorType.BadSwitchDefaultPosition); } else { // empty remaining conditions if (fallThroughConditionsRequireIfStatement(fallThroughConditions, fallThroughVar)) { result = compileRemainingConditions(state, result, fallThroughConditions, anyFallThrough, previousCaseFallsThrough, fallThroughVar); fallThroughConditions = []; } } result += _1.compileStatementedNode(state, clause); if (writeThatWeFellThrough && shouldPushFallThroughVar) { result += state.indent + `${fallThroughVar} = true;\n`; } if (isNonDefault) { state.popIndent(); result += state.indent + `end;\n`; } previousCaseFallsThrough = currentCaseFallsThrough; } // empty remaining conditions if (fallThroughConditionsRequireIfStatement(fallThroughConditions, fallThroughVar)) { result = compileRemainingConditions(state, result, fallThroughConditions, anyFallThrough, previousCaseFallsThrough, fallThroughVar); } } result = state.popHoistStack(result); state.popIdStack(); state.popIndent(); result += state.indent + `until true;\n`; return preResult + result; } exports.compileSwitchStatement = compileSwitchStatement; //# sourceMappingURL=switch.js.map