public function parenthesize(Node $node, ExpressionNode $cutoff, $prepend = '', $conservative = false) { $text = $node->accept($this); if ($node instanceof ExpressionNode) { // Second term is a unary minus if ($node->getOperator() == '-' && $node->getRight() == null) { return "({$text})"; } if ($cutoff->getOperator() == '-' && $node->lowerPrecedenceThan($cutoff)) { return "({$text})"; } if ($conservative) { // Add parentheses more liberally for / and ^ operators, // so that e.g. x/(y*z) is printed correctly if ($cutoff->getOperator() == '/' && $node->lowerPrecedenceThan($cutoff)) { return "({$text})"; } if ($cutoff->getOperator() == '^' && $node->getOperator() == '^') { return "({$text})"; } } if ($node->strictlyLowerPrecedenceThan($cutoff)) { return "({$text})"; } } if (($node instanceof NumberNode || $node instanceof IntegerNode || $node instanceof RationalNode) && $node->getValue() < 0) { return "({$text})"; } // Treat rational numbers as divisions on printing if ($node instanceof RationalNode && $node->getDenominator() != 1) { $fakeNode = new ExpressionNode($node->getNumerator(), '/', $node->getDenominator()); if ($fakeNode->lowerPrecedenceThan($cutoff)) { return "({$text})"; } } return "{$prepend}{$text}"; }
/** * Returns true if the current Node has lower precedence than the one * we compare with. * * In case of a tie, we also consider the associativity. * (Left associative operators are lower precedence in this context.) * * @param Node $other Node to compare to. * @retval boolean */ public function lowerPrecedenceThan($other) { if (!$other instanceof ExpressionNode) { return false; } if ($this->getPrecedence() < $other->getPrecedence()) { return true; } if ($this->getPrecedence() > $other->getPrecedence()) { return false; } if ($this->associativity == self::LEFT_ASSOC) { return true; } return false; }
/** Simplify (x^a)^b when a and b are both numeric. * @param Node $leftOperand * @param Node $rightOperand * @retval Node|null */ private function doubleExponentiation($leftOperand, $rightOperand) { // (x^a)^b -> x^(ab) for a, b numbers if ($leftOperand instanceof ExpressionNode && $leftOperand->getOperator() == '^') { $factory = new MultiplicationNodeFactory(); $power = $factory->makeNode($leftOperand->getRight(), $rightOperand); $base = $leftOperand->getLeft(); return self::makeNode($base, $power); } // No simplification found return null; }
/** * Determine if $node is in fact a unary operator. * * If $node can be a unary operator (i.e. is a '+' or '-' node), * **and** this is the first node we parse or the previous node * was a SubExpressionNode, i.e. an opening parenthesis, or the * previous node was already a unary minus, this means that the * current node is in fact a unary '+' or '-' and we return true, * otherwise we return false. * * @param Node $node Current node * @param Node|null $lastNode Previous node handled by the Parser * @retval boolean */ protected function isUnary($node, $lastNode) { if (!$node->canBeUnary()) { return false; } // Unary if it is the first token if ($this->operatorStack->isEmpty() && $this->operandStack->isEmpty()) { return true; } // or if the previous token was '(' if ($lastNode instanceof SubExpressionNode) { return true; } // or last node was already a unary minus if ($lastNode instanceof ExpressionNode && $lastNode->getOperator() == '~') { return true; } return false; }
/** * Add curly braces around the LaTex representation of $node if needed. * * Nodes representing a single ConstantNode, VariableNode or NumberNodes (0--9) * are returned as-is. Other Nodes get curly braces around their LaTeX code. * * @param Node $node AST to parse * @retval string */ public function bracesNeeded(Node $node) { if ($node instanceof VariableNode || $node instanceof ConstantNode) { return $node->accept($this); } elseif ($node instanceof IntegerNode && $node->getValue() >= 0 && $node->getValue() <= 9) { return $node->accept($this); } else { return '{' . $node->accept($this) . '}'; } }