Skip to content

Commit

Permalink
Now exceptions thrown shows the Zephir file where they were generated
Browse files Browse the repository at this point in the history
  • Loading branch information
phalcon committed Apr 2, 2014
1 parent 86abc8b commit aa09356
Show file tree
Hide file tree
Showing 18 changed files with 339 additions and 55 deletions.
19 changes: 16 additions & 3 deletions Library/ClassMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ public function removeMemoryStackReferences(SymbolTable $symbolTable, $container
{
if (!$symbolTable->getMustGrownStack()) {
$containerCode = str_replace('ZEPHIR_THROW_EXCEPTION_STR', 'ZEPHIR_THROW_EXCEPTION_STRW', $containerCode);
$containerCode = str_replace('ZEPHIR_THROW_EXCEPTION_DEBUG_STR', 'ZEPHIR_THROW_EXCEPTION_DEBUG_STRW', $containerCode);
$containerCode = str_replace('ZEPHIR_THROW_EXCEPTION_ZVAL', 'ZEPHIR_THROW_EXCEPTION_ZVALW', $containerCode);
$containerCode = str_replace('RETURN_THIS', 'RETURN_THISW', $containerCode);
$containerCode = str_replace('RETURN_LCTOR', 'RETURN_LCTORW', $containerCode);
Expand Down Expand Up @@ -913,10 +914,19 @@ public function checkStrictType(array $parameter, CompilationContext $compilatio
return $code;

case 'array':
$code = "\tif (Z_TYPE_P(" . $parameter['name'] . '_param) != IS_' . strtoupper($dataType) . ') {' . PHP_EOL;
$code .= "\t\t" . 'zephir_throw_exception_string(spl_ce_InvalidArgumentException, SL("Parameter \'' . $parameter['name'] . '\' must be an ' . $dataType . '") TSRMLS_CC);' . PHP_EOL;
$code .= "\t\t" . 'RETURN_MM_NULL();' . PHP_EOL;
$code .= "\t" . '}' . PHP_EOL;
$code .= PHP_EOL;
$code .= "\t\t" . $parameter['name'] . ' = ' . $parameter['name'] . '_param;' . PHP_EOL;
$code .= PHP_EOL;
return $code;

case 'object':
case 'resource':
$code = "\tif (Z_TYPE_P(" . $parameter['name'] . ') != IS_'.strtoupper($dataType).') {' . PHP_EOL;
$code .= "\t\t" . 'zephir_throw_exception_string(spl_ce_InvalidArgumentException, SL("Parameter \'' . $parameter['name'] . '\' must be an '.$dataType.'") TSRMLS_CC);' . PHP_EOL;
$code = "\tif (Z_TYPE_P(" . $parameter['name'] . ') != IS_' . strtoupper($dataType) . ') {' . PHP_EOL;
$code .= "\t\t" . 'zephir_throw_exception_string(spl_ce_InvalidArgumentException, SL("Parameter \'' . $parameter['name'] . '\' must be an ' . $dataType . '") TSRMLS_CC);' . PHP_EOL;
$code .= "\t\t" . 'RETURN_MM_NULL();' . PHP_EOL;
$code .= "\t" . '}' . PHP_EOL;
$code .= PHP_EOL;
Expand Down Expand Up @@ -1449,13 +1459,15 @@ public function compile(CompilationContext $compilationContext)
$dataType = 'variable';
}

switch($dataType) {
switch ($dataType) {

case 'object':
case 'callable':
case 'resource':
case 'variable':
$params[] = '&' . $parameter['name'];
break;

default:
$params[] = '&' . $parameter['name'] . '_param';
break;
Expand Down Expand Up @@ -1562,6 +1574,7 @@ public function compile(CompilationContext $compilationContext)
* Initialize optional parameters
*/
foreach ($optionalParams as $parameter) {

if (isset($parameter['mandatory'])) {
$mandatory = $parameter['mandatory'];
} else {
Expand Down
2 changes: 1 addition & 1 deletion Library/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/
class Compiler
{
const VERSION = '0.4.0a';
const VERSION = '0.4.1a';

/**
* @var CompilerFile[]
Expand Down
8 changes: 5 additions & 3 deletions Library/Operators/Other/FetchOperator.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,14 @@ public function compile($expression, CompilationContext $compilationContext)
}

$evalVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression['right']['left']);
if ($evalVariable->getType() != 'variable') {
if ($evalVariable->getType() != 'variable' && $evalVariable->getType() != 'array') {
throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as array", $expression['right']['left']);
}

if ($evalVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) {
$compilationContext->logger->warning('Possible attempt to use non array in fetch operator', 'non-valid-fetch', $expression['right']);
if ($evalVariable->getType() == 'variable') {
if ($evalVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) {
$compilationContext->logger->warning('Possible attempt to use non array in fetch operator', 'non-valid-fetch', $expression['right']);
}
}

$expr = new Expression($expression['right']['right']);
Expand Down
72 changes: 72 additions & 0 deletions Library/Optimizers/FunctionCall/UniquePathKeyOptimizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

/*
+--------------------------------------------------------------------------+
| Zephir Language |
+--------------------------------------------------------------------------+
| Copyright (c) 2013-2014 Zephir Team and contributors |
+--------------------------------------------------------------------------+
| This source file is subject the MIT license, that is bundled with |
| this package in the file LICENSE, and is available through the |
| world-wide-web at the following url: |
| http://zephir-lang.com/license.html |
| |
| If you did not receive a copy of the MIT license and are unable |
| to obtain it through the world-wide-web, please send a note to |
| license@zephir-lang.com so we can mail you a copy immediately. |
+--------------------------------------------------------------------------+
*/

namespace Zephir\Optimizers\FunctionCall;

use Zephir\Call;
use Zephir\CompilationContext;
use Zephir\CompilerException;
use Zephir\CompiledExpression;
use Zephir\Optimizers\OptimizerAbstract;

/**
* UniquePathKeyOptimizer
*
* Optimizes calls to 'unique_path_key' using internal function
*/
class UniquePathKeyOptimizer extends OptimizerAbstract
{
/**
* @param array $expression
* @param Call $call
* @param CompilationContext $context
* @return bool|CompiledExpression|mixed
* @throws CompilerException
*/
public function optimize(array $expression, Call $call, CompilationContext $context)
{
if (!isset($expression['parameters'])) {
return false;
}

if (count($expression['parameters']) != 1) {
throw new CompilerException("'unique_path_key' only accepts three parameter");
}

/**
* Process the expected symbol to be returned
*/
$call->processExpectedReturn($context);

$symbolVariable = $call->getSymbolVariable();
if ($symbolVariable->isNotVariableAndString()) {
throw new CompilerException("Returned values by functions can only be assigned to variant variables", $expression);
}

if ($call->mustInitSymbolVariable()) {
$symbolVariable->initVariant($context);
}

$context->headersManager->add('kernel/file');

$resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
$context->codePrinter->output('zephir_unique_path_key(' . $symbolVariable->getName() . ', ' . $resolvedParams[0] . ' TSRMLS_CC);');
return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
}
}
9 changes: 6 additions & 3 deletions Library/Statements/ThrowStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
namespace Zephir\Statements;

use Zephir\Utils;
use Zephir\Compiler;
use Zephir\Expression;
use Zephir\CompilationContext;
use Zephir\CompilerException;
Expand Down Expand Up @@ -53,14 +54,16 @@ public function compile(CompilationContext $compilationContext)
$className = Utils::getFullName($expr['class'], $compilationContext->classDefinition->getNamespace(), $compilationContext->aliasManager);
if ($compilationContext->compiler->isClass($className)) {
$classDefinition = $compilationContext->compiler->getClassDefinition($className);
$codePrinter->output('ZEPHIR_THROW_EXCEPTION_STR(' . $classDefinition->getClassEntry() . ', "' . Utils::addSlashes($expr['parameters'][0]['parameter']['value']) . '");');
$message = $expr['parameters'][0]['parameter']['value'];
$codePrinter->output('ZEPHIR_THROW_EXCEPTION_DEBUG_STR(' . $classDefinition->getClassEntry() . ', "' . Utils::addSlashes($message) . '", "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');');
$codePrinter->output('return;');
return;
} else {
if ($compilationContext->compiler->isInternalClass($className)) {
$classEntry = $compilationContext->classDefinition->getClassEntryByClassName($className, true);
if ($classEntry) {
$codePrinter->output('ZEPHIR_THROW_EXCEPTION_STR(' . $classEntry . ', "' . Utils::addSlashes($expr['parameters'][0]['parameter']['value']) . '");');
$message = $expr['parameters'][0]['parameter']['value'];
$codePrinter->output('ZEPHIR_THROW_EXCEPTION_DEBUG_STR(' . $classEntry . ', "' . Utils::addSlashes($message) . '", "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ');');
$codePrinter->output('return;');
return;
}
Expand All @@ -83,7 +86,7 @@ public function compile(CompilationContext $compilationContext)
throw new CompilerException("Variable '" . $variableVariable->getType() . "' cannot be used as exception", $expr);
}

$codePrinter->output('zephir_throw_exception(' . $variableVariable->getName() . ' TSRMLS_CC);');
$codePrinter->output('zephir_throw_exception_debug(' . $variableVariable->getName() . ', "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ' TSRMLS_CC);');
if (!$compilationContext->insideTryCatch) {
$codePrinter->output('ZEPHIR_MM_RESTORE();');
$codePrinter->output('return;');
Expand Down
130 changes: 116 additions & 14 deletions Library/StaticCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,98 @@ protected function callFromDynamicClass($methodName, array $expression, $symbolV
$this->addCallStatusOrJump($compilationContext);
}

/**
* Calls static methods on using a dynamic variable as class and a dynamic method
*
* @param array $expression
* @param Variable $symbolVariable
* @param boolean $mustInit
* @param boolean $isExpecting
* @param CompilationContext $compilationContext
*/
protected function callFromDynamicClassDynamicMethod(array $expression, $symbolVariable, $mustInit, $isExpecting, CompilationContext $compilationContext)
{
$codePrinter = $compilationContext->codePrinter;

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

if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}

$cachePointer = 'NULL';

if (isset($expression['parameters']) && count($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
} else {
$params = array();
}

/**
* Obtain the class entry from the variable
*/
$classNameVariable = $compilationContext->symbolTable->getVariableForRead($expression['class'], $compilationContext, $expression);
if ($classNameVariable->isNotVariableAndString()) {
throw new CompilerException("Only dynamic/string variables can be used in dynamic classes", $expression);
}

/**
* @todo Validate if the variable is really a string!
*/
$classEntryVariable = $compilationContext->symbolTable->addTemp('zend_class_entry', $compilationContext);
$codePrinter->output($classEntryVariable->getName() . ' = zend_fetch_class(Z_STRVAL_P(' . $classNameVariable->getName() . '), Z_STRLEN_P(' . $classNameVariable->getName() . '), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);');
$classEntry = $classEntryVariable->getName();


/**
* Obtain the method name from the variable
*/
$methodNameVariable = $compilationContext->symbolTable->getVariableForRead($expression['name'], $compilationContext, $expression);
if ($methodNameVariable->isNotVariableAndString()) {
throw new CompilerException("Only dynamic/string variables can be used in dynamic methods", $expression);
}

/**
* @todo Validate if the variable is really a string!
*/
$methodName = 'Z_STRVAL_P(' . $methodNameVariable->getName() . ')';

if (!count($params)) {
if ($isExpecting) {
if ($symbolVariable->getName() == 'return_value') {
$codePrinter->output('ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ');');
} else {
$codePrinter->output('ZEPHIR_CALL_CE_STATIC(&' . $symbolVariable->getName() . ', ' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ');');
}
} else {
$codePrinter->output('ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ');');
}
} else {
if ($isExpecting) {
if ($symbolVariable->getName() == 'return_value') {
$codePrinter->output('ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
} else {
$codePrinter->output('ZEPHIR_CALL_CE_STATIC(&' . $symbolVariable->getName() . ', ' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
}
} else {
$codePrinter->output('ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', ' . $methodName . ', ' . $cachePointer . ', ' . join(', ', $params) . ');');
}
}

/**
* Temporary variables must be copied if they have more than one reference
*/
foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
$codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
}

$this->addCallStatusOrJump($compilationContext);
}

/**
* Compiles a static method call
*
Expand All @@ -345,7 +437,10 @@ public function compile(Expression $expr, CompilationContext $compilationContext

$expression = $expr->getExpression();

$methodName = strtolower($expression['name']);
$dynamicMethod = $expression['dynamic'];
if (!$dynamicMethod) {
$methodName = strtolower($expression['name']);
}

$symbolVariable = null;

Expand Down Expand Up @@ -435,10 +530,13 @@ public function compile(Expression $expr, CompilationContext $compilationContext
}
}
}
}

/**
* Check if the class implements the method
*/
if (!$dynamicMethod && !$dynamicClass) {

/**
* Check if the class implements the method
*/
if (!$classDefinition->hasMethod($methodName)) {
throw new CompilerException("Class '" . $classDefinition->getCompleteName() . "' does not implement static method: '" . $expression['name'] . "'", $expression);
} else {
Expand Down Expand Up @@ -476,16 +574,14 @@ public function compile(Expression $expr, CompilationContext $compilationContext
}

if ($callNumberParameters < $expectedNumberParameters) {
throw new CompilerException("Method '" . $classDefinition->getCompleteName() . "::" . $expression['name'] . "' called with a wrong number of parameters, the method has: " . $expectedNumberParameters . ", passed: " . $callNumberParameters, $expression);
throw new CompilerException("Method '" . $classDefinition->getCompleteName() . "::" . $expression['name'] . "' called with a wrong number of parameters, the method has: " . $expectedNumberParameters . ", passed: " . $callNumberParameters, $expression);
}
} else {

$method = $classDefinition->getMethod("__callStatic");

if ($method->isPrivate() && $method->getClassDefinition() != $compilationContext->classDefinition) {
throw new CompilerException("Cannot call private magic method '__call' out of its scope", $expression);
}

}
}
}
Expand All @@ -494,18 +590,24 @@ public function compile(Expression $expr, CompilationContext $compilationContext
* Call static methods in the same class, use the special context 'self'
* Call static methods in the 'self' context
*/
if (!$dynamicClass) {
if ($className == 'self' || $classDefinition == $compilationContext->classDefinition) {
$this->callSelf($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $classDefinition, $compilationContext, isset($method) ? $method : null);
if (!$dynamicMethod) {
if ($dynamicClass) {
$this->callFromDynamicClass($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $compilationContext);
} else {
if ($className == 'parent') {
$this->callParent($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $currentClassDefinition, $compilationContext, isset($method) ? $method : null);
if ($className == 'self' || $classDefinition == $compilationContext->classDefinition) {
$this->callSelf($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $classDefinition, $compilationContext, isset($method) ? $method : null);
} else {
$this->callFromClass($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $classDefinition, $compilationContext, isset($method) ? $method : null);
if ($className == 'parent') {
$this->callParent($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $currentClassDefinition, $compilationContext, isset($method) ? $method : null);
} else {
$this->callFromClass($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $classDefinition, $compilationContext, isset($method) ? $method : null);
}
}
}
} else {
$this->callFromDynamicClass($methodName, $expression, $symbolVariable, $mustInit, $isExpecting, $compilationContext);
if ($dynamicClass) {
$this->callFromDynamicClassDynamicMethod($expression, $symbolVariable, $mustInit, $isExpecting, $compilationContext);
}
}

/**
Expand Down
Loading

0 comments on commit aa09356

Please sign in to comment.