package de.gaalop.java;
import de.gaalop.dfg.*;
/**
* Creates code for a single expression. The code can afterwards be queried via {@link #getCode()}.
*/
public class BladePrinter implements ExpressionVisitor {
private StringBuilder code = new StringBuilder();
public String getCode() {
return code.toString();
}
/**
* Handles a binary operation: Prints the operator between the left and the right operand (infix)
* @param operation The binary operation
* @param operator The operator to be used
* @param withSpaces <value>true</value> if spaces should be printed next to operator, otherwise <value>false</value>
*/
private void handleInfix(BinaryOperation operation, String operator, boolean withSpaces) {
addChild(operation, operation.getLeft());
if (withSpaces) {
code.append(' ');
code.append(operator);
code.append(' ');
} else {
code.append(operator);
}
addChild(operation, operation.getRight());
}
/**
* Adds a child expression. If the child has a lower priority than the parent,
* it is parenthesized
* @param parent The parent expression
* @param child The child expression
*/
private void addChild(Expression parent, Expression child) {
if (OperatorPriority.hasLowerPriority(parent, child)) {
code.append('(');
child.accept(this);
code.append(')');
} else {
child.accept(this);
}
}
@Override
public void visit(Subtraction subtraction) {
handleInfix(subtraction, "-", true);
}
@Override
public void visit(Addition addition) {
handleInfix(addition, "+", true);
}
@Override
public void visit(Division division) {
handleInfix(division, "/", true);
}
@Override
public void visit(InnerProduct innerProduct) {
handleInfix(innerProduct, ".", true);
}
@Override
public void visit(Multiplication multiplication) {
handleInfix(multiplication, "*", true);
}
@Override
public void visit(MathFunctionCall mathFunctionCall) {
code.append(mathFunctionCall.getFunction().toString());
code.append('(');
mathFunctionCall.getOperand().accept(this);
code.append(')');
}
@Override
public void visit(Variable variable) {
code.append(variable.getName());
}
@Override
public void visit(MultivectorComponent component) {
code.append(component.getName());
code.append('(');
code.append(component.getBladeIndex() + 1);
code.append(')');
}
@Override
public void visit(Exponentiation exponentiation) {
code.append("Math.pow(");
addChild(exponentiation, exponentiation.getLeft());
code.append(',');
addChild(exponentiation, exponentiation.getRight());
code.append(")");
}
@Override
public void visit(FloatConstant floatConstant) {
code.append(Double.toString(floatConstant.getValue()));
}
@Override
public void visit(OuterProduct outerProduct) {
handleInfix(outerProduct, "^", false);
}
@Override
public void visit(BaseVector baseVector) {
code.append(baseVector.toString());
}
@Override
public void visit(Negation negation) {
code.append('-');
addChild(negation, negation.getOperand());
}
@Override
public void visit(Reverse node) {
code.append('~');
addChild(node, node.getOperand());
}
@Override
public void visit(LogicalOr node) {
handleInfix(node, "||", true);
}
@Override
public void visit(LogicalAnd node) {
handleInfix(node, "&&", true);
}
@Override
public void visit(LogicalNegation node) {
code.append('!');
addChild(node, node.getOperand());
}
@Override
public void visit(Equality node) {
handleInfix(node, "==", true);
}
@Override
public void visit(Inequality node) {
handleInfix(node, "!=", true);
}
@Override
public void visit(Relation relation) {
handleInfix(relation, relation.getTypeString(), false);
}
@Override
public void visit(FunctionArgument node) {
throw new IllegalStateException("Macros should have been inlined and are not allowed for output.");
}
@Override
public void visit(MacroCall node) {
throw new IllegalStateException("Macros should have been inlined and are not allowed for output.");
}
}