Example #1
0
 private function parseShortCircuiting(AstBinaryOp $expr, $isOr)
 {
     $result = new Temporary();
     $longBlock = new Block();
     $endBlock = new Block();
     $left = $this->readVariable($this->parseExprNode($expr->left));
     $if = $isOr ? $endBlock : $longBlock;
     $else = $isOr ? $longBlock : $endBlock;
     $this->block->children[] = new JumpIf($left, $if, $else);
     $longBlock->addParent($this->block);
     $endBlock->addParent($this->block);
     $this->block = $longBlock;
     $right = $this->readVariable($this->parseExprNode($expr->right));
     $boolCast = new Op\Expr\Cast\Bool_($right);
     $this->block->children[] = $boolCast;
     $this->block->children[] = new Jump($endBlock);
     $endBlock->addParent($this->block);
     $this->block = $endBlock;
     $phi = new Op\Phi($result, ['block' => $this->block]);
     $phi->addOperand(new Literal($isOr));
     $phi->addOperand($boolCast->result);
     $this->block->phi[] = $phi;
     $mode = $isOr ? Assertion::MODE_UNION : Assertion::MODE_INTERSECTION;
     foreach ($left->assertions as $assert) {
         $result->addAssertion($assert['var'], $assert['assertion'], $mode);
     }
     foreach ($right->assertions as $assert) {
         $result->addAssertion($assert['var'], $assert['assertion'], $mode);
     }
     return $result;
 }
Example #2
0
 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) {
         return new Variable($this->parseExprNode($expr->name));
     } elseif ($expr instanceof Node\Name) {
         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) {
         $v = $this->parseExprNode($expr->var);
         $e = $this->parseExprNode($expr->expr);
         $class = ["Expr_AssignOp_BitwiseAnd" => Op\Expr\AssignOp\BitwiseAnd::class, "Expr_AssignOp_BitwiseOr" => Op\Expr\AssignOp\BitwiseOr::class, "Expr_AssignOp_BitwiseXor" => Op\Expr\AssignOp\BitwiseXor::class, "Expr_AssignOp_Concat" => Op\Expr\AssignOp\Concat::class, "Expr_AssignOp_Div" => Op\Expr\AssignOp\Div::class, "Expr_AssignOp_Minus" => Op\Expr\AssignOp\Minus::class, "Expr_AssignOp_Mod" => Op\Expr\AssignOp\Mod::class, "Expr_AssignOp_Mul" => Op\Expr\AssignOp\Mul::class, "Expr_AssignOp_Plus" => Op\Expr\AssignOp\Plus::class, "Expr_AssignOp_Pow" => Op\Expr\AssignOp\Pow::class, "Expr_AssignOp_ShiftLeft" => Op\Expr\AssignOp\ShiftLeft::class, "Expr_AssignOp_ShiftRight" => Op\Expr\AssignOp\ShiftRight::class][$expr->getType()];
         if (empty($class)) {
             throw new \RuntimeException("AssignOp Not Found: " . $expr->getType());
         }
         $this->block->children[] = $op = new $class($v, $e, $this->mapAttributes($expr));
         return $op->result;
     } elseif ($expr instanceof Node\Expr\BinaryOp) {
         $left = $this->parseExprNode($expr->left);
         $right = $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_BooleanAnd" => Op\Expr\BinaryOp\BooleanAnd::class, "Expr_BinaryOp_BooleanOr" => Op\Expr\BinaryOp\BooleanOr::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_LogicalAnd" => Op\Expr\BinaryOp\LogicalAnd::class, "Expr_BinaryOp_LogicalOr" => Op\Expr\BinaryOp\LogicalOr::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->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;
     }
     $op = null;
     $attrs = $this->mapAttributes($expr);
     switch ($expr->getType()) {
         case 'Arg':
             // TODO: Handle var-args
             return $this->parseExprNode($expr->value);
         case 'Expr_Array':
             $keys = [];
             $values = [];
             $byRef = [];
             if ($expr->items) {
                 foreach ($expr->items as $item) {
                     if ($item->key) {
                         $keys[] = $this->parseExprNode($item->key);
                     } else {
                         $keys[] = null;
                     }
                     $values[] = $this->parseExprNode($item->value);
                     $byRef[] = $item->byRef;
                 }
             }
             $op = new Op\Expr\Array_($keys, $values, $byRef, $attrs);
             break;
         case 'Expr_ArrayDimFetch':
             $v = $this->parseExprNode($expr->var);
             $d = $this->parseExprNode($expr->dim);
             $op = new Op\Expr\ArrayDimFetch($v, $d, $attrs);
             break;
         case 'Expr_Assign':
             $e = $this->parseExprNode($expr->expr);
             $v = $this->parseExprNode($expr->var);
             $op = new Op\Expr\Assign($v, $e, $attrs);
             break;
         case 'Expr_AssignRef':
             $e = $this->parseExprNode($expr->expr);
             $v = $this->parseExprNode($expr->var);
             $op = new Op\Expr\AssignRef($v, $e, $attrs);
             break;
         case 'Expr_BitwiseNot':
             $op = new Op\Expr\BitwiseNot($this->parseExprNode($expr->expr), $attrs);
             break;
         case 'Expr_BooleanNot':
             $op = new Op\Expr\BooleanNot($this->parseExprNode($expr->expr), $attrs);
             break;
         case 'Expr_Closure':
             $block = new Block();
             $this->parseNodes($expr->stmts, $block);
             $op = new Op\Expr\Closure($this->parseParameterList($expr->params), $expr->byRef, $expr->returnType, $block, $attrs);
             break;
         case 'Expr_ClassConstFetch':
             $c = $this->parseExprNode($expr->class);
             $n = $this->parseExprNode($expr->name);
             $op = new Op\Expr\ClassConstFetch($c, $n, $attrs);
             break;
         case 'Expr_Clone':
             $op = new Op\Expr\Clone_($this->parseExprNode($expr->expr), $attrs);
             break;
         case 'Expr_ConstFetch':
             $op = new Op\Expr\ConstFetch($this->parseExprNode($expr->name), $attrs);
             break;
         case 'Expr_Empty':
             $op = new Op\Expr\Empty_($this->parseNodes([$expr->expr], new Block()), $attrs);
             break;
         case 'Expr_ErrorSuppress':
             $block = new ErrorSuppressBlock();
             $this->block->children[] = new Op\Stmt\Jump($block, $attrs);
             $this->block = $block;
             $result = $this->parseExprNode($expr->expr);
             $end = new Block();
             $this->block->children[] = new Op\Stmt\Jump($end, $attrs);
             $this->block = $end;
             return $result;
         case 'Expr_Eval':
             $op = new Op\Expr\Eval_($this->parseExprNode($expr->expr), $attrs);
             break;
         case 'Expr_Exit':
             $op = new Op\Expr\Exit_($this->parseExprNode($expr->expr), $attrs);
             break;
         case 'Expr_FuncCall':
             $op = new Op\Expr\FuncCall($this->parseExprNode($expr->name), $this->parseExprList($expr->args), $attrs);
             break;
         case 'Expr_Include':
             $op = new Op\Expr\Include_($this->parseExprNode($expr->expr), $expr->type, $attrs);
             break;
         case 'Expr_Instanceof':
             $op = new Op\Expr\InstanceOf_($this->parseExprNode($expr->expr), $this->parseExprNode($expr->class), $attrs);
             break;
         case 'Expr_Isset':
             $op = new Op\Expr\Isset_($this->parseNodes($expr->vars, new Block()), $attrs);
             break;
         case 'Expr_List':
             $op = new Op\Expr\List_($this->parseExprList($expr->vars), $attrs);
             break;
         case 'Expr_MethodCall':
             $op = new Op\Expr\MethodCall($this->parseExprNode($expr->var), $this->parseExprNode($expr->name), $this->parseExprList($expr->args), $attrs);
             break;
         case 'Expr_New':
             $op = new Op\Expr\New_($this->parseExprNode($expr->class), $this->parseExprList($expr->args), $attrs);
             break;
         case 'Expr_PostDec':
             $op = new Op\Expr\PostDec($this->parseExprNode($expr->var), $attrs);
             break;
         case 'Expr_PostInc':
             $op = new Op\Expr\PostInc($this->parseExprNode($expr->var), $attrs);
             break;
         case 'Expr_PreDec':
             $op = new Op\Expr\PreDec($this->parseExprNode($expr->var), $attrs);
             break;
         case 'Expr_PreInc':
             $op = new Op\Expr\PreInc($this->parseExprNode($expr->var), $attrs);
             break;
         case 'Expr_Print':
             $op = new Op\Expr\Print_($this->parseExprNode($expr->expr), $attrs);
             break;
         case 'Expr_PropertyFetch':
             $op = new Op\Expr\PropertyFetch($this->parseExprNode($expr->var), $this->parseExprNode($expr->name), $attrs);
             break;
         case 'Expr_StaticCall':
             $op = new Op\Expr\StaticCall($this->parseExprNode($expr->class), $this->parseExprNode($expr->name), $this->parseExprList($expr->args), $attrs);
             break;
         case 'Expr_StaticPropertyFetch':
             $op = new Op\Expr\StaticPropertyFetch($this->parseExprNode($expr->class), $this->parseExprNode($expr->name), $attrs);
             break;
         case 'Expr_Ternary':
             $cond = $this->parseExprNode($expr->cond);
             $ifBlock = $this->block->create();
             $elseBlock = $this->block->create();
             $endBlock = $this->block->create();
             $result = new Temporary();
             $this->block->children[] = new Op\Stmt\JumpIf($cond, $ifBlock, $elseBlock, $attrs);
             $this->block = $ifBlock;
             if ($expr->if) {
                 $this->block->children[] = new Op\Expr\Assign($result, $this->parseExprNode($expr->if), $attrs);
             } else {
                 $this->block->children[] = new Op\Expr\Assign($result, $cond, $attrs);
             }
             $this->block->children[] = new Op\Stmt\Jump($endBlock, $attrs);
             $this->block = $elseBlock;
             $this->block->children[] = new Op\Expr\Assign($result, $this->parseExprNode($expr->else), $attrs);
             $elseBlock->children[] = new Op\Stmt\Jump($endBlock, $attrs);
             $this->block = $endBlock;
             return $result;
         case 'Expr_UnaryMinus':
             $op = new Op\Expr\UnaryMinus($this->parseExprNode($expr->expr), $attrs);
             break;
         default:
             throw new \RuntimeException("Unknown Expr Type " . $expr->getType());
     }
     if ($op) {
         $this->block->children[] = $op;
         return $op->result;
     }
     throw new \RuntimeException("Invalid state, should never happen");
 }