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