Skip to content

Commit

Permalink
Merge pull request phalcon#8 from ilyk/master
Browse files Browse the repository at this point in the history
static calls
  • Loading branch information
Phalcon committed Oct 1, 2013
2 parents c03b787 + 6d59d3b commit a845498
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 13 deletions.
8 changes: 4 additions & 4 deletions Library/Expression.php
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ public function newInstance($expression, CompilationContext $compilationContext)
* @TODO, check if the variable is really internal
*/
$zendClassEntry = $compilationContext->symbolTable->addTemp('zend_class_entry', $compilationContext);
$codePrinter->output($zendClassEntry->getName() . ' = zend_fetch_class(SL("' . Utils::addSlaches($className) . '"), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);');
$codePrinter->output($zendClassEntry->getName() . ' = zend_fetch_class(SL("' . Utils::addSlaches($className, true) . '"), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);');
$codePrinter->output('object_init_ex(' . $symbolVariable->getName() . ', ' . $zendClassEntry->getName() . ');');
$symbolVariable->setClassType($newExpr['class']);
}
Expand All @@ -403,7 +403,7 @@ public function newInstance($expression, CompilationContext $compilationContext)
if (strtolower($className) == 'stdclass') {
if (isset($newExpr['parameters'])) {
if (count($newExpr['parameters'])) {
throw new CompilerException("stdclass does not receive parameters in its constructor", $statement);
throw new CompilerException("stdclass does not receive parameters in its constructor", $expression);
}
}
return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
Expand All @@ -426,7 +426,7 @@ public function newInstance($expression, CompilationContext $compilationContext)
if ($compilationContext->compiler->isClass($className)) {
$classDefinition = $compilationContext->compiler->getClassDefinition($className);
if ($classDefinition->getType() != 'class') {
throw new CompilerException("Only classes can be instantiated", $statement);
throw new CompilerException("Only classes can be instantiated", $expression);
}
if ($classDefinition->hasMethod("__construct")) {
$callConstructor = true;
Expand Down Expand Up @@ -801,7 +801,7 @@ public function compileInstanceOf($expression, CompilationContext $compilationCo
throw new CompilerException("InstanceOf requires a 'dynamic variable' in the left operand", $expression);
}

return new CompiledExpression('bool', 'zephir_is_instance_of(' . $symbolVariable->getName() . ', SL("' . strtolower(Utils::addSlaches($expression['right']['value'])) . '") TSRMLS_CC)', $expression);
return new CompiledExpression('bool', 'zephir_is_instance_of(' . $symbolVariable->getName() . ', SL("' . strtolower(Utils::addSlaches($expression['right']['value'], true)) . '") TSRMLS_CC)', $expression);
}

/**
Expand Down
146 changes: 145 additions & 1 deletion Library/Statements/LetStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,149 @@ public function assignPropertyArrayIndex($variable, Variable $symbolVariable, Co

}

/**
* Compiles ClassName::foo = {expr}
*
* @param $className
* @param $property
* @param Variable $symbolVariable
* @param CompiledExpression $resolvedExpr
* @param CompilationContext $compilationContext
* @param array $statement
*
* @throws CompilerException
* @internal param string $variable
*/
public function assignStaticProperty($className, $property, Variable $symbolVariable, CompiledExpression $resolvedExpr,
CompilationContext $compilationContext, $statement)
{
$compiler = $compilationContext->compiler;
if ($className != 'self' && $className != 'parent') {
if ($compiler->isClass($className)) {
$classDefinition = $compiler->getClassDefinition($className);
} elseif ($compiler->isInternalClass($className)) {
$classDefinition = $compiler->getInternalClassDefinition($className);
} else {
throw new CompilerException("Cannot locate class '" . $className . "'", $statement);
}
} elseif ($className == 'self') {
$classDefinition = $compilationContext->classDefinition;
} elseif ($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);
}
}

if (!$symbolVariable->isInitialized()) {
throw new CompilerException("Cannot write static property '".$classDefinition->getCompleteName()."::" . $property . "' because it is not initialized", $statement);
}

$dynamicType = $symbolVariable->getDynamicType();

/**
* Variable is probably not initialized here
*/
if ($dynamicType == 'unknown') {
$dynamicType = 'undefined'; // @todo check this. I'm not sure if this hack is correct.
}

/**
* Trying to use a non-object dynamic variable as object
*/
if ($dynamicType != 'undefined' && $dynamicType != 'object') {
$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');
$classEntry = $classDefinition->getClassEntry();

switch ($resolvedExpr->getType()) {
case 'null':
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);');
break;
case 'int':
case 'long':
$tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
$codePrinter->output('ZEPHIR_INIT_ZVAL_NREF(' . $tempVariable->getName() . ');');
$codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');');
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
break;
case 'string':
$tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
$codePrinter->output('ZEPHIR_INIT_ZVAL_NREF(' . $tempVariable->getName() . ');');
$codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);');
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
break;
case 'bool':
if ($resolvedExpr->getBooleanCode() == '1') {
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ZEPHIR_GLOBAL(global_true) TSRMLS_CC);');
} else {
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ZEPHIR_GLOBAL(global_false) TSRMLS_CC);');
}
break;
case 'empty-array':
$tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
$codePrinter->output('ZEPHIR_INIT_ZVAL_NREF(' . $tempVariable->getName() . ');');
$codePrinter->output('array_init(' . $tempVariable->getName() . ');');
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ' . $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->getTempNonTrackedVariable('variable', $compilationContext);
$codePrinter->output('ZEPHIR_INIT_ZVAL_NREF(' . $tempVariable->getName() . ');');
$codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');');
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
break;
case 'bool':
$tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
$codePrinter->output('ZEPHIR_INIT_ZVAL_NREF(' . $tempVariable->getName() . ');');
$codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');');
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);');
break;
case 'string':
case 'variable':
$codePrinter->output('zephir_update_static_property_ce(' . $classEntry .', SL("' . $property . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC);');
break;
default:
throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement);
}
break;
default:
throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement);
}

}

/**
* Compiles the let statement
*
Expand All @@ -1694,6 +1837,7 @@ public function compile(CompilationContext $compilationContext)
case 'static-property':
case 'static-property-append':
case 'static-property-array-index':
$symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, $assignment);
break;
default:
$symbolVariable = $compilationContext->symbolTable->getVariableForWrite($variable, $compilationContext, $assignment);
Expand Down Expand Up @@ -1758,7 +1902,7 @@ public function compile(CompilationContext $compilationContext)
/* @todo, implement this */
break;
case 'static-property':
/* @todo, implement this */
$this->assignStaticProperty($variable, $assignment['property'], $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
break;
case 'static-property-append':
/* @todo, implement this */
Expand Down
71 changes: 65 additions & 6 deletions Library/StaticCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected function callSelf($methodName, array $expression, $symbolVariable, $mu
if ($isExpecting) {
$codePrinter->output('zephir_call_self_p' . count($params) . '(' . $symbolVariable->getName() . ', this_ptr, "' . $methodName . '", ' . join(', ', $params) . ');');
} else {
$codePrinter->output('zephir_call_self_p' . count($params) . '_noret(' . $variableVariable->getName() . ', this_ptr, "' . $methodName . '", ' . join(', ', $params) . ');');
$codePrinter->output('zephir_call_self_p' . count($params) . '_noret(this_ptr, "' . $methodName . '", ' . join(', ', $params) . ');');
}
} else {
if ($isExpecting) {
Expand Down Expand Up @@ -141,6 +141,64 @@ protected function callParent($methodName, array $expression, $symbolVariable, $
}
}

/**
* Calls static methods on the some class context
*
* @param string $methodName
* @param array $expression
* @param Variable $symbolVariable
* @param boolean $mustInit
* @param boolean $isExpecting
* @param ClassDefinition $classDefinition
* @param CompilationContext $compilationContext
*/
protected function callFromClass($methodName, array $expression, $symbolVariable, $mustInit, $isExpecting,
ClassDefinition $classDefinition, CompilationContext $compilationContext)
{

$codePrinter = $compilationContext->codePrinter;
$className = str_replace('\\', '\\\\', $classDefinition->getCompleteName());

/**
* Call static methods must grown the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);

if (!isset($expression['parameters'])) {

if ($mustInit) {
$symbolVariable->initVariant($compilationContext);
}

if ($isExpecting) {
$codePrinter->output('zephir_call_static(' . $symbolVariable->getName() . ', "' . $className . '", "' . $methodName . '");');
} else {
$codePrinter->output('zephir_call_static_noret("' . $className . '", "' . $methodName . '");');
}
} else {

$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);

if ($mustInit) {
$symbolVariable->initVariant($compilationContext);
}

if (count($params)) {
if ($isExpecting) {
$codePrinter->output('zephir_call_static_p' . count($params) . '(' . $symbolVariable->getName() . ', "' . $className . '", "' . $methodName . '", ' . join(', ', $params) . ');');
} else {
$codePrinter->output('zephir_call_static_p' . count($params) . '_noret("' . $className . '", "' . $methodName . '", ' . join(', ', $params) . ');');
}
} else {
if ($isExpecting) {
$codePrinter->output('zephir_call_static(' . $symbolVariable->getName() . ', "' . $className . '", "' . $methodName . '");');
} else {
$codePrinter->output('zephir_call_static("' . $className . '", "' . $methodName . '");');
}
}
}
}

/**
* Compiles a static method call
*
Expand All @@ -155,7 +213,7 @@ public function compile(Expression $expr, CompilationContext $compilationContext
/**
* TODO: implement dynamic calls
*/
if ($expression['dynamic-class']) {
if (array_key_exists('dynamic-class', $expression) && $expression['dynamic-class']) {
return new CompiledExpression('null', null, $expression);
}

Expand Down Expand Up @@ -278,11 +336,12 @@ public function compile(Expression $expr, CompilationContext $compilationContext
if ($type == 'self') {
$this->callSelf($methodName, $expression, $symbolVariable, $mustInit,
$isExpecting, $classDefinition, $compilationContext);
} elseif ($type == 'parent') {
$this->callParent($methodName, $expression, $symbolVariable, $mustInit,
$isExpecting, $currentClassDefinition, $compilationContext);
} else {
if ($type == 'parent') {
$this->callParent($methodName, $expression, $symbolVariable, $mustInit,
$isExpecting, $currentClassDefinition, $compilationContext);
}
$this->callFromClass($methodName, $expression, $symbolVariable, $mustInit,
$isExpecting, $classDefinition, $compilationContext);
}

/**
Expand Down
6 changes: 4 additions & 2 deletions Library/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ class Utils
* @param string $str
* @return string
*/
public static function addSlaches($str)
public static function addSlaches($str, $escapeSlash = false)
{
//$str = str_replace('\\', '\\\\', $str);
if ($escapeSlash) {
$str = str_replace('\\', '\\\\', $str);
}
$str = str_replace("\n", "\\n", $str);
$str = str_replace("\r", "\\r", $str);
$str = str_replace("\t", "\\t", $str);
Expand Down

0 comments on commit a845498

Please sign in to comment.