1*d4d8fb18SAndreas Gohr<?php 2*d4d8fb18SAndreas Gohr 3*d4d8fb18SAndreas Gohrnamespace dokuwiki\Parsing; 4*d4d8fb18SAndreas Gohr 5*d4d8fb18SAndreas Gohruse Doku_Handler; 6*d4d8fb18SAndreas Gohruse dokuwiki\Parsing\Lexer\Lexer; 7*d4d8fb18SAndreas Gohruse dokuwiki\Parsing\ParserMode\Base; 8*d4d8fb18SAndreas Gohruse dokuwiki\Parsing\ParserMode\ModeInterface; 9*d4d8fb18SAndreas Gohr 10*d4d8fb18SAndreas Gohr/** 11*d4d8fb18SAndreas Gohr * Sets up the Lexer with modes and points it to the Handler 12*d4d8fb18SAndreas Gohr * For an intro to the Lexer see: wiki:parser 13*d4d8fb18SAndreas Gohr */ 14*d4d8fb18SAndreas Gohrclass Parser { 15*d4d8fb18SAndreas Gohr 16*d4d8fb18SAndreas Gohr /** @var Doku_Handler */ 17*d4d8fb18SAndreas Gohr protected $handler; 18*d4d8fb18SAndreas Gohr 19*d4d8fb18SAndreas Gohr /** @var Lexer $lexer */ 20*d4d8fb18SAndreas Gohr protected $lexer; 21*d4d8fb18SAndreas Gohr 22*d4d8fb18SAndreas Gohr /** @var ModeInterface[] $modes */ 23*d4d8fb18SAndreas Gohr protected $modes = array(); 24*d4d8fb18SAndreas Gohr 25*d4d8fb18SAndreas Gohr /** @var bool mode connections may only be set up once */ 26*d4d8fb18SAndreas Gohr protected $connected = false; 27*d4d8fb18SAndreas Gohr 28*d4d8fb18SAndreas Gohr /** 29*d4d8fb18SAndreas Gohr * dokuwiki\Parsing\Doku_Parser constructor. 30*d4d8fb18SAndreas Gohr * 31*d4d8fb18SAndreas Gohr * @param Doku_Handler $handler 32*d4d8fb18SAndreas Gohr */ 33*d4d8fb18SAndreas Gohr public function __construct(Doku_Handler $handler) { 34*d4d8fb18SAndreas Gohr $this->handler = $handler; 35*d4d8fb18SAndreas Gohr } 36*d4d8fb18SAndreas Gohr 37*d4d8fb18SAndreas Gohr /** 38*d4d8fb18SAndreas Gohr * Adds the base mode and initialized the lexer 39*d4d8fb18SAndreas Gohr * 40*d4d8fb18SAndreas Gohr * @param Base $BaseMode 41*d4d8fb18SAndreas Gohr */ 42*d4d8fb18SAndreas Gohr protected function addBaseMode($BaseMode) { 43*d4d8fb18SAndreas Gohr $this->modes['base'] = $BaseMode; 44*d4d8fb18SAndreas Gohr if(!$this->lexer) { 45*d4d8fb18SAndreas Gohr $this->lexer = new Lexer($this->handler, 'base', true); 46*d4d8fb18SAndreas Gohr } 47*d4d8fb18SAndreas Gohr $this->modes['base']->Lexer = $this->lexer; 48*d4d8fb18SAndreas Gohr } 49*d4d8fb18SAndreas Gohr 50*d4d8fb18SAndreas Gohr /** 51*d4d8fb18SAndreas Gohr * Add a new syntax element (mode) to the parser 52*d4d8fb18SAndreas Gohr * 53*d4d8fb18SAndreas Gohr * PHP preserves order of associative elements 54*d4d8fb18SAndreas Gohr * Mode sequence is important 55*d4d8fb18SAndreas Gohr * 56*d4d8fb18SAndreas Gohr * @param string $name 57*d4d8fb18SAndreas Gohr * @param ModeInterface $Mode 58*d4d8fb18SAndreas Gohr */ 59*d4d8fb18SAndreas Gohr public function addMode($name, ModeInterface $Mode) { 60*d4d8fb18SAndreas Gohr if(!isset($this->modes['base'])) { 61*d4d8fb18SAndreas Gohr $this->addBaseMode(new Base()); 62*d4d8fb18SAndreas Gohr } 63*d4d8fb18SAndreas Gohr $Mode->Lexer = $this->lexer; // FIXME should be done by setter 64*d4d8fb18SAndreas Gohr $this->modes[$name] = $Mode; 65*d4d8fb18SAndreas Gohr } 66*d4d8fb18SAndreas Gohr 67*d4d8fb18SAndreas Gohr /** 68*d4d8fb18SAndreas Gohr * Connect all modes with each other 69*d4d8fb18SAndreas Gohr * 70*d4d8fb18SAndreas Gohr * This is the last step before actually parsing. 71*d4d8fb18SAndreas Gohr */ 72*d4d8fb18SAndreas Gohr protected function connectModes() { 73*d4d8fb18SAndreas Gohr 74*d4d8fb18SAndreas Gohr if($this->connected) { 75*d4d8fb18SAndreas Gohr return; 76*d4d8fb18SAndreas Gohr } 77*d4d8fb18SAndreas Gohr 78*d4d8fb18SAndreas Gohr foreach(array_keys($this->modes) as $mode) { 79*d4d8fb18SAndreas Gohr // Base isn't connected to anything 80*d4d8fb18SAndreas Gohr if($mode == 'base') { 81*d4d8fb18SAndreas Gohr continue; 82*d4d8fb18SAndreas Gohr } 83*d4d8fb18SAndreas Gohr $this->modes[$mode]->preConnect(); 84*d4d8fb18SAndreas Gohr 85*d4d8fb18SAndreas Gohr foreach(array_keys($this->modes) as $cm) { 86*d4d8fb18SAndreas Gohr 87*d4d8fb18SAndreas Gohr if($this->modes[$cm]->accepts($mode)) { 88*d4d8fb18SAndreas Gohr $this->modes[$mode]->connectTo($cm); 89*d4d8fb18SAndreas Gohr } 90*d4d8fb18SAndreas Gohr 91*d4d8fb18SAndreas Gohr } 92*d4d8fb18SAndreas Gohr 93*d4d8fb18SAndreas Gohr $this->modes[$mode]->postConnect(); 94*d4d8fb18SAndreas Gohr } 95*d4d8fb18SAndreas Gohr 96*d4d8fb18SAndreas Gohr $this->connected = true; 97*d4d8fb18SAndreas Gohr } 98*d4d8fb18SAndreas Gohr 99*d4d8fb18SAndreas Gohr /** 100*d4d8fb18SAndreas Gohr * Parses wiki syntax to instructions 101*d4d8fb18SAndreas Gohr * 102*d4d8fb18SAndreas Gohr * @param string $doc the wiki syntax text 103*d4d8fb18SAndreas Gohr * @return array instructions 104*d4d8fb18SAndreas Gohr */ 105*d4d8fb18SAndreas Gohr public function parse($doc) { 106*d4d8fb18SAndreas Gohr $this->connectModes(); 107*d4d8fb18SAndreas Gohr // Normalize CRs and pad doc 108*d4d8fb18SAndreas Gohr $doc = "\n" . str_replace("\r\n", "\n", $doc) . "\n"; 109*d4d8fb18SAndreas Gohr $this->lexer->parse($doc); 110*d4d8fb18SAndreas Gohr $this->handler->finalize(); 111*d4d8fb18SAndreas Gohr return $this->handler->calls; 112*d4d8fb18SAndreas Gohr } 113*d4d8fb18SAndreas Gohr 114*d4d8fb18SAndreas Gohr} 115