Beispiel #1
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $expr = new Expression($expression['left']);
     $expr->setReadOnly(true);
     $expr->setExpectReturn(true);
     $exprPath = $expr->compile($compilationContext);
     if ($exprPath->getType() == 'variable') {
         $exprVariable = $compilationContext->symbolTable->getVariableForRead($exprPath->getCode(), $compilationContext, $expression);
         if ($exprVariable->getType() == 'variable') {
             if ($exprVariable->hasDifferentDynamicType(array('undefined', 'string'))) {
                 $compilationContext->logger->warning('Possible attempt to use invalid type as path in "require" operator', 'non-valid-require', $expression);
             }
         }
     }
     $symbolVariable = false;
     if ($this->isExpecting()) {
         $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify('variable', $compilationContext, $expression);
     }
     $compilationContext->headersManager->add('kernel/memory');
     $compilationContext->headersManager->add('kernel/require');
     $codePrinter = $compilationContext->codePrinter;
     if ($symbolVariable) {
         $codePrinter->output('ZEPHIR_OBSERVE_OR_NULLIFY_PPZV(&' . $symbolVariable->getName() . ');');
         $codePrinter->output('if (zephir_require_zval_ret(&' . $symbolVariable->getName() . ', ' . $exprPath->getCode() . ' TSRMLS_CC) == FAILURE) {');
     } else {
         $codePrinter->output('if (zephir_require_zval(' . $exprPath->getCode() . ' TSRMLS_CC) == FAILURE) {');
     }
     $codePrinter->output("\t" . 'RETURN_MM_NULL();');
     $codePrinter->output('}');
     if ($symbolVariable) {
         return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
     }
     return new CompiledExpression('null', null, $expression);
 }
Beispiel #2
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $expression = array('type' => 'require', 'left' => $this->_statement['expr'], 'file' => $this->_statement['file'], 'line' => $this->_statement['line'], 'char' => $this->_statement['char']);
     $expr = new Expression($expression);
     $expr->setExpectReturn(false, null);
     $expr->compile($compilationContext);
 }
Beispiel #3
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/object');
     $exprVariable = new Expression($expression['left']);
     $exprVariable->setReadOnly(true);
     $exprVariable->setExpectReturn(true);
     $exprCompiledVariable = $exprVariable->compile($compilationContext);
     if ($exprCompiledVariable->getType() != 'variable') {
         throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as array", $expression);
     }
     $clonedVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression);
     if ($clonedVariable->getType() != 'variable') {
         throw new CompilerException("Variable type: " . $exprVariable->getType() . " cannot be cloned");
     }
     if ($clonedVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to use non array in "clone" operator', 'non-valid-clone', $expression);
     }
     $symbolVariable = $this->getExpected($compilationContext, $expression);
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Objects can only be cloned into dynamic variables", $expression);
     }
     $symbolVariable->setDynamicTypes('object');
     $symbolVariable->setIsInitialized(true, $compilationContext, $expression);
     /* Inherit the dynamic type data from the cloned object */
     $symbolVariable->setDynamicTypes($clonedVariable->getDynamicTypes());
     $symbolVariable->setClassTypes($clonedVariable->getClassTypes());
     $compilationContext->codePrinter->output('if (zephir_clone(' . $symbolVariable->getName() . ', ' . $clonedVariable->getName() . ' TSRMLS_CC) == FAILURE) {');
     $compilationContext->codePrinter->output("\t" . 'RETURN_MM();');
     $compilationContext->codePrinter->output('}');
     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
 }
Beispiel #4
0
 /**
  * @param CompilationContext $compilationContext
  * @param boolean $unreachable
  * @param int $branchType
  * @return Branch
  */
 public function compile(CompilationContext $compilationContext, $unreachable = false, $branchType = Branch::TYPE_UNKNOWN)
 {
     $compilationContext->codePrinter->increaseLevel();
     $compilationContext->currentBranch++;
     /**
      * Create a new branch
      */
     $currentBranch = new Branch();
     $currentBranch->setType($branchType);
     $currentBranch->setUnreachable($unreachable);
     /**
      * Activate branch in the branch manager
      */
     $compilationContext->branchManager->addBranch($currentBranch);
     $this->_unreachable = $unreachable;
     $statements = $this->_statements;
     foreach ($statements as $statement) {
         /**
          * Generate GDB hints
          */
         if ($this->_debug) {
             if (isset($statement['file'])) {
                 if ($statement['type'] != 'declare' && $statement['type'] != 'comment') {
                     $compilationContext->codePrinter->outputNoIndent('#line ' . $statement['line'] . ' "' . $statement['file'] . '"');
                 }
             }
         }
         /**
          * Show warnings if code is generated when the 'unreachable state' is 'on'
          */
         if ($this->_unreachable === true) {
             switch ($statement['type']) {
                 case 'echo':
                     $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement['expressions'][0]);
                     break;
                 case 'let':
                     $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement['assignments'][0]);
                     break;
                 case 'fetch':
                 case 'fcall':
                 case 'mcall':
                 case 'scall':
                 case 'if':
                 case 'while':
                 case 'do-while':
                 case 'switch':
                 case 'for':
                 case 'return':
                 case 'c-block':
                     if (isset($statement['expr'])) {
                         $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement['expr']);
                     } else {
                         $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement);
                     }
                     break;
                 default:
                     $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement);
             }
         }
         switch ($statement['type']) {
             case 'let':
                 $letStatement = new LetStatement($statement);
                 $letStatement->compile($compilationContext);
                 break;
             case 'echo':
                 $echoStatement = new EchoStatement($statement);
                 $echoStatement->compile($compilationContext);
                 break;
             case 'declare':
                 $declareStatement = new DeclareStatement($statement);
                 $declareStatement->compile($compilationContext);
                 break;
             case 'if':
                 $ifStatement = new IfStatement($statement);
                 $ifStatement->compile($compilationContext);
                 break;
             case 'while':
                 $whileStatement = new WhileStatement($statement);
                 $whileStatement->compile($compilationContext);
                 break;
             case 'do-while':
                 $doWhileStatement = new DoWhileStatement($statement);
                 $doWhileStatement->compile($compilationContext);
                 break;
             case 'switch':
                 $switchStatement = new SwitchStatement($statement);
                 $switchStatement->compile($compilationContext);
                 break;
             case 'for':
                 $forStatement = new ForStatement($statement);
                 $forStatement->compile($compilationContext);
                 break;
             case 'return':
                 $returnStatement = new ReturnStatement($statement);
                 $returnStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'require':
                 $requireStatement = new RequireStatement($statement);
                 $requireStatement->compile($compilationContext);
                 break;
             case 'loop':
                 $loopStatement = new LoopStatement($statement);
                 $loopStatement->compile($compilationContext);
                 break;
             case 'break':
                 $breakStatement = new BreakStatement($statement);
                 $breakStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'continue':
                 $continueStatement = new ContinueStatement($statement);
                 $continueStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'unset':
                 $unsetStatement = new UnsetStatement($statement);
                 $unsetStatement->compile($compilationContext);
                 break;
             case 'throw':
                 $throwStatement = new ThrowStatement($statement);
                 $throwStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'try-catch':
                 $throwStatement = new TryCatchStatement($statement);
                 $throwStatement->compile($compilationContext);
                 $this->_unreachable = false;
                 break;
             case 'fetch':
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $compiledExpression = $expr->compile($compilationContext);
                 $compilationContext->codePrinter->output($compiledExpression->getCode() . ';');
                 break;
             case 'mcall':
                 $methodCall = new MethodCall();
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $methodCall->compile($expr, $compilationContext);
                 break;
             case 'fcall':
                 $functionCall = new FunctionCall();
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $compiledExpression = $functionCall->compile($expr, $compilationContext);
                 switch ($compiledExpression->getType()) {
                     case 'int':
                     case 'double':
                     case 'uint':
                     case 'long':
                     case 'ulong':
                     case 'char':
                     case 'uchar':
                     case 'bool':
                         $compilationContext->codePrinter->output($compiledExpression->getCode() . ';');
                         break;
                 }
                 break;
             case 'scall':
                 $methodCall = new StaticCall();
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $methodCall->compile($expr, $compilationContext);
                 break;
             case 'cblock':
                 $compilationContext->codePrinter->output($statement['value']);
                 break;
             case 'empty':
                 break;
             default:
                 throw new Exception('Unsupported statement: ' . $statement['type']);
         }
         if ($statement['type'] != 'comment') {
             $this->_lastStatement = $statement;
         }
     }
     /**
      * Traverses temporal variables created in a specific branch
      * marking them as idle
      */
     $compilationContext->symbolTable->markTemporalVariablesIdle($compilationContext);
     $compilationContext->branchManager->removeBranch($currentBranch);
     $compilationContext->currentBranch--;
     $compilationContext->codePrinter->decreaseLevel();
     return $currentBranch;
 }
Beispiel #5
0
 /**
  * Resolves an expression
  *
  * @param CompilationContext $compilationContext
  * @return bool|CompiledExpression|mixed
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $expression = $this->_expression;
     $type = $expression['type'];
     $compilableExpression = null;
     switch ($type) {
         case 'null':
             return new LiteralCompiledExpression('null', null, $expression);
         case 'int':
         case 'integer':
             return new LiteralCompiledExpression('int', $expression['value'], $expression);
         case 'long':
         case 'double':
         case 'bool':
             return new LiteralCompiledExpression($type, $expression['value'], $expression);
         case 'string':
             if (!$this->_stringOperation) {
                 if (ctype_digit($expression['value'])) {
                     return new CompiledExpression('int', $expression['value'], $expression);
                 }
             }
             return new LiteralCompiledExpression('string', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
         case 'istring':
             return new LiteralCompiledExpression('istring', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
         case 'char':
             if (!strlen($expression['value'])) {
                 throw new CompilerException("Invalid empty char literal", $expression);
             }
             if (strlen($expression['value']) > 2) {
                 if (strlen($expression['value']) > 10) {
                     throw new CompilerException("Invalid char literal: '" . substr($expression['value'], 0, 10) . "...'", $expression);
                 } else {
                     throw new CompilerException("Invalid char literal: '" . $expression['value'] . "'", $expression);
                 }
             }
             return new LiteralCompiledExpression('char', $expression['value'], $expression);
         case 'variable':
             $var = $compilationContext->symbolTable->getVariable($expression['value']);
             if ($var) {
                 if ($var->getRealName() == 'this') {
                     $var = 'this';
                 } else {
                     $var = $var->getName();
                 }
             } else {
                 $var = $expression['value'];
             }
             return new CompiledExpression('variable', $var, $expression);
         case 'constant':
             $compilableExpression = new Constants();
             break;
         case 'empty-array':
             return $this->emptyArray($expression, $compilationContext);
         case 'array-access':
             $compilableExpression = new NativeArrayAccess();
             $compilableExpression->setNoisy($this->isNoisy());
             break;
         case 'property-access':
             $compilableExpression = new PropertyAccess();
             $compilableExpression->setNoisy($this->isNoisy());
             break;
         case 'property-string-access':
         case 'property-dynamic-access':
             $compilableExpression = new PropertyDynamicAccess();
             $compilableExpression->setNoisy($this->isNoisy());
             break;
         case 'static-constant-access':
             $compilableExpression = new StaticConstantAccess();
             break;
         case 'static-property-access':
             $compilableExpression = new StaticPropertyAccess();
             break;
         case 'fcall':
             $functionCall = new FunctionCall();
             return $functionCall->compile($this, $compilationContext);
         case 'mcall':
             $methodCall = new MethodCall();
             return $methodCall->compile($this, $compilationContext);
         case 'scall':
             $staticCall = new StaticCall();
             return $staticCall->compile($this, $compilationContext);
         case 'isset':
             $compilableExpression = new IssetOperator();
             break;
         case 'fetch':
             $compilableExpression = new FetchOperator();
             break;
         case 'empty':
             $compilableExpression = new EmptyOperator();
             break;
         case 'array':
             $compilableExpression = new NativeArray();
             break;
         case 'new':
             $compilableExpression = new NewInstanceOperator();
             break;
         case 'new-type':
             $compilableExpression = new NewInstanceTypeOperator();
             break;
         case 'not':
             $compilableExpression = new NotOperator();
             break;
         case 'bitwise_not':
             $compilableExpression = new BitwiseNotOperator();
             break;
         case 'equals':
             $compilableExpression = new EqualsOperator();
             break;
         case 'not-equals':
             $compilableExpression = new NotEqualsOperator();
             break;
         case 'identical':
             $compilableExpression = new IdenticalOperator();
             break;
         case 'not-identical':
             $compilableExpression = new NotIdenticalOperator();
             break;
         case 'greater':
             $compilableExpression = new GreaterOperator();
             break;
         case 'less':
             $compilableExpression = new LessOperator();
             break;
         case 'less-equal':
             $compilableExpression = new LessEqualOperator();
             break;
         case 'greater-equal':
             $compilableExpression = new GreaterEqualOperator();
             break;
         case 'add':
             $compilableExpression = new AddOperator();
             break;
         case 'minus':
             $compilableExpression = new MinusOperator();
             break;
         case 'sub':
             $compilableExpression = new SubOperator();
             break;
         case 'mul':
             $compilableExpression = new MulOperator();
             break;
         case 'div':
             $compilableExpression = new DivOperator();
             break;
         case 'mod':
             $compilableExpression = new ModOperator();
             break;
         case 'and':
             $compilableExpression = new AndOperator();
             break;
         case 'or':
             $compilableExpression = new OrOperator();
             break;
         case 'bitwise_and':
             $compilableExpression = new BitwiseAndOperator();
             break;
         case 'bitwise_or':
             $compilableExpression = new BitwiseOrOperator();
             break;
         case 'bitwise_xor':
             $compilableExpression = new BitwiseXorOperator();
             break;
         case 'bitwise_shiftleft':
             $compilableExpression = new ShiftLeftOperator();
             break;
         case 'bitwise_shiftright':
             $compilableExpression = new ShiftRightOperator();
             break;
         case 'concat':
             $expr = new ConcatOperator();
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'irange':
             $compilableExpression = new RangeInclusiveOperator();
             break;
         case 'erange':
             $compilableExpression = new RangeExclusiveOperator();
             break;
         case 'list':
             if ($expression['left']['type'] == 'list') {
                 $compilationContext->logger->warning("Unnecessary extra parentheses", "extra-parentheses", $expression);
             }
             $numberPrints = $compilationContext->codePrinter->getNumberPrints();
             $expr = new Expression($expression['left']);
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             $resolved = $expr->compile($compilationContext);
             if ($compilationContext->codePrinter->getNumberPrints() - $numberPrints <= 1) {
                 if (strpos($resolved->getCode(), ' ') !== false) {
                     return new CompiledExpression($resolved->getType(), '(' . $resolved->getCode() . ')', $expression);
                 }
             }
             return $resolved;
         case 'cast':
             $compilableExpression = new CastOperator();
             break;
         case 'type-hint':
             return $this->compileTypeHint($expression, $compilationContext);
         case 'instanceof':
             $compilableExpression = new InstanceOfOperator();
             break;
         case 'clone':
             $compilableExpression = new CloneOperator();
             break;
         case 'ternary':
             $compilableExpression = new TernaryOperator();
             break;
         case 'short-ternary':
             $expr = new ShortTernaryOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'likely':
             if (!$this->_evalMode) {
                 throw new CompilerException("'likely' operator can only be used in evaluation expressions", $expression);
             }
             $expr = new LikelyOperator();
             $expr->setReadOnly($this->isReadOnly());
             return $expr->compile($expression, $compilationContext);
         case 'unlikely':
             if (!$this->_evalMode) {
                 throw new CompilerException("'unlikely' operator can only be used in evaluation expressions", $expression);
             }
             $expr = new UnlikelyOperator();
             $expr->setReadOnly($this->isReadOnly());
             return $expr->compile($expression, $compilationContext);
         case 'typeof':
             $compilableExpression = new TypeOfOperator();
             break;
         case 'require':
             $compilableExpression = new RequireOperator();
             break;
         case 'closure':
             $compilableExpression = new Closure();
             break;
         case 'closure-arrow':
             $compilableExpression = new ClosureArrow();
             break;
         case 'reference':
             $compilableExpression = new Reference();
             break;
         default:
             throw new CompilerException("Unknown expression: " . $type, $expression);
     }
     if (!$compilableExpression) {
         throw new CompilerException("Unknown expression passed as compilableExpression", $expression);
     }
     $compilableExpression->setReadOnly($this->isReadOnly());
     $compilableExpression->setExpectReturn($this->_expecting, $this->_expectingVariable);
     return $compilableExpression->compile($expression, $compilationContext);
 }
Beispiel #6
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();
 }
 /**
  * Creates a new instance
  *
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Resolves the symbol that expects the value
      */
     $this->_literalOnly = false;
     $symbolVariable = $this->getExpectedNonLiteral($compilationContext, $expression);
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Objects can only be instantiated into dynamic variables", $expression);
     }
     if ($symbolVariable->isLocalOnly()) {
         throw new CompilerException("Cannot use non-heap variable to store new instance", $expression);
     }
     if ($symbolVariable->getName() != 'return_value') {
         if ($symbolVariable->hasDifferentDynamicType(array('unknown', 'undefined', 'object', 'null'))) {
             $compilationContext->logger->warning('Possible attempt to use non-object in "new" operator', 'non-valid-new', $expression);
         }
     }
     /**
      * Mark variables as dynamic objects
      */
     $symbolVariable->setDynamicTypes('object');
     $dynamic = false;
     if ($expression['class'] == 'self' || $expression['class'] == 'static') {
         $className = $compilationContext->classDefinition->getCompleteName();
     } else {
         $className = $expression['class'];
         $dynamic = $expression['dynamic'];
         if (!$dynamic) {
             $className = $compilationContext->getFullName($expression['class']);
         }
     }
     if (!$className) {
         throw new CompilerException("A class name is required to instantiate the object", $expression);
     }
     /**
      * stdclass doesn't have constructors
      */
     $lowerClassName = strtolower($className);
     $isStdClass = $lowerClassName === 'stdclass' || $lowerClassName === '\\stdclass';
     if ($isStdClass) {
         if (isset($expression['parameters']) && count($expression['parameters']) > 0) {
             throw new CompilerException("stdclass does not receive parameters in its constructor", $expression);
         }
         $compilationContext->backend->initObject($symbolVariable, null, $compilationContext);
         $symbolVariable->setClassTypes('stdclass');
     } else {
         $classDefinition = false;
         if ($compilationContext->compiler->isClass($className)) {
             $classDefinition = $compilationContext->compiler->getClassDefinition($className);
         }
         /**
          * Classes inside the same extension
          */
         if ($classDefinition) {
             $compilationContext->backend->initObject($symbolVariable, $classDefinition->getClassEntry($compilationContext), $compilationContext);
             $symbolVariable->setClassTypes($className);
             $symbolVariable->setAssociatedClass($classDefinition);
         } else {
             /**
              * Classes outside the extension
              */
             if ($dynamic) {
                 $classNameVariable = $compilationContext->symbolTable->getVariableForRead($className, $compilationContext, $expression);
                 if ($classNameVariable->isNotVariableAndString()) {
                     throw new CompilerException("Only dynamic/string variables can be used in new operator. " . $classNameVariable->getName(), $expression);
                 }
                 /**
                  * Use a safe string version of the variable to avoid segfaults
                  */
                 $compilationContext->headersManager->add('kernel/object');
                 $safeSymbolVariable = $compilationContext->symbolTable->getTempVariable('variable', $compilationContext, $expression);
                 $safeSymbolVariable->setMustInitNull(true);
                 $safeSymbolVariable->setIsInitialized(true, $compilationContext, $expression);
                 $safeSymbolVariable->increaseUses();
                 $compilationContext->codePrinter->output('zephir_fetch_safe_class(' . $safeSymbolVariable->getName() . ', ' . $classNameVariable->getName() . ');');
                 $safeSymbol = $compilationContext->backend->getVariableCode($safeSymbolVariable);
                 $classNameToFetch = 'Z_STRVAL_P(' . $safeSymbol . '), Z_STRLEN_P(' . $safeSymbol . ')';
                 $zendClassEntry = $compilationContext->cacheManager->getClassEntryCache()->get($classNameToFetch, true, $compilationContext);
                 $classEntry = $zendClassEntry->getName();
             } else {
                 if (!class_exists($className, false)) {
                     $compilationContext->logger->warning('Class "' . $className . '" does not exist at compile time', "nonexistent-class", $expression);
                     $classNameToFetch = 'SL("' . Utils::escapeClassName($className) . '")';
                     $zendClassEntry = $compilationContext->cacheManager->getClassEntryCache()->get($classNameToFetch, false, $compilationContext);
                     $classEntry = $zendClassEntry->getName();
                 } else {
                     $reflectionClass = new \ReflectionClass($className);
                     if ($reflectionClass->isInterface()) {
                         throw new CompilerException('Interfaces cannot be instantiated', $expression);
                     } else {
                         if (method_exists($reflectionClass, 'isTrait')) {
                             if ($reflectionClass->isTrait()) {
                                 throw new CompilerException('Traits cannot be instantiated', $expression);
                             }
                         }
                     }
                     $classEntry = $compilationContext->classDefinition->getClassEntryByClassName($className, $compilationContext, true);
                     if (!$classEntry) {
                         $classNameToFetch = 'SL("' . Utils::escapeClassName($className) . '")';
                         $zendClassEntry = $compilationContext->cacheManager->getClassEntryCache()->get($classNameToFetch, false, $compilationContext);
                         $classEntry = $zendClassEntry->getName();
                     } else {
                         $symbolVariable->setAssociatedClass($reflectionClass);
                     }
                 }
                 $symbolVariable->setClassTypes($className);
             }
             $compilationContext->backend->initObject($symbolVariable, $classEntry, $compilationContext);
         }
     }
     /**
      * Mark variable initialized
      */
     $symbolVariable->setIsInitialized(true, $compilationContext, $expression);
     /**
      * Don't check the constructor for stdclass instances
      */
     if ($isStdClass) {
         return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
     }
     /**
      * Call the constructor
      * For classes in the same extension we check if the class does implement a constructor
      * For external classes we always assume the class does implement a constructor
      */
     $callConstructor = false;
     if ($compilationContext->compiler->isClass($className)) {
         $classDefinition = $compilationContext->compiler->getClassDefinition($className);
         if ($classDefinition->getType() != 'class') {
             throw new CompilerException("Only classes can be instantiated", $expression);
         }
         $callConstructor = $classDefinition->hasMethod("__construct");
     } else {
         if ($compilationContext->compiler->isBundledClass($className)) {
             $classDefinition = $compilationContext->compiler->getInternalClassDefinition($className);
             $callConstructor = $classDefinition->hasMethod("__construct");
         }
     }
     /* @TODO use the MethodBuilder here */
     if (isset($expression['parameters'])) {
         $callExpr = new Expression(array('variable' => array('type' => 'variable', 'value' => $symbolVariable->getRealName()), 'name' => '__construct', 'parameters' => $expression['parameters'], 'call-type' => MethodCall::CALL_NORMAL, 'file' => $expression['file'], 'line' => $expression['line'], 'char' => $expression['char'], 'check' => $callConstructor));
     } else {
         $callExpr = new Expression(array('variable' => array('type' => 'variable', 'value' => $symbolVariable->getRealName()), 'name' => '__construct', 'call-type' => MethodCall::CALL_NORMAL, 'file' => $expression['file'], 'line' => $expression['line'], 'char' => $expression['char'], 'check' => $callConstructor));
     }
     /**
      * If we are certain that there is a constructor we call it, otherwise we checked it at runtime.
      */
     if ($callConstructor) {
         $methodCall = new MethodCall();
         $callExpr->setExpectReturn(false);
         $methodCall->compile($callExpr, $compilationContext);
     } else {
         $compilationContext->headersManager->add('kernel/fcall');
         /* @todo, generate the code using builders */
         $compilationContext->backend->checkConstructor($symbolVariable, $compilationContext);
         $codePrinter->increaseLevel();
         $methodCall = new MethodCall();
         $callExpr->setExpectReturn(false);
         $methodCall->compile($callExpr, $compilationContext);
         $codePrinter->decreaseLevel();
         $codePrinter->output('}');
     }
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Beispiel #8
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);
         }
     }
     $code = '';
     /**
      * @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();
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $code .= "\t\t" . $parameter['name'] . ' = 0;' . PHP_EOL;
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $code .= "\t\t" . $parameter['name'] . ' = ' . $parameter['default']['value'] . ';' . PHP_EOL;
                     break;
                 case 'double':
                     $code .= "\t\t" . $parameter['name'] . ' = (int) ' . $parameter['default']['value'] . ';' . PHP_EOL;
                     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();
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $code .= "\t\t" . $parameter['name'] . ' = 0;' . PHP_EOL;
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $code .= "\t\t" . $parameter['name'] . ' = (double) ' . $parameter['default']['value'] . ';' . PHP_EOL;
                     break;
                 case 'double':
                     $code .= "\t\t" . $parameter['name'] . ' = ' . $parameter['default']['value'] . ';' . PHP_EOL;
                     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();
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $code .= "\t\t" . $parameter['name'] . ' = 0;' . PHP_EOL;
                     break;
                 case 'bool':
                     if ($parameter['default']['value'] == 'true') {
                         $code .= "\t\t" . $parameter['name'] . ' = 1;' . PHP_EOL;
                     } else {
                         $code .= "\t\t" . $parameter['name'] . ' = 0;' . PHP_EOL;
                     }
                     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();
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $code .= "\t\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t\t" . 'ZVAL_EMPTY_STRING(' . $parameter['name'] . ');' . PHP_EOL;
                     break;
                 case 'string':
                     $code .= "\t\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t\t" . 'ZVAL_STRING(' . $parameter['name'] . ', "' . Utils::addSlashes($parameter['default']['value'], true) . '", 1);' . PHP_EOL;
                     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':
                     $code .= "\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t" . 'array_init(' . $parameter['name'] . ');' . PHP_EOL;
                     break;
                 case 'empty-array':
                 case 'array':
                     $code .= "\t\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t\t" . 'array_init(' . $parameter['name'] . ');' . PHP_EOL;
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(array)", $parameter);
             }
             break;
         case 'variable':
             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);
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $code .= "\t\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t\t" . 'ZVAL_LONG(' . $parameter['name'] . ', ' . $parameter['default']['value'] . ');' . PHP_EOL;
                     break;
                 case 'double':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $code .= "\t\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t\t" . 'ZVAL_DOUBLE(' . $parameter['name'] . ', ' . $parameter['default']['value'] . ');' . PHP_EOL;
                     break;
                 case 'string':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $code .= "\t\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t\t" . 'ZVAL_STRING(' . $parameter['name'] . ', "' . Utils::addSlashes($parameter['default']['value'], true) . '", 1);' . PHP_EOL;
                     break;
                 case 'bool':
                     $expectedMutations = $compilationContext->symbolTable->getExpectedMutations($parameter['name']);
                     if ($expectedMutations < 2) {
                         if ($parameter['default']['value'] == 'true') {
                             $code .= "\t\t" . $parameter['name'] . ' = ZEPHIR_GLOBAL(global_true);' . PHP_EOL;
                         } else {
                             $code .= "\t\t" . $parameter['name'] . ' = ZEPHIR_GLOBAL(global_false);' . PHP_EOL;
                         }
                     } else {
                         $compilationContext->symbolTable->mustGrownStack(true);
                         $compilationContext->headersManager->add('kernel/memory');
                         if ($parameter['default']['value'] == 'true') {
                             $code .= "\t\t" . 'ZEPHIR_CPY_WRT(' . $parameter['name'] . ', ZEPHIR_GLOBAL(global_true));' . PHP_EOL;
                         } else {
                             $code .= "\t\t" . 'ZEPHIR_CPY_WRT(' . $parameter['name'] . ', ZEPHIR_GLOBAL(global_false));' . PHP_EOL;
                         }
                     }
                     break;
                 case 'null':
                     $expectedMutations = $compilationContext->symbolTable->getExpectedMutations($parameter['name']);
                     if ($expectedMutations < 2) {
                         $code .= "\t\t" . $parameter['name'] . ' = ZEPHIR_GLOBAL(global_null);' . PHP_EOL;
                     } else {
                         $compilationContext->symbolTable->mustGrownStack(true);
                         $compilationContext->headersManager->add('kernel/memory');
                         $code .= "\t\t" . 'ZEPHIR_CPY_WRT(' . $parameter['name'] . ', ZEPHIR_GLOBAL(global_null));' . PHP_EOL;
                     }
                     break;
                 case 'empty-array':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $code .= "\t\t" . 'ZEPHIR_INIT_VAR(' . $parameter['name'] . ');' . PHP_EOL;
                     $code .= "\t\t" . 'array_init(' . $parameter['name'] . ');' . PHP_EOL;
                     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);
     }
     return $code;
 }
Beispiel #9
0
 /**
  * Compiles ClassName::foo = {expr}
  *
  * @param                    $className
  * @param                    $property
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array              $statement
  *
  * @throws CompilerException
  * @internal param string $variable
  */
 public function assignStatic($className, $property, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $compiler = $compilationContext->compiler;
     if (!in_array($className, array('self', 'static', 'parent'))) {
         $className = $compilationContext->getFullName($className);
         if ($compiler->isClass($className)) {
             $classDefinition = $compiler->getClassDefinition($className);
         } else {
             if ($compiler->isBundledClass($className)) {
                 $classDefinition = $compiler->getInternalClassDefinition($className);
             } else {
                 throw new CompilerException("Cannot locate class '" . $className . "'", $statement);
             }
         }
     } else {
         if (in_array($className, array('self', 'static'))) {
             $classDefinition = $compilationContext->classDefinition;
         } else {
             if ($className == 'parent') {
                 $classDefinition = $compilationContext->classDefinition;
                 $extendsClass = $classDefinition->getExtendsClass();
                 if (!$extendsClass) {
                     throw new CompilerException('Cannot assign static property "' . $property . '" on parent because class ' . $classDefinition->getCompleteName() . ' does not extend any class', $statement);
                 } else {
                     $classDefinition = $classDefinition->getExtendsClassDefinition();
                 }
             }
         }
     }
     if (!$classDefinition->hasProperty($property)) {
         throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement);
     }
     /** @var $propertyDefinition ClassProperty */
     $propertyDefinition = $classDefinition->getProperty($property);
     if (!$propertyDefinition->isStatic()) {
         throw new CompilerException("Cannot access non-static property '" . $classDefinition->getCompleteName() . '::' . $property . "'", $statement);
     }
     if ($propertyDefinition->isPrivate()) {
         if ($classDefinition != $compilationContext->classDefinition) {
             throw new CompilerException("Cannot access private static property '" . $classDefinition->getCompleteName() . '::' . $property . "' out of its declaring context", $statement);
         }
     }
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->headersManager->add('kernel/object');
     $classEntry = $classDefinition->getClassEntry($compilationContext);
     switch ($resolvedExpr->getType()) {
         case 'null':
             $compilationContext->backend->updateStaticProperty($classEntry, $property, 'null', $compilationContext);
             break;
         case 'int':
         case 'uint':
         case 'long':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'char':
         case 'uchar':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignLong($tempVariable, '\'' . $resolvedExpr->getCode() . '\'', $compilationContext);
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'double':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getCode(), $compilationContext);
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'string':
             switch ($statement['operator']) {
                 case 'assign':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $tempVariable->initVariant($compilationContext);
                     if ($resolvedExpr->getCode()) {
                         $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                     } else {
                         $codePrinter->output('ZVAL_EMPTY_STRING(' . $tempVariable->getName() . ');');
                     }
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
             }
             $codePrinter->output('zephir_update_static_property_ce(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ' TSRMLS_CC);');
             break;
         case 'bool':
             if ($resolvedExpr->getBooleanCode() == '1') {
                 $compilationContext->backend->updateStaticProperty($classEntry, $property, 'true', $compilationContext);
             } else {
                 if ($resolvedExpr->getBooleanCode() == '0') {
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, 'false', $compilationContext);
                 } else {
                     $codePrinter->output('if (' . $resolvedExpr->getBooleanCode() . ') {');
                     $codePrinter->increaseLevel();
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, 'true', $compilationContext);
                     $codePrinter->decreaseLevel();
                     $codePrinter->output('} else {');
                     $codePrinter->increaseLevel();
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, 'false', $compilationContext);
                     $codePrinter->decreaseLevel();
                     $codePrinter->output('}');
                 }
             }
             break;
         case 'empty-array':
             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
             $compilationContext->backend->initArray($tempVariable, $compilationContext);
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
             if ($tempVariable->isTemporal()) {
                 $tempVariable->setIdle(true);
             }
             break;
         case 'array':
             $compilationContext->backend->updateStaticProperty($classEntry, $property, $resolvedExpr, $compilationContext);
             break;
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
             switch ($variableVariable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext);
                     if ($compilationContext->insideCycle) {
                         $propertyCache = $compilationContext->symbolTable->getTempVariableForWrite('zend_property_info', $compilationContext);
                         $propertyCache->setMustInitNull(true);
                         $propertyCache->setReusable(false);
                         $codePrinter->output('zephir_update_static_property_ce_cache(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ', &' . $propertyCache->getName() . ' TSRMLS_CC);');
                     } else {
                         $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
                     }
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'double':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignDouble($tempVariable, $variableVariable, $compilationContext);
                     if ($compilationContext->insideCycle) {
                         $propertyCache = $compilationContext->symbolTable->getTempVariableForWrite('zend_property_info', $compilationContext);
                         $propertyCache->setMustInitNull(true);
                         $propertyCache->setReusable(false);
                         $codePrinter->output('zephir_update_static_property_ce_cache(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ', &' . $propertyCache->getName() . ' TSRMLS_CC);');
                     } else {
                         $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
                     }
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'bool':
                     $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                     $compilationContext->backend->assignBool($tempVariable, $variableVariable, $compilationContext);
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext);
                     if ($tempVariable->isTemporal()) {
                         $tempVariable->setIdle(true);
                     }
                     break;
                 case 'string':
                     switch ($statement['operator']) {
                         case 'concat-assign':
                             $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                             $expression = new Expression(array('type' => 'static-property-access', 'left' => array('value' => $statement['variable']), 'right' => array('value' => $statement['property'])));
                             $expression->setExpectReturn(true, $tempVariable);
                             $expression->compile($compilationContext);
                             $variableVariableCode = $compilationContext->backend->getVariableCode($variableVariable);
                             $tempVariableCode = $compilationContext->backend->getVariableCode($tempVariable);
                             $compilationContext->codePrinter->output('zephir_concat_function(' . $variableVariableCode . ', ' . $tempVariableCode . ', ' . $variableVariableCode . ');');
                             //continue
                         //continue
                         case 'assign':
                             $compilationContext->backend->updateStaticProperty($classEntry, $property, $variableVariable, $compilationContext);
                             if ($variableVariable->isTemporal()) {
                                 $variableVariable->setIdle(true);
                             }
                             break;
                         default:
                             throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement);
                     }
                     break;
                 case 'variable':
                 case 'array':
                     $compilationContext->backend->updateStaticProperty($classEntry, $property, $variableVariable, $compilationContext);
                     if ($variableVariable->isTemporal()) {
                         $variableVariable->setIdle(true);
                     }
                     break;
                 default:
                     throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement);
             }
             break;
         default:
             throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
     }
 }
Beispiel #10
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();');
 }
Beispiel #11
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $readDetector = new ReadDetector();
     $statement = $this->_statement;
     foreach ($statement['assignments'] as $assignment) {
         $variable = $assignment['variable'];
         /**
          * Get the symbol from the symbol table if necessary
          */
         switch ($assignment['assign-type']) {
             case 'static-property':
             case 'static-property-append':
             case 'static-property-array-index':
             case 'static-property-array-index-append':
             case 'dynamic-variable-string':
                 $symbolVariable = null;
                 break;
             case 'array-index':
             case 'variable-append':
             case 'object-property':
             case 'array-index-append':
             case 'string-dynamic-object-property':
             case 'variable-dynamic-object-property':
                 $symbolVariable = $compilationContext->symbolTable->getVariableForUpdate($variable, $compilationContext, $assignment);
                 break;
             default:
                 $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($variable, $compilationContext, $assignment);
                 break;
         }
         /**
          * Incr/Decr assignments don't require an expression
          */
         if (isset($assignment['expr'])) {
             $expr = new Expression($assignment['expr']);
             switch ($assignment['assign-type']) {
                 case 'variable':
                     if (!$readDetector->detect($variable, $assignment['expr'])) {
                         if (isset($assignment['operator'])) {
                             if ($assignment['operator'] == 'assign') {
                                 $expr->setExpectReturn(true, $symbolVariable);
                             }
                         } else {
                             $expr->setExpectReturn(true, $symbolVariable);
                         }
                     } else {
                         if (isset($assignment['operator'])) {
                             if ($assignment['operator'] == 'assign') {
                                 $expr->setExpectReturn(true);
                             }
                         } else {
                             $expr->setExpectReturn(true);
                         }
                     }
                     break;
             }
             switch ($assignment['expr']['type']) {
                 case 'property-access':
                 case 'array-access':
                 case 'type-hint':
                     $expr->setReadOnly(true);
                     break;
             }
             $resolvedExpr = $expr->compile($compilationContext);
             /**
              * Bad implemented operators could return values different than objects
              */
             if (!is_object($resolvedExpr)) {
                 throw new CompilerException("Resolved expression is not valid", $assignment['expr']);
             }
         }
         /**
          * There are four types of assignments
          */
         switch ($assignment['assign-type']) {
             case 'variable':
                 $let = new LetVariable();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $readDetector, $compilationContext, $assignment);
                 break;
             case 'variable-append':
                 $let = new LetVariableAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property':
                 $let = new LetObjectProperty();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'variable-dynamic-object-property':
                 $let = new LetObjectDynamicProperty();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'string-dynamic-object-property':
                 $let = new LetObjectDynamicStringProperty();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property':
                 $let = new LetStaticProperty();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property-append':
                 $let = new LetStaticPropertyAppend();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property-array-index':
                 $let = new LetStaticPropertyArrayIndex();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property-array-index-append':
                 $let = new LetStaticPropertyArrayIndexAppend();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'array-index':
                 $let = new LetArrayIndex();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'array-index-append':
                 $let = new LetArrayIndexAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property-append':
                 $let = new LetObjectPropertyAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property-array-index':
                 $let = new LetObjectPropertyArrayIndex();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property-array-index-append':
                 $let = new LetObjectPropertyArrayIndexAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'incr':
                 $let = new LetIncr();
                 $let->assign($variable, $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'decr':
                 $let = new LetDecr();
                 $let->assign($variable, $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'object-property-incr':
                 $let = new LetObjectPropertyIncr();
                 $let->assign($variable, $assignment['property'], $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'object-property-decr':
                 $let = new LetObjectPropertyDecr();
                 $let->assign($variable, $assignment['property'], $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'dynamic-variable':
                 $let = new LetExportSymbol();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'dynamic-variable-string':
                 $let = new LetExportSymbolString();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             default:
                 throw new CompilerException("Unknown assignment: " . $assignment['assign-type'], $assignment);
         }
     }
 }
Beispiel #12
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $statement = $this->_statement;
     if (!isset($statement['data-type'])) {
         throw new CompilerException("Data type is required", $this->_statement);
     }
     $typeInference = $compilationContext->typeInference;
     $symbolTable = $compilationContext->symbolTable;
     foreach ($statement['variables'] as $variable) {
         if ($symbolTable->hasVariable($variable['variable'])) {
             throw new CompilerException("Variable '" . $variable['variable'] . "' is already defined", $variable);
         }
         $currentType = $statement['data-type'];
         /**
          * Replace original data type by the pre-processed infered type
          */
         if ($typeInference) {
             if ($currentType == 'variable') {
                 $type = $typeInference->getInferedType($variable['variable']);
                 if (is_string($type)) {
                     $currentType = $type;
                 }
             }
         }
         /**
          * Variables are added to the symbol table
          */
         if (isset($variable['expr'])) {
             $symbolVariable = $symbolTable->addVariable($currentType, $variable['variable'], $compilationContext, $variable['expr']);
         } else {
             $symbolVariable = $symbolTable->addVariable($currentType, $variable['variable'], $compilationContext);
         }
         /**
          * Set the node where the variable is declared
          */
         $symbolVariable->setOriginal($variable);
         if (isset($variable['expr']['type'])) {
             $defaultType = $variable['expr']['type'];
         } else {
             $defaultType = null;
         }
         if (isset($variable['expr']['value'])) {
             $defaultValue = $variable['expr']['value'];
         } else {
             $defaultValue = null;
         }
         /**
          * Variables with a default value are initialized by default
          */
         if ($defaultValue !== null || $defaultType !== null) {
             if ($currentType == 'variable' || $currentType == 'string' || $currentType == 'array') {
                 $symbolVariable->increaseVariantIfNull();
             }
             switch ($currentType) {
                 case 'int':
                 case 'uint':
                 case 'ulong':
                 case 'long':
                     switch ($defaultType) {
                         case 'int':
                         case 'uint':
                         case 'ulong':
                             break;
                         case 'null':
                             $defaultValue = 0;
                             break;
                         default:
                             self::invalidDefaultTypeException($variable['expr']['type'], $statement['data-type'], $variable);
                     }
                     break;
                 case 'double':
                     switch ($defaultType) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'double':
                             break;
                         case 'null':
                             $defaultValue = 0;
                             break;
                         default:
                             self::invalidDefaultTypeException($variable['expr']['type'], $statement['data-type'], $variable);
                     }
                     break;
                 case 'bool':
                     switch ($defaultType) {
                         case 'bool':
                             if ($variable['expr']['value'] == 'true') {
                                 $defaultValue = 1;
                             } else {
                                 $defaultValue = 0;
                             }
                             break;
                         case 'null':
                             $defaultValue = 0;
                             break;
                         default:
                             self::invalidDefaultTypeException($variable['expr']['type'], $statement['data-type'], $variable);
                     }
                     break;
                 case 'char':
                 case 'uchar':
                     switch ($defaultType) {
                         case 'char':
                         case 'uchar':
                             $defaultValue = '\'' . $defaultValue . '\'';
                             break;
                         case 'int':
                             break;
                         case 'null':
                             $defaultValue = 0;
                             break;
                         default:
                             self::invalidDefaultTypeException($variable['expr']['type'], $statement['data-type'], $variable);
                     }
                     break;
                 case 'string':
                     $defaultValue = $variable['expr'];
                     switch ($defaultType) {
                         case 'string':
                         case 'null':
                             break;
                         default:
                             self::invalidDefaultTypeException($variable['expr']['type'], $statement['data-type'], $variable);
                     }
                     break;
                 case 'array':
                     $defaultValue = $variable['expr'];
                     switch ($defaultType) {
                         case 'null':
                         case 'array':
                         case 'empty-array':
                             break;
                         default:
                             self::invalidDefaultTypeException($variable['expr']['type'], $statement['data-type'], $variable);
                     }
                     break;
                 case 'variable':
                     $defaultValue = $variable['expr'];
                     switch ($defaultType) {
                         case 'int':
                         case 'uint':
                         case 'long':
                         case 'char':
                         case 'uchar':
                             $symbolVariable->setDynamicTypes('long');
                             break;
                         case 'double':
                             $symbolVariable->setDynamicTypes('double');
                             break;
                         case 'string':
                         case 'ulong':
                             $symbolVariable->setDynamicTypes('string');
                             break;
                         case 'array':
                             $expression = new Expression($variable['expr']);
                             $expression->setExpectReturn(true, $symbolVariable);
                             $expression->compile($compilationContext);
                             // no break
                         // no break
                         case 'array':
                         case 'empty-array':
                             $symbolVariable->setDynamicTypes('array');
                             break;
                         case 'null':
                             $symbolVariable->setDynamicTypes('null');
                             $symbolVariable->setMustInitNull(true);
                             $symbolVariable->setLocalOnly(false);
                             break;
                         default:
                             self::invalidDefaultTypeException($defaultType, $statement['data-type'], $variable);
                     }
                     break;
                 default:
                     throw new CompilerException('Invalid variable type: ' . $currentType, $variable);
             }
             $symbolVariable->setDefaultInitValue($defaultValue);
             $symbolVariable->setIsInitialized(true, $compilationContext);
             $symbolVariable->increaseMutates();
             $symbolVariable->setPossibleValue(new LiteralCompiledExpression($defaultType, $defaultValue, $variable['expr']), $compilationContext);
         }
     }
 }