You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

132 lines
3.3 KiB

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