class ParserAbstract
Same name in this branch
- 11.1.x vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php \PhpParser\ParserAbstract
Base class for parsers.
@author Marco Marchiò <marco.mm89@gmail.com>
@abstract
Hierarchy
- class \Peast\Syntax\ParserAbstract
Expanded class hierarchy of ParserAbstract
File
-
vendor/
mck89/ peast/ lib/ Peast/ Syntax/ ParserAbstract.php, line 19
Namespace
Peast\SyntaxView source
abstract class ParserAbstract {
/**
* Associated scanner
*
* @var Scanner
*/
protected $scanner;
/**
* Parser features
*
* @var Features
*/
protected $features;
/**
* Parser context
*
* @var \stdClass
*/
protected $context;
/**
* Source type
*
* @var string
*/
protected $sourceType;
/**
* Comments handling
*
* @var bool
*/
protected $comments;
/**
* JSX syntax handling
*
* @var bool
*/
protected $jsx;
/**
* Events emitter
*
* @var EventsEmitter
*/
protected $eventsEmitter;
/**
* Class constructor
*
* @param string $source Source code
* @param Features $features Parser features
* @param array $options Parsing options
*/
public function __construct($source, Features $features, $options = array()) {
$this->features = $features;
$this->sourceType = isset($options["sourceType"]) ? $options["sourceType"] : \Peast\Peast::SOURCE_TYPE_SCRIPT;
//Create the scanner
$this->scanner = new Scanner($source, $features, $options);
//Enable module scanning if required
if ($this->sourceType === \Peast\Peast::SOURCE_TYPE_MODULE) {
$this->scanner
->enableModuleMode();
}
//Enable comments scanning
$this->comments = isset($options["comments"]) && $options["comments"];
if ($this->comments) {
$this->scanner
->enableComments();
//Create the comments registry
new CommentsRegistry($this);
}
// Enable jsx syntax if required
$this->jsx = isset($options["jsx"]) && $options["jsx"];
$this->initContext();
$this->postInit();
}
/**
* Initializes parser context
*
* @return void
*/
protected abstract function initContext();
/**
* Post initialize operations
*
* @return void
*/
protected abstract function postInit();
/**
* Parses the source
*
* @return Node\Node
*
* @abstract
*/
public abstract function parse();
/**
* Returns parsed tokens from the source code
*
* @return Token[]
*/
public function tokenize() {
$this->scanner
->enableTokenRegistration();
$this->parse();
return $this->scanner
->getTokens();
}
/**
* Returns the scanner associated with the parser
*
* @return Scanner
*/
public function getScanner() {
return $this->scanner;
}
/**
* Returns the parser features class
*
* @return Features
*/
public function getFeatures() {
return $this->features;
}
/**
* Returns the parser's events emitter
*
* @return EventsEmitter
*/
public function getEventsEmitter() {
if (!$this->eventsEmitter) {
//The event emitter is created here so that it won't exist if not
//necessary
$this->eventsEmitter = new EventsEmitter();
}
return $this->eventsEmitter;
}
/**
* Calls a method with an isolated parser context, applying the given flags,
* but restoring their values after the execution.
*
* @param array|null $flags Key/value array of changes to apply to the
* context flags. If it's null or the first
* element of the array is null the context will
* be reset before applying new values.
* @param string $fn Method to call
* @param array|null $args Method arguments
*
* @return mixed
*/
protected function isolateContext($flags, $fn, $args = null) {
//Store the current context
$oldContext = clone $this->context;
//If flag argument is null reset the context
if ($flags === null) {
$this->initContext();
}
else {
//Apply new values to the flags
foreach ($flags as $k => $v) {
// If null reset the context
if ($v === null) {
$this->initContext();
}
else {
$this->context->{$k} = $v;
}
}
}
//Call the method with the given arguments
$ret = $args ? call_user_func_array(array(
$this,
$fn,
), $args) : $this->{$fn}();
//Restore previous context
$this->context = $oldContext;
return $ret;
}
/**
* Creates a node
*
* @param string $nodeType Node's type
* @param mixed $position Node's start position
*
* @return Node\Node
*
* @codeCoverageIgnore
*/
protected function createNode($nodeType, $position) {
//Use the right class to get an instance of the node
$nodeClass = "\\Peast\\Syntax\\Node\\" . $nodeType;
$node = new $nodeClass();
//Add the node start position
if ($position instanceof Node\Node || $position instanceof Token) {
$position = $position->location->start;
}
elseif (is_array($position)) {
if (count($position)) {
$position = $position[0]->location->start;
}
else {
$position = $this->scanner
->getPosition();
}
}
$node->location->start = $position;
//Emit the NodeCreated event for the node
$this->eventsEmitter && $this->eventsEmitter
->fire("NodeCreated", array(
$node,
));
return $node;
}
/**
* Completes a node by adding the end position
*
* @param Node\Node $node Node to complete
* @param Position $position Node's end position
*
* @return mixed It actually returns a Node but mixed solves
* a lot of PHPDoc problems
*
* @codeCoverageIgnore
*/
protected function completeNode(Node\Node $node, $position = null) {
//Add the node end position
$node->location->end = $position ?: $this->scanner
->getPosition();
//Emit the NodeCompleted event for the node
$this->eventsEmitter && $this->eventsEmitter
->fire("NodeCompleted", array(
$node,
));
return $node;
}
/**
* Throws a syntax error
*
* @param string $message Error message
* @param Position $position Error position
*
* @return void
*
* @throws Exception
*/
protected function error($message = "", $position = null) {
if (!$message) {
$token = $this->scanner
->getToken();
if ($token === null) {
$message = "Unexpected end of input";
}
else {
$position = $token->location->start;
$message = "Unexpected: " . $token->value;
}
}
if (!$position) {
$position = $this->scanner
->getPosition();
}
throw new Exception($message, $position);
}
/**
* Asserts that a valid end of statement follows the current position
*
* @return boolean
*
* @throws Exception
*/
protected function assertEndOfStatement() {
//The end of statement is reached when it is followed by line
//terminators, end of source, "}" or ";". In the last case the token
//must be consumed
if (!$this->scanner
->noLineTerminators()) {
return true;
}
else {
if ($this->scanner
->consume(";")) {
return true;
}
$token = $this->scanner
->getToken();
if (!$token || $token->value === "}") {
return true;
}
}
$this->error();
}
/**
* Parses a character separated list of instructions or null if the
* sequence is not valid
*
* @param callable $fn Parsing instruction function
* @param string $char Separator
*
* @return array
*
* @throws Exception
*/
protected function charSeparatedListOf($fn, $char = ",") {
$list = array();
$valid = true;
while ($param = $this->{$fn}()) {
$list[] = $param;
$valid = true;
if (!$this->scanner
->consume($char)) {
break;
}
else {
$valid = false;
}
}
if (!$valid) {
$this->error();
}
return $list;
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overrides |
---|---|---|---|---|
ParserAbstract::$comments | protected | property | Comments handling | |
ParserAbstract::$context | protected | property | Parser context | |
ParserAbstract::$eventsEmitter | protected | property | Events emitter | |
ParserAbstract::$features | protected | property | Parser features | |
ParserAbstract::$jsx | protected | property | JSX syntax handling | |
ParserAbstract::$scanner | protected | property | Associated scanner | |
ParserAbstract::$sourceType | protected | property | Source type | |
ParserAbstract::assertEndOfStatement | protected | function | Asserts that a valid end of statement follows the current position | |
ParserAbstract::charSeparatedListOf | protected | function | Parses a character separated list of instructions or null if the sequence is not valid |
|
ParserAbstract::completeNode | protected | function | Completes a node by adding the end position | |
ParserAbstract::createNode | protected | function | Creates a node | |
ParserAbstract::error | protected | function | Throws a syntax error | |
ParserAbstract::getEventsEmitter | public | function | Returns the parser's events emitter | |
ParserAbstract::getFeatures | public | function | Returns the parser features class | |
ParserAbstract::getScanner | public | function | Returns the scanner associated with the parser | |
ParserAbstract::initContext | abstract protected | function | Initializes parser context | 1 |
ParserAbstract::isolateContext | protected | function | Calls a method with an isolated parser context, applying the given flags, but restoring their values after the execution. |
|
ParserAbstract::parse | abstract public | function | Parses the source | 1 |
ParserAbstract::postInit | abstract protected | function | Post initialize operations | 1 |
ParserAbstract::tokenize | public | function | Returns parsed tokens from the source code | |
ParserAbstract::__construct | public | function | Class constructor |