protected function parseExprNode($expr)
{
if (is_null($expr)) {
return null;
} elseif (is_scalar($expr)) {
return new Literal($expr);
} elseif (is_array($expr)) {
$list = $this->parseExprList($expr);
return end($list);
} elseif ($expr instanceof Node\Expr\Variable) {
if ($expr->name === "this") {
return new Operand\BoundVariable($this->parseExprNode($expr->name), false, Operand\BoundVariable::SCOPE_OBJECT, $this->currentClass);
}
return new Variable($this->parseExprNode($expr->name));
} elseif ($expr instanceof Node\Name) {
$isReserved = in_array(strtolower($expr->getLast()), ["int", "string", "array", "callable", "float", "bool"]);
if ($isReserved) {
// always return the unqualified literal
return new Literal($expr->getLast());
}
if (isset($expr->namespacedName)) {
return new Literal($expr->namespacedName->toString());
}
return new Literal($expr->toString());
} elseif ($expr instanceof Node\Scalar) {
return $this->parseScalarNode($expr);
} elseif ($expr instanceof Node\Expr\AssignOp) {
$var = $this->parseExprNode($expr->var);
$read = $this->readVariable($var);
$write = $this->writeVariable($var);
$e = $this->readVariable($this->parseExprNode($expr->expr));
$class = ["Expr_AssignOp_BitwiseAnd" => Op\Expr\BinaryOp\BitwiseAnd::class, "Expr_AssignOp_BitwiseOr" => Op\Expr\BinaryOp\BitwiseOr::class, "Expr_AssignOp_BitwiseXor" => Op\Expr\BinaryOp\BitwiseXor::class, "Expr_AssignOp_Concat" => Op\Expr\BinaryOp\Concat::class, "Expr_AssignOp_Div" => Op\Expr\BinaryOp\Div::class, "Expr_AssignOp_Minus" => Op\Expr\BinaryOp\Minus::class, "Expr_AssignOp_Mod" => Op\Expr\BinaryOp\Mod::class, "Expr_AssignOp_Mul" => Op\Expr\BinaryOp\Mul::class, "Expr_AssignOp_Plus" => Op\Expr\BinaryOp\Plus::class, "Expr_AssignOp_Pow" => Op\Expr\BinaryOp\Pow::class, "Expr_AssignOp_ShiftLeft" => Op\Expr\BinaryOp\ShiftLeft::class, "Expr_AssignOp_ShiftRight" => Op\Expr\BinaryOp\ShiftRight::class][$expr->getType()];
if (empty($class)) {
throw new \RuntimeException("AssignOp Not Found: " . $expr->getType());
}
$attrs = $this->mapAttributes($expr);
$this->block->children[] = $op = new $class($read, $e, $attrs);
$this->block->children[] = new Op\Expr\Assign($write, $op->result, $attrs);
return $op->result;
} elseif ($expr instanceof Node\Expr\BinaryOp) {
if ($expr instanceof AstBinaryOp\LogicalAnd || $expr instanceof AstBinaryOp\BooleanAnd) {
return $this->parseShortCircuiting($expr, false);
} elseif ($expr instanceof AstBinaryOp\LogicalOr || $expr instanceof AstBinaryOp\BooleanOr) {
return $this->parseShortCircuiting($expr, true);
}
$left = $this->readVariable($this->parseExprNode($expr->left));
$right = $this->readVariable($this->parseExprNode($expr->right));
$class = ["Expr_BinaryOp_BitwiseAnd" => Op\Expr\BinaryOp\BitwiseAnd::class, "Expr_BinaryOp_BitwiseOr" => Op\Expr\BinaryOp\BitwiseOr::class, "Expr_BinaryOp_BitwiseXor" => Op\Expr\BinaryOp\BitwiseXor::class, "Expr_BinaryOp_Coalesce" => Op\Expr\BinaryOp\Coalesce::class, "Expr_BinaryOp_Concat" => Op\Expr\BinaryOp\Concat::class, "Expr_BinaryOp_Div" => Op\Expr\BinaryOp\Div::class, "Expr_BinaryOp_Equal" => Op\Expr\BinaryOp\Equal::class, "Expr_BinaryOp_Greater" => Op\Expr\BinaryOp\Greater::class, "Expr_BinaryOp_GreaterOrEqual" => Op\Expr\BinaryOp\GreaterOrEqual::class, "Expr_BinaryOp_Identical" => Op\Expr\BinaryOp\Identical::class, "Expr_BinaryOp_LogicalXor" => Op\Expr\BinaryOp\LogicalXor::class, "Expr_BinaryOp_Minus" => Op\Expr\BinaryOp\Minus::class, "Expr_BinaryOp_Mod" => Op\Expr\BinaryOp\Mod::class, "Expr_BinaryOp_Mul" => Op\Expr\BinaryOp\Mul::class, "Expr_BinaryOp_NotEqual" => Op\Expr\BinaryOp\NotEqual::class, "Expr_BinaryOp_NotIdentical" => Op\Expr\BinaryOp\NotIdentical::class, "Expr_BinaryOp_Plus" => Op\Expr\BinaryOp\Plus::class, "Expr_BinaryOp_Pow" => Op\Expr\BinaryOp\Pow::class, "Expr_BinaryOp_ShiftLeft" => Op\Expr\BinaryOp\ShiftLeft::class, "Expr_BinaryOp_ShiftRight" => Op\Expr\BinaryOp\ShiftRight::class, "Expr_BinaryOp_Smaller" => Op\Expr\BinaryOp\Smaller::class, "Expr_BinaryOp_SmallerOrEqual" => Op\Expr\BinaryOp\SmallerOrEqual::class, "Expr_BinaryOp_Spaceship" => Op\Expr\BinaryOp\Spaceship::class][$expr->getType()];
if (empty($class)) {
throw new \RuntimeException("BinaryOp Not Found: " . $expr->getType());
}
$this->block->children[] = $op = new $class($left, $right, $this->mapAttributes($expr));
return $op->result;
} elseif ($expr instanceof Node\Expr\Cast) {
$e = $this->readVariable($this->parseExprNode($expr->expr));
$class = ["Expr_Cast_Array" => Op\Expr\Cast\Array_::class, "Expr_Cast_Bool" => Op\Expr\Cast\Bool_::class, "Expr_Cast_Double" => Op\Expr\Cast\Double::class, "Expr_Cast_Int" => Op\Expr\Cast\Int_::class, "Expr_Cast_Object" => Op\Expr\Cast\Object_::class, "Expr_Cast_String" => Op\Expr\Cast\String_::class, "Expr_Cast_Unset" => Op\Expr\Cast\Unset_::class][$expr->getType()];
if (empty($class)) {
throw new \RuntimeException("Cast Not Found: " . $expr->getType());
}
$this->block->children[] = $op = new $class($e, $this->mapAttributes($expr));
return $op->result;
}
$method = "parse" . $expr->getType();
if (method_exists($this, $method)) {
$op = $this->{$method}($expr);
if ($op instanceof Op) {
$this->block->children[] = $op;
return $op->result;
} elseif ($op instanceof Operand) {
return $op;
}
} else {
throw new \RuntimeException("Unknown Expr Type " . $expr->getType());
}
throw new \RuntimeException("Invalid state, should never happen");
}