Example #1
0
 /**
  * Compiles ClassName::foo[index] = {expr}
  *
  * @param                    $className
  * @param                    $property
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array              $statement
  *
  * @throws CompilerException
  * @internal param string $variable
  */
 public function assignStatic($className, $property, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $compiler = $compilationContext->compiler;
     if (!in_array($className, array('self', 'static', 'parent'))) {
         $className = $compilationContext->getFullName($className);
         if ($compiler->isClass($className)) {
             $classDefinition = $compiler->getClassDefinition($className);
         } else {
             if ($compiler->isBundledClass($className)) {
                 $classDefinition = $compiler->getInternalClassDefinition($className);
             } else {
                 throw new CompilerException("Cannot locate class '" . $className . "'", $statement);
             }
         }
     } else {
         if (in_array($className, array('self', 'static'))) {
             $classDefinition = $compilationContext->classDefinition;
         } else {
             if ($className == 'parent') {
                 $classDefinition = $compilationContext->classDefinition;
                 $extendsClass = $classDefinition->getExtendsClass();
                 if (!$extendsClass) {
                     throw new CompilerException('Cannot assign static property "' . $property . '" on parent because class ' . $classDefinition->getCompleteName() . ' does not extend any class', $statement);
                 } else {
                     $classDefinition = $classDefinition->getExtendsClassDefinition();
                 }
             }
         }
     }
     if (!$classDefinition->hasProperty($property)) {
         throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement);
     }
     /** @var $propertyDefinition ClassProperty */
     $propertyDefinition = $classDefinition->getProperty($property);
     if (!$propertyDefinition->isStatic()) {
         throw new CompilerException("Cannot access non-static property '" . $classDefinition->getCompleteName() . '::' . $property . "'", $statement);
     }
     if ($propertyDefinition->isPrivate()) {
         if ($classDefinition != $compilationContext->classDefinition) {
             throw new CompilerException("Cannot access private static property '" . $classDefinition->getCompleteName() . '::' . $property . "' out of its declaring context", $statement);
         }
     }
     $compilationContext->headersManager->add('kernel/object');
     $classEntry = $classDefinition->getClassEntry($compilationContext);
     $this->_assignStaticPropertyArrayMultipleIndex($classEntry, $property, $resolvedExpr, $compilationContext, $statement);
 }
Example #2
0
 /**
  * Compiles ClassName::foo = {expr}
  *
  * @param                    $className
  * @param                    $property
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array              $statement
  *
  * @throws CompilerException
  * @internal param string $variable
  */
 public function assignStatic($className, $property, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $compiler = $compilationContext->compiler;
     if (!in_array($className, array('self', 'static', 'parent'))) {
         $className = $compilationContext->getFullName($className);
         if ($compiler->isClass($className)) {
             $classDefinition = $compiler->getClassDefinition($className);
         } else {
             if ($compiler->isBundledClass($className)) {
                 $classDefinition = $compiler->getInternalClassDefinition($className);
             } else {
                 throw new CompilerException("Cannot locate class '" . $className . "'", $statement);
             }
         }
     } else {
         if (in_array($className, array('self', 'static'))) {
             $classDefinition = $compilationContext->classDefinition;
         } else {
             if ($className == 'parent') {
                 $classDefinition = $compilationContext->classDefinition;
                 $extendsClass = $classDefinition->getExtendsClass();
                 if (!$extendsClass) {
                     throw new CompilerException('Cannot assign static property "' . $property . '" on parent because class ' . $classDefinition->getCompleteName() . ' does not extend any class', $statement);
                 } else {
                     $classDefinition = $classDefinition->getExtendsClassDefinition();
                 }
             }
         }
     }
     if (!$classDefinition->hasProperty($property)) {
         throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement);
     }
     /** @var $propertyDefinition ClassProperty */
     $propertyDefinition = $classDefinition->getProperty($property);
     if (!$propertyDefinition->isStatic()) {
         throw new CompilerException("Cannot access non-static property '" . $classDefinition->getCompleteName() . '::' . $property . "'", $statement);
     }
     if ($propertyDefinition->isPrivate()) {
         if ($classDefinition != $compilationContext->classDefinition) {
             throw new CompilerException("Cannot access private static property '" . $classDefinition->getCompleteName() . '::' . $property . "' out of its declaring context", $statement);
         }
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/object');
     $classEntry = $classDefinition->getClassEntry($compilationContext);
     switch ($resolvedExpr->getType()) {
         case 'null':
             $compilationContext->backend->updateStaticProperty($classEntry, $property, 'null', $compilationContext);
             break;
         case 'int':
         case 'uint':
         case 'long':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'char':
         case 'uchar':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignLong($tempVariable, '\'' . $resolvedExpr->getCode() . '\'', $compilationContext);
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $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->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'string':
             switch ($statement['operator']) {
                 case 'assign':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $tempVariable->initVariant($compilationContext);
                     if ($resolvedExpr->getCode()) {
                         $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                     } else {
                         $codePrinter->output('ZVAL_EMPTY_STRING(' . $tempVariable->getName() . ');');
                     }
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
             }
             $codePrinter->output('zephir_update_static_property_ce(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ' TSRMLS_CC);');
             break;
         case 'bool':
             if ($resolvedExpr->getBooleanCode() == '1') {
                 $compilationContext->backend->updateStaticProperty($classEntry, $property, 'true', $compilationContext);
             } else {
                 if ($resolvedExpr->getBooleanCode() == '0') {
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, 'false', $compilationContext);
                 } else {
                     $codePrinter->output('if (' . $resolvedExpr->getBooleanCode() . ') {');
                     $codePrinter->increaseLevel();
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, 'true', $compilationContext);
                     $codePrinter->decreaseLevel();
                     $codePrinter->output('} else {');
                     $codePrinter->increaseLevel();
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, 'false', $compilationContext);
                     $codePrinter->decreaseLevel();
                     $codePrinter->output('}');
                 }
             }
             break;
         case 'empty-array':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->initArray($tempVariable, $compilationContext);
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'array':
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $resolvedExpr, $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->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext);
                     if ($compilationContext->insideCycle) {
                         $propertyCache = $compilationContext->symbolTable->getTempVariableForWrite('zend_property_info', $compilationContext);
                         $propertyCache->setMustInitNull(true);
                         $propertyCache->setReusable(false);
                         $codePrinter->output('zephir_update_static_property_ce_cache(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ', &' . $propertyCache->getName() . ' TSRMLS_CC);');
                     } else {
                         $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
                     }
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignDouble($tempVariable, $variableVariable, $compilationContext);
                     if ($compilationContext->insideCycle) {
                         $propertyCache = $compilationContext->symbolTable->getTempVariableForWrite('zend_property_info', $compilationContext);
                         $propertyCache->setMustInitNull(true);
                         $propertyCache->setReusable(false);
                         $codePrinter->output('zephir_update_static_property_ce_cache(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ', &' . $propertyCache->getName() . ' TSRMLS_CC);');
                     } else {
                         $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
                     }
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignBool($tempVariable, $variableVariable, $compilationContext);
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'string':
                     switch ($statement['operator']) {
                         case 'concat-assign':
                             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                             $expression = new Expression(array('type' => 'static-property-access', 'left' => array('value' => $statement['variable']), 'right' => array('value' => $statement['property'])));
                             $expression->setExpectReturn(true, $tempVariable);
                             $expression->compile($compilationContext);
                             $variableVariableCode = $compilationContext->backend->getVariableCode($variableVariable);
                             $tempVariableCode = $compilationContext->backend->getVariableCode($tempVariable);
                             $compilationContext->codePrinter->output('zephir_concat_function(' . $variableVariableCode . ', ' . $tempVariableCode . ', ' . $variableVariableCode . ');');
                             //continue
                         //continue
                         case 'assign':
                             $compilationContext->backend->updateStaticProperty($classEntry, $property, $variableVariable, $compilationContext);
                             if ($variableVariable->isTemporal()) {
                                 $variableVariable->setIdle(true);
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                     }
                     break;
                 case 'variable':
                 case 'array':
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, $variableVariable, $compilationContext);
                     if ($variableVariable->isTemporal()) {
                         $variableVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
     }
 }
 /**
  * Access a static property
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $className = $expression['left']['value'];
     $compiler = $compilationContext->compiler;
     $property = $expression['right']['value'];
     /**
      * Fetch the class definition according to the class where the constant
      * is supposed to be declared
      */
     if (!in_array($className, array('self', 'static', 'parent'))) {
         $className = $compilationContext->getFullName($className);
         if ($compiler->isClass($className)) {
             $classDefinition = $compiler->getClassDefinition($className);
         } else {
             if ($compiler->isBundledClass($className)) {
                 $classDefinition = $compiler->getInternalClassDefinition($className);
             } else {
                 throw new CompilerException("Cannot locate class '" . $className . "'", $expression['left']);
             }
         }
     } else {
         if (in_array($className, array('self', 'static'))) {
             $classDefinition = $compilationContext->classDefinition;
         } else {
             if ($className == 'parent') {
                 $classDefinition = $compilationContext->classDefinition;
                 $extendsClass = $classDefinition->getExtendsClass();
                 if (!$extendsClass) {
                     throw new CompilerException('Cannot access static property "' . $property . '" on parent because class ' . $classDefinition->getCompleteName() . ' does not extend any class', $expression);
                 } else {
                     $classDefinition = $classDefinition->getExtendsClassDefinition();
                 }
             }
         }
     }
     if (!$classDefinition->hasProperty($property)) {
         throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $expression);
     }
     /** @var $propertyDefinition ClassProperty */
     $propertyDefinition = $classDefinition->getProperty($property);
     if (!$propertyDefinition->isStatic()) {
         throw new CompilerException("Cannot access non-static property '" . $classDefinition->getCompleteName() . '::' . $property . "'", $expression);
     }
     if ($propertyDefinition->isPrivate()) {
         if ($classDefinition != $compilationContext->classDefinition) {
             throw new CompilerException("Cannot access private static property '" . $classDefinition->getCompleteName() . '::' . $property . "' out of its declaring context", $expression);
         }
     }
     if ($propertyDefinition->isProtected()) {
         if ($classDefinition != $compilationContext->classDefinition && $classDefinition != $compilationContext->classDefinition->getExtendsClassDefinition()) {
             throw new CompilerException("Cannot access protected static property '" . $classDefinition->getCompleteName() . '::' . $property . "' out of its declaring context", $expression);
         }
     }
     /**
      * Resolves the symbol that expects the value
      */
     if ($this->_expecting) {
         if ($this->_expectingVariable) {
             $symbolVariable = $this->_expectingVariable;
             if ($symbolVariable->getName() == 'return_value') {
                 $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
         }
     } else {
         $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
     }
     /**
      * Variable that receives property accesses must be polymorphic
      */
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Cannot use variable: " . $symbolVariable->getType() . " to assign class constants", $expression);
     }
     $symbolVariable->setDynamicTypes('undefined');
     $compilationContext->headersManager->add('kernel/object');
     $readOnly = $this->_readOnly;
     if (!$readOnly) {
         if ($symbolVariable->getName() != 'return_value') {
             $symbolVariable->observeVariant($compilationContext);
         }
     }
     $compilationContext->backend->fetchStaticProperty($symbolVariable, $classDefinition, $property, $this->_readOnly, $compilationContext);
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Example #4
0
 /**
  * Access a static constant class
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $compiler =& $compilationContext->compiler;
     $className = $expression['left']['value'];
     $constant = $expression['right']['value'];
     /**
      * Fetch the class definition according to the class where the constant
      * is supposed to be declared
      */
     if (!in_array($className, array('this', 'self', 'static', 'parent'))) {
         $className = $compilationContext->getFullName($className);
         if ($compiler->isClass($className) || $compiler->isInterface($className)) {
             $classDefinition = $compiler->getClassDefinition($className);
         } else {
             if ($compiler->isBundledClass($className) || $compiler->isBundledInterface($className)) {
                 $classDefinition = $compiler->getInternalClassDefinition($className);
             } else {
                 throw new CompilerException("Cannot locate class '" . $className . "'", $expression['left']);
             }
         }
     } else {
         if (in_array($className, array('self', 'static', 'this'))) {
             $classDefinition = $compilationContext->classDefinition;
         } else {
             if ($className == 'parent') {
                 $classDefinition = $compilationContext->classDefinition;
                 $extendsClass = $classDefinition->getExtendsClass();
                 if (!$extendsClass) {
                     throw new CompilerException('Cannot find constant called "' . $constant . '" on parent because class ' . $classDefinition->getCompleteName() . ' does not extend any class', $expression);
                 } else {
                     $classDefinition = $classDefinition->getExtendsClassDefinition();
                 }
             }
         }
     }
     /**
      * Constants are resolved to their values at compile time
      * so we need to check that they effectively do exist
      */
     if (!$classDefinition->hasConstant($constant)) {
         throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a constant called: '" . $constant . "'", $expression);
     }
     /**
      * We can optimize the reading of constants by avoiding query their value every time
      */
     if (!$compilationContext->config->get('static-constant-class-folding', 'optimizations')) {
         /**
          * Resolves the symbol that expects the value
          */
         if ($this->_expecting) {
             if ($this->_expectingVariable) {
                 $symbolVariable = $this->_expectingVariable;
                 $symbolVariable->initVariant($compilationContext);
             } else {
                 $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
         }
         /**
          * Variable that receives property accesses must be polymorphic
          */
         if (!$symbolVariable->isVariable()) {
             throw new CompilerException("Cannot use variable: " . $symbolVariable->getType() . " to assign class constants", $expression);
         }
         $symbolVariable->setDynamicTypes('undefined');
         $compilationContext->headersManager->add('kernel/object');
         $compilationContext->codePrinter->output('zephir_get_class_constant(' . $symbolVariable->getName() . ', ' . $classDefinition->getClassEntry($compilationContext) . ', SS("' . $constant . '") TSRMLS_CC);');
         return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
     }
     $constantDefinition = $classDefinition->getConstant($constant);
     if ($constantDefinition instanceof ClassConstant) {
         $value = $constantDefinition->getValueValue();
         $type = $constantDefinition->getValueType();
     } else {
         $value = $constantDefinition;
         $type = gettype($value);
         if ($type == 'integer') {
             $type = 'int';
         }
     }
     switch ($type) {
         case 'string':
         case 'int':
         case 'double':
         case 'float':
         case 'bool':
         case 'null':
             break;
         default:
             $compilationContext->logger->warning($constantDefinition->getName(), 'nonexistent-constant', $expression);
             return new CompiledExpression('null', null, $expression);
     }
     /**
      * Return the value as a literal expression
      */
     return new CompiledExpression($type, $value, $expression);
 }