/** * 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); } }
/** * Compiles foo[y] = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { /** * Arrays must be stored in the HEAP */ if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->isReadOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is read only", $statement); } if ($symbolVariable->isLocalOnly()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is local only", $statement); } /** * Only dynamic variables can be used as arrays */ if ($symbolVariable->isNotVariableAndArray()) { throw new CompilerException("Cannot use variable type: '" . $symbolVariable->getType() . "' as array", $statement); } if ($symbolVariable->getType() == 'variable') { if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) { $compilationContext->logger->warning('Possible attempt to update index on a non-array dynamic variable', 'non-array-update', $statement); } } /** * Choose one-offset or multiple-offset functions */ if (count($statement['index-expr']) == 1) { $this->_assignArrayIndexSingle($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement); } else { $this->_assignArrayIndexMultiple($variable, $symbolVariable, $resolvedExpr, $compilationContext, $statement); } }
/** * Compiles foo[] = {expr} * * @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': $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: " . $type, $statement); } }