ts-budgie
Version:
Converts TypeScript code to Budgie.
85 lines (68 loc) • 3.44 kB
text/typescript
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);
}
}