1<?php 2 3use dokuwiki\Lexer\Lexer; 4use dokuwiki\ParserMode\Base; 5use dokuwiki\ParserMode\ModeInterface; 6 7/** 8 * Define various types of modes used by the parser - they are used to 9 * populate the list of modes another mode accepts 10 */ 11global $PARSER_MODES; 12$PARSER_MODES = array( 13 // containers are complex modes that can contain many other modes 14 // hr breaks the principle but they shouldn't be used in tables / lists 15 // so they are put here 16 'container' => array('listblock','table','quote','hr'), 17 18 // some mode are allowed inside the base mode only 19 'baseonly' => array('header'), 20 21 // modes for styling text -- footnote behaves similar to styling 22 'formatting' => array('strong', 'emphasis', 'underline', 'monospace', 23 'subscript', 'superscript', 'deleted', 'footnote'), 24 25 // modes where the token is simply replaced - they can not contain any 26 // other modes 27 'substition' => array('acronym','smiley','wordblock','entity', 28 'camelcaselink', 'internallink','media', 29 'externallink','linebreak','emaillink', 30 'windowssharelink','filelink','notoc', 31 'nocache','multiplyentity','quotes','rss'), 32 33 // modes which have a start and end token but inside which 34 // no other modes should be applied 35 'protected' => array('preformatted','code','file','php','html','htmlblock','phpblock'), 36 37 // inside this mode no wiki markup should be applied but lineendings 38 // and whitespace isn't preserved 39 'disabled' => array('unformatted'), 40 41 // used to mark paragraph boundaries 42 'paragraphs' => array('eol') 43); 44 45/** 46 * Sets up the Lexer with modes and points it to the Handler 47 * For an intro to the Lexer see: wiki:parser 48 */ 49class Doku_Parser { 50 51 /** @var Doku_Handler */ 52 protected $handler; 53 54 /** @var Lexer $lexer */ 55 protected $lexer; 56 57 /** @var ModeInterface[] $modes */ 58 protected $modes = array(); 59 60 /** @var bool mode connections may only be set up once */ 61 protected $connected = false; 62 63 /** 64 * Doku_Parser constructor. 65 * 66 * @param Doku_Handler $handler 67 */ 68 public function __construct(Doku_Handler $handler) { 69 $this->handler = $handler; 70 } 71 72 /** 73 * Adds the base mode and initialized the lexer 74 * 75 * @param Base $BaseMode 76 */ 77 protected function addBaseMode($BaseMode) { 78 $this->modes['base'] = $BaseMode; 79 if ( !$this->lexer ) { 80 $this->lexer = new Lexer($this->handler, 'base', true); 81 } 82 $this->modes['base']->Lexer = $this->lexer; 83 } 84 85 /** 86 * Add a new syntax element (mode) to the parser 87 * 88 * PHP preserves order of associative elements 89 * Mode sequence is important 90 * 91 * @param string $name 92 * @param ModeInterface $Mode 93 */ 94 public function addMode($name, ModeInterface $Mode) { 95 if ( !isset($this->modes['base']) ) { 96 $this->addBaseMode(new Base()); 97 } 98 $Mode->Lexer = $this->lexer; // FIXME should be done by setter 99 $this->modes[$name] = $Mode; 100 } 101 102 /** 103 * Connect all modes with each other 104 * 105 * This is the last step before actually parsing. 106 */ 107 protected function connectModes() { 108 109 if ( $this->connected ) { 110 return; 111 } 112 113 foreach ( array_keys($this->modes) as $mode ) { 114 // Base isn't connected to anything 115 if ( $mode == 'base' ) { 116 continue; 117 } 118 $this->modes[$mode]->preConnect(); 119 120 foreach ( array_keys($this->modes) as $cm ) { 121 122 if ( $this->modes[$cm]->accepts($mode) ) { 123 $this->modes[$mode]->connectTo($cm); 124 } 125 126 } 127 128 $this->modes[$mode]->postConnect(); 129 } 130 131 $this->connected = true; 132 } 133 134 /** 135 * Parses wiki syntax to instructions 136 * 137 * @param string $doc the wiki syntax text 138 * @return array instructions 139 */ 140 public function parse($doc) { 141 $this->connectModes(); 142 // Normalize CRs and pad doc 143 $doc = "\n".str_replace("\r\n","\n",$doc)."\n"; 144 $this->lexer->parse($doc); 145 $this->handler->_finalize(); 146 return $this->handler->calls; 147 } 148 149} 150