Example #1
0
 /**
  * Determines the type from the operation (assumes that the type or the value is unknown)
  * 
  * @param string $op the operator
  * @param PC_Obj_MultiType $t1 the type of the first operand
  * @param PC_Obj_MultiType $t2 the type of the second operand (may be null for unary ops)
  * @return PC_Obj_MultiType the variable
  */
 protected function get_type_from_op($op, $t1, $t2 = null)
 {
     switch ($op) {
         // bitwise operators have always int as result
         case '|':
         case '&':
         case '^':
         case '>>':
         case '<<':
         case '~':
         case '?:':
             return PC_Obj_MultiType::create_int();
             // concatenation leads always to string
         // concatenation leads always to string
         case '.':
             return PC_Obj_MultiType::create_string();
         case '+':
         case '-':
         case '*':
         case '/':
         case '%':
             // if one of them is unknown we don't know whether we would get a float or int
             if ($t1->is_unknown() || $t1->is_multiple() || $t2 !== null && ($t2->is_unknown() || $t2->is_multiple())) {
                 return new PC_Obj_MultiType();
             }
             $ti1 = $t1->get_first()->get_type();
             $ti2 = $t2 === null ? -1 : $t2->get_first()->get_type();
             // if both are arrays, the result is an array
             if ($ti1 == PC_Obj_Type::TARRAY && $ti2 == PC_Obj_Type::TARRAY) {
                 return PC_Obj_MultiType::create_array();
             }
             // if one of them is float, the result is float
             if ($ti1 == PC_Obj_Type::FLOAT || $ti2 == PC_Obj_Type::FLOAT) {
                 return PC_Obj_MultiType::create_float();
             }
             // otherwise its always int
             return PC_Obj_MultiType::create_int();
         case '==':
         case '!=':
         case '===':
         case '!==':
         case '<':
         case '>':
         case '<=':
         case '>=':
         case '&&':
         case '||':
         case 'xor':
         case '!':
             // always bool
             return PC_Obj_MultiType::create_bool();
         default:
             FWS_Helper::error('Unknown operator "' . $op . '"');
     }
 }
Example #2
0
 /**
  * Checks whether $arg is ok for $param, assumes that $param is a callable and $arg is known.
  *
  * @param PC_Obj_Location $loc the location
  * @param PC_Obj_MultiType $arg the argument
  */
 private function check_callable($loc, $arg)
 {
     $first = $arg->get_first();
     if ($first->get_type() == PC_Obj_Type::STRING) {
         if ($first->is_val_unknown()) {
             return;
         }
         $func = $this->env->get_types()->get_function($first->get_value());
         if ($func === null) {
             $this->report($loc, 'The function "' . $first->get_value() . '" does not exist!', PC_Obj_Error::E_S_FUNCTION_MISSING);
         }
     } else {
         if ($first->get_type() == PC_Obj_Type::TARRAY) {
             if ($first->is_val_unknown()) {
                 return;
             }
             $callable = $first->get_value();
             if (count($callable) != 2 || !$callable[0]->is_unknown() && $callable[0]->get_first()->get_type() != PC_Obj_Type::OBJECT || !$callable[1]->is_unknown() && $callable[1]->get_first()->get_type() != PC_Obj_Type::STRING) {
                 $this->report($loc, 'Invalid callable: ' . FWS_Printer::to_string($first) . '!', PC_Obj_Error::E_S_CALLABLE_INVALID);
             } else {
                 if ($callable[0]->is_unknown() || $callable[1]->is_unknown()) {
                     return;
                 }
                 $obj = $callable[0]->get_first();
                 $name = $callable[1]->get_first();
                 $classname = $obj->get_class();
                 $class = $this->env->get_types()->get_class($classname);
                 if (!$class) {
                     $this->report($loc, 'The class "#' . $classname . '#" does not exist!', PC_Obj_Error::E_S_CLASS_MISSING);
                 } else {
                     if (!$class->contains_method($name->get_value())) {
                         $this->report($loc, 'The method "' . $name->get_value() . '" does not exist in the class "#' . $classname . '#"!', PC_Obj_Error::E_S_METHOD_MISSING);
                     }
                 }
             }
         } else {
             if ($first->get_type() != PC_Obj_Type::TCALLABLE) {
                 $this->report($loc, 'Invalid callable: ' . FWS_Printer::to_string($first) . '!', PC_Obj_Error::E_S_CALLABLE_INVALID);
             }
         }
     }
 }
Example #3
0
 /**
  * Handles a cast
  * 
  * @param string $cast the cast-type: 'int','float','string','array','object','bool' or 'unset'
  * @param PC_Obj_MultiType $e the expression
  * @return PC_Obj_MultiType the result
  */
 public function handle_cast($cast, $e)
 {
     if (!$e instanceof PC_Obj_MultiType) {
         return $this->handle_error('$e is invalid');
     }
     // unset casts to null. in this case we don't really know the value
     // object-cast make no sense here, I think
     if ($cast == 'unset' || $cast == 'object') {
         return $this->create_unknown();
     }
     // if we don't know the type or value, just provide the type; in loops as well
     if ($this->vars->is_in_loop() || $e->is_array_unknown()) {
         return PC_Obj_MultiType::get_type_by_name($cast);
     }
     // we know the value, so perform a cast
     $res = 0;
     eval('$res = (' . $cast . ')' . $e->get_first()->get_value_for_eval() . ';');
     return $this->get_type_from_php($res);
 }
Example #4
0
 /**
  * Returns a variable pointing to the array-element with given key. If it does not exist, it
  * will be created as soon as the type is assigned.
  *
  * @param PC_Obj_MultiType $key the key (null = append)
  * @return PC_Obj_Variable the type of the element
  */
 public function array_offset($key)
 {
     assert(!$this->type->is_multiple() && !$this->type->is_unknown());
     $first = $this->type->get_first();
     assert($first->get_type() == PC_Obj_Type::TARRAY);
     // fetch element or create it
     $akey = $key;
     if ($key === null) {
         $akey = $key = $first->get_next_array_key();
     } else {
         if (!$key->is_unknown()) {
             $akey = $key;
             $key = $first->get_array_type($key->get_first()->get_value());
         }
     }
     $var = new self($this->get_file(), $this->get_line(), '', $key);
     // connect the var to us
     $var->arrayref = $this;
     $var->arrayoff = $akey;
     return $var;
 }