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