Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. ParserAbstract.php

class ParserAbstract

Same name in this branch
  1. 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\Syntax
View 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&#039;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

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal