/** * Compiles obj->x++ * * @param string $variable * @param string $property * @param ZephirVariable $symbolVariable * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, $property, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } /** * Arrays must be stored in the HEAP */ if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } /** * Only dynamic variables can be used as arrays */ if ($symbolVariable->getType() != 'variable') { throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement); } if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) { $compilationContext->logger->warning('Possible attempt to increment non-object dynamic variable', 'non-object-update', $statement); } $compilationContext->headersManager->add('kernel/object'); $compilationContext->codePrinter->output('RETURN_ON_FAILURE(zephir_property_incr(' . $symbolVariable->getName() . ', SL("' . $property . '") TSRMLS_CC));'); }
/** * Compiles obj->x++ * * @param string $variable * @param string $property * @param ZephirVariable $symbolVariable * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, $property, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } /** * Arrays must be stored in the HEAP */ if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } /** * Only dynamic variables can be used as arrays */ if (!$symbolVariable->isVariable()) { throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement); } if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) { $compilationContext->logger->warning('Possible attempt to increment non-object dynamic variable', 'non-object-update', $statement); } /** * Check if the variable to update is defined */ if ($symbolVariable->getRealName() == 'this') { $classDefinition = $compilationContext->classDefinition; if (!$classDefinition->hasProperty($property)) { throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement); } $propertyDefinition = $classDefinition->getProperty($property); } else { /** * If we know the class related to a variable we could check if the property * is defined on that class */ if ($symbolVariable->hasAnyDynamicType('object')) { $classType = current($symbolVariable->getClassTypes()); $compiler = $compilationContext->compiler; if ($compiler->isClass($classType)) { $classDefinition = $compiler->getClassDefinition($classType); if (!$classDefinition) { throw new CompilerException("Cannot locate class definition for class: " . $classType, $statement); } if (!$classDefinition->hasProperty($property)) { throw new CompilerException("Class '" . $classType . "' does not have a property called: '" . $property . "'", $statement); } } } } $compilationContext->headersManager->add('kernel/object'); $compilationContext->codePrinter->output('RETURN_ON_FAILURE(zephir_property_incr(' . $symbolVariable->getName() . ', SL("' . $property . '") TSRMLS_CC));'); }
/** * Compiles x-- * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->isReadOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement); } $codePrinter = $compilationContext->codePrinter; switch ($symbolVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'double': case 'char': case 'uchar': $codePrinter->output($variable . '--;'); break; case 'variable': /** * Variable is probably not initialized here */ if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Attempt to increment uninitialized variable", $statement); } /** * Decrement non-numeric variables could be expensive */ if (!$symbolVariable->hasAnyDynamicType(array('undefined', 'int', 'long', 'double', 'uint'))) { $compilationContext->logger->warning('Possible attempt to decrement non-numeric dynamic variable', 'non-valid-decrement', $statement); } $compilationContext->headersManager->add('kernel/operators'); if ($symbolVariable->isLocalOnly()) { $codePrinter->output('zephir_decrement(&' . $variable . ');'); } else { $symbolVariable->separate($compilationContext); $codePrinter->output('zephir_decrement(' . $variable . ');'); } break; default: throw new CompilerException("Cannot decrement variable: " . $symbolVariable->getType(), $statement); } }
/** * Compiles x++ * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompilationContext $compilationContext * @param array $statement * * @throws CompilerException */ public function assign($variable, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->isReadOnly()) { /** * @TODO implement increment of objects members */ throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement); } $codePrinter =& $compilationContext->codePrinter; switch ($symbolVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'double': case 'char': case 'uchar': $codePrinter->output($variable . '++;'); break; case 'variable': /** * Update non-numeric dynamic variables could be expensive */ if (!$symbolVariable->hasAnyDynamicType(array('undefined', 'long', 'double'))) { $compilationContext->logger->warning('Possible attempt to increment non-numeric dynamic variable', 'non-valid-increment', $statement); } $compilationContext->headersManager->add('kernel/operators'); if (!$symbolVariable->isLocalOnly()) { $symbolVariable->separate($compilationContext); } $symbol = $compilationContext->backend->getVariableCode($symbolVariable); $codePrinter->output('zephir_increment(' . $symbol . ');'); break; default: throw new CompilerException("Cannot increment: " . $symbolVariable->getType(), $statement); } }
public function generateInitCode(&$groupVariables, $type, $pointer, Variable $variable) { $isComplex = $type == 'variable' || $type == 'string' || $type == 'array' || $type == 'resource' || $type == 'callable' || $type == 'object'; if ($isComplex && !$variable->isDoublePointer()) { /* && $variable->mustInitNull() */ $groupVariables[] = $variable->getName(); if ($variable->getRealname() == '__$null') { return "\t" . 'ZVAL_NULL(&' . $variable->getName() . ');'; } else { if ($variable->getRealname() == '__$true') { return "\t" . 'ZVAL_BOOL(&' . $variable->getName() . ', 1);'; } else { if ($variable->getRealname() == '__$false') { return "\t" . 'ZVAL_BOOL(&' . $variable->getName() . ', 0);'; } } } return "\t" . 'ZVAL_UNDEF(&' . $variable->getName() . ');'; } if ($variable->isLocalOnly()) { $groupVariables[] = $variable->getName(); return; } if ($variable->isDoublePointer()) { /* Double pointers for ZE3 are used as zval * */ $ptr = $isComplex ? $pointer : $pointer . $pointer; if ($variable->mustInitNull()) { $groupVariables[] = $ptr . $variable->getName() . ' = NULL'; } else { $groupVariables[] = $ptr . $variable->getName(); } return; } $defaultValue = $variable->getDefaultInitValue(); if ($defaultValue !== null) { switch ($type) { case 'variable': case 'string': case 'array': case 'resource': case 'callable': case 'object': $groupVariables[] = $pointer . $variable->getName(); break; case 'char': if (strlen($defaultValue) > 4) { if (strlen($defaultValue) > 10) { throw new CompilerException("Invalid char literal: '" . substr($defaultValue, 0, 10) . "...'", $variable->getOriginal()); } else { throw new CompilerException("Invalid char literal: '" . $defaultValue . "'", $variable->getOriginal()); } } /* no break */ /* no break */ default: $groupVariables[] = $pointer . $variable->getName() . ' = ' . $defaultValue; break; } return; } if ($variable->mustInitNull() && $pointer) { $groupVariables[] = $pointer . $variable->getName() . ' = NULL'; return; } $groupVariables[] = $pointer . $variable->getName(); }
public function generateInitCode(&$groupVariables, $type, $pointer, Variable $variable) { $isComplex = $type == 'variable' || $type == 'string' || $type == 'array' || $type == 'resource' || $type == 'callable' || $type == 'object'; if ($isComplex && $variable->mustInitNull()) { if ($variable->isLocalOnly()) { $groupVariables[] = $variable->getName() . ' = zval_used_for_init'; } else { if ($variable->isDoublePointer()) { $groupVariables[] = $pointer . $pointer . $variable->getName() . ' = NULL'; } else { $groupVariables[] = $pointer . $variable->getName() . ' = NULL'; } } return; } if ($variable->isLocalOnly()) { $groupVariables[] = $variable->getName(); return; } if ($variable->isDoublePointer()) { if ($variable->mustInitNull()) { $groupVariables[] = $pointer . $pointer . $variable->getName() . ' = NULL'; } else { $groupVariables[] = $pointer . $pointer . $variable->getName(); } return; } $defaultValue = $variable->getDefaultInitValue(); if ($defaultValue !== null) { switch ($type) { case 'variable': case 'string': case 'array': case 'resource': case 'callable': case 'object': $groupVariables[] = $pointer . $variable->getName(); break; case 'char': if (strlen($defaultValue) > 4) { if (strlen($defaultValue) > 10) { throw new CompilerException("Invalid char literal: '" . substr($defaultValue, 0, 10) . "...'", $variable->getOriginal()); } else { throw new CompilerException("Invalid char literal: '" . $defaultValue . "'", $variable->getOriginal()); } } /* no break */ /* no break */ default: $groupVariables[] = $pointer . $variable->getName() . ' = ' . $defaultValue; break; } return; } if ($variable->mustInitNull() && $pointer) { $groupVariables[] = $pointer . $variable->getName() . ' = NULL'; return; } $groupVariables[] = $pointer . $variable->getName(); }
/** * Compiles foo[y] = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { /** * Arrays must be stored in the HEAP */ if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->isReadOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement); } if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } /** * Only dynamic variables can be used as arrays */ if ($symbolVariable->isNotVariableAndArray()) { throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement); } if ($symbolVariable->getType() == 'variable') { if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) { $compilationContext->logger->warning('Possible attempt to update index on a non-array dynamic variable', 'non-array-update', $statement); } } /** * Choose one-offset or multiple-offset functions */ if (count($statement['index-expr']) == 1) { $this->_assignArrayIndexSingle($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement); } else { $this->_assignArrayIndexMultiple($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement); } }
/** * Compiles foo = {expr} * Changes the value of a mutable variable * * @param $variable * @param Variable $symbolVariable * @param CompiledExpression $resolvedExpr * @param ReadDetector $readDetector * @param CompilationContext $compilationContext * @param $statement * @throws CompilerException */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, ReadDetector $readDetector, CompilationContext $compilationContext, $statement) { if ($symbolVariable->isReadOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement); } $codePrinter = $compilationContext->codePrinter; /** * Only initialize variables if it's direct assignment */ if ($statement['operator'] == 'assign') { $symbolVariable->setIsInitialized(true, $compilationContext, $statement); } else { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } } /** * Set the assigned value to the variable as a CompiledExpression * We could use this expression for further analysis */ $symbolVariable->setPossibleValue($resolvedExpr, $compilationContext); $type = $symbolVariable->getType(); switch ($type) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': switch ($resolvedExpr->getType()) { case 'null': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = 0;'); break; case 'add-assign': $codePrinter->output($variable . ' += 0;'); break; case 'sub-assign': $codePrinter->output($variable . ' -= 0;'); break; case 'mul-assign': $codePrinter->output($variable . ' *= 0;'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; case 'int': case 'uint': case 'long': case 'ulong': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $resolvedExpr->getCode() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += ' . $resolvedExpr->getCode() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= ' . $resolvedExpr->getCode() . ';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= ' . $resolvedExpr->getCode() . ';'); break; case 'div-assign': $codePrinter->output($variable . ' /= ' . $resolvedExpr->getCode() . ';'); break; case 'mod-assign': $codePrinter->output($variable . ' %= ' . $resolvedExpr->getCode() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; case 'char': case 'uchar': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = \'' . $resolvedExpr->getCode() . '\';'); break; case 'add-assign': $codePrinter->output($variable . ' += \'' . $resolvedExpr->getCode() . '\';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= \'' . $resolvedExpr->getCode() . '\';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= \'' . $resolvedExpr->getCode() . '\';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; case 'double': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = (long) (' . $resolvedExpr->getCode() . ');'); break; case 'add-assign': $codePrinter->output($variable . ' += (long) (' . $resolvedExpr->getCode() . ');'); break; case 'sub-assign': $codePrinter->output($variable . ' -= (long) (' . $resolvedExpr->getCode() . ');'); break; case 'mul-assign': $codePrinter->output($variable . ' *= (long) (' . $resolvedExpr->getCode() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; case 'bool': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $resolvedExpr->getBooleanCode() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += ' . $resolvedExpr->getBooleanCode() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= ' . $resolvedExpr->getBooleanCode() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; case 'variable': $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($itemVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'bool': case 'char': case 'uchar': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $itemVariable->getName() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += ' . $itemVariable->getName() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= ' . $itemVariable->getName() . ';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= ' . $itemVariable->getName() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; case 'double': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = (long) ' . $itemVariable->getName() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += (long) ' . $itemVariable->getName() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= (long) ' . $itemVariable->getName() . ';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= (long) ' . $itemVariable->getName() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; case 'variable': $compilationContext->headersManager->add('kernel/operators'); switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');'); break; case 'add-assign': $codePrinter->output($variable . ' += zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');'); break; case 'sub-assign': $codePrinter->output($variable . ' -= zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');'); break; case 'mul-assign': $codePrinter->output($variable . ' *= zephir_get_numberval(' . $resolvedExpr->resolve(null, $compilationContext) . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: int", $statement); } break; default: throw new CompilerException("Unknown type: " . $itemVariable->getType(), $statement); } break; default: throw new CompilerException("Value type '" . $resolvedExpr->getType() . "' cannot be assigned to variable: int", $statement); } break; case 'double': switch ($resolvedExpr->getType()) { case 'null': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = 0.0;'); break; case 'add-assign': $codePrinter->output($variable . ' += 0.0;'); break; case 'sub-assign': $codePrinter->output($variable . ' -= 0.0;'); break; case 'mul-assign': $codePrinter->output($variable . ' *= 0.0;'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement); } break; case 'int': case 'uint': case 'long': case 'ulong': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = (double) (' . $resolvedExpr->getCode() . ');'); break; case 'add-assign': $codePrinter->output($variable . ' += (double) (' . $resolvedExpr->getCode() . ');'); break; case 'sub-assign': $codePrinter->output($variable . ' -= (double) (' . $resolvedExpr->getCode() . ');'); break; case 'mul-assign': $codePrinter->output($variable . ' *= (double) (' . $resolvedExpr->getCode() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement); } break; case 'double': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $resolvedExpr->getCode() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += ' . $resolvedExpr->getCode() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= ' . $resolvedExpr->getCode() . ';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= ' . $resolvedExpr->getCode() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement); } break; case 'bool': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $resolvedExpr->getBooleanCode() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += ' . $resolvedExpr->getBooleanCode() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= ' . $resolvedExpr->getBooleanCode() . ';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= ' . $resolvedExpr->getBooleanCode() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement); } break; case 'variable': $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($itemVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'bool': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = (double) ' . $itemVariable->getName() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += (double) ' . $itemVariable->getName() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= (double) ' . $itemVariable->getName() . ';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= (double) ' . $itemVariable->getName() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement); } break; case 'double': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $itemVariable->getName() . ';'); break; case 'add-assign': $codePrinter->output($variable . ' += ' . $itemVariable->getName() . ';'); break; case 'sub-assign': $codePrinter->output($variable . ' -= ' . $itemVariable->getName() . ';'); break; case 'mul-assign': $codePrinter->output($variable . ' *= ' . $itemVariable->getName() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement); } break; case 'variable': $compilationContext->headersManager->add('kernel/operators'); switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = zephir_get_numberval(' . $itemVariable->getName() . ');'); break; case 'add-assign': $codePrinter->output($variable . ' += zephir_get_numberval(' . $itemVariable->getName() . ');'); break; case 'sub-assign': $codePrinter->output($variable . ' -= zephir_get_numberval(' . $itemVariable->getName() . ');'); break; case 'mul-assign': $codePrinter->output($variable . ' *= zephir_get_numberval(' . $itemVariable->getName() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: double", $statement); } break; default: throw new CompilerException("Unknown type: " . $itemVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } break; case 'array': switch ($resolvedExpr->getType()) { case 'variable': case 'array': switch ($statement['operator']) { case 'assign': if ($variable != $resolvedExpr->getCode()) { $symbolVariable->setMustInitNull(true); $compilationContext->symbolTable->mustGrownStack(true); /* Inherit the dynamic type data from the assigned value */ $symbolVariable->setDynamicTypes('array'); $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $resolvedExpr->getCode() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; default: throw new CompilerException("You cannot {$statement['operator']} {$resolvedExpr->getType()} for array type", $resolvedExpr->getOriginal()); } break; case 'string': switch ($resolvedExpr->getType()) { case 'null': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_EMPTY_STRING(' . $variable . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } break; case 'string': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); if ($resolvedExpr->getCode()) { $codePrinter->output('ZVAL_STRING(' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);'); } else { $codePrinter->output('ZVAL_EMPTY_STRING(' . $variable . ');'); } break; case 'concat-assign': $codePrinter->output('zephir_concat_self_str(&' . $variable . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } break; case 'char': case 'uchar': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); if ($resolvedExpr->getCode()) { $codePrinter->output('ZVAL_STRING(' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);'); } else { $codePrinter->output('ZVAL_EMPTY_STRING(' . $variable . ');'); } break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self_str(&' . $variable . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } break; case 'variable': $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($itemVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $compilationContext->headersManager->add('kernel/string'); $codePrinter->output('Z_STRLEN_P(' . $variable . ') = zephir_spprintf(&Z_STRVAL_P(' . $variable . '), 0, "%ld", ' . $itemVariable->getName() . ');'); $codePrinter->output('Z_TYPE_P(' . $variable . ') = IS_STRING;'); break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self_long(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } break; case 'char': case 'uchar': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $compilationContext->headersManager->add('kernel/string'); $codePrinter->output('Z_STRLEN_P(' . $variable . ') = zephir_spprintf(&Z_STRVAL_P(' . $variable . '), 0, "%c", ' . $itemVariable->getName() . ');'); $codePrinter->output('Z_TYPE_P(' . $variable . ') = IS_STRING;'); break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self_char(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } break; case 'string': switch ($statement['operator']) { case 'assign': $symbolVariable->setMustInitNull(true); $compilationContext->symbolTable->mustGrownStack(true); if ($variable != $itemVariable->getName()) { $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $itemVariable->getName() . ');'); } break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } break; case 'variable': switch ($statement['operator']) { case 'assign': $symbolVariable->setMustInitNull(true); $compilationContext->symbolTable->mustGrownStack(true); $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_get_strval(' . $variable . ', ' . $itemVariable->getName() . ');'); break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type: " . $itemVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } break; case 'bool': switch ($resolvedExpr->getType()) { case 'null': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = 0;'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: null", $statement); } break; case 'int': case 'uint': case 'long': case 'ulong': case 'double': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = (' . $resolvedExpr->getCode() . ') ? 1 : 0;'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $statement); } break; case 'char': case 'uchar': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = (\'' . $resolvedExpr->getCode() . '\') ? 1 : 0;'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $statement); } break; case 'bool': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $resolvedExpr->getBooleanCode() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $statement); } break; case 'variable': $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($itemVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'double': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = (' . $itemVariable->getName() . ') ? 1 : 0;'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; case 'bool': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = ' . $itemVariable->getName() . ';'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; case 'variable': case 'string': case 'array': switch ($statement['operator']) { case 'assign': $codePrinter->output($variable . ' = zephir_is_true(' . $itemVariable->getName() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; default: throw new CompilerException("Cannot assign variable: " . $itemVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type: " . $resolvedExpr->getType(), $statement); } break; case 'variable': switch ($resolvedExpr->getType()) { case 'null': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $symbolVariable->setDynamicTypes('null'); if ($symbolVariable->isLocalOnly()) { $codePrinter->output('ZVAL_NULL(&' . $variable . ');'); } else { $codePrinter->output('ZVAL_NULL(' . $variable . ');'); } break; } break; case 'int': case 'uint': case 'long': case 'ulong': if ($symbolVariable->isLocalOnly()) { $symbol = '&' . $variable; } else { $symbol = $variable; } switch ($statement['operator']) { case 'mul-assign': case 'sub-assign': case 'add-assign': switch ($statement['operator']) { case 'mul-assign': $functionName = 'ZEPHIR_MUL_ASSIGN'; break; case 'sub-assign': $functionName = 'ZEPHIR_SUB_ASSIGN'; break; case 'add-assign': $functionName = 'ZEPHIR_ADD_ASSIGN'; break; } $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $compilationContext->symbolTable->mustGrownStack(true); $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output($functionName . '(' . $symbol . ', ' . $tempVariable->getName() . ');'); break; case 'assign': $symbolVariable->setDynamicTypes('long'); if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) { $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('int', $compilationContext); $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';'); $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_LONG(' . $symbol . ', ' . $tempVariable->getName() . ');'); } else { $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_LONG(' . $symbol . ', ' . $resolvedExpr->getCode() . ');'); } break; case 'div-assign': $symbolVariable->setDynamicTypes('double'); if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) { $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('double', $compilationContext); $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';'); $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $tempVariable->getName() . ');'); } else { $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $resolvedExpr->getCode() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; case 'char': case 'uchar': if ($symbolVariable->isLocalOnly()) { $symbol = '&' . $variable; } else { $symbol = $variable; } switch ($statement['operator']) { case 'assign': $symbolVariable->setDynamicTypes('long'); if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) { $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('char', $compilationContext); $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';'); $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_LONG(' . $symbol . ', ' . $tempVariable->getName() . ');'); } else { $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_LONG(' . $symbol . ', \'' . $resolvedExpr->getCode() . '\');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; case 'double': if ($symbolVariable->isLocalOnly()) { $symbol = '&' . $variable; } else { $symbol = $variable; } switch ($statement['operator']) { case 'assign': $symbolVariable->setDynamicTypes('double'); if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) { $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('double', $compilationContext); $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getCode() . ';'); $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $tempVariable->getName() . ');'); } else { $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $symbol . ', ' . $resolvedExpr->getCode() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; case 'bool': if ($symbolVariable->isLocalOnly()) { $symbol = '&' . $variable; } else { $symbol = $variable; } switch ($statement['operator']) { case 'assign': $symbolVariable->setDynamicTypes('bool'); if ($resolvedExpr->getCode() == 'true') { $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_BOOL(' . $symbol . ', 1);'); } else { if ($resolvedExpr->getCode() == 'false') { $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_BOOL(' . $symbol . ', 0);'); } else { if ($readDetector->detect($variable, $resolvedExpr->getOriginal())) { $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('double', $compilationContext); $codePrinter->output($tempVariable->getName() . ' = ' . $resolvedExpr->getBooleanCode() . ';'); $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_BOOL(' . $symbol . ', ' . $tempVariable->getName() . ');'); } else { $symbolVariable->initVariant($compilationContext); $codePrinter->output('ZVAL_BOOL(' . $symbol . ', ' . $resolvedExpr->getBooleanCode() . ');'); } } } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; case 'string': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $symbolVariable->setDynamicTypes('string'); if ($symbolVariable->isLocalOnly()) { $codePrinter->output('ZVAL_STRING(&' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);'); } else { $codePrinter->output('ZVAL_STRING(' . $variable . ', "' . $resolvedExpr->getCode() . '", 1);'); } break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self_str(&' . $variable . ', SL("' . $resolvedExpr->getCode() . '") TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; case 'array': switch ($statement['operator']) { case 'assign': if ($variable != $resolvedExpr->getCode()) { $symbolVariable->setMustInitNull(true); $compilationContext->symbolTable->mustGrownStack(true); /* Inherit the dynamic type data from the assigned value */ $symbolVariable->setDynamicTypes('array'); $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $resolvedExpr->getCode() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; case 'variable': $itemVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $resolvedExpr->getOriginal()); switch ($itemVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $symbolVariable->setDynamicTypes('long'); if ($symbolVariable->isLocalOnly()) { $codePrinter->output('ZVAL_LONG(&' . $variable . ', ' . $itemVariable->getName() . ');'); } else { $codePrinter->output('ZVAL_LONG(' . $variable . ', ' . $itemVariable->getName() . ');'); } break; case 'add-assign': $compilationContext->headersManager->add('kernel/operators'); $symbolVariable->initVariant($compilationContext); $symbolVariable->setDynamicTypes('long'); $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite($itemVariable->getType(), $compilationContext); if ($symbolVariable->isLocalOnly()) { $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(&' . $variable . ');'); $codePrinter->output('ZVAL_LONG(&' . $variable . ', ' . $tempVariable->getName() . ' + ' . $itemVariable->getName() . ');'); } else { $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(' . $variable . ');'); $codePrinter->output('ZVAL_LONG(' . $variable . ', ' . $tempVariable->getName() . ' + ' . $itemVariable->getName() . ');'); } break; case 'sub-assign': $compilationContext->headersManager->add('kernel/operators'); $symbolVariable->initVariant($compilationContext); $symbolVariable->setDynamicTypes('long'); $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite($itemVariable->getType(), $compilationContext); if ($symbolVariable->isLocalOnly()) { $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(&' . $variable . ');'); $codePrinter->output('ZVAL_LONG(&' . $variable . ', ' . $tempVariable->getName() . ' - ' . $itemVariable->getName() . ');'); } else { $codePrinter->output($tempVariable->getName() . ' = zephir_get_numberval(' . $variable . ');'); $codePrinter->output('ZVAL_LONG(' . $variable . ', ' . $tempVariable->getName() . ' - ' . $itemVariable->getName() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; case 'double': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $symbolVariable->setDynamicTypes('double'); if ($symbolVariable->isLocalOnly()) { $codePrinter->output('ZVAL_DOUBLE(&' . $variable . ', ' . $itemVariable->getName() . ');'); } else { $codePrinter->output('ZVAL_DOUBLE(' . $variable . ', ' . $itemVariable->getName() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; case 'bool': switch ($statement['operator']) { case 'assign': $symbolVariable->initVariant($compilationContext); $symbolVariable->setDynamicTypes('bool'); if ($symbolVariable->isLocalOnly()) { $codePrinter->output('ZVAL_BOOL(&' . $variable . ', ' . $itemVariable->getName() . ');'); } else { $codePrinter->output('ZVAL_BOOL(' . $variable . ', ' . $itemVariable->getName() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; case 'array': switch ($statement['operator']) { case 'assign': if ($variable != $resolvedExpr->getCode()) { $symbolVariable->setMustInitNull(true); $compilationContext->symbolTable->mustGrownStack(true); /* Inherit the dynamic type data from the assigned value */ $symbolVariable->setDynamicTypes('array'); $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $resolvedExpr->getCode() . ');'); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; case 'variable': switch ($statement['operator']) { case 'assign': if ($itemVariable->getName() != $variable) { $symbolVariable->setMustInitNull(true); $compilationContext->symbolTable->mustGrownStack(true); /* Inherit the dynamic type data from the assigned value */ $symbolVariable->setDynamicTypes($itemVariable->getDynamicTypes()); $symbolVariable->setClassTypes($itemVariable->getClassTypes()); $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $itemVariable->getName() . ');'); if ($itemVariable->isTemporal()) { $itemVariable->setIdle(true); } } break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);'); break; case 'add-assign': $compilationContext->symbolTable->mustGrownStack(true); $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('ZEPHIR_ADD_ASSIGN(' . $variable . ', ' . $itemVariable->getName() . ');'); break; case 'sub-assign': $compilationContext->symbolTable->mustGrownStack(true); $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('ZEPHIR_SUB_ASSIGN(' . $variable . ', ' . $itemVariable->getName() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; case 'string': switch ($statement['operator']) { case 'assign': if ($itemVariable->getName() != $variable) { $symbolVariable->setMustInitNull(true); $compilationContext->symbolTable->mustGrownStack(true); /* Inherit the dynamic type data from the assigned value */ $symbolVariable->setDynamicTypes($itemVariable->getDynamicTypes()); $symbolVariable->setClassTypes($itemVariable->getClassTypes()); $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable . ', ' . $itemVariable->getName() . ');'); if ($itemVariable->isTemporal()) { $itemVariable->setIdle(true); } } break; case 'concat-assign': $compilationContext->headersManager->add('kernel/operators'); $codePrinter->output('zephir_concat_self(&' . $variable . ', ' . $itemVariable->getName() . ' TSRMLS_CC);'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: " . $itemVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type: " . $itemVariable->getType(), $resolvedExpr->getOriginal()); } break; default: throw new CompilerException("Unknown type: " . $resolvedExpr->getType(), $resolvedExpr->getOriginal()); } break; default: throw new CompilerException("Unknown type: " . $type, $statement); } }
/** * Compiles foo[] = {expr} * * @param $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param $statement * @throws CompilerException */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->isReadOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement); } if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } if ($symbolVariable->getType() != 'variable') { throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement); } if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'array'))) { $compilationContext->logger->warning('Possible attempt to append elements on a non-array dynamic variable', 'non-array-append', $statement); } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/array'); $type = $symbolVariable->getType(); switch ($type) { case 'variable': switch ($resolvedExpr->getType()) { case 'null': $codePrinter->output('zephir_array_append(&' . $variable . ', ZEPHIR_GLOBAL(global_null), PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); break; case 'int': case 'uint': case 'long': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_LONG(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); $symbolVariable->setIdle(true); break; case 'double': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_DOUBLE(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); $symbolVariable->setIdle(true); break; case 'bool': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_BOOL(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); $symbolVariable->setIdle(true); break; case 'ulong': case 'string': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_STRING(' . $symbolVariable->getName() . ', "' . Utils::addSlashes($resolvedExpr->getCode(), true) . '", 1);'); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); $symbolVariable->setIdle(true); break; case 'array': $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $exprVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); break; case 'variable': $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($exprVariable->getType()) { case 'int': case 'uint': case 'long': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_LONG(' . $symbolVariable->getName() . ', ' . $exprVariable->getName() . ');'); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); $symbolVariable->setIdle(true); break; case 'double': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_DOUBLE(' . $symbolVariable->getName() . ', ' . $exprVariable->getName() . ');'); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); $symbolVariable->setIdle(true); break; case 'bool': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_BOOL(' . $symbolVariable->getName() . ', ' . $exprVariable->getName() . ');'); $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $symbolVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); $symbolVariable->setIdle(true); break; case 'variable': case 'string': case 'array': $codePrinter->output('zephir_array_append(&' . $variable . ', ' . $exprVariable->getName() . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'); break; default: throw new CompilerException("Unknown type " . $exprVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } break; default: throw new CompilerException("Unknown type", $statement); } }
/** * Compiles foo[] = {expr} * * @param $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param $statement * @throws CompilerException */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->isReadOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement); } if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } /** * Only dynamic variables and arrays can be used as arrays */ if ($symbolVariable->isNotVariableAndArray()) { throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as an array", $statement); } if ($symbolVariable->getType() == 'variable') { if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'array'))) { $compilationContext->logger->warning('Possible attempt to append elements on a non-array dynamic variable', 'non-array-append', $statement); } } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/array'); $type = $symbolVariable->getType(); switch ($type) { case 'array': case 'variable': switch ($resolvedExpr->getType()) { case 'null': $compilationContext->backend->addArrayEntry($symbolVariable, null, 'null', $compilationContext, $statement); break; case 'int': case 'uint': case 'long': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement); $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement); $tempVariable->setIdle(true); break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $compilationContext->backend->assignBool($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext); $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement); $tempVariable->setIdle(true); break; case 'ulong': case 'string': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext); $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement); $tempVariable->setIdle(true); break; case 'array': $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); $compilationContext->backend->addArrayEntry($symbolVariable, null, $exprVariable, $compilationContext, $statement); break; case 'variable': $exprVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($exprVariable->getType()) { case 'int': case 'uint': case 'long': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $compilationContext->backend->assignLong($tempVariable, $exprVariable, $compilationContext); $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement); $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $compilationContext->backend->assignDouble($tempVariable, $exprVariable, $compilationContext); $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement); $tempVariable->setIdle(true); break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $compilationContext->backend->assignBool($tempVariable, $exprVariable, $compilationContext); $compilationContext->backend->addArrayEntry($symbolVariable, null, $tempVariable, $compilationContext, $statement); $tempVariable->setIdle(true); break; case 'variable': case 'string': case 'array': $compilationContext->backend->addArrayEntry($symbolVariable, null, $exprVariable, $compilationContext, $statement); break; default: throw new CompilerException("Unknown type: " . $exprVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type: " . $resolvedExpr->getType(), $statement); } break; default: throw new CompilerException("Unknown type: " . $type, $statement); } }