/**
  * Executes the operator
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['parameters'])) {
         throw new CompilerException("Invalid 'parameters' for new-type", $expression);
     }
     switch ($expression['internal-type']) {
         case 'array':
             $compilationContext->headersManager->add('kernel/array');
             $functionName = 'create_array';
             break;
         case 'string':
             $compilationContext->headersManager->add('kernel/string');
             $functionName = 'create_string';
             break;
         default:
             throw new CompilerException("Cannot build instance of type", $expression);
     }
     $builder = new FunctionCallBuilder($functionName, $expression['parameters'], 1, $expression['file'], $expression['line'], $expression['char']);
     /**
      * Implicit type coercing
      */
     $castBuilder = new CastOperatorBuilder($expression['internal-type'], $builder);
     $expression = new Expression($castBuilder->get());
     $expression->setReadOnly($this->_readOnly);
     return $expression->compile($compilationContext);
 }
Example #2
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $expr = new Expression($expression['left']);
     $expr->setReadOnly(true);
     $expr->setExpectReturn(true);
     $exprPath = $expr->compile($compilationContext);
     if ($exprPath->getType() == 'variable') {
         $exprVariable = $compilationContext->symbolTable->getVariableForRead($exprPath->getCode(), $compilationContext, $expression);
         if ($exprVariable->getType() == 'variable') {
             if ($exprVariable->hasDifferentDynamicType(array('undefined', 'string'))) {
                 $compilationContext->logger->warning('Possible attempt to use invalid type as path in "require" operator', 'non-valid-require', $expression);
             }
         }
     }
     $symbolVariable = false;
     if ($this->isExpecting()) {
         $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify('variable', $compilationContext, $expression);
     }
     $compilationContext->headersManager->add('kernel/memory');
     $compilationContext->headersManager->add('kernel/require');
     $codePrinter = $compilationContext->codePrinter;
     if ($symbolVariable) {
         $codePrinter->output('ZEPHIR_OBSERVE_OR_NULLIFY_PPZV(&' . $symbolVariable->getName() . ');');
         $codePrinter->output('if (zephir_require_zval_ret(&' . $symbolVariable->getName() . ', ' . $exprPath->getCode() . ' TSRMLS_CC) == FAILURE) {');
     } else {
         $codePrinter->output('if (zephir_require_zval(' . $exprPath->getCode() . ' TSRMLS_CC) == FAILURE) {');
     }
     $codePrinter->output("\t" . 'RETURN_MM_NULL();');
     $codePrinter->output('}');
     if ($symbolVariable) {
         return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
     }
     return new CompiledExpression('null', null, $expression);
 }
Example #3
0
 /**
  * Compile expression
  *
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  * @throws Exception
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new \Exception("Missing left part of the expression");
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
             return new CompiledExpression($left->getType(), '+' . $left->getCode(), $expression);
         case 'variable':
             $variable = $compilationContext->symbolTable->getVariable($left->getCode());
             switch ($variable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'double':
                     return new CompiledExpression($variable->getType(), '+' . $variable->getName(), $expression);
                 case 'variable':
                     return new CompiledExpression('variable', $variable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot operate plus with variable of '" . $left->getType() . "' type");
             }
             break;
         default:
             throw new CompilerException("Cannot operate plus with '" . $left->getType() . "' type");
     }
 }
Example #4
0
 /**
  * Compiles foo[y][x][] = {expr} (multiple offset)
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 protected function _assignArrayIndexMultiple($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $codePrinter = $compilationContext->codePrinter;
     $offsetExprs = array();
     foreach ($statement['index-expr'] as $indexExpr) {
         $expression = new Expression($indexExpr);
         $expression->setReadOnly(true);
         $exprIndex = $expression->compile($compilationContext);
         switch ($exprIndex->getType()) {
             case 'int':
             case 'uint':
             case 'long':
             case 'ulong':
             case 'string':
             case 'variable':
                 break;
             default:
                 throw new CompilerException("Index: " . $exprIndex->getType() . " cannot be used as array index in assignment without cast", $indexExpr);
         }
         $offsetExprs[] = $exprIndex;
     }
     $compilationContext->headersManager->add('kernel/array');
     /**
      * Create a temporal zval (if needed)
      */
     $symbolVariable = $this->_getResolvedArrayItem($resolvedExpr, $compilationContext);
     $targetVariable = $compilationContext->symbolTable->getVariableForWrite($variable, $compilationContext, $statement);
     $offsetExprs[] = 'a';
     $compilationContext->backend->assignArrayMulti($targetVariable, $symbolVariable, $offsetExprs, $compilationContext);
 }
 /**
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  * @throws Exception
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Missing left part of the expression", $expression);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'bool':
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
             return new CompiledExpression('int', '~(' . $left->getCode() . ')', $expression);
         case 'variable':
             $variable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
             switch ($variable->getType()) {
                 case 'bool':
                 case 'int':
                 case 'uint':
                 case 'long':
                     return new CompiledExpression('int', '~' . $variable->getName(), $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     return new CompiledExpression('int', '~zephir_get_intval(' . $variable->getName() . ')', $expression);
                 default:
                     throw new CompilerException("Unknown type: " . $variable->getType(), $expression);
             }
             break;
         default:
             throw new CompilerException("Unknown type: " . $left->getType(), $expression);
     }
 }
Example #6
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/object');
     $exprVariable = new Expression($expression['left']);
     $exprVariable->setReadOnly(true);
     $exprVariable->setExpectReturn(true);
     $exprCompiledVariable = $exprVariable->compile($compilationContext);
     if ($exprCompiledVariable->getType() != 'variable') {
         throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as array", $expression);
     }
     $clonedVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression);
     if ($clonedVariable->getType() != 'variable') {
         throw new CompilerException("Variable type: " . $exprVariable->getType() . " cannot be cloned");
     }
     if ($clonedVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to use non array in "clone" operator', 'non-valid-clone', $expression);
     }
     $symbolVariable = $this->getExpected($compilationContext, $expression);
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Objects can only be cloned into dynamic variables", $expression);
     }
     $symbolVariable->setDynamicTypes('object');
     $symbolVariable->setIsInitialized(true, $compilationContext, $expression);
     /* Inherit the dynamic type data from the cloned object */
     $symbolVariable->setDynamicTypes($clonedVariable->getDynamicTypes());
     $symbolVariable->setClassTypes($clonedVariable->getClassTypes());
     $compilationContext->codePrinter->output('if (zephir_clone(' . $symbolVariable->getName() . ', ' . $clonedVariable->getName() . ' TSRMLS_CC) == FAILURE) {');
     $compilationContext->codePrinter->output("\t" . 'RETURN_MM();');
     $compilationContext->codePrinter->output('}');
     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
 }
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'irange' expression", $expression['left']);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Invalid 'right' operand for 'irange' expression", $expression['right']);
     }
     $exprBuilder = Expression\Builder\BuilderFactory::getInstance();
     /**
      * Implicit type coercing
      */
     $castBuilder = $exprBuilder->operators()->cast(Types::ARRAY_, $exprBuilder->statements()->functionCall('range', array($expression['left'], $expression['right'])));
     $expression = new Expression($castBuilder->build());
     $expression->setReadOnly($this->_readOnly);
     return $expression->compile($compilationContext);
 }
Example #8
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'irange' expression", $expression['left']);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Invalid 'right' operand for 'irange' expression", $expression['right']);
     }
     $builder = new FunctionCallBuilder('range', array(array('parameter' => $expression['left']), array('parameter' => $expression['right'])));
     /**
      * Implicit type coercing
      */
     $castBuilder = new CastOperatorBuilder('array', $builder);
     $expression = new Expression($castBuilder->get());
     $expression->setReadOnly($this->_readOnly);
     return $expression->compile($compilationContext);
 }
Example #9
0
 /**
  *
  * @param array $expression
  * @param \CompilationContext $compilationContext
  * @return \CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/operators');
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'empty' expression", $expression['left']);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly(true);
     $left = $leftExpr->compile($compilationContext);
     if ($left->getType() != 'variable') {
         throw new CompilerException("'empty' operand only can be a variable", $expression['left']);
     }
     $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
     if ($variableLeft->isNotVariableAndString()) {
         throw new CompilerException("Only dynamic/string variables can be used in 'empty' operators", $expression['left']);
     }
     return new CompiledExpression('bool', 'ZEPHIR_IS_EMPTY(' . $variableLeft->getName() . ')', $expression);
 }
Example #10
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/array');
     $expression = $this->_statement['expr'];
     $flags = 'PH_SEPARATE';
     if ($expression['type'] == 'list') {
         $expression = $expression['left'];
     }
     switch ($expression['type']) {
         case 'array-access':
             $expr = new Expression($expression['left']);
             $expr->setReadOnly(true);
             $exprVar = $expr->compile($compilationContext);
             $variable = $compilationContext->symbolTable->getVariableForWrite($exprVar->getCode(), $compilationContext, $this->_statement);
             $expr = new Expression($expression['right']);
             $expr->setReadOnly(true);
             $exprIndex = $expr->compile($compilationContext);
             break;
         case 'property-access':
             $expr = new Expression($expression['left']);
             $expr->setReadOnly(true);
             $exprVar = $expr->compile($compilationContext);
             $variable = $compilationContext->symbolTable->getVariableForWrite($exprVar->getCode(), $compilationContext, $this->_statement);
             $variableCode = $compilationContext->backend->getVariableCode($variable);
             $compilationContext->headersManager->add('kernel/object');
             $compilationContext->codePrinter->output('zephir_unset_property(' . $variableCode . ', "' . $expression['right']['value'] . '" TSRMLS_CC);');
             return true;
         case 'property-dynamic-access':
             //@todo fix it
         //@todo fix it
         default:
             throw new CompilerException('Cannot use expression type: ' . $expression['type'] . ' in "unset"', $expression);
     }
     if (!in_array($variable->getType(), array('variable', 'array'))) {
         throw new CompilerException('Cannot use variable type: ' . $variable->gettype() . ' in "unset"', $expression['left']);
     }
     if ($variable->hasDifferentDynamicType(array('undefined', 'array', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to use non array/object in unset operator', 'non-valid-unset', $expression['left']);
     }
     $compilationContext->backend->arrayUnset($variable, $exprIndex, $flags, $compilationContext);
 }
Example #11
0
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'unlikely' expression", $expression['left']);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly(true);
     $left = $leftExpr->compile($compilationContext);
     if ($left->getType() == 'bool') {
         return new CompiledExpression('bool', 'unlikely(' . $left->getCode() . ')', $expression);
     }
     if ($left->getType() == 'variable') {
         $variable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
         switch ($variable->getType()) {
             case 'bool':
                 return new CompiledExpression('bool', 'unlikely(' . $variable->getName() . ')', $expression);
             default:
                 return new CompiledExpression('bool', 'unlikely(zephir_is_true(' . $variable->getName() . '))', $expression);
         }
     }
     throw new CompilerException("Cannot use expression type: '" . $left->getType() . "' in 'unlikely' operator", $expression['left']);
 }
Example #12
0
 /**
  * Compile expression
  *
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  * @throws Exception
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new \Exception("Missing left part of the expression");
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
             return new CompiledExpression($left->getType(), '-' . $left->getCode(), $expression);
         case 'variable':
             $variable = $compilationContext->symbolTable->getVariable($left->getCode());
             switch ($variable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'double':
                     return new CompiledExpression($variable->getType(), '-' . $variable->getName(), $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $compilationContext->codePrinter->output('zephir_negate(' . $compilationContext->backend->getVariableCode($variable) . ' TSRMLS_CC);');
                     return new CompiledExpression('variable', $variable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot operate minus with variable of '" . $left->getType() . "' type");
             }
             break;
         default:
             throw new CompilerException("Cannot operate minus with '" . $left->getType() . "' type");
     }
 }
Example #13
0
 /**
  *
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  */
 public function compileTypeHint($expression, CompilationContext $compilationContext)
 {
     $expr = new Expression($expression['right']);
     $expr->setReadOnly(true);
     $resolved = $expr->compile($compilationContext);
     if ($resolved->getType() != 'variable') {
         throw new CompilerException("Type-Hints only can be applied to dynamic variables", $expression);
     }
     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Type-Hints only can be applied to dynamic variables", $expression);
     }
     $symbolVariable->setDynamicTypes('object');
     $symbolVariable->setClassTypes($compilationContext->getFullName($expression['left']['value']));
     return $resolved;
 }
Example #14
0
 /**
  * Compiles a reference to a value
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     /**
      * Resolves the symbol that expects the value
      */
     if ($this->_expecting) {
         if ($this->_expectingVariable) {
             $symbolVariable = $this->_expectingVariable;
             if ($symbolVariable->getType() != 'variable') {
                 throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " to store a reference", $expression);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
         }
     } else {
         $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'variable':
         case 'string':
         case 'object':
         case 'array':
         case 'callable':
             break;
         default:
             throw new CompilerException("Cannot obtain a reference from type: " . $left->getType(), $expression);
     }
     $leftVariable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression);
     switch ($leftVariable->getType()) {
         case 'variable':
         case 'string':
         case 'object':
         case 'array':
         case 'callable':
             break;
         default:
             throw new CompilerException("Cannot obtain reference from variable type: " . $leftVariable->getType(), $expression);
     }
     $symbolVariable->setMustInitNull(true);
     $compilationContext->symbolTable->mustGrownStack(true);
     $symbolVariable->increaseVariantIfNull();
     $compilationContext->codePrinter->output('ZEPHIR_MAKE_REFERENCE(' . $symbolVariable->getName() . ', ' . $leftVariable->getName() . ');');
     return new CompiledExpression('reference', $symbolVariable->getRealName(), $expression);
 }
Example #15
0
 /**
  * Optimizes expressions
  *
  * @param $exprRaw
  * @param CompilationContext $compilationContext
  * @return bool|string
  * @throws CompilerException
  */
 public function optimize($exprRaw, CompilationContext $compilationContext)
 {
     $conditions = $this->optimizeNot($exprRaw, $compilationContext);
     if ($conditions !== false) {
         return $conditions;
     }
     /**
      * Discard first level parentheses
      */
     if ($exprRaw['type'] == 'list') {
         $expr = new Expression($exprRaw['left']);
     } else {
         $expr = new Expression($exprRaw);
     }
     $expr->setReadOnly(true);
     $expr->setEvalMode(true);
     $compiledExpression = $expr->compile($compilationContext);
     /**
      * Possible corrupted expression?
      */
     if (!is_object($compiledExpression)) {
         throw new CompilerException('Corrupted expression: ' . $exprRaw['type'], $exprRaw);
     }
     /**
      * Generate the condition according to the value returned by the evaluated expression
      */
     switch ($compiledExpression->getType()) {
         case 'null':
             $this->_unreachable = true;
             return '0';
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
             $code = $compiledExpression->getCode();
             if (is_numeric($code)) {
                 if ($code == '1') {
                     $this->_unreachableElse = true;
                 } else {
                     $this->_unreachable = true;
                 }
             }
             return $code;
         case 'char':
         case 'uchar':
             return $compiledExpression->getCode();
         case 'bool':
             $code = $compiledExpression->getBooleanCode();
             if ($code == '1') {
                 $this->_unreachableElse = true;
             } else {
                 if ($code == '0') {
                     $this->_unreachable = true;
                 }
             }
             return $code;
         case 'variable':
             $variableRight = $compilationContext->symbolTable->getVariableForRead($compiledExpression->getCode(), $compilationContext, $exprRaw);
             $possibleValue = $variableRight->getPossibleValue();
             if (is_object($possibleValue)) {
                 $possibleValueBranch = $variableRight->getPossibleValueBranch();
                 if ($possibleValueBranch instanceof Branch) {
                     /**
                      * Check if the possible value was assigned in the root branch
                      */
                     if ($possibleValueBranch->getType() == Branch::TYPE_ROOT) {
                         if ($possibleValue instanceof LiteralCompiledExpression) {
                             switch ($possibleValue->getType()) {
                                 case 'null':
                                     $this->_unreachable = true;
                                     break;
                                 case 'bool':
                                     if ($possibleValue->getBooleanCode() == '0') {
                                         $this->_unreachable = true;
                                     } else {
                                         $this->_unreachableElse = true;
                                     }
                                     break;
                                 case 'int':
                                     if (!intval($possibleValue->getCode())) {
                                         $this->_unreachable = true;
                                     } else {
                                         $this->_unreachableElse = true;
                                     }
                                     break;
                                 case 'double':
                                     if (!floatval($possibleValue->getCode())) {
                                         $this->_unreachable = true;
                                     } else {
                                         $this->_unreachableElse = true;
                                     }
                                     break;
                                 default:
                                     //echo $possibleValue->getType();
                             }
                         }
                     }
                 }
             }
             $this->_usedVariables[] = $variableRight->getName();
             /**
              * Evaluate the variable
              */
             switch ($variableRight->getType()) {
                 case 'int':
                 case 'uint':
                 case 'char':
                 case 'uchar':
                 case 'long':
                 case 'ulong':
                     return $variableRight->getName();
                 case 'string':
                     return $variableRight->getName() . ' && Z_STRLEN_P(' . $variableRight->getName() . ')';
                 case 'bool':
                     return $variableRight->getName();
                 case 'double':
                     return $variableRight->getName();
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     if ($variableRight->isLocalOnly()) {
                         return 'zephir_is_true(&' . $variableRight->getName() . ')';
                     } else {
                         return 'zephir_is_true(' . $variableRight->getName() . ')';
                     }
                     break;
                 default:
                     throw new CompilerException("Variable can't be evaluated " . $variableRight->getType(), $exprRaw);
             }
             break;
         default:
             throw new CompilerException("Expression " . $compiledExpression->getType() . " can't be evaluated", $exprRaw);
     }
 }
Example #16
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $exprRaw = $this->_statement['expr'];
     /**
      * @TODO implement optimizers here
      */
     if ($exprRaw['type'] == 'fcall') {
         if ($exprRaw['name'] == 'range') {
             $status = $this->compileRange($exprRaw, $compilationContext);
             if ($status !== false) {
                 return;
             }
         }
         if ($exprRaw['name'] == 'iterator') {
             $status = $this->compileIterator($exprRaw, $compilationContext);
             if ($status !== false) {
                 return;
             }
         }
     }
     $expr = new Expression($exprRaw);
     $expr->setReadOnly(true);
     $expression = $expr->compile($compilationContext);
     /**
      * Check for traversing a constant string
      */
     if ($expression->getType() == 'string') {
         $this->compileStringTraverse($expression, $compilationContext, null);
         return;
     }
     if ($expression->getType() != 'variable' && $expression->getType() != 'array') {
         throw new CompilerException("Unknown type: " . $expression->getType(), $exprRaw);
     }
     $exprVariable = $compilationContext->symbolTable->getVariableForRead($expression->getCode(), $compilationContext, $this->_statement['expr']);
     switch ($exprVariable->getType()) {
         case 'variable':
         case 'array':
             $this->compileHashTraverse($expression, $compilationContext, $exprVariable);
             break;
         case 'string':
             $this->compileStringTraverse($expression, $compilationContext, $exprVariable);
             break;
         default:
             throw new CompilerException("Cannot traverse value type: " . $exprVariable->getType(), $exprRaw);
     }
 }
Example #17
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Missing left part of the expression", $expression);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Missing right part of the expression", $expression);
     }
     /**
      * Check for constant folding optimizations
      */
     switch ($this->_operator) {
         case '&':
         case '|':
         case '^':
         case '<<':
         case '>>':
             $optimized = $this->optimizeConstantFolding($expression, $compilationContext);
             if (is_object($optimized)) {
                 return $optimized;
             }
             break;
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly(true);
     $left = $leftExpr->compile($compilationContext);
     $rightExpr = new Expression($expression['right']);
     $rightExpr->setReadOnly(true);
     $right = $rightExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'char':
         case 'uchar':
             switch ($right->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                 case 'double':
                     return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' (int) (' . $right->getCode() . '))', $expression);
                 case 'bool':
                     return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getBooleanCode() . ')', $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression);
                     switch ($variableRight->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                             return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'double':
                             return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' (int) (' . $variableRight->getName() . '))', $expression);
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             if ($variableRight->isLocalOnly()) {
                                 return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' zephir_get_numberval(&' . $variableRight->getName() . '))', $expression);
                             } else {
                                 return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' zephir_get_numberval(' . $variableRight->getName() . '))', $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot operate variable('int') with variable('" . $variableRight->getType() . "')", $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot operate 'int' with '" . $right->getType() . "'", $expression);
             }
             break;
         case 'bool':
             switch ($right->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'double':
                     return new CompiledExpression('int', '(' . $left->getBooleanCode() . ' ' . $this->_bitOperator . '((' . $right->getCode() . ') ? 1 : 0))', $expression);
                 case 'bool':
                     return new CompiledExpression('int', '(' . $left->getBooleanCode() . ' ' . $this->_bitOperator . ' ' . $right->getBooleanCode() . ')', $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($expression['right']['value'], $compilationContext, $expression);
                     switch ($variableRight->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                             return new CompiledExpression('int', '((int) (' . $left->getBooleanCode() . ') ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('int', '((int) (' . $left->getBooleanCode() . ') ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'double':
                             return new CompiledExpression('int', '((int) (' . $left->getBooleanCode() . ') ' . $this->_operator . ' (int) (' . $variableRight->getName() . '))', $expression);
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             if ($variableRight->isLocalOnly()) {
                                 return new CompiledExpression('int', '((int) (' . $left->getBooleanCode() . ') ' . $this->_operator . ' zephir_get_numberval(&' . $variableRight->getName() . '))', $expression);
                             } else {
                                 return new CompiledExpression('int', '((int) (' . $left->getBooleanCode() . ') ' . $this->_operator . ' zephir_get_numberval(' . $variableRight->getName() . '))', $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot operate ('bool') with variable('" . $variableRight->getType() . "')", $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot operate 'bool' with '" . $right->getType() . "'", $expression);
             }
             break;
         case 'double':
             switch ($right->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                 case 'double':
                     return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' (int) (' . $right->getCode() . '))', $expression);
                 case 'bool':
                     return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' ' . $right->getBooleanCode() . ')', $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($expression['right']['value'], $compilationContext, $expression);
                     switch ($variableRight->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                             return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'double':
                             return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' (int) (' . $variableRight->getName() . '))', $expression);
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             if ($variableRight->isLocalOnly()) {
                                 return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' zephir_get_numberval(&' . $variableRight->getName() . '))', $expression);
                             } else {
                                 return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' zephir_get_numberval(' . $variableRight->getName() . '))', $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot operate variable('double') with variable('" . $variableRight->getType() . "')", $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot operate 'double' with '" . $right->getType() . "'", $expression);
             }
             break;
         case 'string':
             switch ($right->getType()) {
                 default:
                     throw new CompilerException("Operation is not supported between strings", $expression);
             }
             break;
         case 'variable':
             $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->resolve(null, $compilationContext), $compilationContext, $expression);
             switch ($variableLeft->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     switch ($right->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                         case 'char':
                         case 'uchar':
                             return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                 case 'char':
                                 case 'uchar':
                                     return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'bool':
                                     return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'double':
                                     return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' (int) (' . $variableRight->getName() . '))', $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableRight->isLocalOnly()) {
                                         return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' (int) (zephir_get_numberval(&' . $variableRight->getName() . ')))', $expression);
                                     } else {
                                         return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' (int) (zephir_get_numberval(' . $variableRight->getName() . ')))', $expression);
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Cannot operate variable('int') with variable('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot operate variable('int') with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 case 'bool':
                     switch ($right->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                             return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_bitOperator . ' ' . $right->getBooleanCode() . ')', $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                     return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'double':
                                     return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' (int) (' . $variableRight->getName() . '))', $expression);
                                 case 'bool':
                                     return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_bitOperator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableRight->isLocalOnly()) {
                                         return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' zephir_get_numberval(&' . $variableRight->getName() . '))', $expression);
                                     } else {
                                         return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' zephir_get_numberval(' . $variableRight->getName() . '))', $expression);
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Cannot operate variable('int') with variable('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot operate variable('int') with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 case 'double':
                     switch ($right->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                             return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                         case 'double':
                             return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_operator . ' (int) (' . $right->getCode() . '))', $expression);
                         case 'bool':
                             return new CompiledExpression('int', '((int) (' . $left->getCode() . ') ' . $this->_bitOperator . ' ' . $right->getBooleanCode() . ')', $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($expression['right']['value'], $compilationContext, $expression['right']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                     return new CompiledExpression('int', '((int) (' . $variableLeft->getName() . ') ' . $this->_operator . '  ' . $variableRight->getName() . ')', $expression);
                                 case 'double':
                                     return new CompiledExpression('int', '((int) (' . $variableLeft->getName() . ') ' . $this->_operator . ' (int) (' . $variableRight->getName() . '))', $expression);
                                 case 'bool':
                                     return new CompiledExpression('int', '((int) (' . $variableLeft->getName() . ') ' . $this->_bitOperator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableRight->isLocalOnly()) {
                                         return new CompiledExpression('int', '((int) (' . $variableLeft->getName() . ') ' . $this->_operator . ' (int) (zephir_get_numberval(&' . $variableRight->getName() . ')))', $expression);
                                     } else {
                                         return new CompiledExpression('int', '((int) (' . $variableLeft->getName() . ') ' . $this->_operator . ' (int) (zephir_get_numberval(' . $variableRight->getName() . ')))', $expression);
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Cannot operate variable('double') with variable('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot operate variable('int') with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 case 'string':
                     throw new CompilerException("Cannot operate string variables'", $expression);
                 case 'variable':
                     switch ($right->getType()) {
                         /* a + 1 */
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             $compilationContext->headersManager->add('kernel/operators');
                             $op = $this->_operator;
                             if ($variableLeft->isLocalOnly()) {
                                 $op1 = '&' . $variableLeft->getName();
                             } else {
                                 $op1 = $variableLeft->getName();
                             }
                             $op2 = $right->getCode();
                             if ($right->getType() == 'double') {
                                 return new CompiledExpression('int', '((int) (zephir_get_numberval(' . $op1 . ')) ' . $op . ' (int) (' . $op2 . '))', $expression);
                             } else {
                                 return new CompiledExpression('int', '((int) (zephir_get_numberval(' . $op1 . ')) ' . $op . ' ' . $op2 . ')', $expression);
                             }
                             break;
                             /* a(var) + a(x) */
                         /* a(var) + a(x) */
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->resolve(null, $compilationContext), $compilationContext, $expression);
                             switch ($variableRight->getType()) {
                                 /* a(var) + a(int) */
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableLeft->isLocalOnly()) {
                                         return new CompiledExpression('int', '((int) (zephir_get_numberval(&' . $variableLeft->getName() . ')) ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                     } else {
                                         return new CompiledExpression('int', '((int) (zephir_get_numberval(' . $variableLeft->getName() . ')) ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                     }
                                     break;
                                     /* a(var) + a(bool) */
                                 /* a(var) + a(bool) */
                                 case 'bool':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableLeft->isLocalOnly()) {
                                         return new CompiledExpression('int', '((int) (zephir_get_numberval(&' . $variableLeft->getName() . ')) ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                     } else {
                                         return new CompiledExpression('int', '((int) (zephir_get_numberval(' . $variableLeft->getName() . ')) ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                     }
                                     break;
                                     /* a(var) + a(var) */
                                 /* a(var) + a(var) */
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableLeft->isLocalOnly()) {
                                         $op1 = '&' . $variableLeft->getName();
                                     } else {
                                         $op1 = $variableLeft->getName();
                                     }
                                     if ($variableRight->isLocalOnly()) {
                                         $op2 = '&' . $variableRight->getName();
                                     } else {
                                         $op2 = $variableRight->getName();
                                     }
                                     $expected = $this->getExpected($compilationContext, $expression);
                                     if ($expected->isLocalOnly()) {
                                         $compilationContext->codePrinter->output($this->_zvalOperator . '(&' . $expected->getName() . ', ' . $op1 . ', ' . $op2 . ' TSRMLS_CC);');
                                     } else {
                                         $compilationContext->codePrinter->output($this->_zvalOperator . '(' . $expected->getName() . ', ' . $op1 . ', ' . $op2 . ' TSRMLS_CC);');
                                     }
                                     if ($variableLeft->isTemporal()) {
                                         $variableLeft->setIdle(true);
                                     }
                                     if ($variableRight->isTemporal()) {
                                         $variableRight->setIdle(true);
                                     }
                                     return new CompiledExpression('variable', $expected->getName(), $expression);
                                 default:
                                     throw new CompilerException("Cannot operate 'variable' with variable ('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot operate 'variable' with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown '" . $variableLeft->getType() . "'", $expression);
             }
             break;
         default:
             throw new CompilerException("Unsupported type: " . $left->getType(), $expression);
     }
 }
Example #18
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/array');
     $expression = $this->_statement['expr'];
     $flags = 'PH_SEPARATE';
     if ($expression['type'] == 'list') {
         $expression = $expression['left'];
     }
     switch ($expression['type']) {
         case 'array-access':
             $expr = new Expression($expression['left']);
             $expr->setReadOnly(true);
             $exprVar = $expr->compile($compilationContext);
             $expr = new Expression($expression['right']);
             $expr->setReadOnly(true);
             $exprIndex = $expr->compile($compilationContext);
             break;
         case 'property-access':
             $expr = new Expression($expression['left']);
             $expr->setReadOnly(true);
             $exprVar = $expr->compile($compilationContext);
             $compilationContext->headersManager->add('kernel/object');
             if ($exprVar->getCode() == 'this') {
                 $compilationContext->codePrinter->output('zephir_unset_property(this_ptr, "' . $expression['right']['value'] . '" TSRMLS_CC);');
             } else {
                 $compilationContext->codePrinter->output('zephir_unset_property(' . $exprVar->getCode() . ', "' . $expression['right']['value'] . '" TSRMLS_CC);');
             }
             return true;
         case 'property-dynamic-access':
             //@todo fix it
         //@todo fix it
         default:
             throw new CompilerException('Cannot use expression type: ' . $expression['type'] . ' in "unset"', $expression);
     }
     $variable = $compilationContext->symbolTable->getVariableForWrite($exprVar->getCode(), $compilationContext, $this->_statement);
     if (!in_array($variable->getType(), array('variable', 'array'))) {
         throw new CompilerException('Cannot use variable type: ' . $variable->gettype() . ' in "unset"', $expression['left']);
     }
     if ($variable->hasDifferentDynamicType(array('undefined', 'array', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to use non array/object in unset operator', 'non-valid-unset', $expression['left']);
     }
     switch ($exprIndex->getType()) {
         case 'int':
         case 'uint':
         case 'long':
             $compilationContext->headersManager->add('kernel/array');
             $compilationContext->codePrinter->output('zephir_array_unset_long(&' . $variable->getName() . ', ' . $exprIndex->getCode() . ', ' . $flags . ');');
             break;
         case 'string':
             $compilationContext->codePrinter->output('zephir_array_unset_string(&' . $variable->getName() . ', SS("' . $exprIndex->getCode() . '"), ' . $flags . ');');
             break;
         case 'variable':
             $variableIndex = $compilationContext->symbolTable->getVariableForRead($exprIndex->getCode(), $compilationContext, $exprIndex->getOriginal());
             switch ($variableIndex->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                     $compilationContext->headersManager->add('kernel/array');
                     $compilationContext->codePrinter->output('zephir_array_unset_long(&' . $variable->getName() . ', ' . $variableIndex->getName() . ', ' . $flags . ');');
                     break;
                 case 'string':
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/array');
                     $compilationContext->codePrinter->output('zephir_array_unset(&' . $variable->getName() . ', ' . $variableIndex->getName() . ', ' . $flags . ');');
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variableIndex->getType() . " cannot be used as array index without cast", $expression['right']);
             }
             break;
         default:
             throw new CompilerException("Cannot use expression: " . $exprIndex->getType() . " as array index without cast", $expression['right']);
     }
 }
Example #19
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/array');
     $variable = $compilationContext->symbolTable->getVariableForWrite($expression['left']['value'], $compilationContext, $expression['left']);
     if ($variable->getType() != 'variable') {
         throw new CompilerException('Cannot use variable type: ' . $variable->gettype() . ' in "fetch" operator', $expression);
     }
     /**
      * return_value must not be observed
      */
     if ($variable->getName() != 'return_value') {
         /*
          * @todo use a read detector here
          */
         $readOnly = false;
         $line = max($compilationContext->symbolTable->getLastCallLine(), $compilationContext->symbolTable->getLastUnsetLine());
         if ($line === false || $line > 0 && $line < $expression['line']) {
             $numberMutations = $compilationContext->symbolTable->getExpectedMutations($variable->getName());
             if ($numberMutations == 1) {
                 if ($variable->getNumberMutations() == 1) {
                     $variable->setIsInitialized(true, $compilationContext, $expression);
                     $variable->setMemoryTracked(false);
                     $variable->setDynamicTypes('undefined');
                     $readOnly = true;
                 }
             }
         }
         if (!$readOnly || $expression['right']['type'] != 'array-access') {
             $variable->setIsInitialized(true, $compilationContext, $expression);
             $variable->observeVariant($compilationContext);
             $variable->setDynamicTypes('undefined');
             $variable->setPossibleValue(new CompiledExpression('undefined', '', $expression), $compilationContext);
         }
     } else {
         $variable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
     }
     if ($readOnly) {
         $flags = '1';
     } else {
         $flags = '0';
     }
     switch ($expression['right']['type']) {
         case 'array-access':
             $exprVariable = new Expression($expression['right']['left']);
             $exprVariable->setReadOnly(true);
             $exprVariable->setNoisy(false);
             $exprCompiledVariable = $exprVariable->compile($compilationContext);
             if ($exprCompiledVariable->getType() != 'variable') {
                 throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as array", $expression['right']['left']);
             }
             $evalVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression['right']['left']);
             if ($evalVariable->getType() != 'variable' && $evalVariable->getType() != 'array') {
                 throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as array", $expression['right']['left']);
             }
             if ($evalVariable->getType() == 'variable') {
                 if ($evalVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) {
                     $compilationContext->logger->warning('Possible attempt to use non array in fetch operator', 'non-valid-fetch', $expression['right']);
                 }
             }
             $expr = new Expression($expression['right']['right']);
             $expr->setReadOnly(true);
             $expr->setNoisy(false);
             $resolvedExpr = $expr->compile($compilationContext);
             return $compilationContext->backend->arrayIssetFetch($variable, $evalVariable, $resolvedExpr, $flags, $expression, $compilationContext);
             break;
         case 'property-access':
             $exprVariable = new Expression($expression['right']['left']);
             $exprVariable->setReadOnly(true);
             $exprVariable->setNoisy(false);
             $exprCompiledVariable = $exprVariable->compile($compilationContext);
             if ($exprCompiledVariable->getType() != 'variable') {
                 throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as object", $expression['right']['left']);
             }
             $evalVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression['right']['left']);
             if ($evalVariable->getType() != 'variable') {
                 throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as object", $expression['right']['left']);
             }
             if ($evalVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
                 $compilationContext->logger->warning('Possible attempt to use non object in fetch operator', 'non-valid-fetch', $expression['right']);
             }
             $property = $expression['right']['right']['value'];
             $compilationContext->headersManager->add('kernel/object');
             $symbol = $compilationContext->backend->getVariableCodePointer($variable);
             $evalSymbol = $compilationContext->backend->getVariableCode($evalVariable);
             return new CompiledExpression('bool', 'zephir_fetch_property(' . $symbol . ', ' . $evalSymbol . ', SL("' . $property . '"), PH_SILENT_CC)', $expression);
         case 'property-dynamic-access':
             $exprVariable = new Expression($expression['right']['left']);
             $exprVariable->setReadOnly(true);
             $exprVariable->setNoisy(false);
             $exprCompiledVariable = $exprVariable->compile($compilationContext);
             if ($exprCompiledVariable->getType() != 'variable') {
                 throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as object", $expression['right']['left']);
             }
             $evalVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression['right']['left']);
             if ($evalVariable->getType() != 'variable') {
                 throw new CompilerException("Variable type: " . $evalVariable->getType() . " cannot be used as object", $expression['right']['left']);
             }
             if ($evalVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
                 $compilationContext->logger->warning('Possible attempt to use non object in fetch operator', 'non-valid-fetch', $expression['right']);
             }
             $exprVariableProperty = new Expression($expression['right']['right']);
             $exprVariableProperty->setReadOnly(true);
             $exprCompiledVariableProperty = $exprVariableProperty->compile($compilationContext);
             if ($exprCompiledVariableProperty->getType() != 'variable') {
                 throw new CompilerException("Expression type: " . $exprCompiledVariableProperty->getType() . " cannot be used in property-dynamic-access", $expression['right']['right']);
             }
             $evalVariableProperty = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariableProperty->getCode(), $compilationContext, $expression['right']['right']);
             if ($evalVariableProperty->getType() != 'variable' && $evalVariableProperty->getType() != 'string') {
                 throw new CompilerException("Variable type: " . $evalVariableProperty->getType() . " cannot be used in property-dynamic-access", $expression['right']['right']);
             }
             $compilationContext->headersManager->add('kernel/object');
             $symbol = $compilationContext->backend->getVariableCodePointer($variable);
             $evalSymbol = $compilationContext->backend->getVariableCode($evalVariable);
             $evalPropertySymbol = $compilationContext->backend->getVariableCode($evalVariableProperty);
             return new CompiledExpression('bool', 'zephir_fetch_property_zval(' . $symbol . ', ' . $evalSymbol . ', ' . $evalPropertySymbol . ', PH_SILENT_CC)', $expression);
         default:
             throw new CompilerException('Cannot use this expression for "fetch" operators: ' . $expression['right']['type'], $expression);
     }
 }
Example #20
0
 /**
  * Compiles an 'isset' operator
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     if ($expression['left']['type'] == 'list') {
         $left = $expression['left']['left'];
     } else {
         $left = $expression['left'];
     }
     switch ($left['type']) {
         case 'array-access':
             $compilationContext->headersManager->add('kernel/array');
             $exprVariable = new Expression($left['left']);
             $exprVariable->setReadOnly(true);
             $exprVariable->setNoisy(false);
             $exprCompiledVariable = $exprVariable->compile($compilationContext);
             if ($exprCompiledVariable->getType() != 'variable' && $exprCompiledVariable->getType() != 'array') {
                 throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as array", $left['left']);
             }
             $variable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $left['left']);
             switch ($variable->getType()) {
                 case 'array':
                 case 'variable':
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as array", $left['left']);
                     break;
             }
             if ($variable->getType() == 'variable') {
                 if ($variable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) {
                     $compilationContext->logger->warning('Possible attempt to use non array in isset operator', 'non-valid-isset', $expression);
                 }
             }
             $expr = new Expression($left['right']);
             $expr->setReadOnly(true);
             $expr->setNoisy(false);
             $resolvedExpr = $expr->compile($compilationContext);
             switch ($resolvedExpr->getType()) {
                 case 'int':
                 case 'long':
                 case 'string':
                     return $compilationContext->backend->arrayIsset($variable, $resolvedExpr, $left['right'], $compilationContext);
                 case 'variable':
                     $indexVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $left['right']);
                     return $compilationContext->backend->arrayIsset($variable, $indexVariable, $left['right'], $compilationContext);
                     break;
                 default:
                     throw new CompilerException('[' . $left['right']['type'] . ']', $expression);
             }
             break;
         case 'property-access':
         case 'property-dynamic-access':
             $compilationContext->headersManager->add('kernel/object');
             $exprVariable = new Expression($left['left']);
             $exprVariable->setReadOnly(true);
             $exprCompiledVariable = $exprVariable->compile($compilationContext);
             if ($exprCompiledVariable->getType() != 'variable') {
                 throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as object", $left['left']);
             }
             $variable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $left['left']);
             if ($variable->getType() != 'variable') {
                 throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as object", $left['left']);
             }
             if ($variable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
                 $compilationContext->logger->warning('Possible attempt to use non object in isset operator', 'non-valid-isset', $expression);
             }
             $variableCode = $compilationContext->backend->getVariableCode($variable);
             if ($left['type'] == 'property-access') {
                 return $compilationContext->backend->propertyIsset($variable, $left['right']['value'], $compilationContext);
             }
             $expr = new Expression($left['right']);
             $expr->setReadOnly(true);
             $expr->setNoisy(false);
             $resolvedExpr = $expr->compile($compilationContext);
             switch ($resolvedExpr->getType()) {
                 case 'variable':
                     $indexVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $left['right']);
                     switch ($indexVariable->getType()) {
                         case 'variable':
                         case 'string':
                             $indexVariableCode = $compilationContext->backend->getVariableCode($indexVariable);
                             return new CompiledExpression('bool', 'zephir_isset_property_zval(' . $variableCode . ', ' . $indexVariableCode . ' TSRMLS_CC)', $left['right']);
                         default:
                             throw new CompilerException('[' . $indexVariable->getType() . ']', $expression);
                     }
                     break;
                 default:
                     throw new CompilerException('[' . $expression['left']['right']['type'] . ']', $expression);
             }
             break;
         case 'property-string-access':
             return new CompiledExpression('bool', '(0 == 0)', $left);
         case 'static-property-access':
             return new CompiledExpression('bool', '(0 == 0)', $left);
         default:
             throw new CompilerException('This expression is not valid for "isset" operator', $expression);
     }
 }
Example #21
0
 /**
  * Resolves the access to a property in an object
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return \CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     $propertyAccess = $expression;
     $expr = new Expression($propertyAccess['left']);
     $expr->setReadOnly(true);
     $exprVariable = $expr->compile($compilationContext);
     switch ($exprVariable->getType()) {
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprVariable->getCode(), $compilationContext, $expression);
             switch ($variableVariable->getType()) {
                 case 'variable':
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variableVariable->getType() . " cannot be used as object", $propertyAccess['left']);
             }
             break;
         default:
             throw new CompilerException("Cannot use expression: " . $exprVariable->getType() . " as an object", $propertyAccess['left']);
     }
     $property = $propertyAccess['right']['value'];
     $propertyDefinition = null;
     $classDefinition = null;
     $currentClassDefinition = $compilationContext->classDefinition;
     /**
      * If the property is accessed on 'this', we check if the method does exist
      */
     if ($variableVariable->getRealName() == 'this') {
         $classDefinition = $currentClassDefinition;
         if (!$classDefinition->hasProperty($property)) {
             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $expression);
         }
         $propertyDefinition = $classDefinition->getProperty($property);
     } else {
         /**
          * If we know the class related to a variable we could check if the property
          * is defined on that class
          */
         if ($variableVariable->hasAnyDynamicType('object')) {
             $classType = current($variableVariable->getClassTypes());
             $compiler = $compilationContext->compiler;
             if ($compiler->isClass($classType)) {
                 $classDefinition = $compiler->getClassDefinition($classType);
                 if (!$classDefinition) {
                     throw new CompilerException("Cannot locate class definition for class: " . $classType, $expression);
                 }
                 if (!$classDefinition->hasProperty($property)) {
                     throw new CompilerException("Class '" . $classType . "' does not have a property called: '" . $property . "'", $expression);
                 }
                 $propertyDefinition = $classDefinition->getProperty($property);
             }
         }
     }
     /**
      * Having a proper propertyDefinition we can check if the property is readable
      * according to its modifiers
      */
     if ($propertyDefinition) {
         if ($propertyDefinition->isStatic()) {
             throw new CompilerException("Attempt to access static property '" . $property . "' as non static", $expression);
         }
         if (!$propertyDefinition->isPublic()) {
             /**
              * Protected variables only can be read in the class context
              * where they were declared
              */
             if ($classDefinition == $currentClassDefinition) {
                 if ($propertyDefinition->isPrivate()) {
                     $declarationDefinition = $propertyDefinition->getClassDefinition();
                     if ($declarationDefinition != $currentClassDefinition) {
                         throw new CompilerException("Attempt to access private property '" . $property . "' outside of its declared class context: '" . $declarationDefinition->getCompleteName() . "'", $expression);
                     }
                 }
             } else {
                 if ($propertyDefinition->isProtected()) {
                 } else {
                     if ($propertyDefinition->isPrivate()) {
                         $declarationDefinition = $propertyDefinition->getClassDefinition();
                         if ($declarationDefinition != $currentClassDefinition) {
                             throw new CompilerException("Attempt to access private property '" . $property . "' outside of its declared class context: '" . $declarationDefinition->getCompleteName() . "'", $expression);
                         }
                     }
                 }
             }
         }
     }
     /**
      * Resolves the symbol that expects the value
      */
     $readOnly = false;
     if ($classDefinition == $currentClassDefinition && $this->_readOnly) {
         if ($this->_expecting) {
             if ($this->_expectingVariable) {
                 $symbolVariable = $this->_expectingVariable;
                 /**
                  * If a variable is assigned once in the method, we try to promote it
                  * to a read only variable
                  */
                 if ($symbolVariable->getName() != 'return_value') {
                     $line = $compilationContext->symbolTable->getLastCallLine();
                     if ($line === false || $line > 0 && $line < $expression['line']) {
                         $numberMutations = $compilationContext->symbolTable->getExpectedMutations($symbolVariable->getName());
                         if ($numberMutations == 1) {
                             if ($symbolVariable->getNumberMutations() == $numberMutations) {
                                 $symbolVariable->setMemoryTracked(false);
                                 $readOnly = true;
                             }
                         }
                     }
                 }
                 /**
                  * Variable is not read only or it wasn't promoted
                  */
                 if (!$readOnly) {
                     if ($symbolVariable->getName() != 'return_value') {
                         $symbolVariable->observeVariant($compilationContext);
                         $this->_readOnly = false;
                     } else {
                         $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
                     }
                 }
                 $this->_readOnly = false;
             } else {
                 $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
         }
     } else {
         if ($this->_expecting) {
             if ($this->_expectingVariable) {
                 $symbolVariable = $this->_expectingVariable;
                 /**
                  * If a variable is assigned once in the method, we try to promote it
                  * to a read only variable
                  */
                 if ($symbolVariable->getName() != 'return_value') {
                     $line = $compilationContext->symbolTable->getLastCallLine();
                     if ($line === false || $line > 0 && $line < $expression['line']) {
                         $numberMutations = $compilationContext->symbolTable->getExpectedMutations($symbolVariable->getName());
                         if ($numberMutations == 1) {
                             if ($symbolVariable->getNumberMutations() == $numberMutations) {
                                 $symbolVariable->setMemoryTracked(false);
                                 $readOnly = true;
                             }
                         }
                     }
                 }
                 /**
                  * Variable is not read only or it wasn't promoted
                  */
                 if (!$readOnly) {
                     if ($symbolVariable->getName() != 'return_value') {
                         $symbolVariable->observeVariant($compilationContext);
                         $this->_readOnly = false;
                     } else {
                         $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
                     }
                 }
             } else {
                 $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
         }
     }
     /**
      * Variable that receives a property value must be polymorphic
      */
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Cannot use variable: " . $symbolVariable->getType() . " to assign property value", $expression);
     }
     /**
      * At this point, we don't know the exact dynamic type fetched from the property
      */
     $symbolVariable->setDynamicTypes('undefined');
     $compilationContext->headersManager->add('kernel/object');
     if ($classDefinition == $currentClassDefinition) {
         if ($this->_readOnly || $readOnly) {
             $codePrinter->output($symbolVariable->getName() . ' = zephir_fetch_nproperty_this(' . $variableVariable->getName() . ', SL("' . $property . '"), PH_NOISY_CC);');
         } else {
             $codePrinter->output('zephir_read_property_this(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', SL("' . $property . '"), PH_NOISY_CC);');
         }
     } else {
         $codePrinter->output('zephir_read_property(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', SL("' . $property . '"), PH_NOISY_CC);');
     }
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Example #22
0
 /**
  * Compiles a method call
  *
  * @param Expression $expr
  * @param CompilationContext $compilationContext
  */
 public function compile(Expression $expr, CompilationContext $compilationContext)
 {
     $expression = $expr->getExpression();
     $exprVariable = new Expression($expression['variable']);
     $exprVariable->setReadOnly(true);
     $exprCompiledVariable = $exprVariable->compile($compilationContext);
     $builtInType = false;
     switch ($exprCompiledVariable->getType()) {
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression);
             switch ($variableVariable->getType()) {
                 case 'variable':
                     $caller = $variableVariable;
                     break;
                 default:
                     /* Check if there is a built-in type optimizer available */
                     $builtInTypeClass = 'Zephir\\Types\\' . ucfirst($variableVariable->getType()) . 'Type';
                     if (class_exists($builtInTypeClass)) {
                         /**
                          * @var $builtInType \Zephir\Types\AbstractType
                          */
                         $builtInType = new $builtInTypeClass();
                         $caller = $exprCompiledVariable;
                     } else {
                         throw new CompilerException("Methods cannot be called on variable type: " . $variableVariable->getType(), $expression);
                     }
             }
             break;
         default:
             /* Check if there is a built-in type optimizer available */
             $builtInTypeClass = 'Zephir\\Types\\' . ucfirst($exprCompiledVariable->getType()) . 'Type';
             if (class_exists($builtInTypeClass)) {
                 $builtInType = new $builtInTypeClass();
                 $caller = $exprCompiledVariable;
             } else {
                 throw new CompilerException("Cannot use expression: " . $exprCompiledVariable->getType() . " as method caller", $expression['variable']);
             }
     }
     $codePrinter = $compilationContext->codePrinter;
     $type = $expression['call-type'];
     /**
      * In normal method calls and dynamic string method calls we just use the name given by the user
      */
     if ($type == self::CALL_NORMAL || $type == self::CALL_DYNAMIC_STRING) {
         $methodName = strtolower($expression['name']);
     } else {
         $variableMethod = $compilationContext->symbolTable->getVariableForRead($expression['name'], $compilationContext, $expression);
         if (is_object($builtInType)) {
             throw new CompilerException("Dynamic method invocation for type: " . $variableMethod->getType() . " is not supported", $expression);
         }
         if ($variableMethod->isNotVariableAndString()) {
             throw new CompilerException("Cannot use variable type: " . $variableMethod->getType() . " as dynamic method name", $expression);
         }
     }
     $symbolVariable = null;
     /**
      * Create temporary variable if needed
      */
     $mustInit = false;
     $isExpecting = $expr->isExpectingReturn();
     if ($isExpecting) {
         $symbolVariable = $expr->getExpectingVariable();
         if (is_object($symbolVariable)) {
             $readDetector = new ReadDetector($expression);
             if ($caller == $symbolVariable || $readDetector->detect($symbolVariable->getName(), $expression)) {
                 $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify('variable', $compilationContext, $expression);
             } else {
                 $mustInit = true;
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify('variable', $compilationContext, $expression);
         }
     }
     /**
      * Method calls only return zvals so we need to validate the target variable is also a zval
      */
     if (!$builtInType) {
         if ($isExpecting) {
             if (!$symbolVariable->isVariable()) {
                 throw new CompilerException("Returned values by functions can only be assigned to variant variables", $expression);
             }
             /**
              * At this point, we don't know the exact dynamic type returned by the method call
              */
             $symbolVariable->setDynamicTypes('undefined');
         }
     } else {
         return $builtInType->invokeMethod($methodName, $caller, $compilationContext, $this, $expression);
     }
     $check = true;
     if (isset($expression['check'])) {
         $check = $expression['check'];
     }
     /**
      * Try to check if the method exist in the callee, only when method call is self::CALL_NORMAL
      */
     if ($type == self::CALL_NORMAL) {
         if ($variableVariable->getRealName() == 'this') {
             $classDefinition = $compilationContext->classDefinition;
             if (!$classDefinition->hasMethod($methodName)) {
                 if ($check) {
                     $found = false;
                     $interfaces = $classDefinition->isAbstract() ? $classDefinition->getImplementedInterfaces() : null;
                     if (is_array($interfaces)) {
                         $compiler = $compilationContext->compiler;
                         foreach ($interfaces as $interface) {
                             $classInterfaceDefinition = $compiler->getClassDefinition($interface);
                             if ($classInterfaceDefinition->hasMethod($methodName)) {
                                 $found = true;
                                 $classMethod = $classInterfaceDefinition->getMethod($methodName);
                                 break;
                             }
                         }
                     }
                     if (!$found) {
                         $possibleMethod = $classDefinition->getPossibleMethodName($expression['name']);
                         if ($possibleMethod && $expression['name'] != $possibleMethod) {
                             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not implement method: '" . $expression['name'] . "'. Did you mean '" . $possibleMethod . "'?", $expression);
                         } else {
                             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not implement method: '" . $expression['name'] . "'", $expression);
                         }
                     }
                 }
             } else {
                 if ($check) {
                     $classMethod = $classDefinition->getMethod($methodName);
                 }
             }
             if ($check) {
                 /**
                  * Private methods must be called in their declaration scope
                  */
                 if ($classMethod->isPrivate()) {
                     if ($classMethod->getClassDefinition() != $classDefinition) {
                         throw new CompilerException("Cannot call private method '" . $expression['name'] . "' out of its scope", $expression);
                     }
                 }
                 /**
                  * Try to produce an exception if method is called with a wrong number of parameters
                  */
                 if (isset($expression['parameters'])) {
                     $callNumberParameters = count($expression['parameters']);
                 } else {
                     $callNumberParameters = 0;
                 }
                 $expectedNumberParameters = $classMethod->getNumberOfRequiredParameters();
                 if (!$expectedNumberParameters && $callNumberParameters > 0) {
                     $numberParameters = $classMethod->getNumberOfParameters();
                     if ($callNumberParameters > $numberParameters) {
                         throw new CompilerException("Method '" . $classDefinition->getCompleteName() . "::" . $expression['name'] . "' called with a wrong number of parameters, the method has: " . $expectedNumberParameters . ", passed: " . $callNumberParameters, $expression);
                     }
                 }
                 if ($callNumberParameters < $expectedNumberParameters) {
                     throw new CompilerException("Method '" . $classDefinition->getCompleteName() . "::" . $expression['name'] . "' called with a wrong number of parameters, the method has: " . $expectedNumberParameters . ", passed: " . $callNumberParameters, $expression);
                 }
                 $method = $classMethod;
             }
         } else {
             /**
              * Variables whose dynamic type is 'object' can be used
              * to determine method existence in compile time
              */
             if ($check && $variableVariable->hasAnyDynamicType('object')) {
                 $classTypes = $variableVariable->getClassTypes();
                 if (count($classTypes)) {
                     $numberImplemented = 0;
                     $compiler = $compilationContext->compiler;
                     foreach ($classTypes as $classType) {
                         if ($compiler->isClass($classType) || $compiler->isInterface($classType) || $compiler->isBundledClass($classType) || $compiler->isBundledInterface($classType)) {
                             if ($compiler->isClass($classType) || $compiler->isInterface($classType)) {
                                 $classDefinition = $compiler->getClassDefinition($classType);
                             } else {
                                 $classDefinition = $compiler->getInternalClassDefinition($classType);
                             }
                             if (!$classDefinition) {
                                 throw new CompilerException("Cannot locate class definition for class " . $classType, $expression);
                             }
                             if (!$classDefinition->hasMethod($methodName)) {
                                 if (!$classDefinition->isInterface()) {
                                     if (count($classTypes) == 1) {
                                         throw new CompilerException("Class '" . $classType . "' does not implement method: '" . $expression['name'] . "'", $expression);
                                     }
                                 }
                                 continue;
                             }
                             $method = $classDefinition->getMethod($methodName);
                             /**
                              * Private methods must be called in their declaration scope
                              */
                             if ($method->isPrivate()) {
                                 if ($method->getClassDefinition() != $classDefinition) {
                                     throw new CompilerException("Cannot call private method '" . $expression['name'] . "' out of its scope", $expression);
                                 }
                             }
                             /**
                              * Check visibility for protected methods
                              */
                             if ($method->isProtected() && $method->getClassDefinition() != $classDefinition && $method->getClassDefinition() != $classDefinition->getExtendsClass()) {
                                 throw new CompilerException("Cannot call protected method '" . $expression['name'] . "' out of its scope", $expression);
                             }
                             /**
                              * Try to produce an exception if a method is called with a wrong number of parameters
                              * We only check extension parameters if methods are extension methods
                              * Internal methods may have invalid Reflection information
                              */
                             if ($method instanceof ClassMethod && !$method->isBundled()) {
                                 if (isset($expression['parameters'])) {
                                     $callNumberParameters = count($expression['parameters']);
                                 } else {
                                     $callNumberParameters = 0;
                                 }
                                 $classMethod = $classDefinition->getMethod($methodName);
                                 $expectedNumberParameters = $classMethod->getNumberOfRequiredParameters();
                                 if (!$expectedNumberParameters && $callNumberParameters > 0) {
                                     $numberParameters = $classMethod->getNumberOfParameters();
                                     if ($callNumberParameters > $numberParameters) {
                                         $className = $classDefinition->getCompleteName();
                                         throw new CompilerException("Method '" . $className . "::" . $expression['name'] . "' called with a wrong number of parameters, the method has: " . $expectedNumberParameters . ", passed: " . $callNumberParameters, $expression);
                                     }
                                 }
                                 if ($callNumberParameters < $expectedNumberParameters) {
                                     throw new CompilerException("Method '" . $classDefinition->getCompleteName() . "::" . $expression['name'] . "' called with a wrong number of parameters, the method has: " . $expectedNumberParameters . ", passed: " . $callNumberParameters, $expression);
                                 }
                             }
                             /**
                              * The method is checked in the first class that implements the method
                              * We could probably have collisions here
                              */
                             $numberImplemented++;
                             break;
                         } else {
                             $numberImplemented++;
                             $compilationContext->logger->warning("Class \"" . $classType . "\" does not exist at compile time", "nonexistent-class", $expression);
                         }
                     }
                     if ($numberImplemented == 0) {
                         if (!$classDefinition->isInterface()) {
                             if (count($classTypes) > 1) {
                                 throw new CompilerException("None of classes: '" . join(' or ', $classTypes) . "' implement method: '" . $expression['name'] . "'", $expression);
                             } else {
                                 throw new CompilerException("Class '" . $classTypes[0] . "' does not implement method: '" . $expression['name'] . "'", $expression);
                             }
                         } else {
                             // @TODO, raise an exception here?
                         }
                     }
                 }
             }
         }
     }
     if (isset($method)) {
         $this->_reflection = $method;
     }
     /**
      * Transfer the return type-hint to the returned variable
      */
     if ($isExpecting) {
         if (isset($method)) {
             if ($method instanceof ClassMethod) {
                 if ($method->isVoid()) {
                     throw new CompilerException("Method '" . $classDefinition->getCompleteName() . "::" . $expression['name'] . "' is marked as 'void' and it does not return anything", $expression);
                 }
                 $returnClassTypes = $method->getReturnClassTypes();
                 if ($returnClassTypes !== null) {
                     $symbolVariable->setDynamicTypes('object');
                     foreach ($returnClassTypes as &$returnClassType) {
                         $returnClassType = $compilationContext->getFullName($returnClassType);
                     }
                     $symbolVariable->setClassTypes($returnClassTypes);
                 }
                 $returnTypes = $method->getReturnTypes();
                 if ($returnTypes !== null) {
                     foreach ($returnTypes as $dataType => $returnType) {
                         $symbolVariable->setDynamicTypes($dataType);
                     }
                 }
             }
         }
     }
     /**
      * Some parameters in internal methods receive parameters as references
      */
     if (isset($expression['parameters'])) {
         $references = array();
         if ($type == self::CALL_NORMAL || $type == self::CALL_DYNAMIC_STRING) {
             if (isset($method)) {
                 if ($method instanceof \ReflectionMethod) {
                     $position = 0;
                     foreach ($method->getParameters() as $parameter) {
                         if ($parameter->isPassedByReference()) {
                             $references[$position] = true;
                         }
                         $position++;
                     }
                 }
             }
         }
     }
     /**
      * Include fcall header
      */
     $compilationContext->headersManager->add('kernel/fcall');
     /**
      * Call methods must grown the stack
      */
     $compilationContext->symbolTable->mustGrownStack(true);
     /**
      * Mark references
      */
     if (isset($expression['parameters'])) {
         $params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression, isset($method) ? $method : null);
         if (count($references)) {
             foreach ($params as $position => $param) {
                 if (isset($references[$position])) {
                     $compilationContext->codePrinter->output('Z_SET_ISREF_P(' . $param . ');');
                 }
             }
         }
         // We check here if a correct parameter type is passed to the called method
         if ($type == self::CALL_NORMAL) {
             if (isset($method) && $method instanceof ClassMethod && isset($expression['parameters'])) {
                 $resolvedTypes = $this->getResolvedTypes();
                 $resolvedDynamicTypes = $this->getResolvedDynamicTypes();
                 //$typeInference = $method->getStaticTypeInferencePass();
                 foreach ($method->getParameters() as $n => $parameter) {
                     if (isset($parameter['data-type'])) {
                         if (!isset($resolvedTypes[$n])) {
                             continue;
                         }
                         /**
                          * If the passed parameter is different to the expected type we show a warning
                          */
                         if ($resolvedTypes[$n] != $parameter['data-type']) {
                             switch ($resolvedTypes[$n]) {
                                 case 'bool':
                                 case 'boolean':
                                     switch ($parameter['data-type']) {
                                         /* compatible types */
                                         case 'bool':
                                         case 'boolean':
                                         case 'variable':
                                             break;
                                         default:
                                             $compilationContext->logger->warning("Passing possible incorrect type for parameter: " . $classDefinition->getCompleteName() . '::' . $method->getName() . '(' . $parameter['name'] . '), passing: ' . $resolvedDynamicTypes[$n] . ', ' . "expecting: " . $parameter['data-type'], "possible-wrong-parameter", $expression);
                                             break;
                                     }
                                     break;
                                 case 'array':
                                     switch ($parameter['data-type']) {
                                         /* compatible types */
                                         case 'array':
                                         case 'variable':
                                             break;
                                         case 'callable':
                                             /**
                                              * Array can be a callable type, example: [$this, "method"]
                                              *
                                              * @todo we need to check this array if can...
                                              */
                                             break;
                                         default:
                                             $compilationContext->logger->warning("Passing possible incorrect type for parameter: " . $classDefinition->getCompleteName() . '::' . $method->getName() . '(' . $parameter['name'] . '), passing: ' . $resolvedDynamicTypes[$n] . ', ' . "expecting: " . $parameter['data-type'], "possible-wrong-parameter", $expression);
                                             break;
                                     }
                                     break;
                                 case 'callable':
                                     switch ($parameter['data-type']) {
                                         /* compatible types */
                                         case 'callable':
                                         case 'variable':
                                             break;
                                         default:
                                             $compilationContext->logger->warning("Passing possible incorrect type for parameter: " . $classDefinition->getCompleteName() . '::' . $method->getName() . '(' . $parameter['name'] . '), passing: ' . $resolvedDynamicTypes[$n] . ', ' . "expecting: " . $parameter['data-type'], "possible-wrong-parameter", $expression);
                                             break;
                                     }
                                     break;
                                 case 'string':
                                     switch ($parameter['data-type']) {
                                         /* compatible types */
                                         case 'string':
                                         case 'variable':
                                             break;
                                         default:
                                             $compilationContext->logger->warning("Passing possible incorrect type for parameter: " . $classDefinition->getCompleteName() . '::' . $method->getName() . '(' . $parameter['name'] . '), passing: ' . $resolvedDynamicTypes[$n] . ', ' . "expecting: " . $parameter['data-type'], "possible-wrong-parameter", $expression);
                                             break;
                                     }
                                     break;
                                     /**
                                      * Passing polymorphic variables to static typed parameters
                                      * could lead to potential unexpected type coercions
                                      */
                                 /**
                                  * Passing polymorphic variables to static typed parameters
                                  * could lead to potential unexpected type coercions
                                  */
                                 case 'variable':
                                     if ($resolvedDynamicTypes[$n] != $parameter['data-type']) {
                                         if ($resolvedDynamicTypes[$n] == 'undefined') {
                                             $compilationContext->logger->warning("Passing possible incorrect type to parameter: " . $classDefinition->getCompleteName() . '::' . $parameter[$n]['name'] . ', passing: ' . $resolvedDynamicTypes[$n] . ', ' . "expecting: " . $parameter[$n]['data-type'], "possible-wrong-parameter-undefined", $expression);
                                         }
                                         //echo '1: ', $resolvedTypes[$n], ' ', $resolvedDynamicTypes[$n], ' ', $parameter[0]['data-type'], ' ', PHP_EOL;
                                     }
                                     break;
                             }
                         }
                     }
                 }
             }
         }
     } else {
         $params = array();
     }
     // Add the last call status to the current symbol table
     $this->addCallStatusFlag($compilationContext);
     // Initialize non-temporary variables
     if ($mustInit) {
         $symbolVariable->setMustInitNull(true);
         $symbolVariable->trackVariant($compilationContext);
     }
     // Generate the code according to the call type
     if ($type == self::CALL_NORMAL || $type == self::CALL_DYNAMIC_STRING) {
         $realMethod = $this->getRealCalledMethod($compilationContext, $variableVariable, $methodName);
         $isInternal = false;
         if (is_object($realMethod[1])) {
             $isInternal = $realMethod[1]->isInternal();
             if ($isInternal && $realMethod[0] > 1) {
                 throw new CompilerException("Cannot resolve method: '" . $expression['name'] . "' in polymorphic variable", $expression);
             }
         }
         if (!$isInternal) {
             // Check if the method call can have an inline cache
             $methodCache = $compilationContext->cacheManager->getMethodCache();
             $cachePointer = $methodCache->get($compilationContext, $methodName, $variableVariable);
             if (!count($params)) {
                 if ($isExpecting) {
                     if ($symbolVariable->getName() == 'return_value') {
                         $codePrinter->output('ZEPHIR_RETURN_CALL_METHOD(' . $variableVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ');');
                     } else {
                         $codePrinter->output('ZEPHIR_CALL_METHOD(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ');');
                     }
                 } else {
                     $codePrinter->output('ZEPHIR_CALL_METHOD(NULL, ' . $variableVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ');');
                 }
             } else {
                 if ($isExpecting) {
                     if ($symbolVariable->getName() == 'return_value') {
                         $codePrinter->output('ZEPHIR_RETURN_CALL_METHOD(' . $variableVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');');
                     } else {
                         $codePrinter->output('ZEPHIR_CALL_METHOD(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');');
                     }
                 } else {
                     $codePrinter->output('ZEPHIR_CALL_METHOD(NULL, ' . $variableVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');');
                 }
             }
         } else {
             if (!count($params)) {
                 if ($isExpecting) {
                     if ($symbolVariable->getName() == 'return_value') {
                         $codePrinter->output('ZEPHIR_RETURN_CALL_INTERNAL_METHOD_P0(' . $variableVariable->getName() . ', ' . $method->getInternalName() . ');');
                     } else {
                         $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_P0(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $method->getInternalName() . ');');
                     }
                 } else {
                     $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_NORETURN_P0(' . $variableVariable->getName() . ', ' . $method->getInternalName() . ');');
                 }
             } else {
                 if ($isExpecting) {
                     if ($symbolVariable->getName() == 'return_value') {
                         $codePrinter->output('ZEPHIR_RETURN_CALL_INTERNAL_METHOD_P' . count($params) . '(' . $variableVariable->getName() . ', ' . $method->getInternalName() . ', ' . join(', ', $params) . ');');
                     } else {
                         $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_P' . count($params) . '(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $method->getInternalName() . ', ' . join(', ', $params) . ');');
                     }
                 } else {
                     $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_NORETURN_P' . count($params) . '(' . $variableVariable->getName() . ', ' . $method->getInternalName() . ', ' . join(', ', $params) . ');');
                 }
             }
         }
     } else {
         if ($type == self::CALL_DYNAMIC) {
             switch ($variableMethod->getType()) {
                 case 'string':
                 case 'variable':
                     break;
                 default:
                     throw new Exception('Cannot use variable type: ' . $variableMethod->getType() . ' as method caller');
             }
             $cachePointer = 'NULL, 0';
             if (!count($params)) {
                 if ($isExpecting) {
                     if ($symbolVariable->getName() == 'return_value') {
                         $codePrinter->output('ZEPHIR_RETURN_CALL_METHOD_ZVAL(' . $variableVariable->getName() . ', ' . $variableMethod->getName() . ', ' . $cachePointer . ');');
                     } else {
                         $codePrinter->output('ZEPHIR_CALL_METHOD_ZVAL(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $variableMethod->getName() . ',  ' . $cachePointer . ');');
                     }
                 } else {
                     $codePrinter->output('ZEPHIR_CALL_METHOD_ZVAL(NULL, ' . $variableVariable->getName() . ', ' . $variableMethod->getName() . ', ' . $cachePointer . ');');
                 }
             } else {
                 if ($isExpecting) {
                     if ($symbolVariable->getName() == 'return_value') {
                         $codePrinter->output('ZEPHIR_RETURN_CALL_METHOD_ZVAL(' . $variableVariable->getName() . ', ' . $variableMethod->getName() . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
                     } else {
                         $codePrinter->output('ZEPHIR_CALL_METHOD_ZVAL(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $variableMethod->getName() . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
                     }
                 } else {
                     $codePrinter->output('ZEPHIR_CALL_METHOD_ZVAL(NULL, ' . $variableVariable->getName() . ', ' . $variableMethod->getName() . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
                 }
             }
         }
     }
     // Temporary variables must be copied if they have more than one reference
     foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
         $codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
     }
     // We can mark temporary variables generated as idle
     foreach ($this->getTemporalVariables() as $tempVariable) {
         $tempVariable->setIdle(true);
     }
     // Release parameters marked as references
     if (isset($expression['parameters'])) {
         if (count($references)) {
             foreach ($params as $position => $param) {
                 if (isset($references[$position])) {
                     $compilationContext->codePrinter->output('Z_UNSET_ISREF_P(' . $param . ');');
                 }
             }
         }
     }
     $this->addCallStatusOrJump($compilationContext);
     if ($isExpecting) {
         return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
     }
     return new CompiledExpression('null', null, $expression);
 }
Example #23
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $statement = $this->_statement;
     $codePrinter = $compilationContext->codePrinter;
     if (isset($statement['expr'])) {
         $currentMethod = $compilationContext->currentMethod;
         if ($currentMethod->isConstructor()) {
             throw new CompilerException("Constructors cannot return values", $statement['expr']);
         }
         if ($currentMethod->isVoid()) {
             throw new CompilerException("Method is marked as 'void' and it must not return any value", $statement['expr']);
         }
         /**
          * Use return member for properties on this
          */
         if ($statement['expr']['type'] == 'property-access') {
             if ($statement['expr']['left']['type'] == 'variable') {
                 if ($statement['expr']['left']['value'] == 'this') {
                     if ($statement['expr']['right']['type'] == 'variable') {
                         /**
                          * If the property is accessed on 'this', we check if the property does exist
                          */
                         $property = $statement['expr']['right']['value'];
                         $classDefinition = $compilationContext->classDefinition;
                         if (!$classDefinition->hasProperty($property)) {
                             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement['expr']['right']);
                         }
                         $compilationContext->headersManager->add('kernel/object');
                         $codePrinter->output('RETURN_MM_MEMBER(this_ptr, "' . $property . '");');
                         return;
                     }
                 }
             }
         }
         /**
          * Fetches return_value and tries to return the value directly there
          */
         $variable = $compilationContext->symbolTable->getVariable('return_value');
         $expr = new Expression($statement['expr']);
         $expr->setExpectReturn(true, $variable);
         $expr->setReadOnly(true);
         $resolvedExpr = $expr->compile($compilationContext);
         /**
          * Here we check if the variable returns a compatible type according to its type hints
          */
         if ($currentMethod->hasReturnTypes()) {
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     if (!$currentMethod->areReturnTypesNullCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'char':
                 case 'uchar':
                     if (!$currentMethod->areReturnTypesIntCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'bool':
                     if (!$currentMethod->areReturnTypesBoolCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'double':
                     if (!$currentMethod->areReturnTypesDoubleCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'string':
                     if (!$currentMethod->areReturnTypesStringCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'variable':
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['expr']);
                     switch ($symbolVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'char':
                         case 'uchar':
                             if (!$currentMethod->areReturnTypesIntCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'double':
                             if (!$currentMethod->areReturnTypesDoubleCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'string':
                             if (!$currentMethod->areReturnTypesStringCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'bool':
                             if (!$currentMethod->areReturnTypesBoolCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'variable':
                             break;
                     }
                     break;
             }
         }
         switch ($resolvedExpr->getType()) {
             case 'null':
                 $codePrinter->output('RETURN_MM_NULL();');
                 break;
             case 'int':
             case 'uint':
             case 'long':
             case 'char':
             case 'uchar':
                 $codePrinter->output('RETURN_MM_LONG(' . $resolvedExpr->getCode() . ');');
                 break;
             case 'bool':
                 $codePrinter->output('RETURN_MM_BOOL(' . $resolvedExpr->getBooleanCode() . ');');
                 break;
             case 'double':
                 $codePrinter->output('RETURN_MM_DOUBLE(' . $resolvedExpr->getCode() . ');');
                 break;
             case 'string':
             case 'istring':
                 $codePrinter->output('RETURN_MM_STRING("' . Utils::addSlashes($resolvedExpr->getCode()) . '", 1);');
                 break;
             case 'array':
                 if ($resolvedExpr->getCode() != 'return_value') {
                     $codePrinter->output('RETURN_CTOR(' . $resolvedExpr->getCode() . ');');
                 } else {
                     $codePrinter->output('RETURN_MM();');
                 }
                 break;
             case 'variable':
                 if (!isset($symbolVariable)) {
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['expr']);
                 }
                 switch ($symbolVariable->getType()) {
                     case 'int':
                     case 'uint':
                     case 'long':
                     case 'char':
                     case 'uchar':
                         $codePrinter->output('RETURN_MM_LONG(' . $symbolVariable->getName() . ');');
                         break;
                     case 'double':
                         $codePrinter->output('RETURN_MM_DOUBLE(' . $symbolVariable->getName() . ');');
                         break;
                     case 'string':
                     case 'array':
                         $codePrinter->output('RETURN_CTOR(' . $resolvedExpr->getCode() . ');');
                         break;
                     case 'bool':
                         $codePrinter->output('RETURN_MM_BOOL(' . $symbolVariable->getName() . ');');
                         break;
                     case 'variable':
                         if ($symbolVariable->getName() == 'this_ptr') {
                             $codePrinter->output('RETURN_THIS();');
                         } else {
                             if ($symbolVariable->getName() != 'return_value') {
                                 if (!$symbolVariable->isExternal()) {
                                     if ($symbolVariable->isLocalOnly()) {
                                         $codePrinter->output('RETURN_LCTOR(' . $symbolVariable->getName() . ');');
                                     } else {
                                         if (!$symbolVariable->isMemoryTracked()) {
                                             $codePrinter->output('RETURN_CTOR(' . $symbolVariable->getName() . ');');
                                         } else {
                                             $codePrinter->output('RETURN_CCTOR(' . $symbolVariable->getName() . ');');
                                         }
                                     }
                                 } else {
                                     $codePrinter->output('RETVAL_ZVAL(' . $symbolVariable->getName() . ', 1, 0);');
                                     $codePrinter->output('RETURN_MM();');
                                 }
                             } else {
                                 $codePrinter->output('RETURN_MM();');
                             }
                         }
                         if ($symbolVariable->isTemporal()) {
                             $symbolVariable->setIdle(true);
                         }
                         break;
                     default:
                         throw new CompilerException("Cannot return variable '" . $symbolVariable->getType() . "'", $statement['expr']);
                 }
                 break;
             default:
                 throw new CompilerException("Cannot return '" . $resolvedExpr->getType() . "'", $statement['expr']);
         }
         return;
     }
     /**
      * Return without an expression
      */
     $codePrinter->output('RETURN_MM_NULL();');
 }
Example #24
0
 /**
  * Resolves paramameters
  *
  * @param array $parameters
  * @param CompilationContext $compilationContext
  * @param array $expression
  * @param boolean $readOnly
  * @return array|null|CompiledExpression[]
  */
 public function getResolvedParamsAsExpr($parameters, CompilationContext $compilationContext, $expression, $readOnly = false)
 {
     if (!$this->_resolvedParams) {
         $hasParametersByName = false;
         foreach ($parameters as $parameter) {
             if (isset($parameter['name'])) {
                 $hasParametersByName = true;
                 break;
             }
         }
         /**
          * All parameters must be passed by name
          */
         if ($hasParametersByName) {
             foreach ($parameters as $parameter) {
                 if (!isset($parameter['name'])) {
                     throw new CompilerException('All parameters must use named', $parameter);
                 }
             }
         }
         if ($hasParametersByName) {
             if ($this->_reflection) {
                 $positionalParameters = array();
                 foreach ($this->_reflection->getParameters() as $position => $reflectionParameter) {
                     if (is_object($reflectionParameter)) {
                         $positionalParameters[$reflectionParameter->getName()] = $position;
                     } else {
                         $positionalParameters[$reflectionParameter['name']] = $position;
                     }
                 }
                 $orderedParameters = array();
                 foreach ($parameters as $parameter) {
                     if (isset($positionalParameters[$parameter['name']])) {
                         $orderedParameters[$positionalParameters[$parameter['name']]] = $parameter;
                     } else {
                         throw new CompilerException('Named parameter "' . $parameter['name'] . '" is not a valid parameter name, available: ' . join(', ', array_keys($positionalParameters)), $parameter['parameter']);
                     }
                 }
                 $parameters_count = count($parameters);
                 for ($i = 0; $i < $parameters_count; $i++) {
                     if (!isset($orderedParameters[$i])) {
                         $orderedParameters[$i] = array('parameter' => array('type' => 'null'));
                     }
                 }
                 $parameters = $orderedParameters;
             }
         }
         $params = array();
         foreach ($parameters as $parameter) {
             if (is_array($parameter['parameter'])) {
                 $paramExpr = new Expression($parameter['parameter']);
                 switch ($parameter['parameter']['type']) {
                     case 'property-access':
                     case 'array-access':
                     case 'static-property-access':
                         $paramExpr->setReadOnly(true);
                         break;
                     default:
                         $paramExpr->setReadOnly($readOnly);
                         break;
                 }
                 $params[] = $paramExpr->compile($compilationContext);
                 continue;
             }
             if ($parameter['parameter'] instanceof CompiledExpression) {
                 $params[] = $parameter['parameter'];
                 continue;
             }
             throw new CompilerException("Invalid expression ", $expression);
         }
         $this->_resolvedParams = $params;
     }
     return $this->_resolvedParams;
 }
 /**
  * Compile the expression
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $conditions = $this->optimizeTypeOf($expression, $compilationContext);
     if ($conditions !== false) {
         return $conditions;
     }
     if (!isset($expression['left'])) {
         throw new CompilerException("Missing left part of the expression", $expression);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Missing right part of the expression", $expression);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly(true);
     $left = $leftExpr->compile($compilationContext);
     $rightExpr = new Expression($expression['right']);
     $rightExpr->setReadOnly(true);
     $right = $rightExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'null':
             switch ($right->getType()) {
                 case 'null':
                     return new CompiledExpression('bool', '(0 ' . $this->_operator . ' 0)', $expression);
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     return new CompiledExpression('bool', '(0 ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                 case 'char':
                 case 'uchar':
                     return new CompiledExpression('bool', '(\'\\0\' ' . $this->_operator . ' \'' . $right->getCode() . '\')', $expression);
                 case 'double':
                     return new CompiledExpression('bool', '(0 ' . $this->_operator . ' (int) ' . $right->getCode() . ')', $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                     switch ($variableRight->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', '0 ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             $condition = $compilationContext->backend->getTypeofCondition($variableRight, $this->_operator, 'null', $compilationContext);
                             return new CompiledExpression('bool', $condition, $expression);
                         default:
                             throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type: " . $right->getType(), $expression);
             }
             break;
         case 'int':
         case 'uint':
         case 'long':
         case 'double':
         case 'ulong':
         case 'char':
         case 'uchar':
             switch ($right->getType()) {
                 case 'null':
                     return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator, $expression);
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode(), $expression);
                 case 'char':
                 case 'uchar':
                     return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' \'' . $right->getCode() . '\'', $expression);
                 case 'double':
                     return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' (int) ' . $right->getCode(), $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                     switch ($variableRight->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             $variableCode = $compilationContext->backend->getVariableCode($variableRight);
                             return new CompiledExpression('bool', $this->_zvalLongNegOperator . '(' . $variableCode . ', ' . $left->getCode() . ')', $expression);
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot compare " . $left->getType() . " with " . $right->getType(), $expression);
             }
             break;
         case 'bool':
             switch ($right->getType()) {
                 case 'null':
                     return new CompiledExpression('bool', $left->getBooleanCode() . ' ' . $this->_operator . ' 0', $expression);
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     return new CompiledExpression('bool', $left->getBooleanCode() . ' ' . $this->_operator . ' ' . $right->getCode(), $expression);
                 case 'char':
                 case 'uchar':
                     return new CompiledExpression('bool', $left->getBooleanCode() . ' ' . $this->_operator . ' \'' . $right->getCode() . '\'', $expression);
                 case 'double':
                     return new CompiledExpression('bool', $left->getBooleanCode() . ' ' . $this->_operator . ' (int) ' . $right->getCode(), $expression);
                 case 'bool':
                     return new CompiledExpression('bool', $left->getBooleanCode() . ' ' . $this->_operator . ' ' . $right->getBooleanCode(), $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                     switch ($variableRight->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $left->getBooleanCode() . ' ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             $boolOperator = $left->getBooleanCode() == '1' ? $this->_zvalBoolTrueOperator : $this->_zvalBoolFalseOperator;
                             $variableRight = $compilationContext->backend->getVariableCode($variableRight);
                             return new CompiledExpression('bool', $boolOperator . '(' . $variableRight . ')', $expression);
                         default:
                             throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot compare " . $left->getType() . " with " . $right->getType(), $expression);
             }
             break;
         case 'string':
             $variableLeft = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
             $variableLeftCode = $compilationContext->backend->getVariableCode($variableLeft);
             $compilationContext->backend->assignString($variableLeft, $left->getCode(), $compilationContext, true, false);
             switch ($right->getType()) {
                 case 'string':
                 case 'null':
                     $rightStr = $right->getType() == 'null' ? '' : $right->getCode();
                     $compilationContext->headersManager->add('kernel/operators');
                     return new CompiledExpression('bool', $this->_zvalStringOperator . '(' . $variableLeftCode . ', "' . $rightStr . '")', $expression['left']);
                     break;
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                     switch ($variableRight->getType()) {
                         case 'string':
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             $variableRight = $compilationContext->backend->getVariableCode($variableRight);
                             return new CompiledExpression('bool', $this->_zvalOperator . '(' . $variableLeftCode . ', ' . $variableRight . ')', $expression);
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type: " . $right->getType(), $expression['left']);
             }
             break;
         case 'variable':
             $variable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
             $variableCode = $compilationContext->backend->getVariableCode($variable);
             switch ($variable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     switch ($right->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode(), $expression);
                         case 'char':
                         case 'uchar':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' \'' . $right->getCode() . '\'', $expression);
                         case 'bool':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $right->getBooleanCode(), $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                 case 'char':
                                 case 'uchar':
                                 case 'double':
                                     return new CompiledExpression('bool', $variable->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);
                                     $variableCode = $compilationContext->backend->getVariableCode($variable);
                                     return new CompiledExpression('bool', $this->_zvalLongNegOperator . '(' . $variableRightCode . ', ' . $variableCode . ')', $expression);
                                     break;
                                 default:
                                     throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable: " . $variable->getType() . " with: " . $right->getType(), $expression);
                     }
                     break;
                 case 'double':
                     switch ($right->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode(), $expression);
                         case 'bool':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $right->getBooleanCode(), $expression);
                         case 'char':
                         case 'uchar':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' \'' . $right->getCode() . '\'', $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                 case 'double':
                                     return new CompiledExpression('bool', $variable->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);
                                     $variableCode = $compilationContext->backend->getVariableCode($variable);
                                     return new CompiledExpression('bool', $this->_zvalDoubleNegOperator . '(' . $variableRightCode . ', ' . $variableCode . ')', $expression);
                                 default:
                                     throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable: " . $variable->getType() . " with: " . $right->getType(), $expression);
                     }
                     break;
                 case 'bool':
                     switch ($right->getType()) {
                         case 'int':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode(), $expression['left']);
                         case 'bool':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' ' . $right->getBooleanCode(), $expression['left']);
                         case 'null':
                             return new CompiledExpression('bool', $left->getCode() . ' ' . $this->_operator . ' 0', $expression['left']);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                 case 'bool':
                                 case 'double':
                                     return new CompiledExpression('bool', $variable->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $boolOperator = $left->getBooleanCode() == '1' ? $this->_zvalBoolTrueOperator : $this->_zvalBoolFalseOperator;
                                     $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);
                                     return new CompiledExpression('bool', $boolOperator . '(' . $variableRightCode . ')', $expression);
                                 default:
                                     throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable: " . $variable->getType() . " with: " . $right->getType(), $expression);
                     }
                     break;
                 case 'array':
                     switch ($right->getType()) {
                         case 'null':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $this->_zvalStringOperator . '(' . $variableCode . ', "")', $expression['left']);
                             break;
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                             switch ($variableRight->getType()) {
                                 case 'string':
                                 case 'variable':
                                 case 'array':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $variableRight = $compilationContext->backend->getVariableCode($variableRight);
                                     return new CompiledExpression('bool', $this->_zvalOperator . '(' . $variableCode . ', ' . $variableRight . ')', $expression);
                                     break;
                                 default:
                                     throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                             }
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $right->getType(), $expression['left']);
                     }
                     break;
                 case 'string':
                     switch ($right->getType()) {
                         case 'null':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $this->_zvalStringOperator . '(' . $variableCode . ', "")', $expression['left']);
                             break;
                         case 'string':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $this->_zvalStringOperator . '(' . $variableCode . ', "' . $right->getCode() . '")', $expression['left']);
                             break;
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                             switch ($variableRight->getType()) {
                                 case 'string':
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $variableRight = $compilationContext->backend->getVariableCode($variableRight);
                                     return new CompiledExpression('bool', $this->_zvalOperator . '(' . $variableCode . ', ' . $variableRight . ')', $expression);
                                     break;
                                 default:
                                     throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                             }
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $right->getType(), $expression['left']);
                     }
                     break;
                 case 'variable':
                     switch ($right->getType()) {
                         case 'null':
                             $compilationContext->headersManager->add('kernel/operators');
                             $condition = $compilationContext->backend->getTypeofCondition($variable, $this->_operator, 'null', $compilationContext);
                             return new CompiledExpression('bool', $condition, $expression['left']);
                             break;
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $this->_zvalLongOperator . '(' . $variableCode . ', ' . $right->getCode() . ')', $expression['left']);
                             break;
                         case 'char':
                         case 'uchar':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $this->_zvalLongOperator . '(' . $variableCode . ', \'' . $right->getCode() . '\')', $expression['left']);
                             break;
                         case 'bool':
                             $compilationContext->headersManager->add('kernel/operators');
                             $zvalBoolOperator = $right->getCode() == 'true' ? $this->_zvalBoolTrueOperator : $this->_zvalBoolFalseOperator;
                             return new CompiledExpression('bool', $zvalBoolOperator . '(' . $variableCode . ')', $expression['left']);
                             break;
                         case 'string':
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', $this->_zvalStringOperator . '(' . $variableCode . ', "' . $right->getCode() . '")', $expression['left']);
                             break;
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                 case 'uint':
                                 case 'long':
                                 case 'ulong':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     return new CompiledExpression('bool', $this->_zvalLongOperator . '(' . $variableCode . ', ' . $variableRight->getName() . ')', $expression);
                                     break;
                                 case 'double':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     return new CompiledExpression('bool', $this->_zvalDoubleOperator . '(' . $variableCode . ', ' . $variableRight->getName() . ')', $expression);
                                     break;
                                 case 'string':
                                 case 'variable':
                                 case 'array':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $variableRight = $compilationContext->backend->getVariableCode($variableRight);
                                     return new CompiledExpression('bool', $this->_zvalOperator . '(' . $variableCode . ', ' . $variableRight . ')', $expression);
                                     break;
                                 default:
                                     throw new CompilerException("Unknown type: " . $variableRight->getType(), $expression['right']);
                             }
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $right->getType(), $expression['left']);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type: " . $variable->getType(), $expression);
             }
             break;
         default:
             throw new CompilerException("Unknown type: " . $left->getType(), $expression);
     }
 }
Example #26
0
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Missing left part of the expression", $expression);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Missing right part of the expression", $expression);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     $rightExpr = new Expression($expression['right']);
     $rightExpr->setReadOnly($this->_readOnly);
     $right = $rightExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'int':
             switch ($right->getType()) {
                 case 'int':
                     return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                 case 'double':
                     return new CompiledExpression('double', '((double) ' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                 case 'bool':
                     return new CompiledExpression('int', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getBooleanCode() . ')', $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression);
                     switch ($variableRight->getType()) {
                         case 'int':
                             return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'double':
                             return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             if ($variableRight->isLocalOnly()) {
                                 return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' zephir_is_true(&' . $variableRight->getName() . '))', $expression);
                             } else {
                                 return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' zephir_is_true(' . $variableRight->getName() . '))', $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable('int') with variable('" . $variableRight->getType() . "')", $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot compare 'int' with '" . $right->getType() . "'", $expression);
             }
             break;
         case 'bool':
             switch ($right->getType()) {
                 case 'int':
                 case 'double':
                     return new CompiledExpression('bool', '(' . $left->getBooleanCode() . ' ' . $this->_bitOperator . ' ((' . $right->getCode() . ') ? 1 : 0))', $expression);
                 case 'bool':
                     return new CompiledExpression('bool', '(' . $left->getBooleanCode() . ' ' . $this->_bitOperator . ' ' . $right->getBooleanCode() . ')', $expression);
                 case 'variable':
                     $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression);
                     switch ($variableRight->getType()) {
                         case 'int':
                             return new CompiledExpression('bool', '(' . $left->getBooleanCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('bool', '(' . $left->getBooleanCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'double':
                             return new CompiledExpression('bool', '(' . $left->getBooleanCode() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                         case 'variable':
                             if ($variableRight->isLocalOnly()) {
                                 $compilationContext->headersManager->add('kernel/operators');
                                 return new CompiledExpression('bool', '(' . $left->getBooleanCode() . ' ' . $this->_operator . ' zephir_is_true(&' . $variableRight->getName() . '))', $expression);
                             } else {
                                 return new CompiledExpression('bool', '(' . $left->getBooleanCode() . ' ' . $this->_operator . ' zephir_is_true(' . $variableRight->getName() . '))', $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot add variable('int') with variable('" . $variableRight->getType() . "')", $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot compare 'bool' with '" . $right->getType() . "'", $expression);
             }
             break;
         case 'double':
             switch ($right->getType()) {
                 case 'int':
                     return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                 case 'double':
                     return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                 case 'bool':
                     return new CompiledExpression('bool', '(' . $left->getCode() . ' ' . $this->_operator . ' ' . $right->getBooleanCode() . ')', $expression);
                 default:
                     throw new CompilerException("Cannot compare 'double' with '" . $right->getType() . "'", $expression);
             }
             break;
         case 'string':
             switch ($right->getType()) {
                 default:
                     throw new CompilerException("Operation is not supported between strings", $expression);
             }
             break;
         case 'variable':
             $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->resolve(null, $compilationContext), $compilationContext, $expression);
             switch ($variableLeft->getType()) {
                 case 'int':
                     switch ($right->getType()) {
                         case 'int':
                             return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'bool':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'double':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableRight->isLocalOnly()) {
                                         return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' zephir_is_true(&' . $variableRight->getName() . '))', $expression);
                                     } else {
                                         return new CompiledExpression('int', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' zephir_is_true(' . $variableRight->getName() . '))', $expression);
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Cannot compare variable('int') with variable('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable('int') with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 case 'bool':
                     switch ($right->getType()) {
                         case 'int':
                             return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $right->getCode() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_bitOperator . ' ' . $right->getBooleanCode() . ')', $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'bool':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_bitOperator . ' ' . $variableRight->getName() . ')', $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableRight->isLocalOnly()) {
                                         return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' zephir_is_true(&' . $variableRight->getName() . '))', $expression);
                                     } else {
                                         return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' ' . $this->_operator . ' zephir_is_true(' . $variableRight->getName() . '))', $expression);
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Cannot compare variable('int') with variable('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable('int') with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 case 'double':
                     switch ($right->getType()) {
                         case 'int':
                             return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_operator . ' ' . $right->getCode(), $expression);
                         case 'double':
                             return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_operator . ' ' . $right->getCode(), $expression);
                         case 'bool':
                             return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_bitOperator . '' . $right->getBooleanCode(), $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                     return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_operator . '  (double) ' . $variableRight->getName(), $expression);
                                 case 'double':
                                     return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_operator . '  ' . $variableRight->getName(), $expression);
                                 case 'bool':
                                     return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_bitOperator . '' . $variableRight->getName(), $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableRight->isLocalOnly()) {
                                         return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_operator . ' zephir_is_true(&' . $variableRight->getName() . ')', $expression);
                                     } else {
                                         return new CompiledExpression('bool', $variableLeft->getName() . ' ' . $this->_operator . ' zephir_is_true(' . $variableRight->getName() . ')', $expression);
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Cannot compare variable('double') with variable('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable('int') with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 case 'string':
                     switch ($right->getType()) {
                         case 'int':
                             return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . $this->_operator . ' ' . $right->getCode(), $expression);
                         case 'double':
                             return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . $this->_operator . ' ' . $right->getCode(), $expression);
                         case 'bool':
                             return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . $this->_bitOperator . '' . $right->getBooleanCode(), $expression);
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                             switch ($variableRight->getType()) {
                                 case 'int':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                 case 'double':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . $this->_operator . '  ' . $variableRight->getName(), $expression);
                                 case 'string':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . $this->_operator . ' (' . $variableRight->getName() . ' && Z_STRLEN_P(' . $variableRight->getName() . '))', $expression);
                                 case 'bool':
                                     return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . $this->_bitOperator . ' ' . $variableRight->getName(), $expression);
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableRight->isLocalOnly()) {
                                         return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . ' ' . $this->_operator . ' zephir_is_true(&' . $variableRight->getName() . ')', $expression);
                                     } else {
                                         return new CompiledExpression('bool', '(' . $variableLeft->getName() . ' && Z_STRLEN_P(' . $variableLeft->getName() . ')) ' . ' ' . $this->_operator . ' zephir_is_true(' . $variableRight->getName() . ')', $expression);
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Cannot compare variable('double') with variable('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare variable('int') with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 case 'variable':
                     switch ($right->getType()) {
                         /* a && 1 */
                         case 'int':
                         case 'double':
                             $compilationContext->headersManager->add('kernel/operators');
                             $op = $this->_operator;
                             if ($variableLeft->isLocalOnly()) {
                                 $op1 = '&' . $variableLeft->getName();
                             } else {
                                 $op1 = $variableLeft->getName();
                             }
                             $op2 = $right->getCode();
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', 'zephir_is_true(' . $op1 . ') ' . $op . ' ' . $op2, $expression);
                             /* a && 1 */
                         /* a && 1 */
                         case 'bool':
                             $compilationContext->headersManager->add('kernel/operators');
                             $op = $this->_operator;
                             if ($variableLeft->isLocalOnly()) {
                                 $op1 = '&' . $variableLeft->getName();
                             } else {
                                 $op1 = $variableLeft->getName();
                             }
                             $op2 = $right->getCode();
                             $compilationContext->headersManager->add('kernel/operators');
                             return new CompiledExpression('bool', 'zephir_is_true(' . $op1 . ') ' . $op . ' ' . $op2, $expression);
                             /* a(var) && a(x) */
                         /* a(var) && a(x) */
                         case 'variable':
                             $variableRight = $compilationContext->symbolTable->getVariableForRead($right->resolve(null, $compilationContext), $compilationContext, $expression);
                             switch ($variableRight->getType()) {
                                 /* a(var) && a(int) */
                                 case 'int':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableLeft->isLocalOnly()) {
                                         return new CompiledExpression('bool', 'zephir_is_true(&' . $variableLeft->getName() . ') ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                     } else {
                                         return new CompiledExpression('bool', 'zephir_is_true(' . $variableLeft->getName() . ') ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                     }
                                     break;
                                     /* a(var) && a(bool) */
                                 /* a(var) && a(bool) */
                                 case 'bool':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableLeft->isLocalOnly()) {
                                         return new CompiledExpression('bool', 'zephir_is_true(&' . $variableLeft->getName() . ') ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                     } else {
                                         return new CompiledExpression('bool', 'zephir_is_true(' . $variableLeft->getName() . ') ' . $this->_operator . ' ' . $variableRight->getName(), $expression);
                                     }
                                     break;
                                     /* a(var) && a(var) */
                                 /* a(var) && a(var) */
                                 case 'variable':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     if ($variableLeft->isLocalOnly()) {
                                         $op1 = '&' . $variableLeft->getName();
                                     } else {
                                         $op1 = $variableLeft->getName();
                                     }
                                     if ($variableRight->isLocalOnly()) {
                                         $op2 = '&' . $variableRight->getName();
                                     } else {
                                         $op2 = $variableRight->getName();
                                     }
                                     $expected = $this->getExpected($compilationContext, $expression);
                                     if ($expected->isLocalOnly()) {
                                         $compilationContext->codePrinter->output('add_function(&' . $expected->getName() . ', ' . $op1 . ', ' . $op2 . ' TSRMLS_CC);');
                                     } else {
                                         $compilationContext->codePrinter->output('add_function(' . $expected->getName() . ', ' . $op1 . ', ' . $op2 . ' TSRMLS_CC);');
                                     }
                                     return new CompiledExpression('variable', $expected->getName(), $expression);
                                 default:
                                     throw new CompilerException("Cannot compare 'variable' with variable ('" . $variableRight->getType() . "')", $expression);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot compare 'variable' with '" . $right->getType() . "'", $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown '" . $variableLeft->getType() . "'", $expression);
             }
             break;
         default:
             throw new CompilerException("Unsupported type: " . $left->getType(), $expression);
     }
 }
Example #27
0
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new \Exception("Missing left part of the expression");
     }
     if (!isset($expression['right'])) {
         throw new \Exception("Missing right part of the expression");
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     /**
      * This variable is used to check if the compound and expression is evaluated as true or false
      */
     $flagVariable = $compilationContext->symbolTable->getTempVariableForWrite('bool', $compilationContext);
     switch ($left->getType()) {
         case 'int':
         case 'bool':
         case 'char':
         case 'double':
         case 'uint':
         case 'uchar':
             $assignExprLeft = array('type' => $left->getType(), 'value' => $left->getCode());
             break;
         case 'variable':
             $assignExprLeft = array('type' => 'variable', 'value' => $left->getCode());
             break;
         case 'null':
             $assignExprLeft = array('type' => 'null', 'value' => null);
             break;
     }
     if (!isset($assignExprLeft)) {
         throw new CompilerException($left->getType(), $expression['left']);
     }
     /**
      * Create an implicit 'let' operation to update the evaluated left operator
      */
     $statement = new LetStatement(array('type' => 'let', 'assignments' => array(array('assign-type' => 'variable', 'variable' => $flagVariable->getName(), 'operator' => 'assign', 'expr' => $assignExprLeft, 'file' => $expression['left']['file'], 'line' => $expression['left']['line'], 'char' => $expression['left']['char']))));
     $statement->compile($compilationContext);
     $compilationContext->codePrinter->output('if (' . $flagVariable->getName() . ') {');
     $compilationContext->codePrinter->increaseLevel();
     $rightExpr = new Expression($expression['right']);
     $rightExpr->setReadOnly($this->_readOnly);
     $right = $rightExpr->compile($compilationContext);
     switch ($right->getType()) {
         case 'int':
         case 'bool':
         case 'char':
         case 'double':
         case 'uint':
         case 'uchar':
             $assignExprRight = array('type' => $right->getType(), 'value' => $right->getCode());
             break;
         case 'variable':
             $assignExprRight = array('type' => 'variable', 'value' => $right->getCode());
             break;
         case 'null':
             $assignExprRight = array('type' => 'null', 'value' => null);
             break;
     }
     if (!isset($assignExprRight)) {
         throw new CompilerException($right->getType(), $expression['right']);
     }
     /**
      * Create an implicit 'let' operation to update the evaluated right operator
      */
     $statement = new LetStatement(array('type' => 'let', 'assignments' => array(array('assign-type' => 'variable', 'variable' => $flagVariable->getName(), 'operator' => 'assign', 'expr' => $assignExprRight, 'file' => $expression['right']['file'], 'line' => $expression['right']['line'], 'char' => $expression['right']['char']))));
     $statement->compile($compilationContext);
     $compilationContext->codePrinter->decreaseLevel();
     $compilationContext->codePrinter->output('}');
     return new CompiledExpression('bool', $flagVariable->getName(), $expression);
 }
Example #28
0
 /**
  * Performs concat compilation
  *
  * @param Expression $expression
  * @param CompilationContext $compilationContext
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Missing left part of the expression", $expression);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Missing right part of the expression", $expression);
     }
     $compilationContext->headersManager->add('kernel/concat');
     /**
      * Try to optimize the concatenation
      */
     $optimized = $this->_getOptimizedConcat($expression, $compilationContext, $isFullString);
     if (is_array($optimized)) {
         if (!$isFullString) {
             $expected = $this->getExpectedComplexLiteral($compilationContext, $expression);
         } else {
             $expected = $this->getExpectedComplexLiteral($compilationContext, $expression, 'string');
         }
         $expected->setDynamicTypes('string');
         $compilationContext->codePrinter->output('ZEPHIR_CONCAT_' . strtoupper($optimized[0]) . '(' . $expected->getName() . ', ' . $optimized[1] . ');');
         return new CompiledExpression('variable', $expected->getName(), $expression);
     }
     /**
      * If the expression cannot be optimized, fall back to the standard compilation
      */
     $leftExpr = new Expression($expression['left']);
     switch ($expression['left']['type']) {
         case 'array-access':
         case 'property-access':
             $leftExpr->setReadOnly(true);
             break;
         default:
             $leftExpr->setReadOnly($this->_readOnly);
             break;
     }
     $left = $leftExpr->compile($compilationContext);
     if ($left->getType() == 'variable') {
         $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['right']);
     }
     $rightExpr = new Expression($expression['right']);
     switch ($expression['left']['type']) {
         case 'array-access':
         case 'property-access':
             $rightExpr->setReadOnly(true);
             break;
         default:
             $rightExpr->setReadOnly($this->_readOnly);
             break;
     }
     $right = $rightExpr->compile($compilationContext);
     if ($right->getType() == 'variable') {
         $variableLeft = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
     }
     $expected = $this->getExpectedComplexLiteral($compilationContext, $expression);
     if ($left->getType() == 'string' && $right->getType() == 'variable') {
         $compilationContext->codePrinter->output('ZEPHIR_CONCAT_SV(' . $expected->getName() . ', "' . $left->getCode() . '", ' . $right->getCode() . ');');
     }
     if ($left->getType() == 'variable' && $right->getType() == 'string') {
         $compilationContext->codePrinter->output('ZEPHIR_CONCAT_VS(' . $expected->getName() . ', ' . $left->getCode() . ', "' . $right->getCode() . '");');
     }
     if ($left->getType() == 'variable' && $right->getType() == 'variable') {
         $compilationContext->codePrinter->output('zephir_concat_function(' . $expected->getName() . ', ' . $left->getCode() . ', ' . $right->getCode() . ' TSRMLS_CC);');
     }
     $expected->setDynamicTypes('string');
     return new CompiledExpression('variable', $expected->getName(), $expression);
 }
Example #29
0
 /**
  * Compiles foo[x] = {expr}
  *
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     /**
      * Resolve the left part of the expression
      */
     $expr = new Expression($expression['left']);
     $expr->setReadOnly(true);
     $exprVariable = $expr->compile($compilationContext);
     /**
      * Only dynamic variables can be used as arrays
      */
     switch ($exprVariable->getType()) {
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprVariable->getCode(), $compilationContext, $expression);
             switch ($variableVariable->getType()) {
                 case 'variable':
                 case 'array':
                 case 'string':
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variableVariable->getType() . " cannot be used as array", $expression['left']);
             }
             break;
         default:
             throw new CompilerException("Cannot use expression: " . $exprVariable->getType() . " as an array", $expression['left']);
     }
     /**
      * Resolve the dimension according to variable's type
      */
     switch ($variableVariable->getType()) {
         case 'variable':
             return $this->_accessDimensionArray($expression, $variableVariable, $compilationContext);
         case 'array':
             return $this->_accessDimensionArray($expression, $variableVariable, $compilationContext);
         case 'string':
             return $this->_accessStringOffset($expression, $variableVariable, $compilationContext);
     }
 }
Example #30
0
 /**
  * Compiles foo[y][x] = {expr} (multiple offset)
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 protected function _assignArrayIndexMultiple($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $codePrinter = $compilationContext->codePrinter;
     $offsetExprs = array();
     foreach ($statement['index-expr'] as $indexExpr) {
         $expression = new Expression($indexExpr);
         $expression->setReadOnly(true);
         $exprIndex = $expression->compile($compilationContext);
         switch ($exprIndex->getType()) {
             case 'int':
             case 'uint':
             case 'long':
             case 'ulong':
             case 'string':
             case 'variable':
                 break;
             default:
                 throw new CompilerException("Index: " . $exprIndex->getType() . " cannot be used as array index in assignment without cast", $indexExpr);
         }
         $offsetExprs[] = $exprIndex;
     }
     $compilationContext->headersManager->add('kernel/array');
     /**
      * Create a temporal zval (if needed)
      */
     $symbolVariable = $this->_getResolvedArrayItem($resolvedExpr, $compilationContext);
     $keys = '';
     $numberParams = 0;
     $offsetItems = array();
     foreach ($offsetExprs as $offsetExpr) {
         switch ($offsetExpr->getType()) {
             case 'int':
             case 'uint':
             case 'long':
             case 'ulong':
                 $keys .= 'l';
                 $offsetItems[] = $offsetExpr->getCode();
                 $numberParams++;
                 break;
             case 'string':
                 $keys .= 's';
                 $offsetItems[] = 'SL("' . $offsetExpr->getCode() . '")';
                 $numberParams += 2;
                 break;
             case 'variable':
                 $variableIndex = $compilationContext->symbolTable->getVariableForRead($offsetExpr->getCode(), $compilationContext, $statement);
                 switch ($variableIndex->getType()) {
                     case 'int':
                     case 'uint':
                     case 'long':
                     case 'ulong':
                         $keys .= 'l';
                         $offsetItems[] = $variableIndex->getName();
                         $numberParams++;
                         break;
                     case 'string':
                     case 'variable':
                         $keys .= 'z';
                         $offsetItems[] = $variableIndex->getName();
                         $numberParams++;
                         break;
                     default:
                         throw new CompilerException("Variable: " . $variableIndex->getType() . " cannot be used as array index", $statement);
                 }
                 break;
             default:
                 throw new CompilerException("Value: " . $offsetExpr->getType() . " cannot be used as array index", $statement);
         }
     }
     $codePrinter->output('zephir_array_update_multi(&' . $variable . ', &' . $symbolVariable->getName() . ' TSRMLS_CC, SL("' . $keys . '"), ' . $numberParams . ', ' . join(', ', $offsetItems) . ');');
     if ($symbolVariable->isTemporal()) {
         $symbolVariable->setIdle(true);
     }
 }