This represents a variable in a symbol table
Beispiel #1
0
 /**
  * Compiles {var} = {expr}
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext,
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $codePrinter = $compilationContext->codePrinter;
     $codePrinter->output('if (zephir_set_symbol(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ' TSRMLS_CC) == FAILURE){');
     $codePrinter->output('  return;');
     $codePrinter->output('}');
 }
Beispiel #2
0
 /**
  * Examine internal class information and returns the method called
  *
  * @param CompilationContext $compilationContext
  * @param Variable $caller
  * @param string $methodName
  * @return array
  */
 private function getRealCalledMethod(CompilationContext $compilationContext, Variable $caller, $methodName)
 {
     $compiler = $compilationContext->compiler;
     $numberPoly = 0;
     $method = null;
     if ($caller->getRealName() == 'this') {
         $classDefinition = $compilationContext->classDefinition;
         if ($classDefinition->hasMethod($methodName)) {
             $numberPoly++;
             $method = $classDefinition->getMethod($methodName);
         }
     } else {
         $classTypes = $caller->getClassTypes();
         foreach ($classTypes as $classType) {
             if ($compiler->isClass($classType) || $compiler->isInterface($classType) || $compiler->isBundledClass($classType) || $compiler->isBundledInterface($classType)) {
                 if ($compiler->isInterface($classType)) {
                     continue;
                 }
                 if ($compiler->isClass($classType)) {
                     $classDefinition = $compiler->getClassDefinition($classType);
                 } else {
                     $classDefinition = $compiler->getInternalClassDefinition($classType);
                 }
                 if (!$classDefinition) {
                     continue;
                 }
                 if ($classDefinition->hasMethod($methodName) && !$classDefinition->isInterface()) {
                     $numberPoly++;
                     $method = $classDefinition->getMethod($methodName);
                 }
             }
         }
     }
     return array($numberPoly, $method);
 }
Beispiel #3
0
 /**
  * Compiles obj->x++
  *
  * @param string $variable
  * @param string $property
  * @param ZephirVariable $symbolVariable
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 public function assign($variable, $property, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     /**
      * Arrays must be stored in the HEAP
      */
     if ($symbolVariable->isLocalOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement);
     }
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     /**
      * Only dynamic variables can be used as arrays
      */
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement);
     }
     if ($symbolVariable->hasAnyDynamicType('unknown')) {
         throw new CompilerException("Cannot use non-initialized variable as an object", $statement);
     }
     /**
      * Trying to use a non-object dynamic variable as object
      */
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to increment non-object dynamic variable', 'non-object-update', $statement);
     }
     $compilationContext->headersManager->add('kernel/object');
     $compilationContext->codePrinter->output('RETURN_ON_FAILURE(zephir_property_incr(' . $symbolVariable->getName() . ', SL("' . $property . '") TSRMLS_CC));');
 }
Beispiel #4
0
 /**
  * Compiles obj->x++
  *
  * @param string $variable
  * @param string $property
  * @param ZephirVariable $symbolVariable
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 public function assign($variable, $property, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     /**
      * Arrays must be stored in the HEAP
      */
     if ($symbolVariable->isLocalOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement);
     }
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     /**
      * Only dynamic variables can be used as arrays
      */
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement);
     }
     if ($symbolVariable->hasAnyDynamicType('unknown')) {
         throw new CompilerException("Cannot use non-initialized variable as an object", $statement);
     }
     /**
      * Trying to use a non-object dynamic variable as object
      */
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to increment non-object dynamic variable', 'non-object-update', $statement);
     }
     /**
      * Check if the variable to update is defined
      */
     if ($symbolVariable->getRealName() == 'this') {
         $classDefinition = $compilationContext->classDefinition;
         if (!$classDefinition->hasProperty($property)) {
             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement);
         }
         $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 ($symbolVariable->hasAnyDynamicType('object')) {
             $classType = current($symbolVariable->getClassTypes());
             $compiler = $compilationContext->compiler;
             if ($compiler->isClass($classType)) {
                 $classDefinition = $compiler->getClassDefinition($classType);
                 if (!$classDefinition) {
                     throw new CompilerException("Cannot locate class definition for class: " . $classType, $statement);
                 }
                 if (!$classDefinition->hasProperty($property)) {
                     throw new CompilerException("Class '" . $classType . "' does not have a property called: '" . $property . "'", $statement);
                 }
             }
         }
     }
     $compilationContext->headersManager->add('kernel/object');
     $compilationContext->codePrinter->output('RETURN_ON_FAILURE(zephir_property_incr(' . $symbolVariable->getName() . ', SL("' . $property . '") TSRMLS_CC));');
 }
Beispiel #5
0
 /**
  * Compiles {var} = {expr}
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext,
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $codePrinter = $compilationContext->codePrinter;
     $variable = $compilationContext->symbolTable->getTempVariable('variable', $compilationContext, $statement);
     $variable->setMustInitNull(true);
     $letStatement = new LetStatement(array('type' => 'let', 'assignments' => array(array('assign-type' => 'variable', 'variable' => $variable->getName(), 'operator' => 'assign', 'expr' => array('type' => $resolvedExpr->getType(), 'value' => $resolvedExpr->getCode(), 'file' => $statement['file'], 'line' => $statement['line'], 'char' => $statement['char']), 'file' => $statement['file'], 'line' => $statement['line'], 'char' => $statement['char']))));
     $letStatement->compile($compilationContext);
     $codePrinter->output('if (zephir_set_symbol(' . $symbolVariable->getName() . ', ' . $variable->getName() . ' TSRMLS_CC) == FAILURE){');
     $codePrinter->output("\t" . 'return;');
     $codePrinter->output('}');
 }
 /**
  * Compiles foo[y][] = {expr}
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     /**
      * Arrays must be stored in the HEAP
      */
     if ($symbolVariable->isLocalOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement);
     }
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->isReadOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement);
     }
     if ($symbolVariable->isLocalOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement);
     }
     /**
      * Only dynamic variables and arrays can be used as arrays
      */
     if ($symbolVariable->isNotVariableAndArray()) {
         throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement);
     }
     if ($symbolVariable->hasAnyDynamicType('unknown')) {
         throw new CompilerException("Cannot use non-initialized variable as an object", $statement);
     }
     /**
      * Trying to use a non-object dynamic variable as object
      */
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to update index on a non-array dynamic variable', 'non-array-update', $statement);
     }
     $this->_assignArrayIndexMultiple($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement);
 }
Beispiel #7
0
 /**
  * Compiles x--
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->isReadOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     switch ($symbolVariable->getType()) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
         case 'char':
         case 'uchar':
             $codePrinter->output($variable . '--;');
             break;
         case 'variable':
             /**
              * Variable is probably not initialized here
              */
             if ($symbolVariable->hasAnyDynamicType('unknown')) {
                 throw new CompilerException("Attempt to increment uninitialized variable", $statement);
             }
             /**
              * Decrement non-numeric variables could be expensive
              */
             if (!$symbolVariable->hasAnyDynamicType(array('undefined', 'int', 'long', 'double', 'uint'))) {
                 $compilationContext->logger->warning('Possible attempt to decrement non-numeric dynamic variable', 'non-valid-decrement', $statement);
             }
             $compilationContext->headersManager->add('kernel/operators');
             if ($symbolVariable->isLocalOnly()) {
                 $codePrinter->output('zephir_decrement(&' . $variable . ');');
             } else {
                 $symbolVariable->separate($compilationContext);
                 $codePrinter->output('zephir_decrement(' . $variable . ');');
             }
             break;
         default:
             throw new CompilerException("Cannot decrement variable: " . $symbolVariable->getType(), $statement);
     }
 }
Beispiel #8
0
 /**
  * Compiles x++
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompilationContext $compilationContext
  * @param array $statement
  *
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->isReadOnly()) {
         /**
          * @TODO implement increment of objects members
          */
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement);
     }
     $codePrinter =& $compilationContext->codePrinter;
     switch ($symbolVariable->getType()) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
         case 'char':
         case 'uchar':
             $codePrinter->output($variable . '++;');
             break;
         case 'variable':
             /**
              * Update non-numeric dynamic variables could be expensive
              */
             if (!$symbolVariable->hasAnyDynamicType(array('undefined', 'long', 'double'))) {
                 $compilationContext->logger->warning('Possible attempt to increment non-numeric dynamic variable', 'non-valid-increment', $statement);
             }
             $compilationContext->headersManager->add('kernel/operators');
             if (!$symbolVariable->isLocalOnly()) {
                 $symbolVariable->separate($compilationContext);
             }
             $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
             $codePrinter->output('zephir_increment(' . $symbol . ');');
             break;
         default:
             throw new CompilerException("Cannot increment: " . $symbolVariable->getType(), $statement);
     }
 }
 /**
  * Compiles x->y[] = foo
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     $property = $statement['property'];
     $compilationContext->headersManager->add('kernel/object');
     /**
      * Check if the variable to update is defined
      */
     if ($symbolVariable->getRealName() == 'this') {
         $classDefinition = $compilationContext->classDefinition;
         if (!$classDefinition->hasProperty($property)) {
             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement);
         }
         $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 ($symbolVariable->hasAnyDynamicType('object')) {
             $classType = current($symbolVariable->getClassTypes());
             $compiler = $compilationContext->compiler;
             if ($compiler->isClass($classType)) {
                 $classDefinition = $compiler->getClassDefinition($classType);
                 if (!$classDefinition) {
                     throw new CompilerException("Cannot locate class definition for class: " . $classType, $statement);
                 }
                 if (!$classDefinition->hasProperty($property)) {
                     throw new CompilerException("Class '" . $classType . "' does not have a property called: '" . $property . "'", $statement);
                 }
             }
         }
     }
     switch ($resolvedExpr->getType()) {
         case 'null':
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);');
             break;
         case 'bool':
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
             break;
         case 'char':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getCode() . '\');');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'int':
         case 'long':
         case 'uint':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'double':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'string':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'array':
             $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $variableExpr->getName() . ' TSRMLS_CC);');
             break;
         case 'variable':
             $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableExpr->getType()) {
                 case 'int':
                 case 'long':
                 case 'uint':
                 case 'char':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');');
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');');
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');');
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'variable':
                 case 'string':
                 case 'array':
                 case 'resource':
                 case 'object':
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $variableExpr->getName() . ' TSRMLS_CC);');
                     if ($variableExpr->isTemporal()) {
                         $variableExpr->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Variable: " . $variableExpr->getType() . " cannot be appended to array property", $statement);
             }
             break;
         default:
             throw new CompilerException("Expression: " . $resolvedExpr->getType() . " cannot be appended to array property", $statement);
     }
 }
Beispiel #10
0
 public function ifVariableValueUndefined(Variable $var, CompilationContext $context, $onlyBody = false, $useCodePrinter = true)
 {
     $body = '!' . $var->getName();
     $output = 'if (' . $body . ') {';
     if ($useCodePrinter) {
         $context->codePrinter->output($output);
     }
     return $onlyBody ? $body : $output;
 }
Beispiel #11
0
 /**
  * @param array $expression
  * @param Variable $variableVariable
  * @param CompilationContext $compilationContext
  */
 protected function _accessDimensionArray($expression, Variable $variableVariable, CompilationContext $compilationContext)
 {
     $arrayAccess = $expression;
     if ($variableVariable->getType() == 'variable') {
         if ($variableVariable->hasAnyDynamicType('unknown')) {
             throw new CompilerException("Cannot use non-initialized variable as an array", $arrayAccess['left']);
         }
         /**
          * Trying to use a non-object dynamic variable as object
          */
         if ($variableVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) {
             $compilationContext->logger->warning('Possible attempt to access array-index on a non-array dynamic variable', 'non-array-access', $arrayAccess['left']);
         }
     }
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Resolves the symbol that expects the value
      */
     $readOnly = false;
     $symbolVariable = $this->_expectingVariable;
     if ($this->_readOnly) {
         if ($this->_expecting && $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->getTempNonTrackedUninitializedVariable('variable', $compilationContext, $expression);
                 }
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedUninitializedVariable('variable', $compilationContext, $expression);
         }
     } else {
         if ($this->_expecting && $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);
         }
     }
     /**
      * Variable that receives property accesses must be polimorphic
      */
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Cannot use variable: " . $symbolVariable->getType() . " to assign array index", $expression);
     }
     /**
      * At this point, we don't know the type fetched from the index
      */
     $symbolVariable->setDynamicTypes('undefined');
     if ($this->_readOnly || $readOnly) {
         if ($this->_noisy) {
             $flags = 'PH_NOISY | PH_READONLY';
         } else {
             $flags = 'PH_READONLY';
         }
     } else {
         if ($this->_noisy) {
             $flags = 'PH_NOISY';
         } else {
             $flags = '0';
         }
     }
     /**
      * Right part of expression is the index
      */
     $expr = new Expression($arrayAccess['right']);
     $exprIndex = $expr->compile($compilationContext);
     switch ($exprIndex->getType()) {
         case 'int':
         case 'uint':
         case 'long':
             $compilationContext->headersManager->add('kernel/array');
             $codePrinter->output('zephir_array_fetch_long(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $exprIndex->getCode() . ', ' . $flags . ', "' . Compiler::getShortUserPath($arrayAccess['file']) . '", ' . $arrayAccess['line'] . ' TSRMLS_CC);');
             break;
         case 'string':
             $compilationContext->headersManager->add('kernel/array');
             $codePrinter->output('zephir_array_fetch_string(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', SL("' . $exprIndex->getCode() . '"), ' . $flags . ', "' . Compiler::getShortUserPath($arrayAccess['file']) . '", ' . $arrayAccess['line'] . ' TSRMLS_CC);');
             break;
         case 'variable':
             $variableIndex = $compilationContext->symbolTable->getVariableForRead($exprIndex->getCode(), $compilationContext, $expression);
             switch ($variableIndex->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                     $compilationContext->headersManager->add('kernel/array');
                     $codePrinter->output('zephir_array_fetch_long(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $variableIndex->getName() . ', ' . $flags . ', "' . Compiler::getShortUserPath($arrayAccess['file']) . '", ' . $arrayAccess['line'] . ' TSRMLS_CC);');
                     break;
                 case 'string':
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/array');
                     if ($variableIndex->isLocalOnly()) {
                         $codePrinter->output('zephir_array_fetch(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', &' . $variableIndex->getName() . ', ' . $flags . ', "' . Compiler::getShortUserPath($arrayAccess['file']) . '", ' . $arrayAccess['line'] . ' TSRMLS_CC);');
                     } else {
                         $codePrinter->output('zephir_array_fetch(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $variableIndex->getName() . ', ' . $flags . ', "' . Compiler::getShortUserPath($arrayAccess['file']) . '", ' . $arrayAccess['line'] . ' TSRMLS_CC);');
                     }
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variableIndex->getType() . " cannot be used as array index without cast", $arrayAccess['right']);
             }
             break;
         default:
             throw new CompilerException("Cannot use expression: " . $exprIndex->getType() . " as array index without cast", $arrayAccess['right']);
     }
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Beispiel #12
0
 /**
  * Compiles foo = {expr}
  * Changes the value of a mutable variable
  *
  * @param $variable
  * @param Variable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param ReadDetector $readDetector
  * @param CompilationContext $compilationContext
  * @param $statement
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, ReadDetector $readDetector, CompilationContext $compilationContext, $statement)
 {
     if ($symbolVariable->isReadOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Only initialize variables if it's direct assignment
      */
     if ($statement['operator'] == 'assign') {
         $symbolVariable->setIsInitialized(true, $compilationContext, $statement);
     } else {
         if (!$symbolVariable->isInitialized()) {
             throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
         }
     }
     /**
      * Set the assigned value to the variable as a CompiledExpression
      * We could use this expression for further analysis
      */
     $symbolVariable->setPossibleValue($resolvedExpr, $compilationContext);
     $type = $symbolVariable->getType();
     switch ($type) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'char':
         case 'uchar':
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = 0;');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += 0;');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= 0;');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= 0;');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                     }
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'div-assign':
                             $codePrinter->output($variable . ' /= ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'mod-assign':
                             $codePrinter->output($variable . ' %= ' . $resolvedExpr->getCode() . ';');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                     }
                     break;
                 case 'char':
                 case 'uchar':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = \'' . $resolvedExpr->getCode() . '\';');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += \'' . $resolvedExpr->getCode() . '\';');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= \'' . $resolvedExpr->getCode() . '\';');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= \'' . $resolvedExpr->getCode() . '\';');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                     }
                     break;
                 case 'double':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = (long) (' . $resolvedExpr->getCode() . ');');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += (long) (' . $resolvedExpr->getCode() . ');');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= (long) (' . $resolvedExpr->getCode() . ');');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= (long) (' . $resolvedExpr->getCode() . ');');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                     }
                     break;
                 case 'bool':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                     }
                     break;
                 case 'variable':
                     $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     switch ($itemVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'bool':
                         case 'char':
                         case 'uchar':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'add-assign':
                                     $codePrinter->output($variable . ' += ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'sub-assign':
                                     $codePrinter->output($variable . ' -= ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'mul-assign':
                                     $codePrinter->output($variable . ' *= ' . $itemVariable->getName() . ';');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                             }
                             break;
                         case 'double':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = (long) ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'add-assign':
                                     $codePrinter->output($variable . ' += (long) ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'sub-assign':
                                     $codePrinter->output($variable . ' -= (long) ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'mul-assign':
                                     $codePrinter->output($variable . ' *= (long) ' . $itemVariable->getName() . ';');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                             }
                             break;
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');');
                                     break;
                                 case 'add-assign':
                                     $codePrinter->output($variable . ' += zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');');
                                     break;
                                 case 'sub-assign':
                                     $codePrinter->output($variable . ' -= zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');');
                                     break;
                                 case 'mul-assign':
                                     $codePrinter->output($variable . ' *= zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement);
                             }
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $itemVariable->getType(), $statement);
                     }
                     break;
                 default:
                     throw new CompilerException("Value type '" . $resolvedExpr->getType() . "' cannot be assigned to variable: int", $statement);
             }
             break;
         case 'double':
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = 0.0;');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += 0.0;');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= 0.0;');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= 0.0;');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement);
                     }
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = (double) (' . $resolvedExpr->getCode() . ');');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += (double) (' . $resolvedExpr->getCode() . ');');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= (double) (' . $resolvedExpr->getCode() . ');');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= (double) (' . $resolvedExpr->getCode() . ');');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement);
                     }
                     break;
                 case 'double':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= ' . $resolvedExpr->getCode() . ';');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= ' . $resolvedExpr->getCode() . ';');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement);
                     }
                     break;
                 case 'bool':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         case 'add-assign':
                             $codePrinter->output($variable . ' += ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         case 'sub-assign':
                             $codePrinter->output($variable . ' -= ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         case 'mul-assign':
                             $codePrinter->output($variable . ' *= ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement);
                     }
                     break;
                 case 'variable':
                     $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     switch ($itemVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'bool':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = (double) ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'add-assign':
                                     $codePrinter->output($variable . ' += (double) ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'sub-assign':
                                     $codePrinter->output($variable . ' -= (double) ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'mul-assign':
                                     $codePrinter->output($variable . ' *= (double) ' . $itemVariable->getName() . ';');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement);
                             }
                             break;
                         case 'double':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'add-assign':
                                     $codePrinter->output($variable . ' += ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'sub-assign':
                                     $codePrinter->output($variable . ' -= ' . $itemVariable->getName() . ';');
                                     break;
                                 case 'mul-assign':
                                     $codePrinter->output($variable . ' *= ' . $itemVariable->getName() . ';');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement);
                             }
                             break;
                         case 'variable':
                             $compilationContext->headersManager->add('kernel/operators');
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = zephir_get_numberval(' . $itemVariable->getName() . ');');
                                     break;
                                 case 'add-assign':
                                     $codePrinter->output($variable . ' += zephir_get_numberval(' . $itemVariable->getName() . ');');
                                     break;
                                 case 'sub-assign':
                                     $codePrinter->output($variable . ' -= zephir_get_numberval(' . $itemVariable->getName() . ');');
                                     break;
                                 case 'mul-assign':
                                     $codePrinter->output($variable . ' *= zephir_get_numberval(' . $itemVariable->getName() . ');');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement);
                             }
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $itemVariable->getType(), $statement);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
             }
             break;
         case 'array':
             switch ($resolvedExpr->getType()) {
                 case 'variable':
                 case 'array':
                     switch ($statement['operator']) {
                         case 'assign':
                             if ($variable != $resolvedExpr->getCode()) {
                                 $symbolVariable->setMustInitNull(true);
                                 $compilationContext->symbolTable->mustGrownStack(true);
                                 /* Inherit the dynamic type data from the assigned value */
                                 $symbolVariable->setDynamicTypes('array');
                                 $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $resolvedExpr->getCode() . ');');
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 default:
                     throw new CompilerException("You cannot {$statement['operator']} {$resolvedExpr->getType()} for array type", $resolvedExpr->getOriginal());
             }
             break;
         case 'string':
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->initVariant($compilationContext);
                             $codePrinter->output('ZVAL_EMPTY_STRING(' . $variable . ');');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                     }
                     break;
                 case 'string':
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->initVariant($compilationContext);
                             if ($resolvedExpr->getCode()) {
                                 $codePrinter->output('ZVAL_STRING(' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);');
                             } else {
                                 $codePrinter->output('ZVAL_EMPTY_STRING(' . $variable . ');');
                             }
                             break;
                         case 'concat-assign':
                             $codePrinter->output('zephir_concat_self_str(&' . $variable . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                     }
                     break;
                 case 'char':
                 case 'uchar':
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->initVariant($compilationContext);
                             if ($resolvedExpr->getCode()) {
                                 $codePrinter->output('ZVAL_STRING(' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);');
                             } else {
                                 $codePrinter->output('ZVAL_EMPTY_STRING(' . $variable . ');');
                             }
                             break;
                         case 'concat-assign':
                             $compilationContext->headersManager->add('kernel/operators');
                             $codePrinter->output('zephir_concat_self_str(&' . $variable . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                     }
                     break;
                 case 'variable':
                     $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     switch ($itemVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $symbolVariable->initVariant($compilationContext);
                                     $compilationContext->headersManager->add('kernel/string');
                                     $codePrinter->output('Z_STRLEN_P(' . $variable . ') = zephir_spprintf(&Z_STRVAL_P(' . $variable . '), 0, "%ld", ' . $itemVariable->getName() . ');');
                                     $codePrinter->output('Z_TYPE_P(' . $variable . ') = IS_STRING;');
                                     break;
                                 case 'concat-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('zephir_concat_self_long(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                             }
                             break;
                         case 'char':
                         case 'uchar':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $symbolVariable->initVariant($compilationContext);
                                     $compilationContext->headersManager->add('kernel/string');
                                     $codePrinter->output('Z_STRLEN_P(' . $variable . ') = zephir_spprintf(&Z_STRVAL_P(' . $variable . '), 0, "%c", ' . $itemVariable->getName() . ');');
                                     $codePrinter->output('Z_TYPE_P(' . $variable . ') = IS_STRING;');
                                     break;
                                 case 'concat-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('zephir_concat_self_char(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                             }
                             break;
                         case 'string':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $symbolVariable->setMustInitNull(true);
                                     $compilationContext->symbolTable->mustGrownStack(true);
                                     if ($variable != $itemVariable->getName()) {
                                         $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $itemVariable->getName() . ');');
                                     }
                                     break;
                                 case 'concat-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                             }
                             break;
                         case 'variable':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $symbolVariable->setMustInitNull(true);
                                     $compilationContext->symbolTable->mustGrownStack(true);
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('zephir_get_strval(' . $variable . ', ' . $itemVariable->getName() . ');');
                                     break;
                                 case 'concat-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $itemVariable->getType(), $statement);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
             }
             break;
         case 'bool':
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = 0;');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: null", $statement);
                     }
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'double':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = (' . $resolvedExpr->getCode() . ') ? 1 : 0;');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $statement);
                     }
                     break;
                 case 'char':
                 case 'uchar':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = (\'' . $resolvedExpr->getCode() . '\') ? 1 : 0;');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $statement);
                     }
                     break;
                 case 'bool':
                     switch ($statement['operator']) {
                         case 'assign':
                             $codePrinter->output($variable . ' = ' . $resolvedExpr->getBooleanCode() . ';');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $statement);
                     }
                     break;
                 case 'variable':
                     $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     switch ($itemVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'double':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = (' . $itemVariable->getName() . ') ? 1 : 0;');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         case 'bool':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = ' . $itemVariable->getName() . ';');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         case 'variable':
                         case 'string':
                         case 'array':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $codePrinter->output($variable . ' = zephir_is_true(' . $itemVariable->getName() . ');');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         default:
                             throw new CompilerException("Cannot assign variable: " . $itemVariable->getType(), $statement);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type: " . $resolvedExpr->getType(), $statement);
             }
             break;
         case 'variable':
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->initVariant($compilationContext);
                             $symbolVariable->setDynamicTypes('null');
                             if ($symbolVariable->isLocalOnly()) {
                                 $codePrinter->output('ZVAL_NULL(&' . $variable . ');');
                             } else {
                                 $codePrinter->output('ZVAL_NULL(' . $variable . ');');
                             }
                             break;
                     }
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     if ($symbolVariable->isLocalOnly()) {
                         $symbol = '&' . $variable;
                     } else {
                         $symbol = $variable;
                     }
                     switch ($statement['operator']) {
                         case 'mul-assign':
                         case 'sub-assign':
                         case 'add-assign':
                             switch ($statement['operator']) {
                                 case 'mul-assign':
                                     $functionName = 'ZEPHIR_MUL_ASSIGN';
                                     break;
                                 case 'sub-assign':
                                     $functionName = 'ZEPHIR_SUB_ASSIGN';
                                     break;
                                 case 'add-assign':
                                     $functionName = 'ZEPHIR_ADD_ASSIGN';
                                     break;
                             }
                             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                             $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');');
                             $compilationContext->symbolTable->mustGrownStack(true);
                             $compilationContext->headersManager->add('kernel/operators');
                             $codePrinter->output($functionName . '(' . $symbol . ', ' . $tempVariable->getName() . ');');
                             break;
                         case 'assign':
                             $symbolVariable->setDynamicTypes('long');
                             if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) {
                                 $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('int', $compilationContext);
                                 $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';');
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_LONG(' . $symbol . ', ' . $tempVariable->getName() . ');');
                             } else {
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_LONG(' . $symbol . ', ' . $resolvedExpr->getCode() . ');');
                             }
                             break;
                         case 'div-assign':
                             $symbolVariable->setDynamicTypes('double');
                             if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) {
                                 $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('double', $compilationContext);
                                 $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';');
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $tempVariable->getName() . ');');
                             } else {
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $resolvedExpr->getCode() . ');');
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 case 'char':
                 case 'uchar':
                     if ($symbolVariable->isLocalOnly()) {
                         $symbol = '&' . $variable;
                     } else {
                         $symbol = $variable;
                     }
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->setDynamicTypes('long');
                             if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) {
                                 $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('char', $compilationContext);
                                 $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';');
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_LONG(' . $symbol . ', ' . $tempVariable->getName() . ');');
                             } else {
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_LONG(' . $symbol . ', \'' . $resolvedExpr->getCode() . '\');');
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 case 'double':
                     if ($symbolVariable->isLocalOnly()) {
                         $symbol = '&' . $variable;
                     } else {
                         $symbol = $variable;
                     }
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->setDynamicTypes('double');
                             if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) {
                                 $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('double', $compilationContext);
                                 $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';');
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $tempVariable->getName() . ');');
                             } else {
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $resolvedExpr->getCode() . ');');
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 case 'bool':
                     if ($symbolVariable->isLocalOnly()) {
                         $symbol = '&' . $variable;
                     } else {
                         $symbol = $variable;
                     }
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->setDynamicTypes('bool');
                             if ($resolvedExpr->getCode() == 'true') {
                                 $symbolVariable->initVariant($compilationContext);
                                 $codePrinter->output('ZVAL_BOOL(' . $symbol . ', 1);');
                             } else {
                                 if ($resolvedExpr->getCode() == 'false') {
                                     $symbolVariable->initVariant($compilationContext);
                                     $codePrinter->output('ZVAL_BOOL(' . $symbol . ', 0);');
                                 } else {
                                     if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) {
                                         $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('double', $compilationContext);
                                         $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getBooleanCode() . ';');
                                         $symbolVariable->initVariant($compilationContext);
                                         $codePrinter->output('ZVAL_BOOL(' . $symbol . ', ' . $tempVariable->getName() . ');');
                                     } else {
                                         $symbolVariable->initVariant($compilationContext);
                                         $codePrinter->output('ZVAL_BOOL(' . $symbol . ', ' . $resolvedExpr->getBooleanCode() . ');');
                                     }
                                 }
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 case 'string':
                     switch ($statement['operator']) {
                         case 'assign':
                             $symbolVariable->initVariant($compilationContext);
                             $symbolVariable->setDynamicTypes('string');
                             if ($symbolVariable->isLocalOnly()) {
                                 $codePrinter->output('ZVAL_STRING(&' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);');
                             } else {
                                 $codePrinter->output('ZVAL_STRING(' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);');
                             }
                             break;
                         case 'concat-assign':
                             $compilationContext->headersManager->add('kernel/operators');
                             $codePrinter->output('zephir_concat_self_str(&' . $variable . ', SL("' . $resolvedExpr->getCode() . '") TSRMLS_CC);');
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 case 'array':
                     switch ($statement['operator']) {
                         case 'assign':
                             if ($variable != $resolvedExpr->getCode()) {
                                 $symbolVariable->setMustInitNull(true);
                                 $compilationContext->symbolTable->mustGrownStack(true);
                                 /* Inherit the dynamic type data from the assigned value */
                                 $symbolVariable->setDynamicTypes('array');
                                 $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $resolvedExpr->getCode() . ');');
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 case 'variable':
                     $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $resolvedExpr->getOriginal());
                     switch ($itemVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'ulong':
                         case 'char':
                         case 'uchar':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $symbolVariable->initVariant($compilationContext);
                                     $symbolVariable->setDynamicTypes('long');
                                     if ($symbolVariable->isLocalOnly()) {
                                         $codePrinter->output('ZVAL_LONG(&' . $variable . ', ' . $itemVariable->getName() . ');');
                                     } else {
                                         $codePrinter->output('ZVAL_LONG(' . $variable . ', ' . $itemVariable->getName() . ');');
                                     }
                                     break;
                                 case 'add-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $symbolVariable->initVariant($compilationContext);
                                     $symbolVariable->setDynamicTypes('long');
                                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite($itemVariable->getType(), $compilationContext);
                                     if ($symbolVariable->isLocalOnly()) {
                                         $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(&' . $variable . ');');
                                         $codePrinter->output('ZVAL_LONG(&' . $variable . ', ' . $tempVariable->getName() . ' + ' . $itemVariable->getName() . ');');
                                     } else {
                                         $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(' . $variable . ');');
                                         $codePrinter->output('ZVAL_LONG(' . $variable . ', ' . $tempVariable->getName() . ' + ' . $itemVariable->getName() . ');');
                                     }
                                     break;
                                 case 'sub-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $symbolVariable->initVariant($compilationContext);
                                     $symbolVariable->setDynamicTypes('long');
                                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite($itemVariable->getType(), $compilationContext);
                                     if ($symbolVariable->isLocalOnly()) {
                                         $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(&' . $variable . ');');
                                         $codePrinter->output('ZVAL_LONG(&' . $variable . ', ' . $tempVariable->getName() . ' - ' . $itemVariable->getName() . ');');
                                     } else {
                                         $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(' . $variable . ');');
                                         $codePrinter->output('ZVAL_LONG(' . $variable . ', ' . $tempVariable->getName() . ' - ' . $itemVariable->getName() . ');');
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         case 'double':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $symbolVariable->initVariant($compilationContext);
                                     $symbolVariable->setDynamicTypes('double');
                                     if ($symbolVariable->isLocalOnly()) {
                                         $codePrinter->output('ZVAL_DOUBLE(&' . $variable . ', ' . $itemVariable->getName() . ');');
                                     } else {
                                         $codePrinter->output('ZVAL_DOUBLE(' . $variable . ', ' . $itemVariable->getName() . ');');
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         case 'bool':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     $symbolVariable->initVariant($compilationContext);
                                     $symbolVariable->setDynamicTypes('bool');
                                     if ($symbolVariable->isLocalOnly()) {
                                         $codePrinter->output('ZVAL_BOOL(&' . $variable . ', ' . $itemVariable->getName() . ');');
                                     } else {
                                         $codePrinter->output('ZVAL_BOOL(' . $variable . ', ' . $itemVariable->getName() . ');');
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         case 'array':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     if ($variable != $resolvedExpr->getCode()) {
                                         $symbolVariable->setMustInitNull(true);
                                         $compilationContext->symbolTable->mustGrownStack(true);
                                         /* Inherit the dynamic type data from the assigned value */
                                         $symbolVariable->setDynamicTypes('array');
                                         $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $resolvedExpr->getCode() . ');');
                                     }
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
                             }
                             break;
                         case 'variable':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     if ($itemVariable->getName() != $variable) {
                                         $symbolVariable->setMustInitNull(true);
                                         $compilationContext->symbolTable->mustGrownStack(true);
                                         /* Inherit the dynamic type data from the assigned value */
                                         $symbolVariable->setDynamicTypes($itemVariable->getDynamicTypes());
                                         $symbolVariable->setClassTypes($itemVariable->getClassTypes());
                                         $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $itemVariable->getName() . ');');
                                         if ($itemVariable->isTemporal()) {
                                             $itemVariable->setIdle(true);
                                         }
                                     }
                                     break;
                                 case 'concat-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);');
                                     break;
                                 case 'add-assign':
                                     $compilationContext->symbolTable->mustGrownStack(true);
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('ZEPHIR_ADD_ASSIGN(' . $variable . ', ' . $itemVariable->getName() . ');');
                                     break;
                                 case 'sub-assign':
                                     $compilationContext->symbolTable->mustGrownStack(true);
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('ZEPHIR_SUB_ASSIGN(' . $variable . ', ' . $itemVariable->getName() . ');');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         case 'string':
                             switch ($statement['operator']) {
                                 case 'assign':
                                     if ($itemVariable->getName() != $variable) {
                                         $symbolVariable->setMustInitNull(true);
                                         $compilationContext->symbolTable->mustGrownStack(true);
                                         /* Inherit the dynamic type data from the assigned value */
                                         $symbolVariable->setDynamicTypes($itemVariable->getDynamicTypes());
                                         $symbolVariable->setClassTypes($itemVariable->getClassTypes());
                                         $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $itemVariable->getName() . ');');
                                         if ($itemVariable->isTemporal()) {
                                             $itemVariable->setIdle(true);
                                         }
                                     }
                                     break;
                                 case 'concat-assign':
                                     $compilationContext->headersManager->add('kernel/operators');
                                     $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);');
                                     break;
                                 default:
                                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement);
                             }
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $itemVariable->getType(), $resolvedExpr->getOriginal());
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal());
             }
             break;
         default:
             throw new CompilerException("Unknown type: " . $type, $statement);
     }
 }
Beispiel #13
0
 /**
  * Compiles foo[] = {expr}
  *
  * @param $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param $statement
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->isReadOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement);
     }
     if ($symbolVariable->isLocalOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement);
     }
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'array'))) {
         $compilationContext->logger->warning('Possible attempt to append elements on a non-array dynamic variable', 'non-array-append', $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/array');
     $type = $symbolVariable->getType();
     switch ($type) {
         case 'variable':
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     $codePrinter->output('zephir_array_append(&' . $variable . ', ZEPHIR_GLOBAL(global_null), PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $codePrinter->output('ZVAL_LONG(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ');');
                     $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                     $symbolVariable->setIdle(true);
                     break;
                 case 'double':
                     $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $codePrinter->output('ZVAL_DOUBLE(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ');');
                     $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                     $symbolVariable->setIdle(true);
                     break;
                 case 'bool':
                     $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $codePrinter->output('ZVAL_BOOL(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');');
                     $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                     $symbolVariable->setIdle(true);
                     break;
                 case 'ulong':
                 case 'string':
                     $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $codePrinter->output('ZVAL_STRING(' . $symbolVariable->getName() . ', "' . Utils::addSlashes($resolvedExpr->getCode(), true) . '", 1);');
                     $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                     $symbolVariable->setIdle(true);
                     break;
                 case 'array':
                     $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $exprVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                     break;
                 case 'variable':
                     $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     switch ($exprVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                             $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                             $codePrinter->output('ZVAL_LONG(' . $symbolVariable->getName() . ', ' . $exprVariable->getName() . ');');
                             $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                             $symbolVariable->setIdle(true);
                             break;
                         case 'double':
                             $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                             $codePrinter->output('ZVAL_DOUBLE(' . $symbolVariable->getName() . ', ' . $exprVariable->getName() . ');');
                             $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                             $symbolVariable->setIdle(true);
                             break;
                         case 'bool':
                             $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                             $codePrinter->output('ZVAL_BOOL(' . $symbolVariable->getName() . ', ' . $exprVariable->getName() . ');');
                             $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                             $symbolVariable->setIdle(true);
                             break;
                         case 'variable':
                         case 'string':
                         case 'array':
                             $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $exprVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
                             break;
                         default:
                             throw new CompilerException("Unknown type " . $exprVariable->getType(), $statement);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type", $statement);
     }
 }
Beispiel #14
0
 /**
  * Return a variable in the symbol table, it will be used for a mutating operation
  * This method implies mutation of one of the members of the variable but no the variables it self
  *
  * @param string $name
  * @param CompilationContext $compilationContext
  * @param array $statement
  * @return Variable
  */
 public function getVariableForUpdate($name, CompilationContext $compilationContext, array $statement = null)
 {
     /**
      * Create superglobals just in time
      */
     if ($this->isSuperGlobal($name)) {
         if (!$this->hasVariable($name)) {
             /**
              * @TODO, injecting globals, initialize to null and check first?
              */
             $superVar = new Variable('variable', $name, $compilationContext->currentBranch);
             $superVar->setIsInitialized(true, $compilationContext, $statement);
             $superVar->setDynamicTypes('array');
             $superVar->increaseMutates();
             $superVar->increaseUses();
             $superVar->setIsExternal(true);
             $superVar->setUsed(true, $statement);
             $this->variables[$name] = $superVar;
             return $superVar;
         }
     }
     if (!$this->hasVariable($name)) {
         throw new CompilerException("Cannot mutate variable '" . $name . "' because it wasn't defined", $statement);
     }
     $variable = $this->getVariable($name);
     $variable->increaseUses();
     $variable->increaseMutates();
     /**
      * Saves the last place where the variable was mutated
      * We discard mutations inside loops because iterations could use the value
      * and Zephir only provides top-down compilation
      */
     $variable->setUsed(true, $statement);
     return $variable;
 }
Beispiel #15
0
 /**
  * Compiles foo[] = {expr}
  *
  * @param $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param $statement
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->isReadOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement);
     }
     if ($symbolVariable->isLocalOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement);
     }
     /**
      * Only dynamic variables and arrays can be used as arrays
      */
     if ($symbolVariable->isNotVariableAndArray()) {
         throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as an array", $statement);
     }
     if ($symbolVariable->getType() == 'variable') {
         if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'array'))) {
             $compilationContext->logger->warning('Possible attempt to append elements on a non-array dynamic variable', 'non-array-append', $statement);
         }
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/array');
     $type = $symbolVariable->getType();
     switch ($type) {
         case 'array':
         case 'variable':
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     $compilationContext->backend->addArrayEntry($symbolVariable, null, 'null', $compilationContext, $statement);
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                     $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement);
                     $tempVariable->setIdle(true);
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                     $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement);
                     $tempVariable->setIdle(true);
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $compilationContext->backend->assignBool($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                     $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement);
                     $tempVariable->setIdle(true);
                     break;
                 case 'ulong':
                 case 'string':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                     $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                     $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement);
                     $tempVariable->setIdle(true);
                     break;
                 case 'array':
                     $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     $compilationContext->backend->addArrayEntry($symbolVariable, null, $exprVariable, $compilationContext, $statement);
                     break;
                 case 'variable':
                     $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                     switch ($exprVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                             $compilationContext->backend->assignLong($tempVariable, $exprVariable, $compilationContext);
                             $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement);
                             $tempVariable->setIdle(true);
                             break;
                         case 'double':
                             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                             $compilationContext->backend->assignDouble($tempVariable, $exprVariable, $compilationContext);
                             $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement);
                             $tempVariable->setIdle(true);
                             break;
                         case 'bool':
                             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement);
                             $compilationContext->backend->assignBool($tempVariable, $exprVariable, $compilationContext);
                             $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement);
                             $tempVariable->setIdle(true);
                             break;
                         case 'variable':
                         case 'string':
                         case 'array':
                             $compilationContext->backend->addArrayEntry($symbolVariable, null, $exprVariable, $compilationContext, $statement);
                             break;
                         default:
                             throw new CompilerException("Unknown type: " . $exprVariable->getType(), $statement);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type: " . $resolvedExpr->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type: " . $type, $statement);
     }
 }
 /**
  * Compiles foo->{"x"} = {expr}
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  * @throws CompilerException
  * @throws \Exception
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement);
     }
     $propertyName = $statement['property'];
     if (!is_string($propertyName)) {
         throw new CompilerException("Expected string to update object property, " . gettype($propertyName) . " received", $statement);
     }
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate static property '" . $compilationContext->classDefinition->getCompleteName() . "::" . $propertyName . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement);
     }
     if ($symbolVariable->hasAnyDynamicType('unknown')) {
         throw new CompilerException("Cannot use non-initialized variable as an object", $statement);
     }
     /**
      * Trying to use a non-object dynamic variable as object
      */
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/object');
     switch ($resolvedExpr->getType()) {
         case 'null':
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'null', $compilationContext);
             break;
         case 'int':
         case 'long':
             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
             $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getCode(), $compilationContext);
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
             break;
         case 'string':
             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
             $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext);
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
             break;
         case 'bool':
             if ($resolvedExpr->getBooleanCode() == '1') {
                 $value = 'true';
             } else {
                 if ($resolvedExpr->getBooleanCode() == '0') {
                     $value = 'false';
                 } else {
                     throw new \Exception("?");
                 }
             }
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $value, $compilationContext);
             break;
         case 'empty-array':
             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
             $compilationContext->backend->initArray($tempVariable, $compilationContext);
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
             break;
         case 'array':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $variableVariable, $compilationContext);
             break;
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableVariable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext);
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $compilationContext->backend->assignBool($tempVariable, $variableVariable, $compilationContext);
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                     break;
                 case 'string':
                 case 'variable':
                 case 'array':
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr, $compilationContext);
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
     }
 }
Beispiel #17
0
 /**
  * Compiles traversing of hash values
  * - Evaluated expression must be a zval
  * - Every key must be a zval
  * - Every value must be a zval
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @param Variable $exprVariable
  */
 public function compileHashTraverse($expression, $compilationContext, $exprVariable)
 {
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Initialize 'key' variable
      */
     if (isset($this->_statement['key'])) {
         $keyVariable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['key'], $compilationContext, $this->_statement['expr']);
         if ($keyVariable->getType() != 'variable') {
             throw new CompilerException("Cannot use variable: " . $this->_statement['key'] . " type: " . $keyVariable->getType() . " as key in hash traversal", $this->_statement['expr']);
         }
         $keyVariable->setMustInitNull(true);
         $keyVariable->setIsInitialized(true, $compilationContext, $this->_statement);
         $keyVariable->setDynamicTypes('undefined');
     }
     /**
      * Initialize 'value' variable
      */
     if (isset($this->_statement['value'])) {
         $variable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['value'], $compilationContext, $this->_statement['expr']);
         if ($variable->getType() != 'variable') {
             throw new CompilerException("Cannot use variable: " . $this->_statement['value'] . " type: " . $variable->getType() . " as value in hash traversal", $this->_statement['expr']);
         }
         $variable->setMustInitNull(true);
         $variable->setIsInitialized(true, $compilationContext, $this->_statement);
         $variable->setDynamicTypes('undefined');
     }
     /**
      * Variables are initialized in a different way inside cycle
      */
     $compilationContext->insideCycle++;
     /**
      * Create a hash table and hash pointer temporary variables
      */
     $arrayPointer = $compilationContext->symbolTable->addTemp('HashPosition', $compilationContext);
     $arrayHash = $compilationContext->symbolTable->addTemp('HashTable', $compilationContext);
     /**
      * Create a temporary zval to fetch the items from the hash
      */
     $tempVariable = $compilationContext->symbolTable->addTemp('variable', $compilationContext);
     $tempVariable->setIsDoublePointer(true);
     $compilationContext->headersManager->add('kernel/hash');
     /**
      * We have to check if hashes are modified within the for's block
      */
     $duplicateHash = '0';
     if (isset($this->_statement['statements'])) {
         $detector = new ForValueUseDetector();
         if ($detector->detect($exprVariable->getName(), $this->_statement['statements'])) {
             $duplicateHash = '1';
         }
     }
     $codePrinter->output('zephir_is_iterable(' . $expression->getCode() . ', &' . $arrayHash->getName() . ', &' . $arrayPointer->getName() . ', ' . $duplicateHash . ', ' . $this->_statement['reverse'] . ', "' . Compiler::getShortUserPath($this->_statement['file']) . '", ' . $this->_statement['line'] . ');');
     $codePrinter->output('for (');
     $codePrinter->output('  ; zephir_hash_get_current_data_ex(' . $arrayHash->getName() . ', (void**) &' . $tempVariable->getName() . ', &' . $arrayPointer->getName() . ') == SUCCESS');
     if ($this->_statement['reverse']) {
         $codePrinter->output('  ; zephir_hash_move_backwards_ex(' . $arrayHash->getName() . ', &' . $arrayPointer->getName() . ')');
     } else {
         $codePrinter->output('  ; zephir_hash_move_forward_ex(' . $arrayHash->getName() . ', &' . $arrayPointer->getName() . ')');
     }
     $codePrinter->output(') {');
     if (isset($this->_statement['key'])) {
         $compilationContext->symbolTable->mustGrownStack(true);
         $codePrinter->output("\t" . 'ZEPHIR_GET_HMKEY(' . $this->_statement['key'] . ', ' . $arrayHash->getName() . ', ' . $arrayPointer->getName() . ');');
     }
     if (isset($this->_statement['value'])) {
         $compilationContext->symbolTable->mustGrownStack(true);
         $codePrinter->output("\t" . 'ZEPHIR_GET_HVALUE(' . $this->_statement['value'] . ', ' . $tempVariable->getName() . ');');
     }
     /**
      * Compile statements in the 'for' block
      */
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $st->compile($compilationContext);
     }
     /**
      * Restore the cycle counter
      */
     $compilationContext->insideCycle--;
     $codePrinter->output('}');
 }
 /**
  * Compiles x->y[z] = foo
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext,
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement);
     }
     /**
      * Update the property according to the number of array-offsets
      */
     if (count($statement['index-expr']) == 1) {
         $this->_assignPropertyArraySingleIndex($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement);
     } else {
         $this->_assignPropertyArrayMultipleIndex($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement);
     }
 }
Beispiel #19
0
 /**
  * Compiles foo->x = {expr}
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement);
     }
     $propertyName = $statement['property'];
     $className = $compilationContext->classDefinition->getCompleteName();
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate static property '" . $className . "::" . $propertyName . "' because it is not initialized", $statement);
     }
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement);
     }
     if ($symbolVariable->hasAnyDynamicType('unknown')) {
         throw new CompilerException("Cannot use non-initialized variable as an object", $statement);
     }
     /**
      * Trying to use a non-object dynamic variable as object
      */
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object'))) {
         $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement);
     }
     /**
      * Try to check if property is implemented on related object
      */
     if ($variable == 'this') {
         if (!$compilationContext->classDefinition->hasProperty($propertyName)) {
             throw new CompilerException("Property '" . $propertyName . "' is not defined on class '" . $className . "'", $statement);
         }
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/object');
     switch ($resolvedExpr->getType()) {
         case 'null':
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'null', $compilationContext);
             break;
         case 'int':
         case 'long':
         case 'uint':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             switch ($statement['operator']) {
                 case 'mul-assign':
                 case 'sub-assign':
                 case 'add-assign':
                     switch ($statement['operator']) {
                         case 'mul-assign':
                             $functionName = 'ZEPHIR_MUL_ASSIGN';
                             break;
                         case 'sub-assign':
                             $functionName = 'ZEPHIR_SUB_ASSIGN';
                             break;
                         case 'add-assign':
                             $functionName = 'ZEPHIR_ADD_ASSIGN';
                             break;
                     }
                     $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $compilationContext->backend->assignLong($resolvedVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                     $codePrinter->output($functionName . '(' . $compilationContext->backend->getVariableCode($tempVariable) . ', ' . $compilationContext->backend->getVariableCode($resolvedVariable) . ')');
                     break;
                 case 'assign':
                     $tempVariable->initNonReferenced($compilationContext);
                     $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement);
             }
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
             $tempVariable->setIdle(true);
             break;
         case 'char':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             switch ($statement['operator']) {
                 case 'assign':
                     $tempVariable->initNonReferenced($compilationContext);
                     $compilationContext->backend->assignLong($tempVariable, '\'' . $resolvedExpr->getBooleanCode() . '\'', $compilationContext);
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement);
             }
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
             $tempVariable->setIdle(true);
             break;
         case 'double':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             switch ($statement['operator']) {
                 case 'mul-assign':
                 case 'sub-assign':
                 case 'add-assign':
                     switch ($statement['operator']) {
                         case 'mul-assign':
                             $functionName = 'ZEPHIR_MUL_ASSIGN';
                             break;
                         case 'sub-assign':
                             $functionName = 'ZEPHIR_SUB_ASSIGN';
                             break;
                         case 'add-assign':
                             $functionName = 'ZEPHIR_ADD_ASSIGN';
                             break;
                     }
                     $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $compilationContext->backend->assignDouble($resolvedVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                     $codePrinter->output($functionName . '(' . $compilationContext->backend->getVariableCode($tempVariable) . ', ' . $compilationContext->backend->getVariableCode($resolvedVariable) . ')');
                     break;
                 case 'assign':
                     $tempVariable->initNonReferenced($compilationContext);
                     $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement);
             }
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
             $tempVariable->setIdle(true);
             break;
         case 'string':
             if ($compilationContext->backend->getName() == 'ZendEngine2') {
                 $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             } else {
                 $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, false);
             }
             switch ($statement['operator']) {
                 case 'concat-assign':
                     $codePrinter->output('zephir_concat_self_str(&' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);');
                     break;
                 case 'assign':
                     /* We only can use nonReferenced variables for not refcounted stuff in ZE3 */
                     if ($compilationContext->backend->getName() == 'ZendEngine2') {
                         $tempVariable->initNonReferenced($compilationContext);
                     } else {
                         $tempVariable->initVariant($compilationContext);
                     }
                     $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                     break;
             }
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
             $tempVariable->setIdle(true);
             break;
         case 'array':
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr, $compilationContext);
             break;
         case 'bool':
             $codePrinter->output('if (' . $resolvedExpr->getBooleanCode() . ') {');
             $codePrinter->increaseLevel();
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'true', $compilationContext);
             $codePrinter->decreaseLevel();
             $codePrinter->output('} else {');
             $codePrinter->increaseLevel();
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'false', $compilationContext);
             $codePrinter->decreaseLevel();
             $codePrinter->output('}');
             break;
             /* unreachable code */
         /* unreachable code */
         case 'empty-array':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             $compilationContext->backend->initArray($tempVariable, $compilationContext);
             $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr->getCode(), $compilationContext);
             $tempVariable->setIdle(true);
             break;
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableVariable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext);
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                     $tempVariable->setIdle(true);
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignDouble($tempVariable, $variableVariable, $compilationContext);
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                     $tempVariable->setIdle(true);
                     break;
                 case 'bool':
                     $codePrinter->output('if (' . $variableVariable->getName() . ') {');
                     $codePrinter->increaseLevel();
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'true', $compilationContext);
                     $codePrinter->decreaseLevel();
                     $codePrinter->output('} else {');
                     $codePrinter->increaseLevel();
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'false', $compilationContext);
                     $codePrinter->decreaseLevel();
                     $codePrinter->output('}');
                     break;
                 case 'array':
                 case 'string':
                 case 'variable':
                     $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $variableVariable, $compilationContext);
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
     }
 }
Beispiel #20
0
 /**
  * Calls static methods on using a dynamic variable as class and a dynamic method
  *
  * @param array $expression
  * @param Variable $symbolVariable
  * @param boolean $mustInit
  * @param boolean $isExpecting
  * @param CompilationContext $compilationContext
  */
 protected function callFromDynamicClassDynamicMethod(array $expression, $symbolVariable, $mustInit, $isExpecting, CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Call static methods must grown the stack
      */
     $compilationContext->symbolTable->mustGrownStack(true);
     if ($mustInit) {
         $symbolVariable->setMustInitNull(true);
         $symbolVariable->trackVariant($compilationContext);
     }
     $cachePointer = 'NULL';
     if (isset($expression['parameters']) && count($expression['parameters'])) {
         $params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
     } else {
         $params = array();
     }
     /**
      * Obtain the class entry from the variable
      */
     $classNameVariable = $compilationContext->symbolTable->getVariableForRead($expression['class'], $compilationContext, $expression);
     if ($classNameVariable->isNotVariableAndString()) {
         throw new CompilerException("Only dynamic/string variables can be used in dynamic classes", $expression);
     }
     /**
      * @todo Validate if the variable is really a string!
      */
     $classEntryVariable = $compilationContext->symbolTable->addTemp('zend_class_entry', $compilationContext);
     $codePrinter->output($classEntryVariable->getName() . ' = zend_fetch_class(Z_STRVAL_P(' . $classNameVariable->getName() . '), Z_STRLEN_P(' . $classNameVariable->getName() . '), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);');
     $classEntry = $classEntryVariable->getName();
     /**
      * Obtain the method name from the variable
      */
     $methodNameVariable = $compilationContext->symbolTable->getVariableForRead($expression['name'], $compilationContext, $expression);
     if ($methodNameVariable->isNotVariableAndString()) {
         throw new CompilerException("Only dynamic/string variables can be used in dynamic methods", $expression);
     }
     /**
      * @todo Validate if the variable is really a string!
      */
     $methodName = 'Z_STRVAL_P(' . $methodNameVariable->getName() . ')';
     if (!count($params)) {
         if ($isExpecting) {
             if ($symbolVariable->getName() == 'return_value') {
                 $codePrinter->output('ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ');');
             } else {
                 $codePrinter->output('ZEPHIR_CALL_CE_STATIC(&' . $symbolVariable->getName() . ', ' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ');');
             }
         } else {
             $codePrinter->output('ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ');');
         }
     } else {
         if ($isExpecting) {
             if ($symbolVariable->getName() == 'return_value') {
                 $codePrinter->output('ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
             } else {
                 $codePrinter->output('ZEPHIR_CALL_CE_STATIC(&' . $symbolVariable->getName() . ', ' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
             }
         } else {
             $codePrinter->output('ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', ' . $methodName . ', ' . $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 . ');');
     }
     $this->addCallStatusOrJump($compilationContext);
 }
Beispiel #21
0
 /**
  * Add the last-call-status flag to the current symbol table
  *
  * @param CompilationContext $compilationContext
  */
 public function addCallStatusFlag(CompilationContext $compilationContext)
 {
     if (!$compilationContext->symbolTable->hasVariable('ZEPHIR_LAST_CALL_STATUS')) {
         $callStatus = new Variable('int', 'ZEPHIR_LAST_CALL_STATUS', $compilationContext->currentBranch);
         $callStatus->setIsInitialized(true, $compilationContext, array());
         $callStatus->increaseUses();
         $callStatus->setReadOnly(true);
         $compilationContext->symbolTable->addRawVariable($callStatus);
     }
 }
 /**
  * Compiles x->y[] = foo
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     $property = $statement['property'];
     $compilationContext->headersManager->add('kernel/object');
     /**
      * Check if the variable to update is defined
      */
     if ($symbolVariable->getRealName() == 'this') {
         $classDefinition = $compilationContext->classDefinition;
         if (!$classDefinition->hasProperty($property)) {
             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement);
         }
         $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 ($symbolVariable->hasAnyDynamicType('object')) {
             $classType = current($symbolVariable->getClassTypes());
             $compiler = $compilationContext->compiler;
             if ($compiler->isClass($classType)) {
                 $classDefinition = $compiler->getClassDefinition($classType);
                 if (!$classDefinition) {
                     throw new CompilerException("Cannot locate class definition for class: " . $classType, $statement);
                 }
                 if (!$classDefinition->hasProperty($property)) {
                     throw new CompilerException("Class '" . $classType . "' does not have a property called: '" . $property . "'", $statement);
                 }
             }
         }
     }
     switch ($resolvedExpr->getType()) {
         case 'null':
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, 'null', $compilationContext);
             break;
         case 'bool':
             $codePrinter->output('if (' . $resolvedExpr->getBooleanCode() . ') {');
             $codePrinter->increaseLevel();
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, 'true', $compilationContext);
             $codePrinter->decreaseLevel();
             $codePrinter->output('} else {');
             $codePrinter->increaseLevel();
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, 'false', $compilationContext);
             $codePrinter->decreaseLevel();
             $codePrinter->output('}');
             break;
         case 'char':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignLong($tempVariable, '\'' . $resolvedExpr->getCode() . '\'', $compilationContext);
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'int':
         case 'long':
         case 'uint':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getCode(), $compilationContext);
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'double':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getCode(), $compilationContext);
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'string':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext);
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'array':
             $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $variableExpr, $compilationContext);
             break;
         case 'variable':
             $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableExpr->getType()) {
                 case 'int':
                 case 'long':
                 case 'uint':
                 case 'char':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignLong($tempVariable, $variableExpr, $compilationContext);
                     $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignDouble($tempVariable, $variableExpr, $compilationContext);
                     $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignBool($tempVariable, $variableExpr, $compilationContext);
                     $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'variable':
                 case 'string':
                 case 'array':
                 case 'resource':
                 case 'object':
                     $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $variableExpr, $compilationContext);
                     if ($variableExpr->isTemporal()) {
                         $variableExpr->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Variable: " . $variableExpr->getType() . " cannot be appended to array property", $statement);
             }
             break;
         default:
             throw new CompilerException("Expression: " . $resolvedExpr->getType() . " cannot be appended to array property", $statement);
     }
 }
 /**
  * Compiles x->y[z][] = foo
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext,
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement);
     }
     $this->_assignPropertyArrayMultipleIndex($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement);
 }
Beispiel #24
0
 /**
  * Compiles traversing of hash values
  *
  * - Evaluated expression must be a zval
  * - A key must be a zval
  * - A value must be a zval
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @param Variable $exprVariable
  */
 public function compileHashTraverse($expression, CompilationContext $compilationContext, Variable $exprVariable)
 {
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Initialize 'key' variable
      */
     if (isset($this->_statement['key'])) {
         if ($this->_statement['key'] != '_') {
             $keyVariable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['key'], $compilationContext, $this->_statement['expr']);
             if ($keyVariable->getType() != 'variable') {
                 throw new CompilerException("Cannot use variable: " . $this->_statement['key'] . " type: " . $keyVariable->getType() . " as key in hash traversal", $this->_statement['expr']);
             }
         } else {
             $keyVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
         }
         $keyVariable->setMustInitNull(true);
         $keyVariable->setIsInitialized(true, $compilationContext, $this->_statement);
         $keyVariable->setDynamicTypes('undefined');
     }
     /**
      * Initialize 'value' variable
      */
     if (isset($this->_statement['value'])) {
         if ($this->_statement['value'] != '_') {
             $variable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['value'], $compilationContext, $this->_statement['expr']);
             if ($variable->getType() != 'variable') {
                 throw new CompilerException("Cannot use variable: " . $this->_statement['value'] . " type: " . $variable->getType() . " as value in hash traversal", $this->_statement['expr']);
             }
         } else {
             $variable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
         }
         $variable->setMustInitNull(true);
         $variable->setIsInitialized(true, $compilationContext, $this->_statement);
         $variable->setDynamicTypes('undefined');
     }
     /**
      * Variables are initialized in a different way inside cycle
      */
     $compilationContext->insideCycle++;
     $compilationContext->headersManager->add('kernel/hash');
     $duplicateHash = '0';
     $duplicateKey = true;
     /**
      * We have to check if hashes are modified within the for's block
      */
     if (isset($this->_statement['statements'])) {
         /**
          * Create the statements block here to obtain the last use line
          */
         $st = new StatementsBlock($this->_statement['statements']);
         $detector = new ForValueUseDetector();
         if ($detector->detect($exprVariable->getName(), $this->_statement['statements'])) {
             $duplicateHash = '1';
         }
         /**
          * Detect if the key is modified or passed to an external scope
          */
         if (isset($this->_statement['key'])) {
             if (!$keyVariable->isTemporal()) {
                 $detector->setDetectionFlags(ForValueUseDetector::DETECT_ALL);
                 if ($detector->detect($keyVariable->getName(), $this->_statement['statements'])) {
                     $loopContext = $compilationContext->currentMethod->getLocalContextPass();
                     //echo $st->getLastLine();
                     //echo $loopContext->getLastVariableUseLine($keyVariable->getName());
                     $duplicateKey = true;
                 }
             }
         }
     }
     $compilationContext->backend->forStatement($exprVariable, isset($this->_statement['key']) ? $keyVariable : null, isset($this->_statement['value']) ? $variable : null, $duplicateKey, $duplicateHash, $this->_statement, $st, $compilationContext);
     /**
      * Restore the cycle counter
      */
     $compilationContext->insideCycle--;
 }
 /**
  * Compiles foo->{x} = {expr}
  *
  * @param string $variable
  * @param Variable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement);
     }
     $propertyName = $statement['property'];
     $propertyVariable = $compilationContext->symbolTable->getVariableForRead($propertyName, $compilationContext, $statement);
     if ($propertyVariable->isNotVariableAndString()) {
         throw new CompilerException("Cannot use variable type '" . $propertyVariable->getType() . "' to update object property", $statement);
     }
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate static property '" . $compilationContext->classDefinition->getCompleteName() . "::" . $propertyName . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement);
     }
     if ($symbolVariable->hasAnyDynamicType('unknown')) {
         throw new CompilerException("Cannot use non-initialized variable as an object", $statement);
     }
     /**
      * Trying to use a non-object dynamic variable as object
      */
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/object');
     $propertyVariableName = $compilationContext->symbolTable->getVariable($propertyName);
     switch ($resolvedExpr->getType()) {
         case 'null':
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);');
             }
             break;
         case 'int':
         case 'long':
             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
             $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');');
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             break;
         case 'string':
             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
             $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);');
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             break;
         case 'bool':
             if ($variable == 'this') {
                 if ($resolvedExpr->getBooleanCode() == '1') {
                     $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_true) TSRMLS_CC);');
                 } else {
                     $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
                 }
             } else {
                 if ($resolvedExpr->getBooleanCode() == '1') {
                     $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_true) TSRMLS_CC);');
                 } else {
                     $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
                 }
             }
             break;
         case 'empty-array':
             $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
             $codePrinter->output('array_init(' . $tempVariable->getName() . ');');
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             break;
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableVariable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');');
                     $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');');
                     if ($variable == 'this') {
                         $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     } else {
                         $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     }
                     break;
                 case 'string':
                 case 'variable':
                     $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariable->getName() . ', ' . $resolvedExpr->getCode() . ' TSRMLS_CC);');
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
     }
 }
Beispiel #26
0
 /**
  * Retrieves/Creates a function cache for a method call
  *
  * @param CompilationContext $compilationContext
  * @param ClassMethod $method
  * @param Variable $caller
  */
 public function get(CompilationContext $compilationContext, $methodName, Variable $caller)
 {
     $compiler = $compilationContext->compiler;
     $numberPoly = 0;
     if ($caller->getRealName() == 'this') {
         $classDefinition = $compilationContext->classDefinition;
         if ($classDefinition->hasMethod($methodName)) {
             $numberPoly++;
             $method = $classDefinition->getMethod($methodName);
         }
     } else {
         $classTypes = $caller->getClassTypes();
         foreach ($classTypes as $classType) {
             if ($compiler->isClass($classType) || $compiler->isInterface($classType) || $compiler->isBundledClass($classType) || $compiler->isBundledInterface($classType)) {
                 if ($compiler->isInterface($classType)) {
                     continue;
                 }
                 if ($compiler->isClass($classType)) {
                     $classDefinition = $compiler->getClassDefinition($classType);
                 } else {
                     $classDefinition = $compiler->getInternalClassDefinition($classType);
                 }
                 if (!$classDefinition) {
                     continue;
                 }
                 if ($classDefinition->hasMethod($methodName) && !$classDefinition->isInterface()) {
                     $numberPoly++;
                     $method = $classDefinition->getMethod($methodName);
                 }
             }
         }
     }
     if (!$numberPoly) {
         // Try to generate a cache based on the fact the variable is not modified within the loop block
         if ($compilationContext->insideCycle && !$caller->isTemporal()) {
             if (count($compilationContext->cycleBlocks) && $caller->getType() == 'variable') {
                 $currentBlock = $compilationContext->cycleBlocks[count($compilationContext->cycleBlocks) - 1];
                 if ($currentBlock->getMutateGatherer(true)->getNumberOfMutations($caller->getName()) == 0) {
                     $functionCache = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext);
                     $functionCache->setMustInitNull(true);
                     $functionCache->setReusable(false);
                     return '&' . $functionCache->getName() . ', 0';
                 }
             }
         }
         return 'NULL, 0';
     }
     if (!$method instanceof \ReflectionMethod) {
         if ($method->getClassDefinition()->isExternal()) {
             return 'NULL, 0';
         }
         $completeName = $method->getClassDefinition()->getCompleteName();
         if (isset($this->cache[$completeName][$method->getName()])) {
             return $this->cache[$completeName][$method->getName()] . ', ' . SlotsCache::getExistingMethodSlot($method);
         }
         $gatherer = $this->gatherer;
         if (is_object($gatherer)) {
             $number = $gatherer->getNumberOfMethodCalls($method->getClassDefinition()->getCompleteName(), $method->getName());
         } else {
             $number = 0;
         }
         $staticCacheable = !$method->getClassDefinition()->isInterface() && ($compilationContext->currentMethod == $method || $method->getClassDefinition()->isFinal() || $method->isFinal() || $method->isPrivate());
         if ($number > 1 || $compilationContext->insideCycle) {
             $cacheable = true;
         } else {
             $cacheable = false;
         }
     } else {
         $staticCacheable = false;
         $cacheable = false;
     }
     // Recursive methods require warm-up
     if ($compilationContext->currentMethod == $method) {
         if (!$compilationContext->methodWarmUp) {
             $compilationContext->methodWarmUp = new MethodCallWarmUp();
         }
     }
     $associatedClass = false;
     if ($caller->getName() != 'this_ptr') {
         $associatedClass = $caller->getAssociatedClass();
         if ($this->isClassCacheable($associatedClass)) {
             $staticCacheable = true;
         }
     }
     if ($staticCacheable) {
         $cacheSlot = SlotsCache::getMethodSlot($method);
     } else {
         $cacheSlot = '0';
     }
     if ($cacheable) {
         $functionCacheVar = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext);
         $functionCacheVar->setMustInitNull(true);
         $functionCacheVar->setReusable(false);
         $functionCache = '&' . $functionCacheVar->getName();
     } else {
         $functionCache = 'NULL';
     }
     if (!$method instanceof \ReflectionMethod) {
         $this->cache[$completeName][$method->getName()] = $functionCache;
     }
     return $functionCache . ', ' . $cacheSlot;
 }
Beispiel #27
0
 public function ifVariableValueUndefined(Variable $var, CompilationContext $context, $useBody = false, $useCodePrinter = true)
 {
     if ($var->isDoublePointer()) {
         return parent::ifVariableValueUndefined($var, $context, $useBody, $useCodePrinter);
     }
     $body = 'Z_TYPE_P(' . $this->getVariableCode($var) . ') == IS_UNDEF';
     $output = 'if (' . $body . ') {';
     if ($useCodePrinter) {
         $context->codePrinter->output($output);
     }
     return $useBody ? $body : $output;
 }
Beispiel #28
0
 /**
  * Compiles foo->x = {expr}
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement);
     }
     $propertyName = $statement['property'];
     $className = $compilationContext->classDefinition->getCompleteName();
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate static property '" . $className . "::" . $propertyName . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement);
     }
     if ($symbolVariable->hasAnyDynamicType('unknown')) {
         throw new CompilerException("Cannot use non-initialized variable as an object", $statement);
     }
     /**
      * Trying to use a non-object dynamic variable as object
      */
     if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object'))) {
         $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement);
     }
     /**
      * Try to check if property is implemented on related object
      */
     if ($variable == 'this') {
         if (!$compilationContext->classDefinition->hasProperty($propertyName)) {
             throw new CompilerException("Property '" . $propertyName . "' is not defined on class '" . $className . "'", $statement);
         }
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/object');
     switch ($resolvedExpr->getType()) {
         case 'null':
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);');
             }
             break;
         case 'int':
         case 'long':
         case 'uint':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             switch ($statement['operator']) {
                 case 'mul-assign':
                 case 'sub-assign':
                 case 'add-assign':
                     switch ($statement['operator']) {
                         case 'mul-assign':
                             $functionName = 'ZEPHIR_MUL_ASSIGN';
                             break;
                         case 'sub-assign':
                             $functionName = 'ZEPHIR_SUB_ASSIGN';
                             break;
                         case 'add-assign':
                             $functionName = 'ZEPHIR_ADD_ASSIGN';
                             break;
                     }
                     $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $codePrinter->output('ZVAL_LONG(' . $resolvedVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');');
                     $codePrinter->output($functionName . '(' . $tempVariable->getName() . ', ' . $resolvedVariable->getName() . ')');
                     break;
                 case 'assign':
                     $tempVariable->initNonReferenced($compilationContext);
                     $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');');
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement);
             }
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             $tempVariable->setIdle(true);
             break;
         case 'char':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             switch ($statement['operator']) {
                 case 'assign':
                     $tempVariable->initNonReferenced($compilationContext);
                     $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getBooleanCode() . '\');');
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement);
             }
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             $tempVariable->setIdle(true);
             break;
         case 'double':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             switch ($statement['operator']) {
                 case 'mul-assign':
                 case 'sub-assign':
                 case 'add-assign':
                     switch ($statement['operator']) {
                         case 'mul-assign':
                             $functionName = 'ZEPHIR_MUL_ASSIGN';
                             break;
                         case 'sub-assign':
                             $functionName = 'ZEPHIR_SUB_ASSIGN';
                             break;
                         case 'add-assign':
                             $functionName = 'ZEPHIR_ADD_ASSIGN';
                             break;
                     }
                     $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                     $codePrinter->output('ZVAL_DOUBLE(' . $resolvedVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');');
                     $codePrinter->output($functionName . '(' . $tempVariable->getName() . ', ' . $resolvedVariable->getName() . ')');
                     break;
                 case 'assign':
                     $tempVariable->initNonReferenced($compilationContext);
                     $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');');
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement);
             }
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             $tempVariable->setIdle(true);
             break;
         case 'string':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             switch ($statement['operator']) {
                 case 'concat-assign':
                     $codePrinter->output('zephir_concat_self_str(&' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);');
                     break;
                 case 'assign':
                     $tempVariable->initNonReferenced($compilationContext);
                     $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);');
                     break;
             }
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             $tempVariable->setIdle(true);
             break;
         case 'array':
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC);');
             }
             break;
         case 'bool':
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
             }
             break;
         case 'empty-array':
             /* unreachable code */
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             $codePrinter->output('array_init(' . $tempVariable->getName() . ');');
             if ($variable == 'this') {
                 $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             } else {
                 $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             }
             $tempVariable->setIdle(true);
             break;
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableVariable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');');
                     if ($variable == 'this') {
                         $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     } else {
                         $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     }
                     $tempVariable->setIdle(true);
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');');
                     if ($variable == 'this') {
                         $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     } else {
                         $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     }
                     $tempVariable->setIdle(true);
                     break;
                 case 'bool':
                     if ($variable == 'this') {
                         $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
                     } else {
                         $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
                     }
                     break;
                 case 'array':
                 case 'string':
                 case 'variable':
                     if ($variable == 'this') {
                         $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' TSRMLS_CC);');
                     } else {
                         $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' TSRMLS_CC);');
                     }
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
     }
 }
Beispiel #29
0
 /**
  * Compiles foo = {expr}
  * Changes the value of a mutable variable
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param ReadDetector $readDetector
  * @param CompilationContext $compilationContext
  * @param array $statement
  * @throws CompilerException
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, ReadDetector $readDetector, CompilationContext $compilationContext, array $statement)
 {
     if ($symbolVariable->isReadOnly()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Only initialize variables if it's direct assignment
      */
     if ($statement['operator'] == 'assign') {
         $symbolVariable->setIsInitialized(true, $compilationContext, $statement);
     } else {
         if (!$symbolVariable->isInitialized()) {
             throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
         }
     }
     /**
      * Set the assigned value to the variable as a CompiledExpression
      * We could use this expression for further analysis
      */
     $symbolVariable->setPossibleValue($resolvedExpr, $compilationContext);
     $type = $symbolVariable->getType();
     switch ($type) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'char':
         case 'uchar':
             $this->doNumericAssignment($codePrinter, $resolvedExpr, $symbolVariable, $variable, $statement, $compilationContext);
             break;
         case 'double':
             $this->doDoubleAssignment($codePrinter, $resolvedExpr, $symbolVariable, $variable, $statement, $compilationContext);
             break;
         case 'array':
             $this->doArrayAssignment($codePrinter, $resolvedExpr, $symbolVariable, $variable, $statement, $compilationContext);
             break;
         case 'string':
             $this->doStringAssignment($codePrinter, $resolvedExpr, $symbolVariable, $variable, $statement, $compilationContext);
             break;
         case 'bool':
             $this->doBoolAssignment($codePrinter, $resolvedExpr, $symbolVariable, $variable, $statement, $compilationContext);
             break;
         case 'variable':
             $this->doVariableAssignment($codePrinter, $resolvedExpr, $symbolVariable, $variable, $statement, $compilationContext, $readDetector);
             break;
         default:
             throw new CompilerException("Unknown type: " . $type, $statement);
     }
 }
Beispiel #30
0
 /**
  * Compiles x->y[] = foo
  *
  * @param string $variable
  * @param Variable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext,
  * @param array $statement
  */
 public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     if (!$symbolVariable->isInitialized()) {
         throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement);
     }
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement);
     }
     $codePrinter = $compilationContext->codePrinter;
     $property = $statement['property'];
     $compilationContext->headersManager->add('kernel/object');
     /* @todo check whether property really does exist */
     switch ($resolvedExpr->getType()) {
         case 'null':
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);');
             break;
         case 'bool':
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
             break;
         case 'char':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getCode() . '\');');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'int':
         case 'long':
         case 'uint':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'double':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'string':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);');
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'array':
             $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $variableExpr->getName() . ' TSRMLS_CC);');
             break;
         case 'variable':
             $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableExpr->getType()) {
                 case 'int':
                 case 'long':
                 case 'uint':
                 case 'char':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');');
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');');
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');');
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'variable':
                 case 'string':
                 case 'array':
                 case 'resource':
                 case 'object':
                     $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $variableExpr->getName() . ' TSRMLS_CC);');
                     if ($variableExpr->isTemporal()) {
                         $variableExpr->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Variable: " . $variableExpr->getType() . " cannot be appended to array property", $statement);
             }
             break;
         default:
             throw new CompilerException("Expression: " . $resolvedExpr->getType() . " cannot be appended to array property", $statement);
     }
 }