/** * 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->y[] = foo * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement * @throws CompilerException */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement); } $codePrinter = $compilationContext->codePrinter; $property = $statement['property']; $compilationContext->headersManager->add('kernel/object'); /** * Check if the variable to update is defined */ if ($symbolVariable->getRealName() == 'this') { $classDefinition = $compilationContext->classDefinition; if (!$classDefinition->hasProperty($property)) { throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement); } $propertyDefinition = $classDefinition->getProperty($property); } else { /** * If we know the class related to a variable we could check if the property * is defined on that class */ if ($symbolVariable->hasAnyDynamicType('object')) { $classType = current($symbolVariable->getClassTypes()); $compiler = $compilationContext->compiler; if ($compiler->isClass($classType)) { $classDefinition = $compiler->getClassDefinition($classType); if (!$classDefinition) { throw new CompilerException("Cannot locate class definition for class: " . $classType, $statement); } if (!$classDefinition->hasProperty($property)) { throw new CompilerException("Class '" . $classType . "' does not have a property called: '" . $property . "'", $statement); } } } } switch ($resolvedExpr->getType()) { case 'null': $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, 'null', $compilationContext); break; case 'bool': $codePrinter->output('if (' . $resolvedExpr->getBooleanCode() . ') {'); $codePrinter->increaseLevel(); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, 'true', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('} else {'); $codePrinter->increaseLevel(); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, 'false', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('}'); break; case 'char': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignLong($tempVariable, '\'' . $resolvedExpr->getCode() . '\'', $compilationContext); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'int': case 'long': case 'uint': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'array': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $variableExpr, $compilationContext); break; case 'variable': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableExpr->getType()) { case 'int': case 'long': case 'uint': case 'char': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignLong($tempVariable, $variableExpr, $compilationContext); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignDouble($tempVariable, $variableExpr, $compilationContext); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignBool($tempVariable, $variableExpr, $compilationContext); $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'variable': case 'string': case 'array': case 'resource': case 'object': $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $variableExpr, $compilationContext); if ($variableExpr->isTemporal()) { $variableExpr->setIdle(true); } break; default: throw new CompilerException("Variable: " . $variableExpr->getType() . " cannot be appended to array property", $statement); } break; default: throw new CompilerException("Expression: " . $resolvedExpr->getType() . " cannot be appended to array property", $statement); } }
/** * Compiles x->y[] = foo * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement * @throws CompilerException */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement); } $codePrinter = $compilationContext->codePrinter; $property = $statement['property']; $compilationContext->headersManager->add('kernel/object'); /** * Check if the variable to update is defined */ if ($symbolVariable->getRealName() == 'this') { $classDefinition = $compilationContext->classDefinition; if (!$classDefinition->hasProperty($property)) { throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement); } $propertyDefinition = $classDefinition->getProperty($property); } else { /** * If we know the class related to a variable we could check if the property * is defined on that class */ if ($symbolVariable->hasAnyDynamicType('object')) { $classType = current($symbolVariable->getClassTypes()); $compiler = $compilationContext->compiler; if ($compiler->isClass($classType)) { $classDefinition = $compiler->getClassDefinition($classType); if (!$classDefinition) { throw new CompilerException("Cannot locate class definition for class: " . $classType, $statement); } if (!$classDefinition->hasProperty($property)) { throw new CompilerException("Class '" . $classType . "' does not have a property called: '" . $property . "'", $statement); } } } } switch ($resolvedExpr->getType()) { case 'null': $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); break; case 'bool': $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); break; case 'char': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getCode() . '\');'); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'int': case 'long': case 'uint': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'array': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $variableExpr->getName() . ' TSRMLS_CC);'); break; case 'variable': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableExpr->getType()) { case 'int': case 'long': case 'uint': case 'char': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');'); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');'); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');'); $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'variable': case 'string': case 'array': case 'resource': case 'object': $codePrinter->output('zephir_update_property_array_append(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $variableExpr->getName() . ' TSRMLS_CC);'); if ($variableExpr->isTemporal()) { $variableExpr->setIdle(true); } break; default: throw new CompilerException("Variable: " . $variableExpr->getType() . " cannot be appended to array property", $statement); } break; default: throw new CompilerException("Expression: " . $resolvedExpr->getType() . " cannot be appended to array property", $statement); } }
/** * Compiles x->y[z][] = foo * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext, * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement); } $this->_assignPropertyArrayMultipleIndex($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement); }
/** * Compiles foo->x = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement); } $propertyName = $statement['property']; $className = $compilationContext->classDefinition->getCompleteName(); if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate static property '" . $className . "::" . $propertyName . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement); } if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object'))) { $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement); } /** * Try to check if property is implemented on related object */ if ($variable == 'this') { if (!$compilationContext->classDefinition->hasProperty($propertyName)) { throw new CompilerException("Property '" . $propertyName . "' is not defined on class '" . $className . "'", $statement); } } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/object'); switch ($resolvedExpr->getType()) { case 'null': $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'null', $compilationContext); break; case 'int': case 'long': case 'uint': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'mul-assign': case 'sub-assign': case 'add-assign': switch ($statement['operator']) { case 'mul-assign': $functionName = 'ZEPHIR_MUL_ASSIGN'; break; case 'sub-assign': $functionName = 'ZEPHIR_SUB_ASSIGN'; break; case 'add-assign': $functionName = 'ZEPHIR_ADD_ASSIGN'; break; } $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignLong($resolvedVariable, $resolvedExpr->getBooleanCode(), $compilationContext); $codePrinter->output($functionName . '(' . $compilationContext->backend->getVariableCode($tempVariable) . ', ' . $compilationContext->backend->getVariableCode($resolvedVariable) . ')'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); $tempVariable->setIdle(true); break; case 'char': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'assign': $tempVariable->initNonReferenced($compilationContext); $compilationContext->backend->assignLong($tempVariable, '\'' . $resolvedExpr->getBooleanCode() . '\'', $compilationContext); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'mul-assign': case 'sub-assign': case 'add-assign': switch ($statement['operator']) { case 'mul-assign': $functionName = 'ZEPHIR_MUL_ASSIGN'; break; case 'sub-assign': $functionName = 'ZEPHIR_SUB_ASSIGN'; break; case 'add-assign': $functionName = 'ZEPHIR_ADD_ASSIGN'; break; } $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignDouble($resolvedVariable, $resolvedExpr->getBooleanCode(), $compilationContext); $codePrinter->output($functionName . '(' . $compilationContext->backend->getVariableCode($tempVariable) . ', ' . $compilationContext->backend->getVariableCode($resolvedVariable) . ')'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); $tempVariable->setIdle(true); break; case 'string': if ($compilationContext->backend->getName() == 'ZendEngine2') { $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); } else { $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, false); } switch ($statement['operator']) { case 'concat-assign': $codePrinter->output('zephir_concat_self_str(&' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);'); break; case 'assign': /* We only can use nonReferenced variables for not refcounted stuff in ZE3 */ if ($compilationContext->backend->getName() == 'ZendEngine2') { $tempVariable->initNonReferenced($compilationContext); } else { $tempVariable->initVariant($compilationContext); } $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext); break; } $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); $tempVariable->setIdle(true); break; case 'array': $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr, $compilationContext); break; case 'bool': $codePrinter->output('if (' . $resolvedExpr->getBooleanCode() . ') {'); $codePrinter->increaseLevel(); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'true', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('} else {'); $codePrinter->increaseLevel(); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'false', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('}'); break; /* unreachable code */ /* unreachable code */ case 'empty-array': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); $compilationContext->backend->initArray($tempVariable, $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr->getCode(), $compilationContext); $tempVariable->setIdle(true); break; case 'variable': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignDouble($tempVariable, $variableVariable, $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); $tempVariable->setIdle(true); break; case 'bool': $codePrinter->output('if (' . $variableVariable->getName() . ') {'); $codePrinter->increaseLevel(); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'true', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('} else {'); $codePrinter->increaseLevel(); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'false', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('}'); break; case 'array': case 'string': case 'variable': $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $variableVariable, $compilationContext); if ($symbolVariable->isTemporal()) { $symbolVariable->setIdle(true); } break; default: throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } }
/** * Compiles x->y[z] = foo * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext, * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement); } /** * Update the property according to the number of array-offsets */ if (count($statement['index-expr']) == 1) { $this->_assignPropertyArraySingleIndex($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement); } else { $this->_assignPropertyArrayMultipleIndex($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement); } }
/** * Compiles foo->{x} = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement * @throws CompilerException * @throws \Exception */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement); } $propertyName = $statement['property']; $propertyVariable = $compilationContext->symbolTable->getVariableForRead($propertyName, $compilationContext, $statement); if ($propertyVariable->isNotVariableAndString()) { throw new CompilerException("Cannot use variable type '" . $propertyVariable->getType() . "' to update object property", $statement); } if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate static property '" . $compilationContext->classDefinition->getCompleteName() . "::" . $propertyName . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement); } if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) { $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement); } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/object'); $propertyVariableName = $compilationContext->symbolTable->getVariable($propertyName); switch ($resolvedExpr->getType()) { case 'null': if ($variable == 'this') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } break; case 'int': case 'long': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'bool': if ($variable == 'this') { if ($resolvedExpr->getBooleanCode() == '1') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } else { if ($resolvedExpr->getBooleanCode() == '0') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } else { throw new \Exception('?'); } } } else { if ($resolvedExpr->getBooleanCode() == '1') { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } else { if ($resolvedExpr->getBooleanCode() == '0') { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } else { throw new \Exception('?'); } } } break; case 'empty-array': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('array_init(' . $tempVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'array': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); if ($variable == 'this') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ' . $variableVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ' . $variableVariable->getName() . ' TSRMLS_CC);'); } break; case 'variable': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_zval_zval(this_ptr, ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariableName->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'string': case 'variable': case 'array': $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariable->getName() . ', ' . $resolvedExpr->getCode() . ' TSRMLS_CC);'); if ($symbolVariable->isTemporal()) { $symbolVariable->setIdle(true); } break; default: throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } }
/** * Compiles foo->x = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement); } $propertyName = $statement['property']; $className = $compilationContext->classDefinition->getCompleteName(); if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate static property '" . $className . "::" . $propertyName . "' because it is not initialized", $statement); } if (!$symbolVariable->isVariable()) { throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement); } if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object'))) { $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement); } /** * Try to check if property is implemented on related object */ if ($variable == 'this') { if (!$compilationContext->classDefinition->hasProperty($propertyName)) { throw new CompilerException("Property '" . $propertyName . "' is not defined on class '" . $className . "'", $statement); } } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/object'); switch ($resolvedExpr->getType()) { case 'null': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } break; case 'int': case 'long': case 'uint': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'mul-assign': case 'sub-assign': case 'add-assign': switch ($statement['operator']) { case 'mul-assign': $functionName = 'ZEPHIR_MUL_ASSIGN'; break; case 'sub-assign': $functionName = 'ZEPHIR_SUB_ASSIGN'; break; case 'add-assign': $functionName = 'ZEPHIR_ADD_ASSIGN'; break; } $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $resolvedVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); $codePrinter->output($functionName . '(' . $tempVariable->getName() . ', ' . $resolvedVariable->getName() . ')'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'char': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getBooleanCode() . '\');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'mul-assign': case 'sub-assign': case 'add-assign': switch ($statement['operator']) { case 'mul-assign': $functionName = 'ZEPHIR_MUL_ASSIGN'; break; case 'sub-assign': $functionName = 'ZEPHIR_SUB_ASSIGN'; break; case 'add-assign': $functionName = 'ZEPHIR_ADD_ASSIGN'; break; } $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $resolvedVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); $codePrinter->output($functionName . '(' . $tempVariable->getName() . ', ' . $resolvedVariable->getName() . ')'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'concat-assign': $codePrinter->output('zephir_concat_self_str(&' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); break; } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'array': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC);'); } break; case 'bool': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } break; case 'empty-array': /* unreachable code */ $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); $codePrinter->output('array_init(' . $tempVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'variable': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'bool': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } break; case 'array': case 'string': case 'variable': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' TSRMLS_CC);'); } if ($symbolVariable->isTemporal()) { $symbolVariable->setIdle(true); } break; default: throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } }