UNPKG

ts-budgie

Version:

Converts TypeScript code to Budgie.

85 lines (68 loc) 3.44 kB
import { CommandNames } from "budgie"; import * as ts from "typescript"; import { BudgieLine } from "../../output/budgieLine"; import { Transformation } from "../../output/transformation"; import { createUnsupportedBudgieLine } from "../../output/unsupported"; import { getNumericTypeNameFromUsages } from "../../parsing/numerics"; import { NodeVisitor } from "../visitor"; const forLoopsMustBeAdditiveComplaint = "For loops over numbers must change the iterator with addition."; const irregularComplaint = "Could not parse irregular for loop."; export class ForStatementVisitor extends NodeVisitor { public visit(node: ts.ForStatement) { return [Transformation.fromNode(node, this.sourceFile, this.getTransformationContents(node))]; } private getTransformationContents(node: ts.ForStatement) { const { condition, incrementor, initializer } = node; if ( condition === undefined || incrementor === undefined || initializer === undefined || !ts.isVariableDeclarationList(initializer) || initializer.declarations.length !== 1 ) { return [createUnsupportedBudgieLine(irregularComplaint)]; } const declaration = initializer.declarations[0]; if (declaration.initializer === undefined) { return [createUnsupportedBudgieLine(irregularComplaint)]; } const name = (declaration.name as ts.Identifier).text; const incrementorText = this.getIncrementorIfNotOne(name, incrementor); const end = this.getConditionEnd(name, condition); const start = declaration.initializer.getText(this.sourceFile); const realType = typeof end === "string" ? getNumericTypeNameFromUsages([start, end]) : "float"; const bodyNodes = this.router.recurseIntoNode(node.statement); const parameters = [name, realType, start, end]; if (incrementorText !== undefined) { parameters.push(incrementorText); } return [new BudgieLine(CommandNames.ForNumbersStart, ...parameters), ...bodyNodes, new BudgieLine(CommandNames.ForNumbersEnd)]; } private getIncrementorIfNotOne(target: string, incrementor: ts.Expression) { if (ts.isPostfixUnaryExpression(incrementor) || ts.isPrefixUnaryExpression(incrementor)) { return undefined; } if ( ts.isBinaryExpression(incrementor) && incrementor.operatorToken.kind === ts.SyntaxKind.PlusEqualsToken && (incrementor.left as ts.Identifier).text === target ) { const right = incrementor.right as ts.Identifier; return right.text === "1" ? undefined : right.text; } return createUnsupportedBudgieLine(forLoopsMustBeAdditiveComplaint); } private getConditionEnd(target: string, condition: ts.Expression) { if ( !ts.isBinaryExpression(condition) || (condition.left as ts.Identifier).text !== target || condition.operatorToken.kind !== ts.SyntaxKind.LessThanToken ) { return createUnsupportedBudgieLine(irregularComplaint); } if (ts.isNumericLiteral(condition.right)) { return condition.right.text; } return this.router.recurseIntoValue(condition.right); } }