addSlashes() public static method

Prepares a string to be used as a C-string
public static addSlashes ( string $str, boolean $escapeSlash = false ) : string
$str string
$escapeSlash boolean
return string
Esempio n. 1
0
 /**
  * @param array $expression
  * @param Call $call
  * @param CompilationContext $context
  * @return bool|CompiledExpression|mixed
  * @throws CompilerException
  */
 public function optimize(array $expression, Call $call, CompilationContext $context)
 {
     if (!isset($expression['parameters'])) {
         return false;
     }
     if (count($expression['parameters']) != 2) {
         return false;
     }
     /**
      * Process the expected symbol to be returned
      */
     $call->processExpectedReturn($context);
     $symbolVariable = $call->getSymbolVariable();
     if ($symbolVariable->isNotVariableAndString()) {
         throw new CompilerException("Returned values by functions can only be assigned to variant variables", $expression);
     }
     if ($expression['parameters'][0]['parameter']['type'] == 'string') {
         $str = Utils::addSlashes($expression['parameters'][0]['parameter']['value']);
         unset($expression['parameters'][0]);
     }
     if ($call->mustInitSymbolVariable()) {
         $symbolVariable->initVariant($context);
     }
     $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
     $context->headersManager->add('kernel/string');
     $symbolVariable->setDynamicTypes('string');
     if (isset($str)) {
         $context->codePrinter->output('zephir_fast_join_str(' . $symbolVariable->getName() . ', SL("' . $str . '"), ' . $resolvedParams[0] . ' TSRMLS_CC);');
         return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
     }
     $context->codePrinter->output('zephir_fast_join(' . $symbolVariable->getName() . ', ' . $resolvedParams[0] . ', ' . $resolvedParams[1] . ' TSRMLS_CC);');
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Esempio n. 2
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/exception');
     $codePrinter = $compilationContext->codePrinter;
     $statement = $this->_statement;
     $expr = $statement['expr'];
     /**
      * This optimizes throw new Exception("hello")
      */
     if (!$compilationContext->insideTryCatch) {
         if (isset($expr['class'])) {
             if (isset($expr['parameters']) && count($expr['parameters']) == 1) {
                 if ($expr['parameters'][0]['parameter']['type'] == 'string') {
                     $className = Utils::getFullName($expr['class'], $compilationContext->classDefinition->getNamespace(), $compilationContext->aliasManager);
                     if ($compilationContext->compiler->isClass($className)) {
                         $classDefinition = $compilationContext->compiler->getClassDefinition($className);
                         $message = $expr['parameters'][0]['parameter']['value'];
                         $codePrinter->output('ZEPHIR_THROW_EXCEPTION_DEBUG_STR(' . $classDefinition->getClassEntry() . ', "' . Utils::addSlashes($message, true, Types::STRING) . '", "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ');');
                         $codePrinter->output('return;');
                         return;
                     } else {
                         if ($compilationContext->compiler->isInternalClass($className)) {
                             $classEntry = $compilationContext->classDefinition->getClassEntryByClassName($className, true);
                             if ($classEntry) {
                                 $message = $expr['parameters'][0]['parameter']['value'];
                                 $codePrinter->output('ZEPHIR_THROW_EXCEPTION_DEBUG_STR(' . $classEntry . ', "' . Utils::addSlashes($message, true, Types::STRING) . '", "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ');');
                                 $codePrinter->output('return;');
                                 return;
                             }
                         }
                     }
                 }
             }
         }
     }
     $throwExpr = new Expression($expr);
     $resolvedExpr = $throwExpr->compile($compilationContext);
     if ($resolvedExpr->getType() != 'variable') {
         throw new CompilerException("Expression '" . $resolvedExpr->getType() . '" cannot be used as exception', $expr);
     }
     $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $expr);
     if ($variableVariable->getType() != 'variable') {
         throw new CompilerException("Variable '" . $variableVariable->getType() . "' cannot be used as exception", $expr);
     }
     $codePrinter->output('zephir_throw_exception_debug(' . $variableVariable->getName() . ', "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ' TSRMLS_CC);');
     if (!$compilationContext->insideTryCatch) {
         $codePrinter->output('ZEPHIR_MM_RESTORE();');
         $codePrinter->output('return;');
     } else {
         $codePrinter->output('goto try_end_' . $compilationContext->insideTryCatch . ';');
         $codePrinter->outputBlankLine();
     }
     if ($variableVariable->isTemporal()) {
         $variableVariable->setIdle(true);
     }
 }
Esempio n. 3
0
 /**
  * @param array $expression
  * @param Call $call
  * @param CompilationContext $context
  * @return bool|CompiledExpression|mixed
  * @throws CompilerException
  */
 public function optimize(array $expression, Call $call, CompilationContext $context)
 {
     if (!isset($expression['parameters'])) {
         return false;
     }
     if (count($expression['parameters']) < 2) {
         throw new CompilerException("'explode' require two parameter");
     }
     /**
      * Process the expected symbol to be returned
      */
     $call->processExpectedReturn($context);
     $symbolVariable = $call->getSymbolVariable(true, $context);
     if ($symbolVariable->isNotVariableAndString()) {
         throw new CompilerException("Returned values by functions can only be assigned to variant variables", $expression);
     }
     /**
      * Process limit
      */
     $limit = 'LONG_MAX';
     $limitOffset = 2;
     if (count($expression['parameters']) == 3 && $expression['parameters'][2]['parameter']['type'] == 'int') {
         $limit = $expression['parameters'][2]['parameter']['value'] . ' ';
         unset($expression['parameters'][2]);
     }
     if ($expression['parameters'][0]['parameter']['type'] == 'string') {
         $str = Utils::addSlashes($expression['parameters'][0]['parameter']['value']);
         unset($expression['parameters'][0]);
         if (count($expression['parameters']) == 2) {
             $limitOffset = 1;
         }
     }
     $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
     if (isset($resolvedParams[$limitOffset])) {
         $context->headersManager->add('kernel/operators');
         $limit = 'zephir_get_intval(' . $resolvedParams[$limitOffset] . ') ';
     }
     $context->headersManager->add('kernel/string');
     $symbolVariable->setDynamicTypes('array');
     if ($call->mustInitSymbolVariable()) {
         $symbolVariable->initVariant($context);
     }
     $symbol = $context->backend->getVariableCode($symbolVariable);
     if (isset($str)) {
         $context->codePrinter->output('zephir_fast_explode_str(' . $symbol . ', SL("' . $str . '"), ' . $resolvedParams[0] . ', ' . $limit . ' TSRMLS_CC);');
         return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
     }
     $context->codePrinter->output('zephir_fast_explode(' . $symbol . ', ' . $resolvedParams[0] . ', ' . $resolvedParams[1] . ', ' . $limit . ' TSRMLS_CC);');
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Esempio n. 4
0
 /**
  * @param array $expression
  * @param Call $call
  * @param CompilationContext $context
  * @return bool|CompiledExpression|mixed
  */
 public function optimize(array $expression, Call $call, CompilationContext $context)
 {
     if (!isset($expression['parameters'])) {
         return false;
     }
     if (count($expression['parameters']) != 2) {
         return false;
     }
     if ($expression['parameters'][1]['parameter']['type'] == 'string') {
         $str = Utils::addSlashes($expression['parameters'][1]['parameter']['value']);
         unset($expression['parameters'][1]);
     }
     $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
     $context->headersManager->add('kernel/string');
     if (isset($str)) {
         return new CompiledExpression('bool', 'zephir_memnstr_str(' . $resolvedParams[0] . ', SL("' . $str . '"), "' . Compiler::getShortUserPath($expression['file']) . '", ' . $expression['line'] . ')', $expression);
     }
     return new CompiledExpression('bool', 'zephir_memnstr(' . $resolvedParams[0] . ', ' . $resolvedParams[1] . ', "' . Compiler::getShortUserPath($expression['file']) . '", ' . $expression['line'] . ')', $expression);
 }
 /**
  * @param array $expression
  * @param Call $call
  * @param CompilationContext $context
  * @return bool|CompiledExpression|mixed
  */
 public function optimize(array $expression, Call $call, CompilationContext $context)
 {
     if (!isset($expression['parameters'])) {
         return false;
     }
     if (count($expression['parameters']) != 2) {
         return false;
     }
     if ($expression['parameters'][1]['parameter']['type'] == 'string') {
         $str = Utils::addSlashes($expression['parameters'][1]['parameter']['value']);
         unset($expression['parameters'][1]);
     }
     $context->headersManager->add('kernel/object');
     $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
     if (isset($str)) {
         return new CompiledExpression('bool', '(zephir_method_exists_ex(' . $resolvedParams[0] . ', SS("' . strtolower($str) . '") TSRMLS_CC) == SUCCESS)', $expression);
     }
     return new CompiledExpression('bool', '(zephir_method_exists(' . $resolvedParams[0] . ', ' . $resolvedParams[1] . ' TSRMLS_CC)  == SUCCESS)', $expression);
 }
 /**
  * @param array $expression
  * @param Call $call
  * @param CompilationContext $context
  * @return bool|CompiledExpression|mixed
  */
 public function optimize(array $expression, Call $call, CompilationContext $context)
 {
     if (!isset($expression['parameters'])) {
         return false;
     }
     if (count($expression['parameters']) != 1) {
         return false;
     }
     if ($expression['parameters'][0]['parameter']['type'] == 'string') {
         $str = Utils::addSlashes($expression['parameters'][0]['parameter']['value']);
         unset($expression['parameters'][0]);
     }
     $context->headersManager->add('kernel/object');
     $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
     if (isset($str)) {
         /* TODO: Solve this macro stuff better, move to backend */
         $macro = $context->backend->isZE3() ? 'SL' : 'SS';
         return new CompiledExpression('bool', '(zephir_function_exists_ex(' . $macro . '("' . strtolower($str) . '") TSRMLS_CC) == SUCCESS)', $expression);
     }
     return new CompiledExpression('bool', '(zephir_function_exists(' . $resolvedParams[0] . ' TSRMLS_CC)  == SUCCESS)', $expression);
 }
Esempio n. 7
0
 public function declareConstant($type, $name, $value, CompilationContext $context)
 {
     $ce = $context->classDefinition->getClassEntry($context);
     $dType = null;
     switch ($type) {
         case 'bool':
             $value = $value == 'false' ? '0' : 1;
             break;
         case 'long':
         case 'int':
             $dType = 'long';
             break;
         case 'double':
             break;
         case 'string':
         case 'char':
             if ($type == 'string' || $type == 'char') {
                 $value = "\"" . Utils::addSlashes($value) . "\"";
             }
             $dType = 'string';
             break;
     }
     if (!isset($dType)) {
         $dType = $type;
     }
     if ($dType == 'null') {
         $context->codePrinter->output('zephir_declare_class_constant_null(' . $ce . ', SL("' . $name . '"));');
     } else {
         $context->codePrinter->output('zephir_declare_class_constant_' . $dType . '(' . $ce . ', SL("' . $name . '"), ' . $value . ');');
     }
 }
 /**
  * Resolves the access to a property in an object
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return \CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     $propertyAccess = $expression;
     $expr = new Expression($propertyAccess['left']);
     $exprVariable = $expr->compile($compilationContext);
     switch ($exprVariable->getType()) {
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprVariable->getCode(), $compilationContext, $expression);
             switch ($variableVariable->getType()) {
                 case 'variable':
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variableVariable->getType() . " cannot be used as object", $propertyAccess['left']);
             }
             break;
         default:
             throw new CompilerException("Cannot use expression: " . $exprVariable->getType() . " as an object", $propertyAccess['left']);
     }
     switch ($propertyAccess['right']['type']) {
         case 'variable':
             $propertyVariable = $compilationContext->symbolTable->getVariableForRead($propertyAccess['right']['value'], $compilationContext, $expression);
             break;
         case 'string':
             $propertyVariable = null;
             break;
         default:
             throw new CompilerException("Variable type: " . $propertyAccess['right']['type'] . " cannot be used as object", $propertyAccess['left']);
     }
     /**
      * Resolves the symbol that expects the value
      */
     if ($this->_expecting) {
         if ($this->_expectingVariable) {
             $symbolVariable = $this->_expectingVariable;
             if ($symbolVariable->getName() != 'return_value') {
                 $symbolVariable->observeVariant($compilationContext);
             } else {
                 $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
         }
     }
     /**
      * Variable that receives a property value must be polymorphic
      */
     if ($symbolVariable && !$symbolVariable->isVariable()) {
         throw new CompilerException("Cannot use variable: " . $symbolVariable->getType() . " to assign property value", $expression);
     }
     /**
      * At this point, we don't know the exact dynamic type fetched from the property
      */
     $symbolVariable->setDynamicTypes('undefined');
     $compilationContext->headersManager->add('kernel/object');
     $property = $propertyVariable ? $propertyVariable : Utils::addSlashes($expression['right']['value']);
     $compilationContext->backend->fetchProperty($symbolVariable, $variableVariable, $property, false, $compilationContext, false);
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Esempio n. 9
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $statement = $this->_statement;
     $codePrinter = $compilationContext->codePrinter;
     if (isset($statement['expr'])) {
         $currentMethod = $compilationContext->currentMethod;
         if ($currentMethod->isConstructor()) {
             throw new CompilerException("Constructors cannot return values", $statement['expr']);
         }
         if ($currentMethod->isVoid()) {
             throw new CompilerException("Method is marked as 'void' and it must not return any value", $statement['expr']);
         }
         /**
          * Use return member for properties on this
          */
         if ($statement['expr']['type'] == 'property-access') {
             if ($statement['expr']['left']['type'] == 'variable') {
                 if ($statement['expr']['left']['value'] == 'this') {
                     if ($statement['expr']['right']['type'] == 'variable') {
                         /**
                          * If the property is accessed on 'this', we check if the property does exist
                          */
                         $property = $statement['expr']['right']['value'];
                         $classDefinition = $compilationContext->classDefinition;
                         if (!$classDefinition->hasProperty($property)) {
                             throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement['expr']['right']);
                         }
                         $compilationContext->headersManager->add('kernel/object');
                         $codePrinter->output('RETURN_MM_MEMBER(this_ptr, "' . $property . '");');
                         return;
                     }
                 }
             }
         }
         /**
          * Fetches return_value and tries to return the value directly there
          */
         $variable = $compilationContext->symbolTable->getVariable('return_value');
         $expr = new Expression($statement['expr']);
         $expr->setExpectReturn(true, $variable);
         $expr->setReadOnly(true);
         $resolvedExpr = $expr->compile($compilationContext);
         /**
          * Here we check if the variable returns a compatible type according to its type hints
          */
         if ($currentMethod->hasReturnTypes()) {
             switch ($resolvedExpr->getType()) {
                 case 'null':
                     if (!$currentMethod->areReturnTypesNullCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'char':
                 case 'uchar':
                     if (!$currentMethod->areReturnTypesIntCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'bool':
                     if (!$currentMethod->areReturnTypesBoolCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'double':
                     if (!$currentMethod->areReturnTypesDoubleCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'string':
                     if (!$currentMethod->areReturnTypesStringCompatible()) {
                         throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                     }
                     break;
                 case 'variable':
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['expr']);
                     switch ($symbolVariable->getType()) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'char':
                         case 'uchar':
                             if (!$currentMethod->areReturnTypesIntCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'double':
                             if (!$currentMethod->areReturnTypesDoubleCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'string':
                             if (!$currentMethod->areReturnTypesStringCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'bool':
                             if (!$currentMethod->areReturnTypesBoolCompatible()) {
                                 throw new CompilerException("Returning type: " . $resolvedExpr->getType() . " but this type is not compatible with return-type hints declared in the method", $statement['expr']);
                             }
                             break;
                         case 'variable':
                             break;
                     }
                     break;
             }
         }
         switch ($resolvedExpr->getType()) {
             case 'null':
                 $codePrinter->output('RETURN_MM_NULL();');
                 break;
             case 'int':
             case 'uint':
             case 'long':
             case 'char':
             case 'uchar':
                 $codePrinter->output('RETURN_MM_LONG(' . $resolvedExpr->getCode() . ');');
                 break;
             case 'bool':
                 $codePrinter->output('RETURN_MM_BOOL(' . $resolvedExpr->getBooleanCode() . ');');
                 break;
             case 'double':
                 $codePrinter->output('RETURN_MM_DOUBLE(' . $resolvedExpr->getCode() . ');');
                 break;
             case 'string':
             case 'istring':
                 $codePrinter->output('RETURN_MM_STRING("' . Utils::addSlashes($resolvedExpr->getCode()) . '", 1);');
                 break;
             case 'array':
                 if ($resolvedExpr->getCode() != 'return_value') {
                     $codePrinter->output('RETURN_CTOR(' . $resolvedExpr->getCode() . ');');
                 } else {
                     $codePrinter->output('RETURN_MM();');
                 }
                 break;
             case 'variable':
                 if (!isset($symbolVariable)) {
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['expr']);
                 }
                 switch ($symbolVariable->getType()) {
                     case 'int':
                     case 'uint':
                     case 'long':
                     case 'char':
                     case 'uchar':
                         $codePrinter->output('RETURN_MM_LONG(' . $symbolVariable->getName() . ');');
                         break;
                     case 'double':
                         $codePrinter->output('RETURN_MM_DOUBLE(' . $symbolVariable->getName() . ');');
                         break;
                     case 'string':
                     case 'array':
                         $codePrinter->output('RETURN_CTOR(' . $resolvedExpr->getCode() . ');');
                         break;
                     case 'bool':
                         $codePrinter->output('RETURN_MM_BOOL(' . $symbolVariable->getName() . ');');
                         break;
                     case 'variable':
                         if ($symbolVariable->getName() == 'this_ptr') {
                             $codePrinter->output('RETURN_THIS();');
                         } else {
                             if ($symbolVariable->getName() != 'return_value') {
                                 if (!$symbolVariable->isExternal()) {
                                     if ($symbolVariable->isLocalOnly()) {
                                         $codePrinter->output('RETURN_LCTOR(' . $symbolVariable->getName() . ');');
                                     } else {
                                         if (!$symbolVariable->isMemoryTracked()) {
                                             $codePrinter->output('RETURN_CTOR(' . $symbolVariable->getName() . ');');
                                         } else {
                                             $codePrinter->output('RETURN_CCTOR(' . $symbolVariable->getName() . ');');
                                         }
                                     }
                                 } else {
                                     $codePrinter->output('RETVAL_ZVAL(' . $symbolVariable->getName() . ', 1, 0);');
                                     $codePrinter->output('RETURN_MM();');
                                 }
                             } else {
                                 $codePrinter->output('RETURN_MM();');
                             }
                         }
                         if ($symbolVariable->isTemporal()) {
                             $symbolVariable->setIdle(true);
                         }
                         break;
                     default:
                         throw new CompilerException("Cannot return variable '" . $symbolVariable->getType() . "'", $statement['expr']);
                 }
                 break;
             default:
                 throw new CompilerException("Cannot return '" . $resolvedExpr->getType() . "'", $statement['expr']);
         }
         return;
     }
     /**
      * Return without an expression
      */
     $codePrinter->output('RETURN_MM_NULL();');
 }
Esempio n. 10
0
 /**
  * Resolve parameters using zvals in the stack and without allocating memory for constants
  *
  * @param array $parameters
  * @param CompilationContext $compilationContext
  * @param array $expression
  * @return array
  */
 public function getReadOnlyResolvedParams($parameters, CompilationContext $compilationContext, array $expression)
 {
     $codePrinter = $compilationContext->codePrinter;
     $exprParams = $this->getResolvedParamsAsExpr($parameters, $compilationContext, $expression, true);
     $params = array();
     $types = array();
     $dynamicTypes = array();
     foreach ($exprParams as $compiledExpression) {
         $expression = $compiledExpression->getOriginal();
         switch ($compiledExpression->getType()) {
             case 'null':
                 $params[] = $compilationContext->backend->resolveValue('null', $compilationContext);
                 $types[] = 'null';
                 $dynamicTypes[] = 'null';
                 break;
             case 'int':
             case 'uint':
             case 'long':
                 $parameterVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext, true);
                 $compilationContext->backend->assignLong($parameterVariable, $compiledExpression->getCode(), $compilationContext);
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'char':
             case 'uchar':
                 $parameterVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext, true);
                 $compilationContext->backend->assignLong($parameterVariable, '\'' . $compiledExpression->getCode() . '\'', $compilationContext);
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'double':
                 $parameterVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext, true);
                 $codePrinter->output('ZVAL_DOUBLE(&' . $parameterVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'bool':
                 if ($compiledExpression->getCode() == 'true') {
                     $params[] = $compilationContext->backend->resolveValue('true', $compilationContext);
                 } else {
                     if ($compiledExpression->getCode() == 'false') {
                         $params[] = $compilationContext->backend->resolveValue('false', $compilationContext);
                     } else {
                         throw new Exception('?');
                     }
                 }
                 $types[] = 'bool';
                 $dynamicTypes[] = 'bool';
                 break;
             case 'ulong':
             case 'string':
             case 'istring':
                 if ($compilationContext->backend->getName() == 'ZendEngine2') {
                     $parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                 } else {
                     $parameterVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
                 }
                 $compilationContext->backend->assignString($parameterVariable, Utils::addSlashes($compiledExpression->getCode()), $compilationContext, true, false);
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'array':
                 $parameterVariable = $compilationContext->symbolTable->getVariableForRead($compiledExpression->getCode(), $compilationContext, $expression);
                 $params[] = $compilationContext->backend->getVariableCode($parameterVariable);
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'variable':
                 $parameterVariable = $compilationContext->symbolTable->getVariableForRead($compiledExpression->getCode(), $compilationContext, $expression);
                 switch ($parameterVariable->getType()) {
                     case 'int':
                     case 'uint':
                     case 'long':
                     case 'ulong':
                         $parameterTempVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext, true);
                         $codePrinter->output('ZVAL_LONG(&' . $parameterTempVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                         $params[] = '&' . $parameterTempVariable->getName();
                         $types[] = $parameterTempVariable->getType();
                         $dynamicTypes[] = $parameterTempVariable->getType();
                         $this->_temporalVariables[] = $parameterTempVariable;
                         break;
                     case 'char':
                     case 'uchar':
                         $parameterTempVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext, true);
                         $codePrinter->output('ZVAL_LONG(&' . $parameterTempVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                         $params[] = '&' . $parameterTempVariable->getName();
                         $types[] = $parameterTempVariable->getType();
                         $dynamicTypes[] = $parameterTempVariable->getType();
                         $this->_temporalVariables[] = $parameterTempVariable;
                         break;
                     case 'double':
                         $parameterTempVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext, true);
                         $codePrinter->output('ZVAL_DOUBLE(&' . $parameterTempVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                         $params[] = '&' . $parameterTempVariable->getName();
                         $types[] = $parameterTempVariable->getType();
                         $dynamicTypes[] = $parameterTempVariable->getType();
                         $this->_temporalVariables[] = $parameterTempVariable;
                         break;
                     case 'bool':
                         $parameterTempVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext, true);
                         $compilationContext->backend->assignBool($parameterTempVariable, '(' . $parameterVariable->getName() . ' ? 1 : 0)', $compilationContext);
                         $params[] = $compilationContext->backend->getVariableCode($parameterTempVariable);
                         $dynamicTypes[] = $parameterTempVariable->getType();
                         $types[] = $parameterTempVariable->getType();
                         break;
                     case 'string':
                     case 'variable':
                     case 'array':
                         $params[] = $compilationContext->backend->getVariableCode($parameterVariable);
                         $dynamicTypes[] = $parameterVariable->getType();
                         $types[] = $parameterVariable->getType();
                         break;
                     default:
                         throw new CompilerException("Cannot use variable type: " . $parameterVariable->getType() . " as parameter", $expression);
                 }
                 break;
             default:
                 throw new CompilerException("Cannot use value type: " . $compiledExpression->getType() . " as parameter", $expression);
         }
     }
     $this->_resolvedTypes = $types;
     $this->_resolvedDynamicTypes = $dynamicTypes;
     return $params;
 }
Esempio n. 11
0
 /**
  * Produce the code to register a class constant
  *
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  * @throws Exception
  */
 public function compile(CompilationContext $compilationContext)
 {
     if ($this->value['type'] == 'static-constant-access') {
         $name = $this->value['left']['value'] . '::' . $this->value['right']['value'];
         if (defined($name)) {
             $value = constant($name);
             if (is_int($value)) {
                 $this->value['type'] = 'int';
                 $this->value['value'] = $value;
             } elseif (is_float($value)) {
                 $this->value['type'] = 'double';
                 $this->value['value'] = $value;
             } elseif (is_bool($value)) {
                 $this->value['type'] = 'bool';
                 if (!$value) {
                     $this->value['value'] = 'false';
                 } else {
                     $this->value['value'] = 'true';
                 }
             } elseif (is_string($value)) {
                 $this->value['type'] = 'string';
                 $this->value['value'] = $value;
             } elseif (is_null($value)) {
                 $this->value['type'] = 'null';
             }
         }
     }
     switch ($this->value['type']) {
         case 'constant':
             $constant = new Constants();
             $compiledExpression = $constant->compile($this->value, $compilationContext);
             $this->value['type'] = $compiledExpression->getType();
             $this->value['value'] = $compiledExpression->getCode();
             /**
              * With no-break this will be broken (unexpected), use re-compile for new type pass
              * @todo review variant without break
              */
             $this->compile($compilationContext);
             break;
         case 'long':
         case 'int':
             $compilationContext->codePrinter->output("zend_declare_class_constant_long(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), " . $this->value['value'] . " TSRMLS_CC);");
             break;
         case 'double':
             $compilationContext->codePrinter->output("zend_declare_class_constant_double(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), " . $this->value['value'] . " TSRMLS_CC);");
             break;
         case 'bool':
             if ($this->value['value'] == 'false') {
                 $compilationContext->codePrinter->output("zend_declare_class_constant_bool(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), 0 TSRMLS_CC);");
             } else {
                 $compilationContext->codePrinter->output("zend_declare_class_constant_bool(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), 1 TSRMLS_CC);");
             }
             break;
         case 'string':
         case 'char':
             $compilationContext->codePrinter->output("zend_declare_class_constant_string(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), \"" . Utils::addSlashes($this->value['value']) . "\" TSRMLS_CC);");
             break;
         case 'null':
             $compilationContext->codePrinter->output("zend_declare_class_constant_null(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\") TSRMLS_CC);");
             break;
         default:
             throw new CompilerException('Type "' . $this->value['type'] . '" is not supported.');
     }
 }
Esempio n. 12
0
 /**
  * Declare class property with default value
  *
  * @param CompilationContext $compilationContext
  * @param $type
  * @param $value
  * @throws CompilerException
  */
 protected function declareProperty(CompilationContext $compilationContext, $type, $value)
 {
     $codePrinter = $compilationContext->codePrinter;
     if (is_object($value)) {
         //fix this
         return;
     }
     switch ($type) {
         case 'long':
         case 'int':
             $codePrinter->output("zend_declare_property_long(" . $compilationContext->classDefinition->getClassEntry() . ", SL(\"" . $this->getName() . "\"), " . $value . ", " . $this->getVisibilityAccesor() . " TSRMLS_CC);");
             break;
         case 'double':
             $codePrinter->output("zend_declare_property_double(" . $compilationContext->classDefinition->getClassEntry() . ", SL(\"" . $this->getName() . "\"), " . $value . ", " . $this->getVisibilityAccesor() . " TSRMLS_CC);");
             break;
         case 'bool':
             $codePrinter->output("zend_declare_property_bool(" . $compilationContext->classDefinition->getClassEntry() . ", SL(\"" . $this->getName() . "\"), " . $this->getBooleanCode($value) . ", " . $this->getVisibilityAccesor() . " TSRMLS_CC);");
             break;
         case Types::CHAR:
         case Types::STRING:
             $codePrinter->output("zend_declare_property_string(" . $compilationContext->classDefinition->getClassEntry() . ", SL(\"" . $this->getName() . "\"), \"" . Utils::addSlashes($value, true, $type) . "\", " . $this->getVisibilityAccesor() . " TSRMLS_CC);");
             break;
         case 'array':
         case 'empty-array':
         case 'null':
             $codePrinter->output("zend_declare_property_null(" . $compilationContext->classDefinition->getClassEntry() . ", SL(\"" . $this->getName() . "\"), " . $this->getVisibilityAccesor() . " TSRMLS_CC);");
             break;
         default:
             throw new CompilerException('Unknown default type: ' . $type, $this->original);
     }
 }
Esempio n. 13
0
File: Call.php Progetto: edin/zephir
 /**
  * Resolve parameters using zvals in the stack and without allocating memory for constants
  *
  * @param array $parameters
  * @param CompilationContext $compilationContext
  * @param array $expression
  * @return array
  */
 public function getReadOnlyResolvedParams($parameters, CompilationContext $compilationContext, array $expression)
 {
     $codePrinter = $compilationContext->codePrinter;
     $exprParams = $this->getResolvedParamsAsExpr($parameters, $compilationContext, $expression, true);
     $params = array();
     $types = array();
     $dynamicTypes = array();
     foreach ($exprParams as $compiledExpression) {
         $expression = $compiledExpression->getOriginal();
         switch ($compiledExpression->getType()) {
             case 'null':
                 $params[] = 'ZEPHIR_GLOBAL(global_null)';
                 $types[] = 'null';
                 $dynamicTypes[] = 'null';
                 break;
             case 'int':
             case 'uint':
             case 'long':
                 $parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                 $codePrinter->output('ZVAL_LONG(&' . $parameterVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'char':
             case 'uchar':
                 $parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                 $codePrinter->output('ZVAL_LONG(&' . $parameterVariable->getName() . ', \'' . $compiledExpression->getCode() . '\');');
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'double':
                 $parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                 $codePrinter->output('ZVAL_DOUBLE(&' . $parameterVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'bool':
                 if ($compiledExpression->getCode() == 'true') {
                     $params[] = 'ZEPHIR_GLOBAL(global_true)';
                 } else {
                     if ($compiledExpression->getCode() == 'false') {
                         $params[] = 'ZEPHIR_GLOBAL(global_false)';
                     } else {
                         throw new Exception('?');
                     }
                 }
                 $types[] = 'bool';
                 $dynamicTypes[] = 'bool';
                 break;
             case 'ulong':
             case 'string':
             case 'istring':
                 $parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                 $codePrinter->output('ZVAL_STRING(&' . $parameterVariable->getName() . ', "' . Utils::addSlashes($compiledExpression->getCode()) . '", 0);');
                 $this->_temporalVariables[] = $parameterVariable;
                 $params[] = '&' . $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'array':
                 $parameterVariable = $compilationContext->symbolTable->getVariableForRead($compiledExpression->getCode(), $compilationContext, $expression);
                 $params[] = $parameterVariable->getName();
                 $types[] = $parameterVariable->getType();
                 $dynamicTypes[] = $parameterVariable->getType();
                 break;
             case 'variable':
                 $parameterVariable = $compilationContext->symbolTable->getVariableForRead($compiledExpression->getCode(), $compilationContext, $expression);
                 switch ($parameterVariable->getType()) {
                     case 'int':
                     case 'uint':
                     case 'long':
                     case 'ulong':
                         $parameterTempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                         $codePrinter->output('ZVAL_LONG(&' . $parameterTempVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                         $params[] = '&' . $parameterTempVariable->getName();
                         $types[] = $parameterVariable->getType();
                         $dynamicTypes[] = $parameterVariable->getType();
                         $this->_temporalVariables[] = $parameterTempVariable;
                         break;
                     case 'char':
                     case 'uchar':
                         $parameterTempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                         $codePrinter->output('ZVAL_LONG(&' . $parameterTempVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                         $params[] = '&' . $parameterTempVariable->getName();
                         $types[] = $parameterVariable->getType();
                         $dynamicTypes[] = $parameterVariable->getType();
                         $this->_temporalVariables[] = $parameterTempVariable;
                         break;
                     case 'double':
                         $parameterTempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                         $codePrinter->output('ZVAL_DOUBLE(&' . $parameterTempVariable->getName() . ', ' . $compiledExpression->getCode() . ');');
                         $params[] = '&' . $parameterTempVariable->getName();
                         $types[] = $parameterVariable->getType();
                         $dynamicTypes[] = $parameterVariable->getType();
                         $this->_temporalVariables[] = $parameterTempVariable;
                         break;
                     case 'bool':
                         $params[] = '(' . $parameterVariable->getName() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false))';
                         $dynamicTypes[] = $parameterVariable->getType();
                         $types[] = $parameterVariable->getType();
                         break;
                     case 'string':
                     case 'variable':
                     case 'array':
                         if ($parameterVariable->isLocalOnly()) {
                             $params[] = '&' . $parameterVariable->getName();
                         } else {
                             $params[] = $parameterVariable->getName();
                         }
                         $dynamicTypes[] = $parameterVariable->getType();
                         $types[] = $parameterVariable->getType();
                         break;
                     default:
                         throw new CompilerException("Cannot use variable type: " . $parameterVariable->getType() . " as parameter", $expression);
                 }
                 break;
             default:
                 throw new CompilerException("Cannot use value type: " . $compiledExpression->getType() . " as parameter", $expression);
         }
     }
     $this->_resolvedTypes = $types;
     $this->_resolvedDynamicTypes = $dynamicTypes;
     return $params;
 }
Esempio n. 14
0
 /**
  * Compiles traversing of string values
  * - Evaluated expression must be a string
  * - Every key must be an integer or compatible
  * - Every value must be a char/integer or compatible
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @param Variable $exprVariable
  */
 public function compileStringTraverse($expression, CompilationContext $compilationContext, $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']);
             switch ($keyVariable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     break;
                 default:
                     throw new CompilerException("Cannot use variable: " . $this->_statement['key'] . " type: " . $keyVariable->getType() . " as key in string traversal", $this->_statement['expr']);
             }
         } else {
             $keyVariable = $compilationContext->symbolTable->getTempVariableForWrite('int', $compilationContext);
             $keyVariable->increaseUses();
         }
         $keyVariable->setMustInitNull(true);
         $keyVariable->setIsInitialized(true, $compilationContext, $this->_statement);
     }
     /**
      * Initialize 'value' variable
      */
     if (isset($this->_statement['value'])) {
         if ($this->_statement['value'] != '_') {
             $variable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['value'], $compilationContext, $this->_statement['expr']);
             switch ($variable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     break;
                 default:
                     throw new CompilerException("Cannot use variable: " . $this->_statement['value'] . " type: " . $variable->getType() . " as value in string traversal", $this->_statement['expr']);
             }
         } else {
             $variable = $compilationContext->symbolTable->getTempVariableForWrite('char', $compilationContext);
             $variable->increaseUses();
         }
         $variable->setMustInitNull(true);
         $variable->setIsInitialized(true, $compilationContext, $this->_statement);
     }
     $tempVariable = $compilationContext->symbolTable->addTemp('long', $compilationContext);
     /**
      * Create a temporary value to store the constant string
      */
     if ($expression->getType() == 'string') {
         $constantVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $this->_statement);
         $compilationContext->backend->assignString($constantVariable, Utils::addSlashes($expression->getCode()), $compilationContext, true, false);
         $stringVariable = $constantVariable;
     } else {
         $stringVariable = $exprVariable;
     }
     $stringVariableCode = $compilationContext->backend->getVariableCode($stringVariable);
     if ($this->_statement['reverse']) {
         $codePrinter->output('for (' . $tempVariable->getName() . ' = Z_STRLEN_P(' . $stringVariableCode . '); ' . $tempVariable->getName() . ' >= 0; ' . $tempVariable->getName() . '--) {');
     } else {
         $codePrinter->output('for (' . $tempVariable->getName() . ' = 0; ' . $tempVariable->getName() . ' < Z_STRLEN_P(' . $stringVariableCode . '); ' . $tempVariable->getName() . '++) {');
     }
     if (isset($this->_statement['key'])) {
         $codePrinter->output("\t" . $keyVariable->getName() . ' = ' . $tempVariable->getName() . '; ');
     }
     $compilationContext->headersManager->add('kernel/operators');
     $codePrinter->output("\t" . $variable->getName() . ' = ZEPHIR_STRING_OFFSET(' . $stringVariableCode . ', ' . $tempVariable->getName() . ');');
     /**
      * Variables are initialized in a different way inside cycle
      */
     $compilationContext->insideCycle++;
     /**
      * Compile statements in the 'for' block
      */
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $st->isLoop(true);
         if (isset($this->_statement['key'])) {
             $st->getMutateGatherer()->increaseMutations($this->_statement['key']);
         }
         $st->getMutateGatherer()->increaseMutations($this->_statement['value']);
         $st->compile($compilationContext);
     }
     $compilationContext->insideCycle--;
     $codePrinter->output('}');
 }
Esempio n. 15
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     foreach ($this->_statement['expressions'] as $echoExpr) {
         $expr = new Expression($echoExpr);
         $expr->setReadOnly(true);
         $resolvedExpr = $expr->compile($compilationContext);
         switch ($resolvedExpr->getType()) {
             case 'int':
                 $compilationContext->codePrinter->output('php_printf("%d", ' . $resolvedExpr->getCode() . ');');
                 break;
             case 'bool':
                 $compilationContext->codePrinter->output('php_printf("%s", ' . $resolvedExpr->getBooleanCode() . ' ? "1": "");');
                 break;
             case 'double':
                 $compilationContext->codePrinter->output('php_printf("%f", ' . $resolvedExpr->getCode() . ');');
                 break;
             case 'char':
             case 'uchar':
                 $compilationContext->codePrinter->output('php_printf("%c", \'' . $resolvedExpr->getCode() . '\');');
                 break;
             case 'long':
                 $compilationContext->codePrinter->output('php_printf("%ld", ' . $resolvedExpr->getCode() . ');');
                 break;
             case 'string':
                 $compilationContext->codePrinter->output('php_printf("' . Utils::addSlashes($resolvedExpr->getCode()) . '");');
                 break;
             case 'null':
                 break;
             case 'variable':
                 $variable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $echoExpr);
                 switch ($variable->getType()) {
                     case 'int':
                         $compilationContext->codePrinter->output('php_printf("%d", ' . $variable->getName() . ');');
                         break;
                     case 'long':
                         $compilationContext->codePrinter->output('php_printf("%ld", ' . $variable->getName() . ');');
                         break;
                     case 'double':
                         $compilationContext->codePrinter->output('php_printf("%f", ' . $variable->getName() . ');');
                         break;
                     case 'uchar':
                     case 'char':
                         $compilationContext->codePrinter->output('php_printf("%c", ' . $variable->getName() . ');');
                         break;
                     case 'bool':
                         $compilationContext->codePrinter->output('php_printf("%s", ' . $variable->getName() . ' ? "1": "");');
                         break;
                     case 'string':
                     case 'variable':
                         $compilationContext->codePrinter->output('zend_print_zval(' . $variable->getName() . ', 0);');
                         break;
                     case 'null':
                         break;
                     default:
                         throw new CompilerException("Unknown type: " . $variable->getType(), $echoExpr);
                 }
                 break;
             default:
                 throw new CompilerException("Unknown type: " . $resolvedExpr->getType(), $echoExpr);
         }
     }
 }
Esempio n. 16
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);
     }
 }
Esempio n. 17
0
 /**
  * Compiles the method
  *
  * @param CompilationContext $compilationContext
  * @return null
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     /**
      * Set the method currently being compiled
      */
     $compilationContext->currentMethod = $this;
     if (is_object($this->_statements)) {
         /**
          * This pass checks for zval variables than can be potentially
          * used without allocating memory and track it
          * these variables are stored in the stack
          */
         if ($compilationContext->config->get('local-context-pass', 'optimizations')) {
             $localContext = new LocalContextPass();
             $localContext->pass($this->_statements);
         } else {
             $localContext = null;
         }
         /**
          * This pass tries to infer types for dynamic variables
          * replacing them by low level variables
          */
         if ($compilationContext->config->get('static-type-inference', 'optimizations')) {
             $typeInference = new StaticTypeInference();
             $typeInference->pass($this->_statements);
             if ($compilationContext->config->get('static-type-inference-second-pass', 'optimizations')) {
                 $typeInference->reduce();
                 $typeInference->pass($this->_statements);
             }
         } else {
             $typeInference = null;
         }
         /**
          * This pass counts how many times a specific
          */
         if ($compilationContext->config->get('call-gatherer-pass', 'optimizations')) {
             $callGathererPass = new CallGathererPass($compilationContext);
             $callGathererPass->pass($this->_statements);
         } else {
             $callGathererPass = null;
         }
     } else {
         $localContext = null;
         $typeInference = null;
         $callGathererPass = null;
     }
     /**
      * Every method has its own symbol table
      */
     $symbolTable = new SymbolTable($compilationContext);
     if ($localContext) {
         $symbolTable->setLocalContext($localContext);
     }
     /**
      * Parameters has an additional extra mutation
      */
     $parameters = $this->_parameters;
     if ($localContext) {
         if (is_object($parameters)) {
             foreach ($parameters->getParameters() as $parameter) {
                 $localContext->increaseMutations($parameter['name']);
             }
         }
     }
     /**
      * Initialization of parameters happens in a fictitious external branch
      */
     $branch = new Branch();
     $branch->setType(Branch::TYPE_EXTERNAL);
     /**
      * BranchManager helps to create graphs of conditional/loop/root/jump branches
      */
     $branchManager = new BranchManager();
     $branchManager->addBranch($branch);
     /**
      * Cache Manager manages both function and method call caches
      */
     $cacheManager = new CacheManager();
     $cacheManager->setGatherer($callGathererPass);
     $compilationContext->branchManager = $branchManager;
     $compilationContext->cacheManager = $cacheManager;
     $compilationContext->typeInference = $typeInference;
     $compilationContext->symbolTable = $symbolTable;
     $oldCodePrinter = $compilationContext->codePrinter;
     /**
      * Change the code printer to a single method instance
      */
     $codePrinter = new CodePrinter();
     $compilationContext->codePrinter = $codePrinter;
     /**
      * Set an empty function cache
      */
     $compilationContext->functionCache = null;
     /**
      * Reset try/catch and loop counter
      */
     $compilationContext->insideCycle = 0;
     $compilationContext->insideTryCatch = 0;
     if (is_object($parameters)) {
         /**
          * Round 1. Create variables in parameters in the symbol table
          */
         $classCastChecks = array();
         foreach ($parameters->getParameters() as $parameter) {
             /**
              * Change dynamic variables to low level types
              */
             if ($typeInference) {
                 if (isset($parameter['data-type'])) {
                     if ($parameter['data-type'] == 'variable') {
                         $type = $typeInference->getInferedType($parameter['name']);
                         if (is_string($type)) {
                             /* promote polymorphic parameters to low level types */
                         }
                     }
                 } else {
                     $type = $typeInference->getInferedType($parameter['name']);
                     if (is_string($type)) {
                         /* promote polymorphic parameters to low level types */
                     }
                 }
             }
             $symbolParam = null;
             if (isset($parameter['data-type'])) {
                 switch ($parameter['data-type']) {
                     case 'object':
                     case 'callable':
                     case 'resource':
                     case 'variable':
                         $symbol = $symbolTable->addVariable($parameter['data-type'], $parameter['name'], $compilationContext);
                         break;
                     default:
                         $symbol = $symbolTable->addVariable($parameter['data-type'], $parameter['name'], $compilationContext);
                         $symbolParam = $symbolTable->addVariable('variable', $parameter['name'] . '_param', $compilationContext);
                         if ($parameter['data-type'] == 'string' || $parameter['data-type'] == 'array') {
                             $symbol->setMustInitNull(true);
                         }
                         break;
                 }
             } else {
                 $symbol = $symbolTable->addVariable('variable', $parameter['name'], $compilationContext);
             }
             /**
              * Some parameters can be read-only
              */
             if (isset($parameter['const']) && $parameter['const']) {
                 $symbol->setReadOnly(true);
                 if (is_object($symbolParam)) {
                     $symbolParam->setReadOnly(true);
                 }
             }
             if (is_object($symbolParam)) {
                 /**
                  * Parameters are marked as 'external'
                  */
                 $symbolParam->setIsExternal(true);
                 /**
                  * Assuming they're initialized
                  */
                 $symbolParam->setIsInitialized(true, $compilationContext, $parameter);
                 /**
                  * Initialize auxiliar parameter zvals to null
                  */
                 $symbolParam->setMustInitNull(true);
                 /**
                  * Increase uses
                  */
                 $symbolParam->increaseUses();
             } else {
                 if (isset($parameter['default'])) {
                     if (isset($parameter['data-type'])) {
                         if ($parameter['data-type'] == 'variable') {
                             $symbol->setMustInitNull(true);
                         }
                     } else {
                         $symbol->setMustInitNull(true);
                     }
                 }
             }
             /**
              * Original node where the variable was declared
              */
             $symbol->setOriginal($parameter);
             /**
              * Parameters are marked as 'external'
              */
             $symbol->setIsExternal(true);
             /**
              * Assuming they're initialized
              */
             $symbol->setIsInitialized(true, $compilationContext, $parameter);
             /**
              * Variables with class/type must be objects across the execution
              */
             if (isset($parameter['cast'])) {
                 $symbol->setDynamicTypes('object');
                 $symbol->setClassTypes($compilationContext->getFullName($parameter['cast']['value']));
                 $classCastChecks[] = array($symbol, $parameter);
             } else {
                 if (isset($parameter['data-type'])) {
                     if ($parameter['data-type'] == 'variable') {
                         $symbol->setDynamicTypes('undefined');
                     }
                 } else {
                     $symbol->setDynamicTypes('undefined');
                 }
             }
         }
         $compilationContext->codePrinter->increaseLevel();
         /**
          * Checks that a class-hinted variable meets its declaration
          */
         foreach ($classCastChecks as $classCastCheck) {
             foreach ($classCastCheck[0]->getClassTypes() as $className) {
                 /**
                  * If the parameter is nullable check it must pass the 'instanceof' validation
                  */
                 if (!isset($classCastCheck[1]['default'])) {
                     $evalExpr = new UnaryOperatorBuilder('not', new BinaryOperatorBuilder('instanceof', new VariableBuilder($classCastCheck[0]->getName()), new VariableBuilder('\\' . $className)));
                 } else {
                     $evalExpr = new BinaryOperatorBuilder('and', new BinaryOperatorBuilder('not-equals', new TypeOfOperatorBuilder(new VariableBuilder($classCastCheck[0]->getName())), new LiteralBuilder("string", "null")), new UnaryOperatorBuilder('not', new BinaryOperatorBuilder('instanceof', new VariableBuilder($classCastCheck[0]->getName()), new VariableBuilder('\\' . $className))));
                 }
                 $ifCheck = new IfStatementBuilder($evalExpr, new StatementsBlockBuilder(array(new ThrowStatementBuilder(new NewInstanceOperatorBuilder('\\InvalidArgumentException', array(new ParameterBuilder(new LiteralBuilder("string", "Parameter '" . $classCastCheck[0]->getName() . "' must be an instance of '" . Utils::escapeClassName($className) . "'"))))))));
                 $ifStatement = new IfStatement($ifCheck->get());
                 $ifStatement->compile($compilationContext);
             }
         }
         $compilationContext->codePrinter->decreaseLevel();
     }
     /**
      * Compile the block of statements if any
      */
     if (is_object($this->_statements)) {
         if ($this->hasModifier('static')) {
             $compilationContext->staticContext = true;
         } else {
             $compilationContext->staticContext = false;
         }
         /**
          * Compile the statements block as a 'root' branch
          */
         $this->_statements->compile($compilationContext, false, Branch::TYPE_ROOT);
     }
     /**
      * Initialize default values in dynamic variables
      */
     $initVarCode = "";
     foreach ($symbolTable->getVariables() as $variable) {
         /**
          * Initialize 'dynamic' variables with default values
          */
         if ($variable->getType() == 'variable') {
             if ($variable->getNumberUses() > 0) {
                 if ($variable->getName() != 'this_ptr' && $variable->getName() != 'return_value' && $variable->getName() != 'return_value_ptr') {
                     $defaultValue = $variable->getDefaultInitValue();
                     if (is_array($defaultValue)) {
                         $symbolTable->mustGrownStack(true);
                         switch ($defaultValue['type']) {
                             case 'int':
                             case 'uint':
                             case 'long':
                             case 'char':
                             case 'uchar':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_LONG(' . $variable->getName() . ', ' . $defaultValue['value'] . ');' . PHP_EOL;
                                 break;
                             case 'null':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_NULL(' . $variable->getName() . ');' . PHP_EOL;
                                 break;
                             case 'double':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_DOUBLE(' . $variable->getName() . ', ' . $defaultValue['value'] . ');' . PHP_EOL;
                                 break;
                             case 'string':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_STRING(' . $variable->getName() . ', "' . Utils::addSlashes($defaultValue['value'], true) . '", 1);' . PHP_EOL;
                                 break;
                             case 'array':
                             case 'empty-array':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'array_init(' . $variable->getName() . ');' . PHP_EOL;
                                 break;
                             default:
                                 throw new CompilerException('Invalid default type: ' . $defaultValue['type'] . ' for data type: ' . $variable->getType(), $variable->getOriginal());
                         }
                     }
                 }
             }
             continue;
         }
         /**
          * Initialize 'string' variables with default values
          */
         if ($variable->getType() == 'string') {
             if ($variable->getNumberUses() > 0) {
                 $defaultValue = $variable->getDefaultInitValue();
                 if (is_array($defaultValue)) {
                     $symbolTable->mustGrownStack(true);
                     switch ($defaultValue['type']) {
                         case 'string':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'ZVAL_STRING(' . $variable->getName() . ', "' . Utils::addSlashes($defaultValue['value'], true) . '", 1);' . PHP_EOL;
                             break;
                         case 'null':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'ZVAL_EMPTY_STRING(' . $variable->getName() . ');' . PHP_EOL;
                             break;
                         default:
                             throw new CompilerException('Invalid default type: ' . $defaultValue['type'] . ' for data type: ' . $variable->getType(), $variable->getOriginal());
                     }
                 }
             }
             continue;
         }
         /**
          * Initialize 'array' variables with default values
          */
         if ($variable->getType() == 'array') {
             if ($variable->getNumberUses() > 0) {
                 $defaultValue = $variable->getDefaultInitValue();
                 if (is_array($defaultValue)) {
                     $symbolTable->mustGrownStack(true);
                     switch ($defaultValue['type']) {
                         case 'null':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'ZVAL_NULL(' . $variable->getName() . ');' . PHP_EOL;
                             break;
                         case 'array':
                         case 'empty-array':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'array_init(' . $variable->getName() . ');' . PHP_EOL;
                             break;
                         default:
                             throw new CompilerException('Invalid default type: ' . $defaultValue['type'] . ' for data type: ' . $variable->getType(), $variable->getOriginal());
                     }
                 }
             }
         }
     }
     /**
      * Fetch parameters from vm-top
      */
     $initCode = "";
     $code = "";
     if (is_object($parameters)) {
         /**
          * Round 2. Fetch the parameters in the method
          */
         $params = array();
         $requiredParams = array();
         $optionalParams = array();
         $numberRequiredParams = 0;
         $numberOptionalParams = 0;
         foreach ($parameters->getParameters() as $parameter) {
             if (isset($parameter['data-type'])) {
                 $dataType = $parameter['data-type'];
             } else {
                 $dataType = 'variable';
             }
             switch ($dataType) {
                 case 'object':
                 case 'callable':
                 case 'resource':
                 case 'variable':
                     $params[] = '&' . $parameter['name'];
                     break;
                 default:
                     $params[] = '&' . $parameter['name'] . '_param';
                     break;
             }
             if (isset($parameter['default'])) {
                 $optionalParams[] = $parameter;
                 $numberOptionalParams++;
             } else {
                 $requiredParams[] = $parameter;
                 $numberRequiredParams++;
             }
         }
         /**
          * Pass the write detector to the method statement block to check if the parameter
          * variable is modified so as do the proper separation
          */
         $parametersToSeparate = array();
         if (is_object($this->_statements)) {
             /**
              * If local context is not available
              */
             if (!$localContext) {
                 $writeDetector = new WriteDetector();
             }
             foreach ($parameters->getParameters() as $parameter) {
                 if (isset($parameter['data-type'])) {
                     $dataType = $parameter['data-type'];
                 } else {
                     $dataType = 'variable';
                 }
                 switch ($dataType) {
                     case 'variable':
                     case 'string':
                     case 'array':
                     case 'resource':
                     case 'object':
                     case 'callable':
                         $name = $parameter['name'];
                         if (!$localContext) {
                             if ($writeDetector->detect($name, $this->_statements->getStatements())) {
                                 $parametersToSeparate[$name] = true;
                             }
                         } else {
                             if ($localContext->getNumberOfMutations($name) > 1) {
                                 $parametersToSeparate[$name] = true;
                             }
                         }
                         break;
                 }
             }
         }
         /**
          * Initialize required parameters
          */
         foreach ($requiredParams as $parameter) {
             if (isset($parameter['mandatory'])) {
                 $mandatory = $parameter['mandatory'];
             } else {
                 $mandatory = 0;
             }
             if (isset($parameter['data-type'])) {
                 $dataType = $parameter['data-type'];
             } else {
                 $dataType = 'variable';
             }
             if ($dataType != 'variable') {
                 /**
                  * Assign value from zval to low level type
                  */
                 if ($mandatory) {
                     $initCode .= $this->checkStrictType($parameter, $compilationContext);
                 } else {
                     $initCode .= $this->assignZvalValue($parameter, $compilationContext);
                 }
             }
             switch ($dataType) {
                 case 'variable':
                 case 'string':
                 case 'array':
                 case 'resource':
                 case 'object':
                 case 'callable':
                     if (isset($parametersToSeparate[$parameter['name']])) {
                         $symbolTable->mustGrownStack(true);
                         $initCode .= "\t" . "ZEPHIR_SEPARATE_PARAM(" . $parameter['name'] . ");" . PHP_EOL;
                     }
                     break;
             }
         }
         /**
          * Initialize optional parameters
          */
         foreach ($optionalParams as $parameter) {
             if (isset($parameter['mandatory'])) {
                 $mandatory = $parameter['mandatory'];
             } else {
                 $mandatory = 0;
             }
             if (isset($parameter['data-type'])) {
                 $dataType = $parameter['data-type'];
             } else {
                 $dataType = 'variable';
             }
             switch ($dataType) {
                 case 'object':
                 case 'callable':
                 case 'resource':
                 case 'variable':
                     $name = $parameter['name'];
                     break;
                 default:
                     $name = $parameter['name'] . '_param';
                     break;
             }
             /**
              * Assign the default value according to the variable's type
              */
             $initCode .= "\t" . 'if (!' . $name . ') {' . PHP_EOL;
             $initCode .= $this->assignDefaultValue($parameter, $compilationContext);
             if (isset($parametersToSeparate[$name]) || $dataType != 'variable') {
                 $initCode .= "\t" . '} else {' . PHP_EOL;
                 if (isset($parametersToSeparate[$name])) {
                     $initCode .= "\t\t" . "ZEPHIR_SEPARATE_PARAM(" . $name . ");" . PHP_EOL;
                 } else {
                     if ($mandatory) {
                         $initCode .= $this->checkStrictType($parameter, $compilationContext, $mandatory);
                     } else {
                         $initCode .= "\t" . $this->assignZvalValue($parameter, $compilationContext);
                     }
                 }
             }
             $initCode .= "\t" . '}' . PHP_EOL;
         }
         /**
          * Fetch the parameters to zval pointers
          */
         $codePrinter->preOutputBlankLine();
         $compilationContext->headersManager->add('kernel/memory');
         if ($symbolTable->getMustGrownStack()) {
             $code .= "\t" . 'zephir_fetch_params(1, ' . $numberRequiredParams . ', ' . $numberOptionalParams . ', ' . join(', ', $params) . ');' . PHP_EOL;
         } else {
             $code .= "\t" . 'zephir_fetch_params(0, ' . $numberRequiredParams . ', ' . $numberOptionalParams . ', ' . join(', ', $params) . ');' . PHP_EOL;
         }
         $code .= PHP_EOL;
     }
     $code .= $initCode . $initVarCode;
     $codePrinter->preOutput($code);
     /**
      * Grow the stack if needed
      */
     if ($symbolTable->getMustGrownStack()) {
         $compilationContext->headersManager->add('kernel/memory');
         $codePrinter->preOutput("\t" . 'ZEPHIR_MM_GROW();');
     }
     /**
      * Check if there are unused variables
      */
     $usedVariables = array();
     $completeName = $compilationContext->classDefinition->getCompleteName();
     foreach ($symbolTable->getVariables() as $variable) {
         if ($variable->getNumberUses() <= 0) {
             if ($variable->isExternal() == false) {
                 $compilationContext->logger->warning('Variable "' . $variable->getName() . '" declared but not used in ' . $completeName . '::' . $this->getName(), "unused-variable", $variable->getOriginal());
                 continue;
             }
             $compilationContext->logger->warning('Variable "' . $variable->getName() . '" declared but not used in ' . $completeName . '::' . $this->getName(), "unused-variable-external", $variable->getOriginal());
         }
         if ($variable->getName() != 'this_ptr' && $variable->getName() != 'return_value' && $variable->getName() != 'return_value_ptr') {
             $type = $variable->getType();
             if (!isset($usedVariables[$type])) {
                 $usedVariables[$type] = array();
             }
             $usedVariables[$type][] = $variable;
         }
     }
     if (count($usedVariables)) {
         $codePrinter->preOutputBlankLine();
     }
     /**
      * Generate the variable definition for variables used
      */
     foreach ($usedVariables as $type => $variables) {
         $pointer = null;
         switch ($type) {
             case 'int':
                 $code = 'int ';
                 break;
             case 'uint':
                 $code = 'unsigned int ';
                 break;
             case 'char':
                 $code = 'char ';
                 break;
             case 'uchar':
                 $code = 'unsigned char ';
                 break;
             case 'long':
                 $code = 'long ';
                 break;
             case 'ulong':
                 $code = 'unsigned long ';
                 break;
             case 'bool':
                 $code = 'zend_bool ';
                 break;
             case 'double':
                 $code = 'double ';
                 break;
             case 'string':
             case 'variable':
             case 'array':
             case 'null':
                 $pointer = '*';
                 $code = 'zval ';
                 break;
             case 'HashTable':
                 $pointer = '*';
                 $code = 'HashTable ';
                 break;
             case 'HashPosition':
                 $code = 'HashPosition ';
                 break;
             case 'zend_class_entry':
                 $pointer = '*';
                 $code = 'zend_class_entry ';
                 break;
             case 'zend_function':
                 $pointer = '*';
                 $code = 'zend_function ';
                 break;
             case 'zend_object_iterator':
                 $pointer = '*';
                 $code = 'zend_object_iterator ';
                 break;
             case 'zend_property_info':
                 $pointer = '*';
                 $code = 'zend_property_info ';
                 break;
             case 'zephir_fcall_cache_entry':
                 $pointer = '*';
                 $code = 'zephir_fcall_cache_entry ';
                 break;
             case 'static_zephir_fcall_cache_entry':
                 $pointer = '*';
                 $code = 'zephir_nts_static zephir_fcall_cache_entry ';
                 break;
             default:
                 throw new CompilerException("Unsupported type in declare: " . $type);
         }
         $groupVariables = array();
         $defaultValues = array();
         /**
          * @var $variables Variable[]
          */
         foreach ($variables as $variable) {
             if (($type == 'variable' || $type == 'string' || $type == 'array' || $type == 'resource' || $type == 'callable' || $type == 'object') && $variable->mustInitNull()) {
                 if ($variable->isLocalOnly()) {
                     $groupVariables[] = $variable->getName() . ' = zval_used_for_init';
                 } else {
                     if ($variable->isDoublePointer()) {
                         $groupVariables[] = $pointer . $pointer . $variable->getName() . ' = NULL';
                     } else {
                         $groupVariables[] = $pointer . $variable->getName() . ' = NULL';
                     }
                 }
             } else {
                 if ($variable->isLocalOnly()) {
                     $groupVariables[] = $variable->getName();
                 } else {
                     if ($variable->isDoublePointer()) {
                         if ($variable->mustInitNull()) {
                             $groupVariables[] = $pointer . $pointer . $variable->getName() . ' = NULL';
                         } else {
                             $groupVariables[] = $pointer . $pointer . $variable->getName();
                         }
                     } else {
                         $defaultValue = $variable->getDefaultInitValue();
                         if ($defaultValue !== null) {
                             switch ($type) {
                                 case 'variable':
                                 case 'string':
                                 case 'array':
                                 case 'resource':
                                 case 'callable':
                                 case 'object':
                                     $groupVariables[] = $pointer . $variable->getName();
                                     break;
                                 default:
                                     $groupVariables[] = $pointer . $variable->getName() . ' = ' . $defaultValue;
                                     break;
                             }
                         } else {
                             if ($variable->mustInitNull() && $pointer) {
                                 $groupVariables[] = $pointer . $variable->getName() . ' = NULL';
                             } else {
                                 $groupVariables[] = $pointer . $variable->getName();
                             }
                         }
                     }
                 }
             }
         }
         $codePrinter->preOutput("\t" . $code . join(', ', $groupVariables) . ';');
     }
     /**
      * Finalize the method compilation
      */
     if (is_object($this->_statements)) {
         /**
          * If the last statement is not a 'return' or 'throw' we need to
          * restore the memory stack if needed
          */
         $lastType = $this->_statements->getLastStatementType();
         if ($lastType != 'return' && $lastType != 'throw' && !$this->hasChildReturnStatementType($this->_statements->getLastStatement())) {
             if ($symbolTable->getMustGrownStack()) {
                 $compilationContext->headersManager->add('kernel/memory');
                 $codePrinter->output("\t" . 'ZEPHIR_MM_RESTORE();');
             }
             /**
              * If a method has return-type hints we need to ensure the last statement is a 'return' statement
              */
             if ($this->hasReturnTypes()) {
                 throw new CompilerException('Reached end of the method without returning a valid type specified in the return-type hints', $this->_expression['return-type']);
             }
         }
     }
     /**
      * Remove macros that restore the memory stack if it wasn't used
      */
     $code = $this->removeMemoryStackReferences($symbolTable, $codePrinter->getOutput());
     /**
      * Restore the compilation context
      */
     $oldCodePrinter->output($code);
     $compilationContext->codePrinter = $oldCodePrinter;
     $compilationContext->branchManager = null;
     $compilationContext->cacheManager = null;
     $compilationContext->typeInference = null;
     $codePrinter->clear();
     return null;
 }
Esempio n. 18
0
 /**
  * Resolves a PHP constant value into C-code
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws \Zephir\CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $isPhpConstant = false;
     $isZephirConstant = false;
     $constantName = $expression['value'];
     $mergedConstants = array_merge($this->envConstans, $this->magickConstants, $this->resources);
     if (!defined($expression['value']) && !in_array($constantName, $mergedConstants)) {
         if (!$compilationContext->compiler->isConstant($constantName)) {
             $compilationContext->logger->warning("Constant '" . $constantName . "' does not exist at compile time", 'nonexistent-constant', $expression);
         } else {
             $isZephirConstant = true;
         }
     } else {
         if (strpos($constantName, 'VERSION') !== false) {
             $isPhpConstant = false;
         } else {
             $isPhpConstant = true;
         }
     }
     if ($isZephirConstant && !in_array($constantName, $this->resources)) {
         $constant = $compilationContext->compiler->getConstant($constantName);
         return new LiteralCompiledExpression($constant[0], $constant[1], $expression);
     }
     if ($isPhpConstant && !in_array($constantName, $mergedConstants)) {
         $constantName = constant($constantName);
         $type = strtolower(gettype($constantName));
         switch ($type) {
             case 'integer':
                 return new LiteralCompiledExpression('int', $constantName, $expression);
             case 'double':
                 return new LiteralCompiledExpression('double', $constantName, $expression);
             case 'string':
                 return new LiteralCompiledExpression('string', Utils::addSlashes($constantName, true, Types::STRING), $expression);
             case 'object':
                 throw new CompilerException('?');
             default:
                 return new LiteralCompiledExpression($type, $constantName, $expression);
         }
     }
     if (in_array($constantName, $this->magickConstants)) {
         switch ($constantName) {
             case '__CLASS__':
                 return new CompiledExpression('string', $compilationContext->classDefinition->getCompleteName(), $expression);
                 //no break
             //no break
             case '__NAMESPACE__':
                 return new CompiledExpression('string', $compilationContext->classDefinition->getNamespace(), $expression);
                 //no break
             //no break
             case '__METHOD__':
                 return new CompiledExpression('string', $compilationContext->classDefinition->getName() . ':' . $compilationContext->currentMethod->getName(), $expression);
                 //no break
             //no break
             case '__FUNCTION__':
                 return new CompiledExpression('string', $compilationContext->currentMethod->getName(), $expression);
                 //no break
         }
         $compilationContext->logger->warning("Magic constant '" . $constantName . "' is not supported", 'not-supported-magic-constant', $expression);
         return new LiteralCompiledExpression('null', null, $expression);
     }
     if ($this->_expecting && $this->_expectingVariable) {
         $symbolVariable = $this->_expectingVariable;
         $symbolVariable->setLocalOnly(false);
         $symbolVariable->setMustInitNull(true);
         $symbolVariable->initVariant($compilationContext);
     } else {
         $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
     }
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException('Cannot use variable: ' . $symbolVariable->getType() . ' to assign property value', $expression);
     }
     $compilationContext->codePrinter->output('ZEPHIR_GET_CONSTANT(' . $symbolVariable->getName() . ', "' . $expression['value'] . '");');
     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
 }
Esempio n. 19
0
 /**
  * Throws an exception escaping the data
  *
  * @param CodePrinter $printer
  * @param string $class
  * @param string $message
  * @param array $expression
  */
 private function throwStringException(CodePrinter $printer, $class, $message, $expression)
 {
     $message = Utils::addSlashes($message);
     $path = Compiler::getShortUserPath($expression['file']);
     $printer->output(sprintf('ZEPHIR_THROW_EXCEPTION_DEBUG_STR(%s, "%s", "%s", %s);', $class, $message, $path, $expression['line']));
     $printer->output('return;');
 }
Esempio n. 20
0
 /**
  * Compiles the method
  *
  * @param CompilationContext $compilationContext
  * @return null
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     /**
      * Set the method currently being compiled
      */
     $compilationContext->currentMethod = $this;
     /**
      * Initialize the method warm-up to null
      */
     $compilationContext->methodWarmUp = null;
     /**
      * Assign pre-made compilation passses
      */
     $localContext = $this->localContext;
     $typeInference = $this->typeInference;
     $callGathererPass = $this->callGathererPass;
     /**
      * Every method has its own symbol table
      */
     $symbolTable = new SymbolTable($compilationContext);
     if ($localContext) {
         $symbolTable->setLocalContext($localContext);
     }
     /**
      * Parameters has an additional extra mutation
      */
     $parameters = $this->parameters;
     if ($localContext) {
         if (is_object($parameters)) {
             foreach ($parameters->getParameters() as $parameter) {
                 $localContext->increaseMutations($parameter['name']);
             }
         }
     }
     /**
      * Initialization of parameters happens in a fictitious external branch
      */
     $branch = new Branch();
     $branch->setType(Branch::TYPE_EXTERNAL);
     /**
      * BranchManager helps to create graphs of conditional/loop/root/jump branches
      */
     $branchManager = new BranchManager();
     $branchManager->addBranch($branch);
     /**
      * Cache Manager manages function calls, method calls and class entries caches
      */
     $cacheManager = new CacheManager();
     $cacheManager->setGatherer($callGathererPass);
     $compilationContext->branchManager = $branchManager;
     $compilationContext->cacheManager = $cacheManager;
     $compilationContext->typeInference = $typeInference;
     $compilationContext->symbolTable = $symbolTable;
     $oldCodePrinter = $compilationContext->codePrinter;
     /**
      * Change the code printer to a single method instance
      */
     $codePrinter = new CodePrinter();
     $compilationContext->codePrinter = $codePrinter;
     /**
      * Set an empty function cache
      */
     $compilationContext->functionCache = null;
     /**
      * Reset try/catch and loop counter
      */
     $compilationContext->insideCycle = 0;
     $compilationContext->insideTryCatch = 0;
     $compilationContext->currentTryCatch = 0;
     if (is_object($parameters)) {
         /**
          * Round 1. Create variables in parameters in the symbol table
          */
         $classCastChecks = array();
         foreach ($parameters->getParameters() as $parameter) {
             /**
              * Change dynamic variables to low level types
              */
             if ($typeInference) {
                 if (isset($parameter['data-type'])) {
                     if ($parameter['data-type'] == 'variable') {
                         $type = $typeInference->getInferedType($parameter['name']);
                         if (is_string($type)) {
                             /* promote polymorphic parameters to low level types */
                         }
                     }
                 } else {
                     $type = $typeInference->getInferedType($parameter['name']);
                     if (is_string($type)) {
                         /* promote polymorphic parameters to low level types */
                     }
                 }
             }
             $symbolParam = null;
             if (isset($parameter['data-type'])) {
                 switch ($parameter['data-type']) {
                     case 'object':
                     case 'callable':
                     case 'resource':
                     case 'variable':
                         $symbol = $symbolTable->addVariable($parameter['data-type'], $parameter['name'], $compilationContext);
                         break;
                     default:
                         $symbol = $symbolTable->addVariable($parameter['data-type'], $parameter['name'], $compilationContext);
                         $symbolParam = $symbolTable->addVariable('variable', $parameter['name'] . '_param', $compilationContext);
                         if ($parameter['data-type'] == 'string' || $parameter['data-type'] == 'array') {
                             $symbol->setMustInitNull(true);
                         }
                         break;
                 }
             } else {
                 $symbol = $symbolTable->addVariable('variable', $parameter['name'], $compilationContext);
             }
             /**
              * Some parameters can be read-only
              */
             if (isset($parameter['const']) && $parameter['const']) {
                 $symbol->setReadOnly(true);
                 if (is_object($symbolParam)) {
                     $symbolParam->setReadOnly(true);
                 }
             }
             if (is_object($symbolParam)) {
                 /**
                  * Parameters are marked as 'external'
                  */
                 $symbolParam->setIsExternal(true);
                 /**
                  * Assuming they're initialized
                  */
                 $symbolParam->setIsInitialized(true, $compilationContext, $parameter);
                 /**
                  * Initialize auxiliar parameter zvals to null
                  */
                 $symbolParam->setMustInitNull(true);
                 /**
                  * Increase uses
                  */
                 $symbolParam->increaseUses();
             } else {
                 if (isset($parameter['default'])) {
                     if (isset($parameter['data-type'])) {
                         if ($parameter['data-type'] == 'variable') {
                             $symbol->setMustInitNull(true);
                         }
                     } else {
                         $symbol->setMustInitNull(true);
                     }
                 }
             }
             /**
              * Original node where the variable was declared
              */
             $symbol->setOriginal($parameter);
             /**
              * Parameters are marked as 'external'
              */
             $symbol->setIsExternal(true);
             /**
              * Assuming they're initialized
              */
             $symbol->setIsInitialized(true, $compilationContext, $parameter);
             /**
              * Variables with class/type must be objects across the execution
              */
             if (isset($parameter['cast'])) {
                 $symbol->setDynamicTypes('object');
                 $symbol->setClassTypes($compilationContext->getFullName($parameter['cast']['value']));
                 $classCastChecks[] = array($symbol, $parameter);
             } else {
                 if (isset($parameter['data-type'])) {
                     if ($parameter['data-type'] == 'variable') {
                         $symbol->setDynamicTypes('undefined');
                     }
                 } else {
                     $symbol->setDynamicTypes('undefined');
                 }
             }
         }
     }
     /**
      * Initialize the properties within create_object, handler code
      */
     if ($this->getName() == 'zephir_init_properties') {
         $codePrinter->increaseLevel();
         $codePrinter->output('{');
         $codePrinter->increaseLevel();
         $codePrinter->output('zval *this_ptr = NULL;');
         $codePrinter->output('ZEPHIR_CREATE_OBJECT(this_ptr, class_type);');
         $codePrinter->decreaseLevel();
     }
     /**
      * Compile the block of statements if any
      */
     if (is_object($this->statements)) {
         if ($this->hasModifier('static')) {
             $compilationContext->staticContext = true;
         } else {
             $compilationContext->staticContext = false;
         }
         /**
          * Compile the statements block as a 'root' branch
          */
         $this->statements->compile($compilationContext, false, Branch::TYPE_ROOT);
     }
     /**
      * Initialize default values in dynamic variables
      */
     $initVarCode = "";
     foreach ($symbolTable->getVariables() as $variable) {
         /**
          * Initialize 'dynamic' variables with default values
          */
         if ($variable->getType() == 'variable') {
             if ($variable->getNumberUses() > 0) {
                 if ($variable->getName() != 'this_ptr' && $variable->getName() != 'return_value' && $variable->getName() != 'return_value_ptr') {
                     $defaultValue = $variable->getDefaultInitValue();
                     if (is_array($defaultValue)) {
                         $symbolTable->mustGrownStack(true);
                         switch ($defaultValue['type']) {
                             case 'int':
                             case 'uint':
                             case 'long':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_LONG(' . $variable->getName() . ', ' . $defaultValue['value'] . ');' . PHP_EOL;
                                 break;
                             case 'char':
                             case 'uchar':
                                 if (strlen($defaultValue['value']) > 2) {
                                     if (strlen($defaultValue['value']) > 10) {
                                         throw new CompilerException("Invalid char literal: '" . substr($defaultValue['value'], 0, 10) . "...'", $defaultValue);
                                     } else {
                                         throw new CompilerException("Invalid char literal: '" . $defaultValue['value'] . "'", $defaultValue);
                                     }
                                 }
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_LONG(' . $variable->getName() . ', \'' . $defaultValue['value'] . '\');' . PHP_EOL;
                                 break;
                             case 'null':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_NULL(' . $variable->getName() . ');' . PHP_EOL;
                                 break;
                             case 'double':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_DOUBLE(' . $variable->getName() . ', ' . $defaultValue['value'] . ');' . PHP_EOL;
                                 break;
                             case 'string':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'ZVAL_STRING(' . $variable->getName() . ', "' . Utils::addSlashes($defaultValue['value'], true) . '", 1);' . PHP_EOL;
                                 break;
                             case 'array':
                             case 'empty-array':
                                 $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                                 $initVarCode .= "\t" . 'array_init(' . $variable->getName() . ');' . PHP_EOL;
                                 break;
                             default:
                                 throw new CompilerException('Invalid default type: ' . $defaultValue['type'] . ' for data type: ' . $variable->getType(), $variable->getOriginal());
                         }
                     }
                 }
             }
             continue;
         }
         /**
          * Initialize 'string' variables with default values
          */
         if ($variable->getType() == 'string') {
             if ($variable->getNumberUses() > 0) {
                 $defaultValue = $variable->getDefaultInitValue();
                 if (is_array($defaultValue)) {
                     $symbolTable->mustGrownStack(true);
                     switch ($defaultValue['type']) {
                         case 'string':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'ZVAL_STRING(' . $variable->getName() . ', "' . Utils::addSlashes($defaultValue['value'], true) . '", 1);' . PHP_EOL;
                             break;
                         case 'null':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'ZVAL_EMPTY_STRING(' . $variable->getName() . ');' . PHP_EOL;
                             break;
                         default:
                             throw new CompilerException('Invalid default type: ' . $defaultValue['type'] . ' for data type: ' . $variable->getType(), $variable->getOriginal());
                     }
                 }
             }
             continue;
         }
         /**
          * Initialize 'array' variables with default values
          */
         if ($variable->getType() == 'array') {
             if ($variable->getNumberUses() > 0) {
                 $defaultValue = $variable->getDefaultInitValue();
                 if (is_array($defaultValue)) {
                     $symbolTable->mustGrownStack(true);
                     switch ($defaultValue['type']) {
                         case 'null':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'ZVAL_NULL(' . $variable->getName() . ');' . PHP_EOL;
                             break;
                         case 'array':
                         case 'empty-array':
                             $initVarCode .= "\t" . 'ZEPHIR_INIT_VAR(' . $variable->getName() . ');' . PHP_EOL;
                             $initVarCode .= "\t" . 'array_init(' . $variable->getName() . ');' . PHP_EOL;
                             break;
                         default:
                             throw new CompilerException('Invalid default type: ' . $defaultValue['type'] . ' for data type: ' . $variable->getType(), $variable->getOriginal());
                     }
                 }
             }
         }
     }
     /**
      * Fetch parameters from vm-top
      */
     $initCode = "";
     $code = "";
     if (is_object($parameters)) {
         /**
          * Round 2. Fetch the parameters in the method
          */
         $params = array();
         $requiredParams = array();
         $optionalParams = array();
         $numberRequiredParams = 0;
         $numberOptionalParams = 0;
         foreach ($parameters->getParameters() as $parameter) {
             if (isset($parameter['data-type'])) {
                 $dataType = $parameter['data-type'];
             } else {
                 $dataType = 'variable';
             }
             switch ($dataType) {
                 case 'object':
                 case 'callable':
                 case 'resource':
                 case 'variable':
                     if (!$this->isInternal()) {
                         $params[] = '&' . $parameter['name'];
                     } else {
                         $params[] = $parameter['name'];
                     }
                     break;
                 default:
                     if (!$this->isInternal()) {
                         $params[] = '&' . $parameter['name'] . '_param';
                     } else {
                         $params[] = $parameter['name'] . '_param';
                     }
                     break;
             }
             if (isset($parameter['default'])) {
                 $optionalParams[] = $parameter;
                 $numberOptionalParams++;
             } else {
                 $requiredParams[] = $parameter;
                 $numberRequiredParams++;
             }
         }
         /**
          * Pass the write detector to the method statement block to check if the parameter
          * variable is modified so as do the proper separation
          */
         $parametersToSeparate = array();
         if (is_object($this->statements)) {
             /**
              * If local context is not available
              */
             if (!$localContext) {
                 $writeDetector = new WriteDetector();
             }
             foreach ($parameters->getParameters() as $parameter) {
                 if (isset($parameter['data-type'])) {
                     $dataType = $parameter['data-type'];
                 } else {
                     $dataType = 'variable';
                 }
                 switch ($dataType) {
                     case 'variable':
                     case 'string':
                     case 'array':
                     case 'resource':
                     case 'object':
                     case 'callable':
                         $name = $parameter['name'];
                         if (!$localContext) {
                             if ($writeDetector->detect($name, $this->statements->getStatements())) {
                                 $parametersToSeparate[$name] = true;
                             }
                         } else {
                             if ($localContext->getNumberOfMutations($name) > 1) {
                                 $parametersToSeparate[$name] = true;
                             }
                         }
                         break;
                 }
             }
         }
         /**
          * Initialize required parameters
          */
         foreach ($requiredParams as $parameter) {
             if (isset($parameter['mandatory'])) {
                 $mandatory = $parameter['mandatory'];
             } else {
                 $mandatory = 0;
             }
             if (isset($parameter['data-type'])) {
                 $dataType = $parameter['data-type'];
             } else {
                 $dataType = 'variable';
             }
             if ($dataType != 'variable') {
                 /**
                  * Assign value from zval to low level type
                  */
                 if ($mandatory) {
                     $initCode .= $this->checkStrictType($parameter, $compilationContext);
                 } else {
                     $initCode .= $this->assignZvalValue($parameter, $compilationContext);
                 }
             }
             switch ($dataType) {
                 case 'variable':
                 case 'resource':
                 case 'object':
                 case 'callable':
                     if (isset($parametersToSeparate[$parameter['name']])) {
                         $symbolTable->mustGrownStack(true);
                         $initCode .= "\t" . "ZEPHIR_SEPARATE_PARAM(" . $parameter['name'] . ");" . PHP_EOL;
                     }
                     break;
             }
         }
         /**
          * Initialize optional parameters
          */
         foreach ($optionalParams as $parameter) {
             if (isset($parameter['mandatory'])) {
                 $mandatory = $parameter['mandatory'];
             } else {
                 $mandatory = 0;
             }
             if (isset($parameter['data-type'])) {
                 $dataType = $parameter['data-type'];
             } else {
                 $dataType = 'variable';
             }
             switch ($dataType) {
                 case 'object':
                 case 'callable':
                 case 'resource':
                 case 'variable':
                     $name = $parameter['name'];
                     break;
                 default:
                     $name = $parameter['name'] . '_param';
                     break;
             }
             /**
              * Assign the default value according to the variable's type
              */
             $initCode .= "\t" . 'if (!' . $name . ') {' . PHP_EOL;
             $initCode .= $this->assignDefaultValue($parameter, $compilationContext);
             if (isset($parametersToSeparate[$name]) || $dataType != 'variable') {
                 $initCode .= "\t" . '} else {' . PHP_EOL;
                 if (isset($parametersToSeparate[$name])) {
                     $initCode .= "\t\t" . "ZEPHIR_SEPARATE_PARAM(" . $name . ");" . PHP_EOL;
                 } else {
                     if ($mandatory) {
                         $initCode .= $this->checkStrictType($parameter, $compilationContext, $mandatory);
                     } else {
                         $initCode .= "\t" . $this->assignZvalValue($parameter, $compilationContext);
                     }
                 }
             }
             $initCode .= "\t" . '}' . PHP_EOL;
         }
         /**
          * Fetch the parameters to zval pointers
          */
         $codePrinter->preOutputBlankLine();
         if (!$this->isInternal()) {
             $compilationContext->headersManager->add('kernel/memory');
             if ($symbolTable->getMustGrownStack()) {
                 $code .= "\t" . 'zephir_fetch_params(1, ' . $numberRequiredParams . ', ' . $numberOptionalParams . ', ' . join(', ', $params) . ');' . PHP_EOL;
             } else {
                 $code .= "\t" . 'zephir_fetch_params(0, ' . $numberRequiredParams . ', ' . $numberOptionalParams . ', ' . join(', ', $params) . ');' . PHP_EOL;
             }
         } else {
             foreach ($params as $param) {
                 $code .= "\t" . $param . ' = ' . $param . '_ext;' . PHP_EOL;
             }
         }
         $code .= PHP_EOL;
     }
     $code .= $initCode . $initVarCode;
     $codePrinter->preOutput($code);
     /**
      * Fetch used superglobals
      */
     foreach ($symbolTable->getVariables() as $name => $variable) {
         if ($symbolTable->isSuperGlobal($name)) {
             $codePrinter->preOutput("\t" . 'zephir_get_global(&' . $name . ', SS("' . $name . '") TSRMLS_CC);');
         }
     }
     /**
      * Grow the stack if needed
      */
     if ($symbolTable->getMustGrownStack()) {
         $compilationContext->headersManager->add('kernel/memory');
         $codePrinter->preOutput("\t" . 'ZEPHIR_MM_GROW();');
     }
     /**
      * Check if there are unused variables
      */
     $usedVariables = array();
     $completeName = $compilationContext->classDefinition->getCompleteName();
     foreach ($symbolTable->getVariables() as $variable) {
         if ($variable->getNumberUses() <= 0) {
             if ($variable->isExternal() == false) {
                 $compilationContext->logger->warning('Variable "' . $variable->getName() . '" declared but not used in ' . $completeName . '::' . $this->getName(), "unused-variable", $variable->getOriginal());
                 continue;
             }
             $compilationContext->logger->warning('Variable "' . $variable->getName() . '" declared but not used in ' . $completeName . '::' . $this->getName(), "unused-variable-external", $variable->getOriginal());
         }
         if ($variable->getName() != 'this_ptr' && $variable->getName() != 'return_value' && $variable->getName() != 'return_value_ptr') {
             $type = $variable->getType();
             if (!isset($usedVariables[$type])) {
                 $usedVariables[$type] = array();
             }
             $usedVariables[$type][] = $variable;
         }
     }
     /**
      * Check if there are assigned but not used variables
      * Warn whenever a variable is unused aside from its declaration.
      */
     foreach ($symbolTable->getVariables() as $variable) {
         if ($variable->isExternal() == true || $variable->isTemporal()) {
             continue;
         }
         if ($variable->getName() == 'this_ptr' || $variable->getName() == 'return_value' || $variable->getName() == 'return_value_ptr' || $variable->getName() == 'ZEPHIR_LAST_CALL_STATUS') {
             continue;
         }
         if (!$variable->isUsed()) {
             $node = $variable->getLastUsedNode();
             if (is_array($node)) {
                 $compilationContext->logger->warning('Variable "' . $variable->getName() . '" assigned but not used in ' . $completeName . '::' . $this->getName(), "unused-variable", $node);
             } else {
                 $compilationContext->logger->warning('Variable "' . $variable->getName() . '" assigned but not used in ' . $completeName . '::' . $this->getName(), "unused-variable", $variable->getOriginal());
             }
         }
     }
     if (count($usedVariables)) {
         $codePrinter->preOutputBlankLine();
     }
     /**
      * Generate the variable definition for variables used
      */
     foreach ($usedVariables as $type => $variables) {
         $pointer = null;
         switch ($type) {
             case 'int':
                 $code = 'int ';
                 break;
             case 'uint':
                 $code = 'unsigned int ';
                 break;
             case 'char':
                 $code = 'char ';
                 break;
             case 'uchar':
                 $code = 'unsigned char ';
                 break;
             case 'long':
                 $code = 'long ';
                 break;
             case 'ulong':
                 $code = 'unsigned long ';
                 break;
             case 'bool':
                 $code = 'zend_bool ';
                 break;
             case 'double':
                 $code = 'double ';
                 break;
             case 'string':
             case 'variable':
             case 'array':
             case 'null':
                 $pointer = '*';
                 $code = 'zval ';
                 break;
             case 'HashTable':
                 $pointer = '*';
                 $code = 'HashTable ';
                 break;
             case 'HashPosition':
                 $code = 'HashPosition ';
                 break;
             case 'zend_class_entry':
                 $pointer = '*';
                 $code = 'zend_class_entry ';
                 break;
             case 'zend_function':
                 $pointer = '*';
                 $code = 'zend_function ';
                 break;
             case 'zend_object_iterator':
                 $pointer = '*';
                 $code = 'zend_object_iterator ';
                 break;
             case 'zend_property_info':
                 $pointer = '*';
                 $code = 'zend_property_info ';
                 break;
             case 'zephir_fcall_cache_entry':
                 $pointer = '*';
                 $code = 'zephir_fcall_cache_entry ';
                 break;
             case 'static_zephir_fcall_cache_entry':
                 $pointer = '*';
                 $code = 'zephir_nts_static zephir_fcall_cache_entry ';
                 break;
             case 'static_zend_class_entry':
                 $pointer = '*';
                 $code = 'zephir_nts_static zend_class_entry ';
                 break;
             case 'zephir_ce_guard':
                 $code = 'zephir_nts_static zend_bool ';
                 break;
             default:
                 throw new CompilerException("Unsupported type in declare: " . $type);
         }
         $groupVariables = array();
         $defaultValues = array();
         /**
          * @var $variables Variable[]
          */
         foreach ($variables as $variable) {
             $isComplex = $type == 'variable' || $type == 'string' || $type == 'array' || $type == 'resource' || $type == 'callable' || $type == 'object';
             if ($isComplex && $variable->mustInitNull()) {
                 if ($variable->isLocalOnly()) {
                     $groupVariables[] = $variable->getName() . ' = zval_used_for_init';
                 } else {
                     if ($variable->isDoublePointer()) {
                         $groupVariables[] = $pointer . $pointer . $variable->getName() . ' = NULL';
                     } else {
                         $groupVariables[] = $pointer . $variable->getName() . ' = NULL';
                     }
                 }
                 continue;
             }
             if ($variable->isLocalOnly()) {
                 $groupVariables[] = $variable->getName();
                 continue;
             }
             if ($variable->isDoublePointer()) {
                 if ($variable->mustInitNull()) {
                     $groupVariables[] = $pointer . $pointer . $variable->getName() . ' = NULL';
                 } else {
                     $groupVariables[] = $pointer . $pointer . $variable->getName();
                 }
                 continue;
             }
             $defaultValue = $variable->getDefaultInitValue();
             if ($defaultValue !== null) {
                 switch ($type) {
                     case 'variable':
                     case 'string':
                     case 'array':
                     case 'resource':
                     case 'callable':
                     case 'object':
                         $groupVariables[] = $pointer . $variable->getName();
                         break;
                     case 'char':
                         if (strlen($defaultValue) > 4) {
                             if (strlen($defaultValue) > 10) {
                                 throw new CompilerException("Invalid char literal: '" . substr($defaultValue, 0, 10) . "...'", $variable->getOriginal());
                             } else {
                                 throw new CompilerException("Invalid char literal: '" . $defaultValue . "'", $variable->getOriginal());
                             }
                         }
                         /* no break */
                     /* no break */
                     default:
                         $groupVariables[] = $pointer . $variable->getName() . ' = ' . $defaultValue;
                         break;
                 }
                 continue;
             }
             if ($variable->mustInitNull() && $pointer) {
                 $groupVariables[] = $pointer . $variable->getName() . ' = NULL';
                 continue;
             }
             $groupVariables[] = $pointer . $variable->getName();
         }
         $codePrinter->preOutput("\t" . $code . join(', ', $groupVariables) . ';');
     }
     /**
      * Finalize the method compilation
      */
     if (is_object($this->statements)) {
         /**
          * If the last statement is not a 'return' or 'throw' we need to
          * restore the memory stack if needed
          */
         $lastType = $this->statements->getLastStatementType();
         if ($lastType != 'return' && $lastType != 'throw' && !$this->hasChildReturnStatementType($this->statements->getLastStatement())) {
             if ($symbolTable->getMustGrownStack()) {
                 $compilationContext->headersManager->add('kernel/memory');
                 $codePrinter->output("\t" . 'ZEPHIR_MM_RESTORE();');
             }
             /**
              * If a method has return-type hints we need to ensure the last statement is a 'return' statement
              */
             if ($this->hasReturnTypes()) {
                 throw new CompilerException('Reached end of the method without returning a valid type specified in the return-type hints', $this->expression['return-type']);
             }
         }
     }
     if ($this->getName() == 'zephir_init_properties') {
         $codePrinter->increaseLevel();
         $codePrinter->output('return Z_OBJVAL_P(this_ptr);');
         $codePrinter->decreaseLevel();
         $codePrinter->output('}');
         $codePrinter->decreaseLevel();
     }
     /**
      * Remove macros that grow/restore the memory frame stack if it wasn't used
      */
     $code = $this->removeMemoryStackReferences($symbolTable, $codePrinter->getOutput());
     /**
      * Restore the compilation context
      */
     $oldCodePrinter->output($code);
     $compilationContext->codePrinter = $oldCodePrinter;
     $compilationContext->branchManager = null;
     $compilationContext->cacheManager = null;
     $compilationContext->typeInference = null;
     $codePrinter->clear();
     return null;
 }
Esempio n. 21
0
 /**
  * Produce the code to register a class constant
  *
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  * @throws Exception
  */
 public function compile(CompilationContext $compilationContext)
 {
     $this->processValue($compilationContext);
     switch ($this->value['type']) {
         case 'long':
         case 'int':
             $compilationContext->codePrinter->output("zend_declare_class_constant_long(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), " . $this->value['value'] . " TSRMLS_CC);");
             break;
         case 'double':
             $compilationContext->codePrinter->output("zend_declare_class_constant_double(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), " . $this->value['value'] . " TSRMLS_CC);");
             break;
         case 'bool':
             if ($this->value['value'] == 'false') {
                 $compilationContext->codePrinter->output("zend_declare_class_constant_bool(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), 0 TSRMLS_CC);");
             } else {
                 $compilationContext->codePrinter->output("zend_declare_class_constant_bool(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), 1 TSRMLS_CC);");
             }
             break;
         case 'string':
         case 'char':
             $compilationContext->codePrinter->output("zend_declare_class_constant_string(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\"), \"" . Utils::addSlashes($this->value['value']) . "\" TSRMLS_CC);");
             break;
         case 'null':
             $compilationContext->codePrinter->output("zend_declare_class_constant_null(" . $compilationContext->classDefinition->getClassEntry($compilationContext) . ", SL(\"" . $this->getName() . "\") TSRMLS_CC);");
             break;
         default:
             throw new CompilerException('Type "' . $this->value['type'] . '" is not supported.');
     }
 }
Esempio n. 22
0
 /**
  * Assigns a default value
  *
  * @param array $parameter
  * @param CompilationContext $compilationContext
  * @return string
  * @throws CompilerException
  */
 public function assignDefaultValue(array $parameter, CompilationContext $compilationContext)
 {
     if (isset($parameter['data-type'])) {
         $dataType = $parameter['data-type'];
     } else {
         $dataType = 'variable';
     }
     /**
      * Class-Hinted parameters only can be null?
      */
     if (isset($parameter['cast'])) {
         if ($parameter['default']['type'] != 'null') {
             throw new CompilerException('Class-Hinted parameters only can have "null" as default parameter', $parameter);
         }
     }
     $oldCodePrinter = $compilationContext->codePrinter;
     $codePrinter = new CodePrinter();
     $codePrinter->increaseLevel();
     $codePrinter->increaseLevel();
     $compilationContext->codePrinter = $codePrinter;
     $paramVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext);
     /**
      * @todo Refactoring this place, move to one - static-constant-access
      */
     switch ($dataType) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'int') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(int)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $codePrinter->output($parameter['name'] . ' = 0;');
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $codePrinter->output($parameter['name'] . ' = ' . $parameter['default']['value'] . ';');
                     break;
                 case 'double':
                     $codePrinter->output($parameter['name'] . ' = (int) ' . $parameter['default']['value'] . ';');
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(int)", $parameter);
             }
             break;
         case 'double':
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'double') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(double)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $codePrinter->output($parameter['name'] . ' = 0;');
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $codePrinter->output($parameter['name'] . ' = (double) ' . $parameter['default']['value'] . ';');
                     break;
                 case 'double':
                     $codePrinter->output($parameter['name'] . ' = ' . $parameter['default']['value'] . ';');
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(double)", $parameter);
             }
             break;
         case 'bool':
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'bool') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(bool)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $codePrinter->output($parameter['name'] . ' = 0;');
                     break;
                 case 'bool':
                     if ($parameter['default']['value'] == 'true') {
                         $codePrinter->output($parameter['name'] . ' = 1;');
                     } else {
                         $codePrinter->output($parameter['name'] . ' = 0;');
                     }
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(bool)", $parameter);
             }
             break;
         case 'string':
             $compilationContext->symbolTable->mustGrownStack(true);
             $compilationContext->headersManager->add('kernel/memory');
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'string') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(string)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->assignString($paramVariable, null, $compilationContext);
                     break;
                 case 'string':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->assignString($paramVariable, Utils::addSlashes($parameter['default']['value'], true), $compilationContext);
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(string)", $parameter);
             }
             break;
         case 'array':
             $compilationContext->symbolTable->mustGrownStack(true);
             $compilationContext->headersManager->add('kernel/memory');
             switch ($parameter['default']['type']) {
                 case 'null':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->initArray($paramVariable, $compilationContext, null);
                     break;
                 case 'empty-array':
                 case 'array':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->initArray($paramVariable, $compilationContext, null);
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(array)", $parameter);
             }
             break;
         case 'variable':
             $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->assignLong($symbolVariable, $parameter['default']['value'], $compilationContext);
                     break;
                 case 'double':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->assignDouble($symbolVariable, $parameter['default']['value'], $compilationContext);
                     break;
                 case 'string':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->assignString($paramVariable, Utils::addSlashes($parameter['default']['value'], true), $compilationContext);
                     break;
                 case 'bool':
                     $expectedMutations = $compilationContext->symbolTable->getExpectedMutations($parameter['name']);
                     if ($expectedMutations < 2) {
                         if ($parameter['default']['value'] == 'true') {
                             $compilationContext->backend->assignZval($paramVariable, $compilationContext->backend->resolveValue('true', $compilationContext), $compilationContext);
                         } else {
                             $compilationContext->backend->assignZval($paramVariable, $compilationContext->backend->resolveValue('false', $compilationContext), $compilationContext);
                         }
                     } else {
                         $compilationContext->symbolTable->mustGrownStack(true);
                         $compilationContext->headersManager->add('kernel/memory');
                         if ($parameter['default']['value'] == 'true') {
                             $compilationContext->backend->copyOnWrite($paramVariable, $compilationContext->backend->resolveValue('true', $compilationContext), $compilationContext);
                         } else {
                             $compilationContext->backend->copyOnWrite($paramVariable, $compilationContext->backend->resolveValue('false', $compilationContext), $compilationContext);
                         }
                     }
                     break;
                 case 'null':
                     $expectedMutations = $compilationContext->symbolTable->getExpectedMutations($parameter['name']);
                     if ($expectedMutations < 2) {
                         $compilationContext->backend->assignZval($symbolVariable, $compilationContext->backend->resolveValue('null', $compilationContext), $compilationContext);
                     } else {
                         $compilationContext->symbolTable->mustGrownStack(true);
                         $compilationContext->headersManager->add('kernel/memory');
                         $compilationContext->backend->copyOnWrite($paramVariable, $compilationContext->backend->resolveValue('null', $compilationContext), $compilationContext);
                     }
                     break;
                 case 'empty-array':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->initArray($symbolVariable, $compilationContext, null);
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(variable)", $parameter);
             }
             break;
         default:
             throw new CompilerException("Default parameter type: " . $dataType, $parameter);
     }
     $compilationContext->codePrinter = $oldCodePrinter;
     return $codePrinter->getOutput();
 }
Esempio n. 23
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @param boolean $isFullString
  */
 private function _getOptimizedConcat($expression, CompilationContext $compilationContext, &$isFullString)
 {
     $originalExpr = $expression;
     $isFullString = true;
     $parts = array();
     while ($expression && isset($expression['left'])) {
         $parts[] = $expression['right'];
         if ($expression['left']['type'] == 'concat') {
             $expression = $expression['left'];
         } else {
             $parts[] = $expression['left'];
             $expression = null;
         }
     }
     if ($expression) {
         $parts[] = $expression['right'];
         $parts[] = $expression['left'];
     }
     $key = '';
     $concatParts = array();
     $parts = array_reverse($parts);
     foreach ($parts as $part) {
         $expr = new Expression($part);
         $expr->setStringOperation(true);
         switch ($part['type']) {
             case 'array-access':
             case 'property-access':
                 $expr->setReadOnly(true);
                 break;
             default:
                 $expr->setReadOnly($this->_readOnly);
                 break;
         }
         $compiledExpr = $expr->compile($compilationContext);
         switch ($compiledExpr->getType()) {
             case 'variable':
                 $variable = $compilationContext->symbolTable->getVariableForRead($compiledExpr->getCode(), $compilationContext, $originalExpr);
                 switch ($variable->getType()) {
                     case 'variable':
                         $key .= 'v';
                         $concatParts[] = $variable->getName();
                         $isFullString = false;
                         break;
                     case 'string':
                         $key .= 'v';
                         $concatParts[] = $variable->getName();
                         break;
                     case 'int':
                     case 'long':
                         $key .= 'v';
                         $tempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $originalExpr);
                         $compilationContext->codePrinter->output('ZVAL_LONG(&' . $tempVariable->getName() . ', ' . $compiledExpr->getCode() . ');');
                         $concatParts[] = '&' . $tempVariable->getName();
                         break;
                     default:
                         throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used in concat operation", $compiledExpr->getOriginal());
                 }
                 break;
             case 'string':
                 $key .= 's';
                 $concatParts[] = '"' . Utils::addSlashes($compiledExpr->getCode()) . '"';
                 break;
             default:
                 throw new CompilerException("Variable type: " . $compiledExpr->getType() . " cannot be used in concat operation", $compiledExpr->getOriginal());
         }
     }
     $compilationContext->stringsManager->addConcatKey($key);
     return array($key, join(', ', $concatParts));
 }