/** * Compiles {var} = {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) { $codePrinter = $compilationContext->codePrinter; $codePrinter->output('if (zephir_set_symbol(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ' TSRMLS_CC) == FAILURE){'); $codePrinter->output(' return;'); $codePrinter->output('}'); }
/** * Compiles {"var"} = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext, * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable = null, CompiledExpression $resolvedExpr = null, CompilationContext $compilationContext = null, $statement = null) { $codePrinter = $compilationContext->codePrinter; $codePrinter->output('if (zephir_set_symbol_str(SS("' . $statement["variable"] . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC) == FAILURE){'); $codePrinter->output(' return;'); $codePrinter->output('}'); }
/** * Compiles {"var"} = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext, * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable = null, CompiledExpression $resolvedExpr = null, CompilationContext $compilationContext = null, $statement = null) { $codePrinter = $compilationContext->codePrinter; $variable = $compilationContext->symbolTable->getTempVariable('variable', $compilationContext, $statement); $variable->setMustInitNull(true); $letStatement = new LetStatement(array('type' => 'let', 'assignments' => array(array('assign-type' => 'variable', 'variable' => $variable->getName(), 'operator' => 'assign', 'expr' => array('type' => $resolvedExpr->getType(), 'value' => $resolvedExpr->getCode(), 'file' => $statement['file'], 'line' => $statement['line'], 'char' => $statement['char']), 'file' => $statement['file'], 'line' => $statement['line'], 'char' => $statement['char'])))); $letStatement->compile($compilationContext); $codePrinter->output('if (zephir_set_symbol_str(SS("' . $statement["variable"] . '"), ' . $variable->getName() . ' TSRMLS_CC) == FAILURE){'); $codePrinter->output(' return;'); $codePrinter->output('}'); }
/** * Compiles foo->{x} = {expr} * * @param string $variable * @param Variable $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->getType() != 'variable') { 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->getType() != 'variable') { 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_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $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_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $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_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'bool': if ($variable == 'this') { if ($resolvedExpr->getBooleanCode() == '1') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } } else { if ($resolvedExpr->getBooleanCode() == '1') { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } } break; case 'empty-array': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('array_init(' . $tempVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->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(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $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_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'string': case 'variable': $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 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 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 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->getType() != 'variable') { 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->getType() != 'variable') { 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); } }
/** * Resolves an item that will be assigned to an array offset * * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext */ protected function _getResolvedArrayItem(CompiledExpression $resolvedExpr, CompilationContext $compilationContext) { $codePrinter = $compilationContext->codePrinter; switch ($resolvedExpr->getType()) { case 'null': $symbolVariable = new GlobalConstant('ZEPHIR_GLOBAL(global_null)'); break; case 'int': case 'uint': case 'long': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_LONG(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); break; case 'char': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_LONG(' . $symbolVariable->getName() . ', \'' . $resolvedExpr->getCode() . '\');'); break; case 'double': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_DOUBLE(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); break; case 'bool': if ($resolvedExpr->getBooleanCode() == '1') { $symbolVariable = new GlobalConstant('ZEPHIR_GLOBAL(global_true)'); } else { if ($resolvedExpr->getBooleanCode() == '0') { $symbolVariable = new GlobalConstant('ZEPHIR_GLOBAL(global_false)'); } else { $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_BOOL(' . $symbolVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); } } break; case 'string': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_STRING(' . $symbolVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); break; case 'array': $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $resolvedExpr->getOriginal()); break; case 'variable': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $resolvedExpr->getOriginal()); switch ($variableExpr->getType()) { case 'int': case 'uint': case 'long': case 'ulong': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_LONG(' . $symbolVariable->getName() . ', ' . $variableExpr->getName() . ');'); break; case 'double': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_DOUBLE(' . $symbolVariable->getName() . ', ' . $variableExpr->getName() . ');'); break; case 'bool': $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $resolvedExpr->getOriginal()); $codePrinter->output('ZVAL_BOOL(' . $symbolVariable->getName() . ', ' . $variableExpr->getName() . ');'); break; case 'variable': case 'string': case 'array': $symbolVariable = $variableExpr; break; default: throw new CompilerException("Variable: " . $variableExpr->getType() . " cannot be assigned to array offset", $resolvedExpr->getOriginal()); } break; default: throw new CompilerException("Expression: " . $resolvedExpr->getType() . " cannot be assigned to array offset", $resolvedExpr->getOriginal()); } return $symbolVariable; }
/** * Compiles x->y[z] = {expr} (single offset assignment) * * @param string $variable * @param Variable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext, * @param array $statement */ protected function _assignPropertyArraySingleIndex($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { $codePrinter = $compilationContext->codePrinter; $property = $statement['property']; $compilationContext->headersManager->add('kernel/object'); /** * Only string/variable/int */ $indexExpression = new Expression($statement['index-expr'][0]); $resolvedIndex = $indexExpression->compile($compilationContext); switch ($resolvedIndex->getType()) { case 'string': case 'int': case 'uint': case 'ulong': case 'long': case 'variable': break; default: throw new CompilerException("Expression: " . $resolvedIndex->getType() . " cannot be used as index without cast", $statement['index-expr']); } if ($resolvedIndex->getType() == 'variable') { $indexVariable = $compilationContext->symbolTable->getVariableForRead($resolvedIndex->getCode(), $compilationContext, $statement['index-expr']); switch ($indexVariable->getType()) { case 'string': case 'int': case 'uint': case 'ulong': case 'long': case 'variable': break; default: throw new CompilerException("Variable: " . $indexVariable->getType() . " cannot be used as index without cast", $statement); } if ($indexVariable->getType() == 'variable') { if ($indexVariable->hasDifferentDynamicType(array('undefined', 'int', 'string'))) { $compilationContext->logger->warning('Possible attempt to use non string/long dynamic variable as array index', 'invalid-array-offset', $statement); } } } switch ($resolvedIndex->getType()) { case 'int': case 'uint': case 'long': $indexVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_LONG(' . $indexVariable->getName() . ', ' . $resolvedIndex->getCode() . ');'); break; case 'string': $indexVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_STRING(' . $indexVariable->getName() . ', "' . $resolvedIndex->getCode() . '", 1);'); break; case 'variable': $variableIndex = $compilationContext->symbolTable->getVariableForRead($resolvedIndex->getCode(), $compilationContext, $statement['index-expr']); switch ($variableIndex->getType()) { case 'int': case 'uint': case 'long': $indexVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_LONG(' . $indexVariable->getName() . ', ' . $variableIndex->getName() . ');'); break; } break; } switch ($indexVariable->getType()) { case 'variable': case 'string': switch ($resolvedExpr->getType()) { case 'null': $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); break; case 'bool': if ($resolvedExpr->getBooleanCode() == '1') { $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } break; case 'int': case 'long': case 'uint': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'char': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getCode() . '\');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'array': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['index-expr']); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $variableExpr->getName() . ' TSRMLS_CC);'); break; case 'variable': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['index-expr']); switch ($variableExpr->getType()) { case 'bool': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'int': case 'long': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'variable': case 'string': case 'array': $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $variableExpr->getName() . ' TSRMLS_CC);'); if ($variableExpr->isTemporal()) { $variableExpr->setIdle(true); } break; default: throw new CompilerException("Cannot update variable type: " . $variableExpr->getType(), $statement); } break; default: throw new CompilerException("Variable index: " . $indexVariable->getType() . " cannot be updated into array property", $statement); } break; default: throw new CompilerException("Index: " . $resolvedIndex->getType() . " cannot be updated into array property", $statement); } }
/** * Compiles ClassName::foo = {expr} * * @param $className * @param $property * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement * * @throws CompilerException * @internal param string $variable */ public function assignStatic($className, $property, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { $compiler = $compilationContext->compiler; if (!in_array($className, array('self', 'static', 'parent'))) { $className = $compilationContext->getFullName($className); if ($compiler->isClass($className)) { $classDefinition = $compiler->getClassDefinition($className); } else { if ($compiler->isBundledClass($className)) { $classDefinition = $compiler->getInternalClassDefinition($className); } else { throw new CompilerException("Cannot locate class '" . $className . "'", $statement); } } } else { if (in_array($className, array('self', 'static'))) { $classDefinition = $compilationContext->classDefinition; } else { if ($className == 'parent') { $classDefinition = $compilationContext->classDefinition; $extendsClass = $classDefinition->getExtendsClass(); if (!$extendsClass) { throw new CompilerException('Cannot assign static property "' . $property . '" on parent because class ' . $classDefinition->getCompleteName() . ' does not extend any class', $statement); } else { $classDefinition = $classDefinition->getExtendsClassDefinition(); } } } } if (!$classDefinition->hasProperty($property)) { throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not have a property called: '" . $property . "'", $statement); } /** @var $propertyDefinition ClassProperty */ $propertyDefinition = $classDefinition->getProperty($property); if (!$propertyDefinition->isStatic()) { throw new CompilerException("Cannot access non-static property '" . $classDefinition->getCompleteName() . '::' . $property . "'", $statement); } if ($propertyDefinition->isPrivate()) { if ($classDefinition != $compilationContext->classDefinition) { throw new CompilerException("Cannot access private static property '" . $classDefinition->getCompleteName() . '::' . $property . "' out of its declaring context", $statement); } } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/object'); $classEntry = $classDefinition->getClassEntry($compilationContext); switch ($resolvedExpr->getType()) { case 'null': $compilationContext->backend->updateStaticProperty($classEntry, $property, 'null', $compilationContext); break; case 'int': case 'uint': case 'long': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext); $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignLong($tempVariable, '\'' . $resolvedExpr->getCode() . '\'', $compilationContext); $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'string': switch ($statement['operator']) { case 'assign': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $tempVariable->initVariant($compilationContext); if ($resolvedExpr->getCode()) { $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext); } else { $codePrinter->output('ZVAL_EMPTY_STRING(' . $tempVariable->getName() . ');'); } if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } $codePrinter->output('zephir_update_static_property_ce(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'bool': if ($resolvedExpr->getBooleanCode() == '1') { $compilationContext->backend->updateStaticProperty($classEntry, $property, 'true', $compilationContext); } else { if ($resolvedExpr->getBooleanCode() == '0') { $compilationContext->backend->updateStaticProperty($classEntry, $property, 'false', $compilationContext); } else { $codePrinter->output('if (' . $resolvedExpr->getBooleanCode() . ') {'); $codePrinter->increaseLevel(); $compilationContext->backend->updateStaticProperty($classEntry, $property, 'true', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('} else {'); $codePrinter->increaseLevel(); $compilationContext->backend->updateStaticProperty($classEntry, $property, 'false', $compilationContext); $codePrinter->decreaseLevel(); $codePrinter->output('}'); } } break; case 'empty-array': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->initArray($tempVariable, $compilationContext); $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'array': $compilationContext->backend->updateStaticProperty($classEntry, $property, $resolvedExpr, $compilationContext); break; case 'variable': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext); if ($compilationContext->insideCycle) { $propertyCache = $compilationContext->symbolTable->getTempVariableForWrite('zend_property_info', $compilationContext); $propertyCache->setMustInitNull(true); $propertyCache->setReusable(false); $codePrinter->output('zephir_update_static_property_ce_cache(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ', &' . $propertyCache->getName() . ' TSRMLS_CC);'); } else { $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext); } if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignDouble($tempVariable, $variableVariable, $compilationContext); if ($compilationContext->insideCycle) { $propertyCache = $compilationContext->symbolTable->getTempVariableForWrite('zend_property_info', $compilationContext); $propertyCache->setMustInitNull(true); $propertyCache->setReusable(false); $codePrinter->output('zephir_update_static_property_ce_cache(' . $classEntry . ', SL("' . $property . '"), &' . $tempVariable->getName() . ', &' . $propertyCache->getName() . ' TSRMLS_CC);'); } else { $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext); } if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $compilationContext->backend->assignBool($tempVariable, $variableVariable, $compilationContext); $compilationContext->backend->updateStaticProperty($classEntry, $property, $tempVariable, $compilationContext); if ($tempVariable->isTemporal()) { $tempVariable->setIdle(true); } break; case 'string': switch ($statement['operator']) { case 'concat-assign': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $expression = new Expression(array('type' => 'static-property-access', 'left' => array('value' => $statement['variable']), 'right' => array('value' => $statement['property']))); $expression->setExpectReturn(true, $tempVariable); $expression->compile($compilationContext); $variableVariableCode = $compilationContext->backend->getVariableCode($variableVariable); $tempVariableCode = $compilationContext->backend->getVariableCode($tempVariable); $compilationContext->codePrinter->output('zephir_concat_function(' . $variableVariableCode . ', ' . $tempVariableCode . ', ' . $variableVariableCode . ');'); //continue //continue case 'assign': $compilationContext->backend->updateStaticProperty($classEntry, $property, $variableVariable, $compilationContext); if ($variableVariable->isTemporal()) { $variableVariable->setIdle(true); } break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for variable type: string", $statement); } break; case 'variable': case 'array': $compilationContext->backend->updateStaticProperty($classEntry, $property, $variableVariable, $compilationContext); if ($variableVariable->isTemporal()) { $variableVariable->setIdle(true); } break; default: throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } }
/** * Resolves an item to be added in an array * * @param CompiledExpression $exprCompiled * @param CompilationContext $compilationContext * @return Variable */ public function getArrayValue(CompiledExpression $exprCompiled, CompilationContext $compilationContext) { $codePrinter = $compilationContext->codePrinter; switch ($exprCompiled->getType()) { case 'int': case 'uint': case 'long': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignLong($tempVar, $exprCompiled->getCode(), $compilationContext); return $tempVar; case 'char': case 'uchar': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignLong($tempVar, '\'' . $exprCompiled->getCode() . '\'', $compilationContext); return $tempVar; case 'double': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignDouble($tempVar, $exprCompiled->getCode(), $compilationContext); return $tempVar; case 'bool': if ($exprCompiled->getCode() == 'true') { return new GlobalConstant('ZEPHIR_GLOBAL(global_true)'); } if ($exprCompiled->getCode() == 'false') { return new GlobalConstant('ZEPHIR_GLOBAL(global_false)'); } $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignBool($tempVar, $exprCompiled->getCode(), $compilationContext); return $tempVar; case 'null': return new GlobalConstant('ZEPHIR_GLOBAL(global_null)'); case 'string': case 'ulong': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignString($tempVar, $exprCompiled->getCode(), $compilationContext); return $tempVar; case 'array': return $compilationContext->symbolTable->getVariableForRead($exprCompiled->getCode(), $compilationContext, $exprCompiled->getOriginal()); case 'variable': $itemVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiled->getCode(), $compilationContext, $exprCompiled->getOriginal()); switch ($itemVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignLong($tempVar, $itemVariable, $compilationContext); return $tempVar; case 'double': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignDouble($tempVar, $itemVariable, $compilationContext); return $tempVar; case 'bool': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignBool($tempVar, $itemVariable, $compilationContext); return $tempVar; case 'string': case 'variable': case 'array': return $itemVariable; default: throw new CompilerException("Unknown " . $itemVariable->getType(), $itemVariable); } break; default: throw new CompilerException("Unknown", $exprCompiled); } }
/** * 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->{"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->getType() != 'variable') { throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement); } $propertyName = $statement['property']; if (!is_string($propertyName)) { throw new CompilerException("Expected string to update object property, " . gettype($propertyName) . " received", $statement); } if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate static property '" . $compilationContext->classDefinition->getCompleteName() . "::" . $propertyName . "' because it is not initialized", $statement); } if ($symbolVariable->getType() != 'variable') { 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'); switch ($resolvedExpr->getType()) { case 'null': $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'null', $compilationContext); break; case 'int': case 'long': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); break; case 'bool': if ($resolvedExpr->getBooleanCode() == '1') { $value = 'true'; } else { if ($resolvedExpr->getBooleanCode() == '0') { $value = 'false'; } else { throw new \Exception("?"); } } $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $value, $compilationContext); break; case 'empty-array': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->initArray($tempVariable, $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); break; case 'array': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $variableVariable, $compilationContext); break; case 'variable': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $compilationContext->backend->assignBool($tempVariable, $variableVariable, $compilationContext); $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext); break; case 'string': case 'variable': case 'array': $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr, $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 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); } }
/** * @param CompiledExpression $compiledExpression * @param array $expression * @return CompiledExpression */ protected function passNativeFCall($compiledExpression, $expression) { return new CompiledExpression('double', $this->getFunctionName() . '(' . $compiledExpression->getCode() . ')', $expression); }
/** * 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[z] = {expr} (single offset assignment) * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement * @throws CompilerException */ protected function _assignPropertyArraySingleIndex($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement) { $codePrinter = $compilationContext->codePrinter; $property = $statement['property']; $compilationContext->headersManager->add('kernel/object'); /** * Only string/variable/int */ $indexExpression = new Expression($statement['index-expr'][0]); $resolvedIndex = $indexExpression->compile($compilationContext); switch ($resolvedIndex->getType()) { case 'string': case 'int': case 'uint': case 'ulong': case 'long': case 'variable': break; default: throw new CompilerException("Expression: " . $resolvedIndex->getType() . " cannot be used as index without cast", $statement); } if ($resolvedIndex->getType() == 'variable') { $indexVariable = $compilationContext->symbolTable->getVariableForRead($resolvedIndex->getCode(), $compilationContext, $statement); switch ($indexVariable->getType()) { case 'string': case 'int': case 'uint': case 'ulong': case 'long': case 'variable': break; default: throw new CompilerException("Variable: " . $indexVariable->getType() . " cannot be used as index without cast", $statement); } if ($indexVariable->getType() == 'variable') { if ($indexVariable->hasDifferentDynamicType(array('undefined', 'int', 'string'))) { $compilationContext->logger->warning('Possible attempt to use non string/long dynamic variable as array index', 'invalid-array-offset', $statement); } } } switch ($resolvedIndex->getType()) { case 'int': case 'uint': case 'long': $indexVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_LONG(' . $indexVariable->getName() . ', ' . $resolvedIndex->getCode() . ');'); break; case 'string': $indexVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_STRING(' . $indexVariable->getName() . ', "' . $resolvedIndex->getCode() . '", 1);'); break; case 'variable': $variableIndex = $compilationContext->symbolTable->getVariableForRead($resolvedIndex->getCode(), $compilationContext, $statement['index-expr']); switch ($variableIndex->getType()) { case 'int': case 'uint': case 'long': $indexVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $statement); $codePrinter->output('ZVAL_LONG(' . $indexVariable->getName() . ', ' . $variableIndex->getName() . ');'); break; } break; } /** * 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 ($indexVariable->getType()) { case 'variable': case 'string': switch ($resolvedExpr->getType()) { case 'null': $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); break; case 'bool': $booleanCode = $resolvedExpr->getBooleanCode(); if ($booleanCode == '1') { $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } elseif ($booleanCode == '0') { $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } else { $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $booleanCode . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'int': case 'long': case 'uint': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'char': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getCode() . '\');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getCode() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'array': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['index-expr']); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $variableExpr->getName() . ' TSRMLS_CC);'); break; case 'variable': $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement['index-expr']); switch ($variableExpr->getType()) { case 'bool': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'int': case 'long': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableExpr->getName() . ');'); $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'variable': case 'string': case 'array': $codePrinter->output('zephir_update_property_array(' . $symbolVariable->getName() . ', SL("' . $property . '"), ' . $indexVariable->getName() . ', ' . $variableExpr->getName() . ' TSRMLS_CC);'); if ($variableExpr->isTemporal()) { $variableExpr->setIdle(true); } break; default: throw new CompilerException("Cannot update variable type: " . $variableExpr->getType(), $statement); } break; default: throw new CompilerException("Variable index: " . $indexVariable->getType() . " cannot be updated into array property", $statement); } break; default: throw new CompilerException("Index: " . $resolvedIndex->getType() . " cannot be updated into array property", $statement); } }
/** * Resolves an item to be added in an array * * @param CompiledExpression $exprCompiled * @param CompilationContext $compilationContext * @return Variable */ public function getArrayValue($exprCompiled, CompilationContext $compilationContext) { $codePrinter = $compilationContext->codePrinter; switch ($exprCompiled->getType()) { case 'int': case 'uint': case 'long': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVar->getName() . ', ' . $exprCompiled->getCode() . ');'); return $tempVar; case 'char': case 'uchar': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVar->getName() . ', \'' . $exprCompiled->getCode() . '\');'); return $tempVar; case 'double': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $tempVar->getName() . ', ' . $exprCompiled->getCode() . ');'); return $tempVar; case 'bool': if ($exprCompiled->getCode() == 'true') { return new GlobalConstant('ZEPHIR_GLOBAL(global_true)'); } else { if ($exprCompiled->getCode() == 'false') { return new GlobalConstant('ZEPHIR_GLOBAL(global_false)'); } else { throw new Exception('?'); } } break; case 'null': return new GlobalConstant('ZEPHIR_GLOBAL(global_null)'); case 'string': case 'ulong': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_STRING(' . $tempVar->getName() . ', "' . $exprCompiled->getCode() . '", 1);'); return $tempVar; case 'array': return $compilationContext->symbolTable->getVariableForRead($exprCompiled->getCode(), $compilationContext, $exprCompiled->getOriginal()); case 'variable': $itemVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiled->getCode(), $compilationContext, $exprCompiled->getOriginal()); switch ($itemVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVar->getName() . ', ' . $itemVariable->getName() . ');'); return $tempVar; case 'double': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $tempVar->getName() . ', ' . $itemVariable->getName() . ');'); return $tempVar; case 'bool': $tempVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_BOOL(' . $tempVar->getName() . ', ' . $itemVariable->getName() . ');'); return $tempVar; case 'string': case 'variable': case 'array': return $itemVariable; default: throw new CompilerException("Unknown " . $itemVariable->getType(), $itemVariable); } break; default: throw new CompilerException("Unknown", $exprCompiled); } }
/** * Compiles x->y[] = foo * * @param string $variable * @param Variable $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->getType() != 'variable') { throw new CompilerException("Attempt to use variable type: " . $symbolVariable->getType() . " as object", $statement); } $codePrinter = $compilationContext->codePrinter; $property = $statement['property']; $compilationContext->headersManager->add('kernel/object'); /* @todo check whether property really does exist */ 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); } }