<?php namespace dokuwiki\Parsing; use dokuwiki\Debug\DebugHelper; use Doku_Handler; use dokuwiki\Parsing\Lexer\Lexer; use dokuwiki\Parsing\ParserMode\Base; use dokuwiki\Parsing\ParserMode\ModeInterface; /** * Sets up the Lexer with modes and points it to the Handler * For an intro to the Lexer see: wiki:parser */ class Parser { /** @var Doku_Handler */ protected $handler; /** @var Lexer $lexer */ protected $lexer; /** @var ModeInterface[] $modes */ protected $modes = []; /** @var bool mode connections may only be set up once */ protected $connected = false; /** * dokuwiki\Parsing\Doku_Parser constructor. * * @param Doku_Handler $handler */ public function __construct(Doku_Handler $handler) { $this->handler = $handler; } /** * Adds the base mode and initialized the lexer * * @param Base $BaseMode */ protected function addBaseMode($BaseMode) { $this->modes['base'] = $BaseMode; if (!$this->lexer) { $this->lexer = new Lexer($this->handler, 'base', true); } $this->modes['base']->Lexer = $this->lexer; } /** * Add a new syntax element (mode) to the parser * * PHP preserves order of associative elements * Mode sequence is important * * @param string $name * @param ModeInterface $Mode */ public function addMode($name, ModeInterface $Mode) { if (!isset($this->modes['base'])) { $this->addBaseMode(new Base()); } $Mode->Lexer = $this->lexer; // FIXME should be done by setter $this->modes[$name] = $Mode; } /** * Connect all modes with each other * * This is the last step before actually parsing. */ protected function connectModes() { if ($this->connected) { return; } foreach (array_keys($this->modes) as $mode) { // Base isn't connected to anything if ($mode == 'base') { continue; } $this->modes[$mode]->preConnect(); foreach (array_keys($this->modes) as $cm) { if ($this->modes[$cm]->accepts($mode)) { $this->modes[$mode]->connectTo($cm); } } $this->modes[$mode]->postConnect(); } $this->connected = true; } /** * Parses wiki syntax to instructions * * @param string $doc the wiki syntax text * @return array instructions */ public function parse($doc) { $this->connectModes(); // Normalize CRs and pad doc $doc = "\n" . str_replace("\r\n", "\n", $doc) . "\n"; $this->lexer->parse($doc); if (!method_exists($this->handler, 'finalize')) { /** @deprecated 2019-10 we have a legacy handler from a plugin, assume legacy _finalize exists */ DebugHelper::dbgCustomDeprecationEvent( 'finalize()', get_class($this->handler) . '::_finalize()', __METHOD__, __FILE__, __LINE__ ); $this->handler->_finalize(); } else { $this->handler->finalize(); } return $this->handler->calls; } }