Parser.php 3.2 KB

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