blob: 8c2f7c8beae4af03d9711fb5cf42bcaf3dc9f5ab [file] [log] [blame]
<?php
/**
* File containing the ezcTemplateSourceToTstParserException class
*
* @package Template
* @version //autogen//
* @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Exception for failed element parsers.
* The exception will display the exact location(s) where the error occured
* with some extra description of what went wrong.
*
* @package Template
* @version //autogen//
*/
class ezcTemplateSourceToTstParserException extends ezcTemplateException
{
/**
* Array of elements which should be used to extract failed code.
* Each element needs to have the property $startCursor and $endCursor.
*
* @var array
*/
public $elements;
/**
* The source code object which caused the error.
*
* @var ezcTemplateSource
*/
public $source;
/**
* The one-liner error message.
*
* @var string
*/
public $errorMessage;
/**
* A more detailed error message which can for instance give hints to the
* end-user why it failed.
*
* @var string
*/
public $errorDetails;
/**
* Initialises the exception with the failing elements, parser, source code
* and error messages.
*
* @param ezcTemplateSourceToTstParser $parser The parser which was used when error occured, can be null.
* @param ezcTemplateCursor $cursor The cursor pointing to the error.
* @param string $errorMessage The error message.
* @param string $errorDetails Extra details for error.
*/
public function __construct( /*ezcTemplateSourceToTstParser*/ $parser,
ezcTemplateCursor $cursor,
$errorMessage,
$errorDetails = "" )
{
// TODO fix this.
$this->elements = array( $parser );
$this->parser = $parser;
$this->source = $parser->parser->source;
$this->elements[0]->startCursor = $cursor;
$this->errorMessage = $errorMessage;
$this->errorDetails = $errorDetails;
parent::__construct( $this->getErrorMessage() );
}
/**
* Generates the error message from member variables and returns it.
* @return string
*/
public function getErrorMessage()
{
// Display tree structure of parsers, for debugging
if ( $this->parser !== null )
{
$parser = $this->parser;
$parsers = array();
$currentParser = $parser->programParser;
$parsers = get_class( $currentParser );
$level = 0;
while ( $currentParser->subParser !== null )
{
++$level;
$currentParser = $currentParser->subParser;
$parsers .= "\n" . str_repeat( " ", $level ) . "-> " . get_class( $currentParser );
}
$parsers .= "\n";
}
// Extract code parts which failed
$code = '';
$i = 0;
$lastStartCursor = $this->elements[0]->startCursor;
$lastEndCursor = $this->elements[0]->endCursor;
foreach ( $this->elements as $element )
{
if ( $i > 0 )
{
$code .= "\n";
// Diff-style marker for line number difference
$code .= "@@ -{$lastStartCursor->line} +{$element->endCursor->line}\n";
}
++$i;
// Show failed code for element
$code .= $this->getAstNodeFailure( $element->startCursor, $element->endCursor, $element->startCursor );
// Store cursor for next iteration
$lastStartCursor = $element->startCursor;
$lastEndCursor = $element->endCursor;
}
$details = $this->errorDetails;
if ( strlen( $details ) > 0 )
{
$details = "\n" . $details;
}
$locationMessage = "{$this->source->stream}:{$lastEndCursor->line}:{$lastEndCursor->column}:";
$message = $locationMessage . " " . $this->errorMessage . "\n\n" . $code . $details . "\n\nfailed in:\n" . $parsers;
return $message;
}
/**
* Extracts the code which failed as denoted by $startCursor and $endCursor
* and display the exact column were it happened.
* The cursor $markCursor is used to mark where the error occured, it will
* displayed using a ^ character.
*
* @param ezcTemplateCursor $startCursor The start point of the code to extract
* @param ezcTemplateCursor $endCursor The ending point of the code to extract
* @param ezcTemplateCursor $markCursor The point in the code which should be highlighted.
* @return string
*/
private function getAstNodeFailure( $startCursor, $endCursor, $markCursor )
{
$code = substr( $startCursor->text,
$startCursor->position - $startCursor->column,
$endCursor->position - $startCursor->position + $startCursor->column );
// Include some code which appears after the failure points, max 10 characters
$extraAstNode = substr( $startCursor->text,
$endCursor->position,
$markCursor->position - $endCursor->position + 10 );
$eolPos = strpos( $extraAstNode, "\n" );
if ( $eolPos !== false )
{
$extraAstNode = substr( $extraAstNode, 0, $eolPos );
}
$code .= $extraAstNode;
$code .= "\n";
if ( $markCursor->column > 0 )
{
$code .= str_repeat( " ", $markCursor->column );
}
$code .= "^";
return $code;
}
}
?>