/** * 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; }
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}"; }
/** 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; }