Exemplo n.º 1
0
 protected function resolveVarOp(Operand $var, Op $op, SplObjectStorage $resolved)
 {
     $method = 'resolveOp_' . $op->getType();
     if (method_exists($this, $method)) {
         return call_user_func([$this, $method], $var, $op, $resolved);
     }
     switch ($op->getType()) {
         case 'Expr_InstanceOf':
         case 'Expr_BinaryOp_Equal':
         case 'Expr_BinaryOp_NotEqual':
         case 'Expr_BinaryOp_Greater':
         case 'Expr_BinaryOp_GreaterOrEqual':
         case 'Expr_BinaryOp_Identical':
         case 'Expr_BinaryOp_NotIdentical':
         case 'Expr_BinaryOp_Smaller':
         case 'Expr_BinaryOp_SmallerOrEqual':
         case 'Expr_BinaryOp_LogicalAnd':
         case 'Expr_BinaryOp_LogicalOr':
         case 'Expr_BinaryOp_LogicalXor':
         case 'Expr_BooleanNot':
         case 'Expr_Cast_Bool':
         case 'Expr_Empty':
         case 'Expr_Isset':
             return [Type::bool()];
         case 'Expr_BinaryOp_BitwiseAnd':
         case 'Expr_BinaryOp_BitwiseOr':
         case 'Expr_BinaryOp_BitwiseXor':
             if ($resolved->contains($op->left) && $resolved->contains($op->right)) {
                 switch ([$resolved[$op->left]->type, $resolved[$op->right]->type]) {
                     case [Type::TYPE_STRING, Type::TYPE_STRING]:
                         return [Type::string()];
                     default:
                         return [Type::int()];
                 }
             }
             return false;
         case 'Expr_BitwiseNot':
             if ($resolved->contains($op->expr)) {
                 switch ($resolved[$op->expr]->type) {
                     case Type::TYPE_STRING:
                         return [Type::string()];
                     default:
                         return [Type::int()];
                 }
             }
             return false;
         case 'Expr_BinaryOp_Div':
         case 'Expr_BinaryOp_Plus':
         case 'Expr_BinaryOp_Minus':
         case 'Expr_BinaryOp_Mul':
             if ($resolved->contains($op->left) && $resolved->contains($op->right)) {
                 switch ([$resolved[$op->left]->type, $resolved[$op->right]->type]) {
                     case [Type::TYPE_LONG, Type::TYPE_LONG]:
                         return [Type::int()];
                     case [Type::TYPE_DOUBLE, TYPE::TYPE_LONG]:
                     case [Type::TYPE_LONG, TYPE::TYPE_DOUBLE]:
                     case [Type::TYPE_DOUBLE, TYPE::TYPE_DOUBLE]:
                         return [Type::float()];
                     case [Type::TYPE_ARRAY, Type::TYPE_ARRAY]:
                         $sub = $this->computeMergedType(array_merge($resolved[$op->left]->subTypes, $resolved[$op->right]->subTypes));
                         if ($sub) {
                             return [new Type(Type::TYPE_ARRAY, [$sub])];
                         }
                         return [new Type(Type::TYPE_ARRAY)];
                     default:
                         return [Type::mixed()];
                         throw new \RuntimeException("Math op on unknown types {$resolved[$op->left]} + {$resolved[$op->right]}");
                 }
             }
             return false;
         case 'Expr_BinaryOp_Concat':
         case 'Expr_Cast_String':
         case 'Expr_ConcatList':
             return [Type::string()];
         case 'Expr_BinaryOp_Mod':
         case 'Expr_BinaryOp_ShiftLeft':
         case 'Expr_BinaryOp_ShiftRight':
         case 'Expr_Cast_Int':
         case 'Expr_Print':
             return [Type::int()];
         case 'Expr_Cast_Double':
             return [Type::float()];
         case 'Expr_UnaryMinus':
         case 'Expr_UnaryPlus':
             if ($resolved->contains($op->expr)) {
                 switch ($resolved[$op->expr]->type) {
                     case Type::TYPE_LONG:
                     case Type::TYPE_DOUBLE:
                         return [$resolved[$op->expr]];
                 }
                 return [Type::numeric()];
             }
             return false;
         case 'Expr_Eval':
             return false;
         case 'Iterator_Key':
             if ($resolved->contains($op->var)) {
                 // TODO: implement this as well
                 return false;
             }
             return false;
         case 'Expr_Exit':
         case 'Iterator_Reset':
             return [Type::null()];
         case 'Iterator_Valid':
             return [Type::bool()];
         case 'Iterator_Value':
             if ($resolved->contains($op->var)) {
                 if ($resolved[$op->var]->subTypes) {
                     return $resolved[$op->var]->subTypes;
                 }
                 return false;
             }
             return false;
         case 'Expr_StaticCall':
             return $this->resolveMethodCall($op->class, $op->name, $op, $resolved);
         case 'Expr_MethodCall':
             return $this->resolveMethodCall($op->var, $op->name, $op, $resolved);
         case 'Expr_Yield':
         case 'Expr_Include':
             // TODO: we may be able to determine these...
             return false;
     }
     throw new \LogicException("Unknown variable op found: " . $op->getType());
 }