DokuWiki

It's better when it's simple

User Tools

Site Tools


devel:parser

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
devel:parser [2014-01-08 22:01] – [Lexer] hexcodes aren't needed anymore (sofar i know) Klap-indevel:parser [2023-09-18 16:38] (current) – [Linefeed grabbing] Add link to Github for workaround 69.14.68.110
Line 8: Line 8:
 Broadly these elements are; Broadly these elements are;
  
-  - Lexer((__L__exer refers to the class ''Doku_Lexer'' and the contents of the file ''inc/parser/lexer.php'')): scans ((scan: reading a PHP string from start to end)) from a DokuWiki document and outputs a sequence of "tokens" ((the term token in this document refers to a regex match, made by the Lexer, and the corresponding method call on the Handler)), corresponding to the syntax in the document+  - Lexer((__L__exer refers to the class ''dokuwiki\Lexer\Lexer'' and the contents of the file ''inc/Parsing/Lexer/Lexer.php'')): scans ((scan: reading a PHP string from start to end)) from a DokuWiki document and outputs a sequence of "tokens" ((the term token in this document refers to a regex match, made by the Lexer, and the corresponding method call on the Handler)), corresponding to the syntax in the document
   - Handler((__H__andler refers to the class ''Doku_Handler'' and the contents of the file ''inc/parser/handler.php'')): receives the tokens from the Lexer and transforms them into a sequence of "instructions" ((the sequence of instructions is stored in an array called ''$calls'', which is a property of the Handler. It is intended for use with [[phpfn>call_user_func_array]])). It describes how the document should be rendered, from start to finish, without the Renderer needing to keep track of state.   - Handler((__H__andler refers to the class ''Doku_Handler'' and the contents of the file ''inc/parser/handler.php'')): receives the tokens from the Lexer and transforms them into a sequence of "instructions" ((the sequence of instructions is stored in an array called ''$calls'', which is a property of the Handler. It is intended for use with [[phpfn>call_user_func_array]])). It describes how the document should be rendered, from start to finish, without the Renderer needing to keep track of state.
-  - Parser((__P__arser refers to the class ''Doku_Parser'' and the contents of the file ''inc/parser/parser.php'')): "connects up" the Lexer with the Handler, providing the DokuWiki syntax rules as well as the point of access to the system (the Parser::parse() method)+  - Parser((__P__arser refers to the class ''dokuwiki\Parsing\Parser'' and the contents of the file ''inc/Parsing/Parser.php'')): "connects up" the Lexer with the Handler, providing the DokuWiki syntax rules as well as the point of access to the system (the Parser::parse() method)
   - Renderer((__R__ender refers to some class implementing ''Doku_Renderer'' - see ''inc/parser/renderer.php'' and ''inc/parser/xhtml.php'')): accepts the instructions from the Handler and "draws" the document ready for viewing (e.g. as XHTML)   - Renderer((__R__ender refers to some class implementing ''Doku_Renderer'' - see ''inc/parser/renderer.php'' and ''inc/parser/xhtml.php'')): accepts the instructions from the Handler and "draws" the document ready for viewing (e.g. as XHTML)
  
Line 46: Line 46:
 ==== Lexer ==== ==== Lexer ====
  
-Defined in ''inc/parser/lexer.php''+Defined in the folder [[xref>inc/Parsing/Lexer.php|inc/Parsing/Lexer]]
  
 In the most general sense, it provides a tool for managing complex regular expressions, where state is important. The Lexer comes from [[http://www.lastcraft.com/simple_test.php|Simple Test]] but contains three modifications (read: hacks); In the most general sense, it provides a tool for managing complex regular expressions, where state is important. The Lexer comes from [[http://www.lastcraft.com/simple_test.php|Simple Test]] but contains three modifications (read: hacks);
Line 58: Line 58:
 The Lexer as a whole is made of three main classes; The Lexer as a whole is made of three main classes;
  
-  * ''Doku_LexerParallelRegex'': allows regular expressions to be constructed from multiple, separate patterns, each pattern being associated with an identifying "label" , the class combining them into a single regex using subpatterns. //When using the Lexer, you should not need to worry about this class//. +  * [[xref>dokuwiki\Lexer\ParallelRegex]]: allows regular expressions to be constructed from multiple, separate patterns, each pattern being associated with an identifying "label" , the class combining them into a single regex using subpatterns. //When using the Lexer, you should not need to worry about this class//. 
-  * ''Doku_LexerStateStack'': provides a simple state machine so that lexing can be "context aware". //When using the Lexer, you should not need to worry about this class//. +  * [[xref>dokuwiki\Lexer\StateStack]]: provides a simple state machine so that lexing can be "context aware". //When using the Lexer, you should not need to worry about this class//. 
-  * ''Doku_Lexer'': provides the point of access for client code using the Lexer. Manages multiple instances of ParallelRegex, using the StateStack to apply the correct ParallelRegex instance, depending on "context". On encountering "interesting text", it calls functions on a user provided object (the Handler).+  * [[xref>dokuwiki\Lexer\Lexer]]: provides the point of access for client code using the Lexer. Manages multiple instances of ParallelRegex, using the StateStack to apply the correct ParallelRegex instance, depending on "context". On encountering "interesting text", it calls functions on a user provided object (the Handler).
  
 ===The need for state=== ===The need for state===
Line 85: Line 85:
  
 <code php> <code php>
-$Handler new MyHandler(); +$handler = new MyHandler(); 
-$Lexer new Doku_Lexer($Handler, 'base', TRUE);+$lexer = new dokuwiki\Lexer\Lexer($handler, 'base', true);
 </code> </code>
  
Line 92: Line 92:
  
 == addEntryPattern / addExitPattern == == addEntryPattern / addExitPattern ==
-Used to register a pattern for entering and exiting a particular parsing mode. For example;+[[xref>addEntryPattern()]] and [[xref>addExitPattern()]] are used to register a pattern for entering and exiting a particular parsing mode. For example;
  
 <code php> <code php>
Line 98: Line 98:
 // arg1: name of mode where this entry pattern may be used // arg1: name of mode where this entry pattern may be used
 // arg2: name of mode to enter // arg2: name of mode to enter
-$Lexer->addEntryPattern('<file>','base','file');+$lexer->addEntryPattern('<file>','base','file');
  
 // arg0: regex to match // arg0: regex to match
 // arg1: name of mode to exit // arg1: name of mode to exit
-$Lexer->addExitPattern('</file>','file');+$lexer->addExitPattern('</file>','file');
 </code> </code>
  
Line 110: Line 110:
  
 == addPattern == == addPattern ==
-Used to trigger additional "tokens" inside an existing mode (no transitions). It accepts a pattern and the name of a mode it should be used inside.+[[xref>addPattern()]] is used to trigger additional "tokens" inside an existing mode (no transitions). It accepts a pattern and the name of a mode it should be used inside.
  
 This is best seen from considering the list syntax in the parser. Lists syntax looks like this in DokuWiki; This is best seen from considering the list syntax in the parser. Lists syntax looks like this in DokuWiki;
Line 122: Line 122:
 </code> </code>
  
-Using ''%%addPattern%%'' it becomes possible to match the complete list at once while still exiting correctly and tokenizing each list item;+Using ''%%addPattern()%%'' it becomes possible to match the complete list at once while still exiting correctly and tokenizing each list item;
  
 <code php> <code php>
 // Match the opening list item and change mode // Match the opening list item and change mode
-$Lexer->addEntryPattern('\n {2,}[\*]','base','list');+$lexer->addEntryPattern('\n {2,}[\*]','base','list');
  
 // Match new list items but stay in the list mode // Match new list items but stay in the list mode
-$Lexer->addPattern('\n {2,}[\*]','list');+$lexer->addPattern('\n {2,}[\*]','list');
  
 // If it's a linefeed that fails to match the above addPattern rule, exit the mode // If it's a linefeed that fails to match the above addPattern rule, exit the mode
-$Lexer->addExitPattern('\n','list');+$lexer->addExitPattern('\n','list');
 </code> </code>
  
 == addSpecialPattern == == addSpecialPattern ==
  
-Used to enter a new mode just for the match then drop straight back into the "parent" mode. Accepts a pattern, a name of a mode it can be applied inside and the name of the "temporary" mode to enter for the match. Typically this would be used if you want to substitute wiki markup with something else. For example to match a smiley like %%:-)%% you might have;+[[xref>addSpecialPattern()]] is used to enter a new mode just for the match then drop straight back into the "parent" mode. Accepts a pattern, a name of a mode it can be applied inside and the name of the "temporary" mode to enter for the match. Typically this would be used if you want to substitute wiki markup with something else. For example to match a smiley like %%:-)%% you might have;
  
 <code php> <code php>
-$Lexer->addSpecialPattern(':-)','base','smiley');+$lexer->addSpecialPattern(':-)','base','smiley');
 </code> </code>
  
 == mapHandler == == mapHandler ==
  
-Allows a particular named mode to be mapped onto a method with a different name in the Handler. This may be useful when differing syntax should be handled in the same manner, such as the DokuWiki syntax for disabling other syntax inside a particular text block;+[[xref>mapHandler()]] allows a particular named mode to be mapped onto a method with a different name in the Handler. This may be useful when differing syntax should be handled in the same manner, such as the DokuWiki syntax for disabling other syntax inside a particular text block;
  
 <code php> <code php>
-$Lexer->addEntryPattern('<nowiki>','base','unformatted'); +$lexer->addEntryPattern('<nowiki>','base', 'unformatted'); 
-$Lexer->addEntryPattern('%%','base','unformattedalt'); +$lexer->addEntryPattern('%%','base', 'unformattedalt'); 
-$Lexer->addExitPattern('</nowiki>','unformatted'); +$lexer->addExitPattern('</nowiki>', 'unformatted'); 
-$Lexer->addExitPattern('%%','unformattedalt');+$lexer->addExitPattern('%%', 'unformattedalt');
  
 // Both syntaxes should be handled the same way... // Both syntaxes should be handled the same way...
-$Lexer->mapHandler('unformattedalt','unformatted');+$lexer->mapHandler('unformattedalt', 'unformatted');
 </code> </code>
  
 === Subpatterns Not Allowed === === Subpatterns Not Allowed ===
  
-Because the Lexer itself uses subpatterns (inside the ''ParallelRegex'' class), code //using// the Lexer cannot. This may take some getting used to but, generally, the ''%%addPattern%%'' method can be applied for solving the types problems where subpatterns are typically applied. It has the advantage of keeping regexs simpler and thereby easier to manage.+Because the Lexer itself uses subpatterns (inside the ''ParallelRegex'' class), code //using// the Lexer cannot. This may take some getting used to but, generally, the ''%%addPattern()%%'' method can be applied for solving the types problems where subpatterns are typically applied. It has the advantage of keeping regexs simpler and thereby easier to manage.
  
 === Syntax Errors and State === === Syntax Errors and State ===
Line 167: Line 167:
 <code php> <code php>
 // Use lookahead in entry pattern... // Use lookahead in entry pattern...
-$Lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); +$lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); 
-$Lexer->addExitPattern('</file>','file');+$lexer->addExitPattern('</file>','file');
 </code> </code>
  
Line 177: Line 177:
 ==== Handler ==== ==== Handler ====
  
-Defined in ''inc/parser/handler.php''+Defined in [[xref>inc/parser/handler.php]] and the folder [[xref>inc/Parsing/Handler.php|inc/Parsing/Handler]]
  
 The Handler is a class providing methods which are called by the Lexer as it matches tokens. It then "fine tunes" the tokens into a sequence of instructions ready for a Renderer. The Handler is a class providing methods which are called by the Lexer as it matches tokens. It then "fine tunes" the tokens into a sequence of instructions ready for a Renderer.
Line 183: Line 183:
 The Handler as a whole contains the following classes: The Handler as a whole contains the following classes:
  
-  * ''Doku_Handler'': all calls from the Lexer are made to this class. For every mode registered with the Lexer, there will be a corresponding method in the Handler +  * [[xref>inc::Doku_Handler|Doku_Handler]]: all calls from the Lexer are made to this class. For every mode registered with the Lexer, there will be a corresponding method in the Handler 
-  * ''Doku_Handler_CallWriter'': provides a layer between the array of instructions (the ''Doku_Handler::$calls'' array) and the Handler methods //writing// the instructions. It will be temporarily replaced with other objects, such as ''Doku_Handler_List'', while lexing is in progress. +  * [[xref>dokuwiki\Parsing\Handler\CallWriter]]: provides a layer between the array of instructions (the ''Doku_Handler::$calls'' array) and the Handler methods //writing// the instructions. It will be temporarily replaced with other objects, such as ''dokuwiki\Parsing\Handler\List'', while lexing is in progress. 
-  * ''Doku_Handler_List'': responsible for transforming list tokens into instructions while lexing is still in progress +  * [[xref>dokuwiki\Parsing\Handler\Lists]]: responsible for transforming list tokens into instructions while lexing is still in progress 
-  * ''Doku_Handler_Preformatted'': responsible for transforming preformatted tokens (indented text in dokuwiki) into instructions while lexing is still in progress +  * [[xref>dokuwiki\Parsing\Handler\Quote]]: responsible for transforming blockquote tokens (text beginning with one or more >) into instructions while lexing is still in progress 
-  * ''Doku_Handler_Quote'': responsible for transforming blockquote tokens (text beginning with one or more >) into instructions while lexing is still in progress +  * [[xref>dokuwiki\Parsing\Handler\Table]]: responsible for transforming table tokens into instructions while lexing is still in progress 
-  * ''Doku_Handler_Table'': responsible for transforming table tokens into instructions while lexing is still in progress +  * [[xref>dokuwiki\Parsing\Handler\Block]]: responsible for inserting 'p_open' and 'p_close' instructions, while being aware of 'block level' instructions, once all lexing has finished (i.e. it loops once through the complete list of instructions and inserts more instructions) 
-  * ''Doku_Handler_Section'': responsible for inserting 'section' instructions, based on the position of header instructions, once all lexing has finished - loops once through the complete list of instructions +  * [[xref>dokuwiki\Parsing\Handler\AbstractRewriter]]: ...extended by ''Preformatted'' and ''Nest'' ... FIXME 
-  * ''Doku_Handler_Block'': responsible for inserting 'p_open' and 'p_close' instructions, while being aware of 'block level' instructions, once all lexing has finished (i.e. it loops once through the complete list of instructions and inserts more instructions) +  * [[xref>dokuwiki\Parsing\Handler\Nest]]: ...FIXME 
-  * ''Doku_Handler_Toc'': responsible for adding table of contents instructions at the start of the sequence, based on header instructions found, once all lexing has finished (i.eit loops once through the complete list of instructions and inserts more instructions)+  * [[xref>dokuwiki\Parsing\Handler\Preformatted]]: responsible for transforming preformatted tokens (indented text in dokuwiki) into instructions while lexing is still in progress 
 + 
 + 
 +Interfaces: 
 +  * [[xref>dokuwiki\Parsing\Handler\CallWriterInterface]]: ... implemented by ''CallWriter'' 
 +  * [[xref>dokuwiki\Parsing\Handler\ReWriterInterface]]: ... extends the ''CallWriterInterface'', implemented by ''AbstractRewriter''
  
 === Handler Token Methods === === Handler Token Methods ===
Line 200: Line 205:
  
 <code php> <code php>
-$Lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); +$lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); 
-$Lexer->addExitPattern('</file>','file');+$lexer->addExitPattern('</file>','file');
 </code> </code>
  
Line 214: Line 219:
     * @param int pos - byte index where match was made     * @param int pos - byte index where match was made
     */     */
-    function file($match, $state, $pos) { +    public function file($match, $state, $pos) { 
-        return TRUE;+        return true;
     }     }
 } }
 </code> </code>
  
-**Note:** a Handler method //must// return TRUE or the Lexer will halt immediately. This behaviour can be useful when dealing with other types of parsing problem but for the DokuWiki parser, all Handler methods will //always// return TRUE.+**Note:** a Handler method //must// return true or the Lexer will halt immediately. This behaviour can be useful when dealing with other types of parsing problem but for the DokuWiki parser, all Handler methods will //always// return true.
  
 The arguments provided to a handler method are; The arguments provided to a handler method are;
Line 236: Line 241:
  
 <code php> <code php>
-    function connectTo($mode) { +public function connectTo($mode) { 
-        $this->Lexer->addEntryPattern('\n {2,}[\-\*]',$mode,'listblock'); +    $this->Lexer->addEntryPattern('\n {2,}[\-\*]', $mode, 'listblock'); 
-        $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]',$mode,'listblock'); +    $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]', $mode, 'listblock'); 
-         + 
-        $this->Lexer->addPattern('\n {2,}[\-\*]','listblock'); +    $this->Lexer->addPattern('\n {2,}[\-\*]', 'listblock'); 
-        $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock'); +    $this->Lexer->addPattern('\n\t{1,}[\-\*]', 'listblock'); 
-         +
-    + 
-     +public function postConnect() { 
-    function postConnect() { +    $this->Lexer->addExitPattern('\n', 'listblock'); 
-        $this->Lexer->addExitPattern('\n','listblock'); +}
-    }+
 </code> </code>
  
Line 253: Line 257:
  
 <code php> <code php>
-    function listblock($match, $state, $pos) { +public function listblock($match, $state, $pos) { 
-         +    switch ($state) { 
-        switch ( $state ) { +        // The start of the list... 
-             +        case DOKU_LEXER_ENTER: 
-            // The start of the list... +            // Create the List rewriter, passing in the current CallWriter 
-            case DOKU_LEXER_ENTER: +            $reWriter = new dokuwiki\Parsing\Handler\Lists($this->callWriter); 
-                // Create the List rewriter, passing in the current CallWriter + 
-                $ReWriter new Doku_Handler_List($this->CallWriter); +            // Replace the current CallWriter with the List rewriter 
-                 +            // all incoming tokens (even if not list tokens) 
-                // Replace the current CallWriter with the List rewriter +            // are now diverted to the list 
-                // all incoming tokens (even if not list tokens) +            $this->callWriter = $reWriter
-                // are now diverted to the list + 
-                $this->CallWriter $ReWriter+            $this->addCall('list_open', [$match], $pos);
-                 +
-                $this->__addCall('list_open', array($match), $pos);+
             break;             break;
-             + 
-            // The end of the list +        // The end of the list 
-            case DOKU_LEXER_EXIT: +        case DOKU_LEXER_EXIT: 
-                $this->__addCall('list_close', array(), $pos); +            $this->addCall('list_close', [], $pos); 
-                 + 
-                // Tell the List rewriter to clean up +            // Tell the List rewriter to clean up 
-                $this->CallWriter->process(); +            $this->callWriter->process(); 
-                 + 
-                // Restore the old CallWriter +            // Restore the old CallWriter 
-                $ReWriter $this->CallWriter+            $reWriter = $this->callWriter
-                $this->CallWriter $ReWriter->CallWriter; +            $this->callWriter = $reWriter->callWriter;
-                +
             break;             break;
-             + 
-            case DOKU_LEXER_MATCHED: +        case DOKU_LEXER_MATCHED: 
-                $this->__addCall('list_item', array($match), $pos);+            $this->addCall('list_item', [$match], $pos);
             break;             break;
-             + 
-            case DOKU_LEXER_UNMATCHED: +        case DOKU_LEXER_UNMATCHED: 
-                $this->__addCall('cdata', array($match), $pos);+            $this->addCall('cdata', [$match], $pos);
             break;             break;
-        } 
-        return TRUE; 
     }     }
 +    return true;
 +}
 </code> </code>
  
Line 341: Line 342:
  
  
-In the case of lists, this requires the help of the ''Doku_Handler_List'' class, which has its own knowledge of state and is captures the incoming tokens, replacing them with the correct instructions for a Renderer.+In the case of lists, this requires the help of the ''dokuwiki\Parsing\Handler\Lists'' class, which has its own knowledge of state and is captures the incoming tokens, replacing them with the correct instructions for a Renderer. 
 ==== Parser ==== ==== Parser ====
 +Defined in [[xref>inc\Parsing\Parser.php]] and [[xref>inc/parser/parser.php]].
  
-The Parser acts as the front end to external code and sets up the Lexer with the patterns and modes describing DokuWiki syntax.+The [[xref>dokuwiki\Parsing\Parser]] acts as the front end to external code and sets up the Lexer with the patterns and modes describing DokuWiki syntax. 
  
 Using the Parser will generally look like: Using the Parser will generally look like:
  
 <code php> <code php>
-// Create the parser +// Create the Handler 
-$Parser new Doku_Parser();+$handler = new Doku_Handler();
  
-// Create the handler and store in the parser +// Create the parser with the handler 
-$Parser->Handler new Doku_Handler();+$parser = new dokuwiki\Parsing\Parser($handler);
  
 // Add required syntax modes to parser // Add required syntax modes to parser
-$Parser->addMode('footnote',new Doku_Parser_Mode_Footnote()); +$parser->addMode('footnote', new dokuwiki\Parsing\ParserMode\Footnote()); 
-$Parser->addMode('hr',new Doku_Parser_Mode_HR()); +$parser->addMode('hr', new dokuwiki\Parsing\ParserMode\Hr()); 
-$Parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted());+$parser->addMode('unformatted', new dokuwiki\Parsing\ParserMode\Unformatted());
 # etc. # etc.
  
 $doc = file_get_contents('wikipage.txt.'); $doc = file_get_contents('wikipage.txt.');
-$instructions = $Parser->parse($doc);+$instructions = $parser->parse($doc);
 </code> </code>
  
 More detailed examples are below. More detailed examples are below.
  
-As a whole, the Parser also contains classes representing each available syntax mode, the base class for all of these being ''Doku_Parser_Mode''. The behaviour of these modes are best understood by looking at the examples of adding syntax later in this document.+As a whole, the Parser also contains classes representing each available syntax mode, the base class for all of these being [[xref>dokuwiki\Parsing\ParserMode\AbstractMode]]. The behaviour of these modes are best understood by looking at the examples of adding syntax later in this document.
  
 The //reason// for representing the modes with classes is to avoid repeated calls to the Lexer methods. Without them it would be necessary to hard code each pattern rule for every mode that pattern can be matched in, for example, registering a single pattern rule for the CamelCase link syntax would require something like; The //reason// for representing the modes with classes is to avoid repeated calls to the Lexer methods. Without them it would be necessary to hard code each pattern rule for every mode that pattern can be matched in, for example, registering a single pattern rule for the CamelCase link syntax would require something like;
  
 <code php> <code php>
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','base','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'base', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','footnote','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'footnote', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','table','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'table', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','listblock','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'listblock', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','strong','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'strong', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','underline','camelcaselink');+$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'underline', 'camelcaselink');
 // etc. // etc.
 </code> </code>
Line 386: Line 389:
  
 <code php> <code php>
-class Doku_Parser_Mode_CamelCaseLink extends Doku_Parser_Mode +namespace dokuwiki\Parsing\ParserMode; 
-     + 
-    function connectTo($mode) {+class CamelCaseLink extends AbstractMode 
 + 
 +    public function connectTo($mode) {
         $this->Lexer->addSpecialPattern(         $this->Lexer->addSpecialPattern(
-                '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' +            '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', $mode, 'camelcaselink' 
-            );+        );
     }     }
-     
 } }
 </code> </code>
  
-When setting up the Lexer, the Parser calls the ''%%connectTo%%'' method on the ''Doku_Parser_Mode_CamelCaseLink'' object for every other mode which accepts the CamelCase syntax (some don't such as the ''%%<code />%%'' syntax).+When setting up the Lexer, the Parser calls the ''%%connectTo()%%'' method on the ''dokuwiki\Parsing\ParserMode\CamelCaseLink'' object for every other mode which accepts the CamelCase syntax (some don't such as the ''%%<code />%%'' syntax).
  
 At the expense of making the Lexer setup harder to understand, this allows the code to be more flexible when adding new syntax. At the expense of making the Lexer setup harder to understand, this allows the code to be more flexible when adding new syntax.
Line 419: Line 423:
  
 <code> <code>
-Array +Array( 
-+    [0] => Array(
-    [0] => Array +
-        (+
             [0] => document_start             [0] => document_start
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 0             [2] => 0
         )         )
- +    [1] => Array(
-    [1] => Array +
-        (+
             [0] => p_open             [0] => p_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 0             [2] => 0
         )         )
- +    [2] => Array(
-    [2] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                      [0] => 
  
 abc abc
                 )                 )
- 
             [2] => 0             [2] => 0
         )         )
- +    [3] => Array(
-    [3] => Array +
-        (+
             [0] => p_close             [0] => p_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 5             [2] => 5
         )         )
- +    [4] => Array(
-    [4] => Array +
-        (+
             [0] => table_open             [0] => table_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 3                     [0] => 3
                     [1] => 2                     [1] => 2
                 )                 )
- 
             [2] => 5             [2] => 5
         )         )
- +    [5] => Array(
-    [5] => Array +
-        (+
             [0] => tablerow_open             [0] => tablerow_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 5             [2] => 5
         )         )
- +    [6] => Array(
-    [6] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 5             [2] => 5
         )         )
- +    [7] => Array(
-    [7] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 1                     [0] =>  Row 0 Col 1
                 )                 )
- 
             [2] => 7             [2] => 7
         )         )
- +    [8] => Array(
-    [8] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                          [0] =>     
                 )                 )
- 
             [2] => 19             [2] => 19
         )         )
- +    [9] => Array(
-    [9] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 23             [2] => 23
         )         )
- +    [10] => Array(
-    [10] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 23             [2] => 23
         )         )
- +    [11] => Array(
-    [11] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 2                     [0] =>  Row 0 Col 2
                 )                 )
- 
             [2] => 24             [2] => 24
         )         )
- +    [12] => Array(
-    [12] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                           [0] =>      
                 )                 )
- 
             [2] => 36             [2] => 36
         )         )
- +    [13] => Array(
-    [13] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 41             [2] => 41
         )         )
- +    [14] => Array(
-    [14] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 41             [2] => 41
         )         )
- +    [15] => Array(
-    [15] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 3                     [0] =>  Row 0 Col 3
                 )                 )
- 
             [2] => 42             [2] => 42
         )         )
- +    [16] => Array(
-    [16] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                              [0] =>         
                 )                 )
- 
             [2] => 54             [2] => 54
         )         )
- +    [17] => Array(
-    [17] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 62             [2] => 62
         )         )
- +    [18] => Array(
-    [18] => Array +
-        (+
             [0] => tablerow_close             [0] => tablerow_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 63             [2] => 63
         )         )
- +    [19] => Array(
-    [19] => Array +
-        (+
             [0] => tablerow_open             [0] => tablerow_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 63             [2] => 63
         )         )
- +    [20] => Array(
-    [20] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 63             [2] => 63
         )         )
- +    [21] => Array(
-    [21] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 1                     [0] =>  Row 1 Col 1
                 )                 )
- 
             [2] => 65             [2] => 65
         )         )
- +    [22] => Array(
-    [22] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                          [0] =>     
                 )                 )
- 
             [2] => 77             [2] => 77
         )         )
- +    [23] => Array(
-    [23] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 81             [2] => 81
         )         )
- +    [24] => Array(
-    [24] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 81             [2] => 81
         )         )
- +    [25] => Array(
-    [25] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 2                     [0] =>  Row 1 Col 2
                 )                 )
- 
             [2] => 82             [2] => 82
         )         )
- +    [26] => Array(
-    [26] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                           [0] =>      
                 )                 )
- 
             [2] => 94             [2] => 94
         )         )
- +    [27] => Array(
-    [27] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 99             [2] => 99
         )         )
- +    [28] => Array(
-    [28] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 99             [2] => 99
         )         )
- +    [29] => Array(
-    [29] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 3                     [0] =>  Row 1 Col 3
                 )                 )
- 
             [2] => 100             [2] => 100
         )         )
- +    [30] => Array(
-    [30] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                              [0] =>         
                 )                 )
- 
             [2] => 112             [2] => 112
         )         )
- +    [31] => Array(
-    [31] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 120             [2] => 120
         )         )
- +    [32] => Array(
-    [32] => Array +
-        (+
             [0] => tablerow_close             [0] => tablerow_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [33] => Array(
-    [33] => Array +
-        (+
             [0] => table_close             [0] => table_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [34] => Array(
-    [34] => Array +
-        (+
             [0] => p_open             [0] => p_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [35] => Array(
-    [35] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => def                     [0] => def
  
                 )                 )
- 
             [2] => 122             [2] => 122
         )         )
- +    [36] => Array(
-    [36] => Array +
-        (+
             [0] => p_close             [0] => p_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 122             [2] => 122
         )         )
- +    [37] => Array(
-    [37] => Array +
-        (+
             [0] => document_end             [0] => document_end
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 122             [2] => 122
         )         )
- 
 ) )
 </code> </code>
Line 842: Line 676:
  
 <code> <code>
-    [35] => Array +    [35] => Array(
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => def                     [0] => def
  
                 )                 )
- 
             [2] => 122             [2] => 122
         )         )
 </code> </code>
  
-The first element (index 0 ) is the name of a method or function in the Renderer to execute.+The first element (index 0) is the name of a method or function in the Renderer to execute.
  
 The second element (index 1) is itself an array, each of //its// elements being the arguments for the Renderer method that will be called. The second element (index 1) is itself an array, each of //its// elements being the arguments for the Renderer method that will be called.
Line 862: Line 693:
  
 <code php> <code php>
-$Render->cdata("def\n");+$render->cdata("def\n");
 </code> </code>
  
-The third element (index 2) is the byte index of the first character that "triggered" this instruction in the raw text document. It should be the same as the value returned by PHP's [[phpfn>strpos]] function. This can be used to retrieve sections of the raw wiki text, based on the positions of the instructions generated from it (example later).+The third element (index 2) is the byte index of the first character that "triggered" this instruction in the raw text document. It should be the same as the value returned by PHP's [[phpfn>strpos()]] function. This can be used to retrieve sections of the raw wiki text, based on the positions of the instructions generated from it (example later).
  
 **Note:** The Parser's ''parse'' method pads the raw wiki text with a preceding and proceeding linefeed character, to make sure particular Lexer states exit correctly, so you may need to subtract 1 from the byte index to get the correct location in the original raw wiki text. The Parser also normalizes linefeeds to Unix style (i.e. all ''%%\r\n%%'' becomes ''%%\n%%'') so the document the Lexer sees may be smaller than the one you actually fed it. **Note:** The Parser's ''parse'' method pads the raw wiki text with a preceding and proceeding linefeed character, to make sure particular Lexer states exit correctly, so you may need to subtract 1 from the byte index to get the correct location in the original raw wiki text. The Parser also normalizes linefeeds to Unix style (i.e. all ''%%\r\n%%'' becomes ''%%\n%%'') so the document the Lexer sees may be smaller than the one you actually fed it.
Line 873: Line 704:
 ==== Renderer ==== ==== Renderer ====
  
-The Renderer is a class (or a collection of functions can be used) which you define. The interface is defined in ''inc/parser/renderer.php'' and looks like;+The Renderer is a class which you define to create the output. The interface [[xref>inc::Doku_Renderer|Doku_Renderer]] is defined in [[xref>inc/parser/renderer.php]] and looks like;
  
 <code php> <code php>
Line 881: Line 712:
     // snip     // snip
          
-    function header($text, $level) {}+    public function header($text, $level) {}
          
-    function section_open($level) {}+    public function section_open($level) {}
          
-    function section_close() {}+    public function section_close() {}
          
-    function cdata($text) {}+    public function cdata($text) {}
          
-    function p_open() {}+    public function p_open() {}
          
-    function p_close() {}+    public function p_close() {}
          
-    function linebreak() {}+    public function linebreak() {}
          
-    function hr() {}+    public function hr() {}
          
     // snip     // snip
Line 903: Line 734:
 It is used to document the Renderer although it could be also be extended if you wanted to write a Renderer which only captures certain calls. It is used to document the Renderer although it could be also be extended if you wanted to write a Renderer which only captures certain calls.
  
-The basic principle for how the instructions, returned from the parser, are used against a Renderer is similar to the notion of a [[wp>SAX XML API]] - the instructions are a list of function / method names and their arguments. Looping through the list of instructions, each instruction can be called against the Renderer (i.e. the methods provided by the Renderer are [[wp>Callback_(computer_science)|callbacks]]). Unlike the SAX API, where only a few, fairly general, callbacks are available (e.g. tag_start, tag_end, cdata etc.), the Renderer defines a more explicit API, where the methods typically correspond one-to-one with the act of generating the output. +The basic principle for how the instructions, returned from the parser, are used against a Renderer is similar to the notion of a [[wp>Simple_API_for_XML|SAX XML API]] - the instructions are a list of function / method names and their arguments. Looping through the list of instructions, each instruction can be called against the Renderer (i.e. the methods provided by the Renderer are [[wp>Callback_(computer_science)|callbacks]]). Unlike the SAX API, where only a few, fairly general, callbacks are available (e.g. tag_start, tag_end, cdata etc.), the Renderer defines a more explicit API, where the methods typically correspond one-to-one with the act of generating the output. 
-In the section of the Renderer shown above, the ''p_open'' and ''p_close'' methods would be used to output the tags ''%%<p>%%'' and ''%%</p>%%'' in XHTML, respectively, while the ''header'' function takes two arguments - some text to display and the "level" of the header so a call like ''%%header('Some Title',1)%%'' would be output in XHTML like ''%%<h1>Some Title</h1>%%''.+In the section of the Renderer shown above, the ''p_open'' and ''p_close'' methods would be used to output the tags ''%%<p>%%'' and ''%%</p>%%'' in XHTML, respectively, while the ''header'' function takes two arguments - some text to display and the "level" of the header so a call like ''%%header('Some Title', 1)%%'' would be output in XHTML like ''%%<h1>Some Title</h1>%%''.
  
 === Invoking the Renderer with Instructions === === Invoking the Renderer with Instructions ===
  
-It is left up to the client code using the Parser to execute the list of instructions against a Renderer. Typically this will be done using PHP's [[phpfn>call_user_func_array]] function. For example;+It is left up to the client code using the Parser to execute the list of instructions against a Renderer. Typically this will be done using PHP's [[phpfn>call_user_func_array()]] function. For example;
  
 <code php> <code php>
 // Get a list of instructions from the parser // Get a list of instructions from the parser
-$instructions = $Parser->parse($rawDoc);+$instructions = $parser->parse($rawDoc);
  
 // Create a renderer // Create a renderer
-$Renderer new Doku_Renderer_XHTML();+$renderer = new Doku_Renderer_xhtml();
  
 // Loop through the instructions // Loop through the instructions
-foreach ( $instructions as $instruction ) { +foreach ($instructions as $instruction) {
-    +
     // Execute the callback against the Renderer     // Execute the callback against the Renderer
-    call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);+    call_user_func_array([$renderer, $instruction[0]], $instruction[1]);
 } }
 </code> </code>
Line 929: Line 759:
 The key Renderer methods for handling the different kinds of link are; The key Renderer methods for handling the different kinds of link are;
  
-  * ''%%function camelcaselink($link) {} // $link like "SomePage"%%''+  * ''function [[xref>camelcaselink($link)]] %%{} // $link like "SomePage"%%''
     *This can probably be ignored for spam checking - it shouldn't be possible for someone to link offsite with this syntax     *This can probably be ignored for spam checking - it shouldn't be possible for someone to link offsite with this syntax
-  * ''%%function internallink($link, $title = NULL) {} // $link like "[[syntax]]"%%''+  * ''function [[xref>internallink($link, $title = null)]]%% {} // $link like "[[syntax]]"%%''
     *Although ''$link'' itself is internal, ''$title'' could be an image which is offsite, so needs checking     *Although ''$link'' itself is internal, ''$title'' could be an image which is offsite, so needs checking
-  * ''%%function externallink($link, $title = NULL) {}%%''+  * ''function [[xref>externallink($link, $title = null)]] {}''
     *Both ''$link'' and ''$title'' (images) need checking     *Both ''$link'' and ''$title'' (images) need checking
-  * ''%%function interwikilink($link, $title = NULL, $wikiName, $wikiUri) {}%%''+  * ''function [[xref>interwikilink($link, $title = null, $wikiName, $wikiUri)]] {}''
     *The ''$title'' needs checking for images     *The ''$title'' needs checking for images
-  * ''%%function filelink($link, $title = NULL) {}%%''+  * ''function [[xref>filelink($link, $title = null)]] {}''
     *Technically only valid ''%%file://%%'' URLs should match but probably best to check anyway plus ''$title'' may be an offsite image     *Technically only valid ''%%file://%%'' URLs should match but probably best to check anyway plus ''$title'' may be an offsite image
-  * ''%%function windowssharelink($link, $title = NULL) {}%%''+  * ''function [[xref>windowssharelink($link, $title = null)]] {}''
     *Should only match valid Windows share URLs but check anyway plus ''$title'' for images     *Should only match valid Windows share URLs but check anyway plus ''$title'' for images
-  * ''%%function email($address, $title = NULL) {}%%''+  * ''function [[xref>emaillink($address, $title = null)]] {}''
     *''$title'' could be an image. Check the email as well?     *''$title'' could be an image. Check the email as well?
-  * ''%%function internalmedialink ($src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL) {}%%''+  * ''function [[xref>internalmedialink($src, $title = null, $align = null $width = null, $height = null, $cache = null)]] {}''
     *This shouldn't need check - should only link to local images. ''$title'' itself cannot be an image     *This shouldn't need check - should only link to local images. ''$title'' itself cannot be an image
-  * ''%%function externalmedialink($src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL) {}%%''+  * ''function [[xref>externalmedialink($src, $title = null, $align = null, $width = null, $height = null, $cache = null)]] {}''
     *''$src'' needs checking     *''$src'' needs checking
  
Line 951: Line 781:
  
 <code html> <code html>
-<a href="http://www.example.com">This is the title</a>+<a href="https://www.example.com">This is the title</a>
 </code> </code>
  
 The ''%%$title%%'' argument can have three possible types of value; The ''%%$title%%'' argument can have three possible types of value;
  
-  - ''NULL'': no title was provided in the wiki document.+  - ''null'': no title was provided in the wiki document.
   - string: a plain text string was used as the title   - string: a plain text string was used as the title
   - array (hash): an image was used as the title.   - array (hash): an image was used as the title.
Line 963: Line 793:
  
 <code php> <code php>
-$title = array(+$title = [
     // Could be 'internalmedia' (local image) or 'externalmedia' (offsite image)     // Could be 'internalmedia' (local image) or 'externalmedia' (offsite image)
-    'type'=>'internalmedia',+    'type' => 'internalmedia',
          
-    // The URL to the image (may be a wiki URL or http://static.example.com/img.png) +    // The URL to the image (may be a wiki URL or https://static.example.com/img.png) 
-    'src'=>'wiki:php-powered.png',+    'src' => 'wiki:php-powered.png',
          
-    // For the alt attribute - a string or NULL +    // For the alt attribute - a string or null 
-    'title'=>'Powered by PHP',+    'title' => 'Powered by PHP',
          
-    // 'left', 'right', 'center' or NULL +    // 'left', 'right', 'center' or null 
-    'align'=>'right',+    'align' => 'right',
          
-    // Width in pixels or NULL +    // Width in pixels or null 
-    'width'=> 50,+    'width' => 50,
          
-    // Height in pixels or NULL +    // Height in pixels or null 
-    'height'=>75,+    'height' => 75,
          
     // Whether to cache the image (for external images)     // Whether to cache the image (for external images)
-    'cache'=>FALSE+    'cache' => false
-);+];
 </code> </code>
  
Line 996: Line 826:
  
 <code php> <code php>
-require_once DOKU_INC . 'parser/parser.php';+global $conf;
  
-// Create the parser +// Create the Handler 
-$Parser new Doku_Parser();+$handler = new Doku_Handler();
  
-// Add the Handler +// Create the parser with the handler 
-$Parser->Handler new Doku_Handler();+$parser = new dokuwiki\Parsing\Parser($handler);
  
 // Load all the modes // Load all the modes
-$Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock()); +$parser->addMode('listblock', new dokuwiki\Parsing\ParserMode\ListBlock()); 
-$Parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted());  +$parser->addMode('preformatted', new dokuwiki\Parsing\ParserMode\Preformatted()); 
-$Parser->addMode('notoc',new Doku_Parser_Mode_NoToc()); +$parser->addMode('notoc', new dokuwiki\Parsing\ParserMode\NoToc()); 
-$Parser->addMode('header',new Doku_Parser_Mode_Header()); +$parser->addMode('header', new dokuwiki\Parsing\ParserMode\Header()); 
-$Parser->addMode('table',new Doku_Parser_Mode_Table());+$parser->addMode('table', new dokuwiki\Parsing\ParserMode\Table());
  
-$formats = array (+$formats = [
     'strong', 'emphasis', 'underline', 'monospace',     'strong', 'emphasis', 'underline', 'monospace',
     'subscript', 'superscript', 'deleted',     'subscript', 'superscript', 'deleted',
-)+]
-foreach ( $formats as $format ) { +foreach ($formats as $format) { 
-    $Parser->addMode($format,new Doku_Parser_Mode_Formatting($format));+    $parser->addMode($format, new dokuwiki\Parsing\ParserMode\Formatting($format));
 } }
  
-$Parser->addMode('linebreak',new Doku_Parser_Mode_Linebreak()); +$parser->addMode('linebreak', new dokuwiki\Parsing\ParserMode\Linebreak()); 
-$Parser->addMode('footnote',new Doku_Parser_Mode_Footnote()); +$parser->addMode('footnote', new dokuwiki\Parsing\ParserMode\Footnote()); 
-$Parser->addMode('hr',new Doku_Parser_Mode_HR());+$parser->addMode('hr', new dokuwiki\Parsing\ParserMode\Hr());
  
-$Parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted()); +$parser->addMode('unformatted', new dokuwiki\Parsing\ParserMode\Unformatted()); 
-$Parser->addMode('php',new Doku_Parser_Mode_PHP()); +$parser->addMode('code', new dokuwiki\Parsing\ParserMode\Code()); 
-$Parser->addMode('html',new Doku_Parser_Mode_HTML()); +$parser->addMode('file', new dokuwiki\Parsing\ParserMode\File()); 
-$Parser->addMode('code',new Doku_Parser_Mode_Code()); +$parser->addMode('quote', new dokuwiki\Parsing\ParserMode\Quote());
-$Parser->addMode('file',new Doku_Parser_Mode_File()); +
-$Parser->addMode('quote',new Doku_Parser_Mode_Quote());+
  
 // These need data files. The get* functions are left to your imagination // These need data files. The get* functions are left to your imagination
-$Parser->addMode('acronym',new Doku_Parser_Mode_Acronym(array_keys(getAcronyms()))); +$parser->addMode('acronym', new dokuwiki\Parsing\ParserMode\Acronym(array_keys(getAcronyms()))); 
-$Parser->addMode('wordblock',new Doku_Parser_Mode_Wordblock(array_keys(getBadWords()))); +// not used anymore, and unsure if getWordblocks() actually works here? 
-$Parser->addMode('smiley',new Doku_Parser_Mode_Smiley(array_keys(getSmileys()))); +//$parser->addMode('wordblock',new dokuwiki\Parsing\ParserMode\Wordblock(getWordblocks())); 
-$Parser->addMode('entity',new Doku_Parser_Mode_Entity(array_keys(getEntities())));+$parser->addMode('smiley', new dokuwiki\Parsing\ParserMode\Smiley(array_keys(getSmileys()))); 
 +$parser->addMode('entity', new dokuwiki\Parsing\ParserMode\Entity(array_keys(getEntities())));
  
-$Parser->addMode('multiplyentity',new Doku_Parser_Mode_MultiplyEntity()); +$parser->addMode('multiplyentity', new dokuwiki\Parsing\ParserMode\Multiplyentity()); 
-$Parser->addMode('quotes',new Doku_Parser_Mode_Quotes());+$parser->addMode('quotes', new dokuwiki\Parsing\ParserMode\Quotes());
  
-$Parser->addMode('camelcaselink',new Doku_Parser_Mode_CamelCaseLink()); +$parser->addMode('camelcaselink', new dokuwiki\Parsing\ParserMode\CamelCaselink()); 
-$Parser->addMode('internallink',new Doku_Parser_Mode_InternalLink()); +$parser->addMode('internallink', new dokuwiki\Parsing\ParserMode\Internallink()); 
-$Parser->addMode('media',new Doku_Parser_Mode_Media()); +$parser->addMode('media', new dokuwiki\Parsing\ParserMode\Media()); 
-$Parser->addMode('externallink',new Doku_Parser_Mode_ExternalLink()); +$parser->addMode('externallink', new dokuwiki\Parsing\ParserMode\Externallink()); 
-$Parser->addMode('emaillink',new Doku_Parser_Mode_EmailLink()); +$parser->addMode('emaillink', new dokuwiki\Parsing\ParserMode\Emaillink()); 
-$Parser->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink()); +$parser->addMode('windowssharelink', new dokuwiki\Parsing\ParserMode\Windowssharelink()); 
-$Parser->addMode('filelink',new Doku_Parser_Mode_FileLink()); +$parser->addMode('filelink', new dokuwiki\Parsing\ParserMode\Filelink()); 
-$Parser->addMode('eol',new Doku_Parser_Mode_Eol());+$parser->addMode('eol', new dokuwiki\Parsing\ParserMode\Eol());
  
 // Loads the raw wiki document // Loads the raw wiki document
-$doc = file_get_contents(DOKU_DATA . 'wiki/syntax.txt');+$doc = file_get_contents($conf['datadir'. 'wiki/syntax.txt');
  
 // Get a list of instructions // Get a list of instructions
-$instructions = $Parser->parse($doc);+$instructions = $parser->parse($doc);
  
 // Create a renderer // Create a renderer
-require_once DOKU_INC . 'parser/xhtml.php'; +$renderer = new Doku_Renderer_xhtml();
-$Renderer new Doku_Renderer_XHTML();+
  
 # Load data like smileys into the Renderer here # Load data like smileys into the Renderer here
  
 // Loop through the instructions // Loop through the instructions
-foreach ( $instructions as $instruction ) { +foreach ($instructions as $instruction) {
-    +
     // Execute the callback against the Renderer     // Execute the callback against the Renderer
-    call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);+    call_user_func_array([$renderer, $instruction[0]], $instruction[1]);
 } }
  
 // Display the output // Display the output
-echo $Renderer->doc;+echo $renderer->doc; 
 </code> </code>
  
Line 1076: Line 904:
  
 <code php> <code php>
-// Create the parser +global $conf;
-$Parser = & new Doku_Parser();+
  
-// Add the Handler +// Create the Handler 
-$Parser->Handler new Doku_Handler();+$handler = new Doku_Handler(); 
 + 
 +// Create the parser with the handler 
 +$parser = new dokuwiki\Parsing\Parser($handler);
  
 // Load the header mode to find headers // Load the header mode to find headers
-$Parser->addMode('header',new Doku_Parser_Mode_Header());+$parser->addMode('header', new dokuwiki\Parsing\ParserMode\Header());
  
 // Load the modes which could contain markup that might be // Load the modes which could contain markup that might be
 // mistaken for a header // mistaken for a header
-$Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock()); +$parser->addMode('listblock', new dokuwiki\Parsing\ParserMode\Listblock()); 
-$Parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted());  +$parser->addMode('preformatted', new dokuwiki\Parsing\ParserMode\Preformatted()); 
-$Parser->addMode('table',new Doku_Parser_Mode_Table()); +$parser->addMode('table', new dokuwiki\Parsing\ParserMode\Table()); 
-$Parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted()); +$parser->addMode('unformatted', new dokuwiki\Parsing\ParserMode\Unformatted()); 
-$Parser->addMode('php',new Doku_Parser_Mode_PHP()); +$parser->addMode('code', new dokuwiki\Parsing\ParserMode\Code()); 
-$Parser->addMode('html',new Doku_Parser_Mode_HTML()); +$parser->addMode('file', new dokuwiki\Parsing\ParserMode\File()); 
-$Parser->addMode('code',new Doku_Parser_Mode_Code()); +$parser->addMode('quote', new dokuwiki\Parsing\ParserMode\Quote()); 
-$Parser->addMode('file',new Doku_Parser_Mode_File()); +$parser->addMode('footnote', new dokuwiki\Parsing\ParserMode\Footnote()); 
-$Parser->addMode('quote',new Doku_Parser_Mode_Quote()); +$parser->addMode('internallink', new dokuwiki\Parsing\ParserMode\Internallink()); 
-$Parser->addMode('footnote',new Doku_Parser_Mode_Footnote()); +$parser->addMode('media', new dokuwiki\Parsing\ParserMode\Media()); 
-$Parser->addMode('internallink',new Doku_Parser_Mode_InternalLink()); +$parser->addMode('externallink', new dokuwiki\Parsing\ParserMode\Externallink()); 
-$Parser->addMode('media',new Doku_Parser_Mode_Media()); +$parser->addMode('email', new dokuwiki\Parsing\ParserMode\Emaillink()); 
-$Parser->addMode('externallink',new Doku_Parser_Mode_ExternalLink()); +$parser->addMode('windowssharelink', new dokuwiki\Parsing\ParserMode\Windowssharelink()); 
-$Parser->addMode('email',new Doku_Parser_Mode_Email()); +$parser->addMode('filelink', new dokuwiki\Parsing\ParserMode\Filelink());
-$Parser->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink()); +
-$Parser->addMode('filelink',new Doku_Parser_Mode_FileLink());+
  
 // Loads the raw wiki document // Loads the raw wiki document
-$doc = file_get_contents(DOKU_DATA . 'wiki/syntax.txt');+$doc = file_get_contents($conf['datadir'. 'wiki/syntax.txt');
  
 // Get a list of instructions // Get a list of instructions
-$instructions = $Parser->parse($doc);+$instructions = $parser->parse($doc);
  
 // Use this to watch when we're inside the section we want // Use this to watch when we're inside the section we want
-$inSection = FALSE;+$inSection = false;
 $startPos = 0; $startPos = 0;
 $endPos = 0; $endPos = 0;
  
 // Loop through the instructions // Loop through the instructions
-foreach ( $instructions as $instruction ) { +foreach ($instructions as $instruction) { 
-     +    if (!$inSection) {
-    if ( !$inSection ) { +
-        +
         // Look for the header for the "Lists" heading         // Look for the header for the "Lists" heading
-        if ( $instruction[0] == 'header' && +        if ($instruction[0] == 'header' && 
-                trim($instruction[1][0]) == 'Lists' ) { +            trim($instruction[1][0]) == 'Lists') { 
-            +
             $startPos = $instruction[2];             $startPos = $instruction[2];
-            $inSection = TRUE;+            $inSection = true;
         }         }
     } else {     } else {
-         
         // Look for the end of the section         // Look for the end of the section
-        if ( $instruction[0] == 'section_close' ) {+        if ($instruction[0] == 'section_close') {
             $endPos = $instruction[2];             $endPos = $instruction[2];
             break;             break;
Line 1139: Line 964:
 // Normalize and pad the document in the same way the parse does // Normalize and pad the document in the same way the parse does
 // so that byte indexes with match // so that byte indexes with match
-$doc = "\n".str_replace("\r\n","\n",$doc)."\n";+$doc = "\n" . str_replace("\r\n", "\n", $doc) . "\n";
  
 // Get the text before the section we want // Get the text before the section we want
 $before = substr($doc, 0, $startPos); $before = substr($doc, 0, $startPos);
-$section = substr($doc, $startPos, ($endPos-$startPos));+$section = substr($doc, $startPos, ($endPos - $startPos));
 $after = substr($doc, $endPos); $after = substr($doc, $endPos);
 </code> </code>
Line 1157: Line 982:
 <code php> <code php>
 // A plain list of smiley tokens... // A plain list of smiley tokens...
-$smileys = array(+$smileys = [
     ':-)',     ':-)',
     ':-(',     ':-(',
     ';-)',     ';-)',
     // etc.     // etc.
-    );+];
          
 // Create the mode // Create the mode
-$SmileyMode new Doku_Parser_Mode_Smiley($smileys);+$smileyMode = new dokuwiki\Parsing\ParserMode\Smiley($smileys);
  
 // Add it to the parser // Add it to the parser
-$Parser->addMode($SmileyMode);+$parser->addMode($smileyMode);
 </code> </code>
  
Line 1175: Line 1000:
 The other modes this applies to are defined by the classes; The other modes this applies to are defined by the classes;
  
-  * ''Doku_Parser_Mode_Acronym'' - for acronyms +  * ''dokuwiki\Parsing\ParserMode\Acronym'' - for acronyms 
-  * ''Doku_Parser_Mode_Wordblock'' - to block specific words (e.g. bad language) +  * ''dokuwiki\Parsing\ParserMode\Wordblock'' - to block specific words (e.g. bad language) 
-  * ''Doku_Parser_Mode_Entity'' - for typography+  * ''dokuwiki\Parsing\ParserMode\Entity'' - for typography
  
 Each accepts a list of "interesting strings" to its constructor, in the same way as the smileys. Each accepts a list of "interesting strings" to its constructor, in the same way as the smileys.
Line 1185: Line 1010:
 <code php> <code php>
 function getSmileys() { function getSmileys() {
 +    static $smileys = null;
          
-    static $smileys = NULL; +    if (!$smileys) {
-     +
-    if ( !$smileys ) { +
-        +
         $smileys = array();         $smileys = array();
-         
         $lines = file( DOKU_CONF . 'smileys.conf');         $lines = file( DOKU_CONF . 'smileys.conf');
                  
         foreach($lines as $line){         foreach($lines as $line){
-             
             //ignore comments             //ignore comments
             $line = preg_replace('/#.*$/','',$line);             $line = preg_replace('/#.*$/','',$line);
-             
             $line = trim($line);             $line = trim($line);
                          
Line 1209: Line 1029:
         }         }
     }     }
-     
     return $smileys;     return $smileys;
 } }
Line 1218: Line 1037:
 <code php> <code php>
 // Load the smiley patterns into the mode // Load the smiley patterns into the mode
-$SmileyMode new Doku_Parser_Mode_Smiley(array_keys(getSmileys()));+$smileyMode = new dokuwiki\Parsing\ParserMode\Smiley(array_keys(getSmileys()));
 </code> </code>
  
 <code php> <code php>
 // Load the associate array in a renderer for lookup on output // Load the associate array in a renderer for lookup on output
-$Renderer->smileys = getSmileys();+$renderer->smileys = getSmileys();
 </code> </code>
  
Line 1243: Line 1062:
 function getSpamPattern() { function getSpamPattern() {
     static $spamPattern = NULL;     static $spamPattern = NULL;
-     + 
-    if ( is_null($spamPattern) ) { +    if (is_null($spamPattern)) {
-        +
         $lines = @file(DOKU_CONF . 'spam.conf');         $lines = @file(DOKU_CONF . 'spam.conf');
-         +        if (!$lines) {
-        if ( !$lines ) { +
-        +
             $spamPattern = '';             $spamPattern = '';
-             
         } else {         } else {
-             
             $spamPattern = '#';             $spamPattern = '#';
             $sep = '';             $sep = '';
-             +            foreach ($lines as $line) {
-            foreach($lines as $line){ +
-                +
                 // Strip comments                 // Strip comments
-                $line = preg_replace('/#.*$/','',$line); +                $line = preg_replace('/#.*$/', '', $line); 
-                +
                 // Ignore blank lines                 // Ignore blank lines
                 $line = trim($line);                 $line = trim($line);
-                if(empty($line)) continue; +                if (empty($line)) continue; 
-                 + 
-                $spamPattern.= $sep.$line; +                $spamPattern .= $sep . $line;
-                +
                 $sep = '|';                 $sep = '|';
             }             }
-             
             $spamPattern .= '#si';             $spamPattern .= '#si';
         }         }
     }     }
-     
     return $spamPattern;     return $spamPattern;
 } }
Line 1282: Line 1091:
  
 <code php> <code php>
-require_once DOKU_INC . 'parser/renderer.php';+class Doku_Renderer_SpamCheck extends Doku_Renderer {
  
-class Doku_Renderer_SpamCheck extends Doku_Renderer { 
-     
     // This should be populated by the code executing the instructions     // This should be populated by the code executing the instructions
-    var $currentCall; +    protected $currentCall; 
-    +
     // An array of instructions that contain spam     // An array of instructions that contain spam
-    var $spamFound = array()+    protected $spamFound = []
-    +
     // pcre pattern for finding spam     // pcre pattern for finding spam
-    var $spamPattern = '#^$#'; +    protected $spamPattern = '#^$#'; 
-     + 
-    function internallink($link, $title = NULL) { +    public function internallink($link, $title = null) { 
-        $this->__checkTitle($title);+        $this->checkTitle($title);
     }     }
-     + 
-    function externallink($link, $title = NULL) { +    public function externallink($link, $title = null) { 
-        $this->__checkLinkForSpam($link); +        $this->checkLinkForSpam($link); 
-        $this->__checkTitle($title);+        $this->checkTitle($title);
     }     }
-     + 
-    function interwikilink($link, $title = NULL) { +    public function interwikilink($link, $title = null) { 
-        $this->__checkTitle($title);+        $this->checkTitle($title);
     }     }
-     + 
-    function filelink($link, $title = NULL) { +    public function filelink($link, $title = null) { 
-        $this->__checkLinkForSpam($link); +        $this->checkLinkForSpam($link); 
-        $this->__checkTitle($title);+        $this->checkTitle($title);
     }     }
-     + 
-    function windowssharelink($link, $title = NULL) { +    public function windowssharelink($link, $title = null) { 
-        $this->__checkLinkForSpam($link); +        $this->checkLinkForSpam($link); 
-        $this->__checkTitle($title);+        $this->checkTitle($title);
     }     }
-     + 
-    function email($address, $title = NULL) { +    public function emaillink($address, $title = null) { 
-        $this->__checkLinkForSpam($address); +        $this->checkLinkForSpam($address); 
-        $this->__checkTitle($title);+        $this->checkTitle($title);
     }     }
-     + 
-    function internalmedialink ($src) { +    public function internalmedialink($src) { 
-        $this->__checkLinkForSpam($src);+        $this->checkLinkForSpam($src);
     }     }
  
-    function externalmedialink($src) { +    public function externalmedialink($src) { 
-        $this->__checkLinkForSpam($src);+        $this->checkLinkForSpam($src);
     }     }
  
-    function __checkTitle($title) { +    protected function checkTitle($title) { 
-        if ( is_array($title) && isset($title['src'])) { +        if (is_array($title) && isset($title['src'])) { 
-            $this->__checkLinkForSpam($title['src']);+            $this->checkLinkForSpam($title['src']);
         }         }
     }     }
-    +
     // Pattern matching happens here     // Pattern matching happens here
-    function __checkLinkForSpam($link) { +    protected function checkLinkForSpam($link) { 
-        if( preg_match($this->spamPattern,$link) ) {+        if (preg_match($this->spamPattern, $link)) {
             $spam = $this->currentCall;             $spam = $this->currentCall;
             $spam[3] = $link;             $spam[3] = $link;
             $this->spamFound[] = $spam;             $this->spamFound[] = $spam;
         }         }
 +    }
 +    
 +    public getSpamFound() {
 +        return $this->spamFound;
     }     }
 } }
 </code> </code>
  
-Note the line ''%%$spam[3] = $link;%%'' in the ''%%__checkLinkForSpam%%'' method. This adds an additional element to the list of spam instructions found, making it easy to determine what the bad URLs were (e.g. for logging).+Note the line ''%%$spam[3] = $link;%%'' in the ''%%checkLinkForSpam()%%'' method. This adds an additional element to the list of spam instructions found, making it easy to determine what the bad URLs were (e.g. for logging).
  
 Finally we can use this spam checking renderer like; Finally we can use this spam checking renderer like;
  
 <code php> <code php>
-// Create the parser +global $conf;
-$Parser = & new Doku_Parser();+
  
-// Add the Handler +// Create the Handler 
-$Parser->Handler new Doku_Handler();+$handler = new Doku_Handler(); 
 + 
 +// Create the parser with the handler 
 +$parser = new dokuwiki\Parsing\Parser($handler);
  
 // Load the modes which could contain markup that might be // Load the modes which could contain markup that might be
 // mistaken for a link // mistaken for a link
-$Parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted());  +$parser->addMode('preformatted', new dokuwiki\Parsing\ParserMode\Preformatted()); 
-$Parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted()); +$parser->addMode('unformatted', new dokuwiki\Parsing\ParserMode\Unformatted()); 
-$Parser->addMode('php',new Doku_Parser_Mode_PHP()); +$parser->addMode('code', new dokuwiki\Parsing\ParserMode\Code()); 
-$Parser->addMode('html',new Doku_Parser_Mode_HTML()); +$parser->addMode('file', new dokuwiki\Parsing\ParserMode\File()); 
-$Parser->addMode('code',new Doku_Parser_Mode_Code()); +$parser->addMode('quote', new dokuwiki\Parsing\ParserMode\Quote());
-$Parser->addMode('file',new Doku_Parser_Mode_File()); +
-$Parser->addMode('quote',new Doku_Parser_Mode_Quote());+
  
 // Load the link modes... // Load the link modes...
-$Parser->addMode('internallink',new Doku_Parser_Mode_InternalLink()); +$parser->addMode('internallink', new dokuwiki\Parsing\ParserMode\Internallink()); 
-$Parser->addMode('media',new Doku_Parser_Mode_Media()); +$parser->addMode('media', new dokuwiki\Parsing\ParserMode\Media()); 
-$Parser->addMode('externallink',new Doku_Parser_Mode_ExternalLink()); +$parser->addMode('externallink', new dokuwiki\Parsing\ParserMode\Externallink()); 
-$Parser->addMode('email',new Doku_Parser_Mode_Email()); +$parser->addMode('email', new dokuwiki\Parsing\ParserMode\Emaillink()); 
-$Parser->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink()); +$parser->addMode('windowssharelink', new dokuwiki\Parsing\ParserMode\Windowssharelink()); 
-$Parser->addMode('filelink',new Doku_Parser_Mode_FileLink());+$parser->addMode('filelink', new dokuwiki\Parsing\ParserMode\Filelink());
  
 // Loads the raw wiki document // Loads the raw wiki document
-$doc = file_get_contents(DOKU_DATA . 'wiki/spam.txt');+$doc = file_get_contents($conf['datadir'. 'wiki/spam.txt');
  
 // Get a list of instructions // Get a list of instructions
-$instructions = $Parser->parse($doc);+$instructions = $parser->parse($doc);
  
 // Create a renderer // Create a renderer
-require_once DOKU_INC . 'parser/spamcheck.php'; +$renderer = new Doku_Renderer_SpamCheck();
-$Renderer new Doku_Renderer_SpamCheck();+
  
 // Load the spam regex // Load the spam regex
-$Renderer->spamPattern = getSpamPattern();+$renderer->spamPattern = getSpamPattern();
  
 // Loop through the instructions // Loop through the instructions
-foreach ( $instructions as $instruction ) { +foreach ($instructions as $instruction) {
-    +
     // Store the current instruction     // Store the current instruction
-    $Renderer->currentCall = $instruction; +    $renderer->currentCall = $instruction; 
-     +    call_user_func_array([$renderer, $instruction[0]], $instruction[1]);
-    call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);+
 } }
  
 // What spam did we find? // What spam did we find?
 echo '<pre>'; echo '<pre>';
-print_r($Renderer->spamFound);+print_r($renderer->getSpamFound());
 echo '</pre>'; echo '</pre>';
 </code> </code>
Line 1429: Line 1237:
  
   - Create a parser syntax mode to register with the Lexer   - Create a parser syntax mode to register with the Lexer
-  - Update the ''Doku_Parser_Substition'' function found at the end of ''parser.php'', which is used to deliver a quick list of modes (used in classes like ''Doku_Parser_Mode_Table''+  - Update the ''$PARSER_MODES['substition']'' subarray found at the end of ''inc/parser/parser.php'', which is used to deliver a quick list of modes (used in classes like ''dokuwiki\Parsing\ParserMode\Table''
   - Update the Handler with a method to catch bookmark tokens   - Update the Handler with a method to catch bookmark tokens
   - Update the abstract Renderer as documentation and any concrete Renderer implementations that need it.   - Update the abstract Renderer as documentation and any concrete Renderer implementations that need it.
  
-Creating the parser mode means extending the ''Doku_Parser_Mode'' class and overriding its ''connectTo'' method;+Creating the parser mode means extending the ''dokuwiki\Parsing\ParserMode\AbstractMode'' class and overriding its ''connectTo'' method;
  
 <code php> <code php>
-class Doku_Parser_Mode_Bookmark extends Doku_Parser_Mode +namespace dokuwiki\Parsing\ParserMode; 
-     + 
-    function connectTo($mode) {+class Bookmark extends AbstractMode 
 +    public function connectTo($mode) {
         // Allow word and space characters         // Allow word and space characters
-        $this->Lexer->addSpecialPattern('BM\{[\w ]+\}',$mode,'bookmark');+        $this->Lexer->addSpecialPattern('BM\{[\w ]+\}', $mode, 'bookmark');
     }     }
-     
 } }
 </code> </code>
  
-This will match the complete bookmark using a single pattern (extracting the bookmark name from the rest of the syntax will be left to the Handler). It uses the Lexer ''%%addSpecialPattern%%'' method so that the bookmark lives in its own state.+This will match the complete bookmark using a single pattern (extracting the bookmark name from the rest of the syntax will be left to the Handler). It uses the Lexer ''%%addSpecialPattern()%%'' method so that the bookmark lives in its own state.
  
 **Note** the Lexer does not require the start / end pattern delimiters - it takes care of this for you. **Note** the Lexer does not require the start / end pattern delimiters - it takes care of this for you.
Line 1453: Line 1261:
 Because nothing //inside// the bookmark should be considered valid wiki markup, there is no reference here to other modes which this mode might accept. Because nothing //inside// the bookmark should be considered valid wiki markup, there is no reference here to other modes which this mode might accept.
  
-Next the ''Doku_Parser_Substition'' function in the ''inc/parser/parser.php'' file needs updating so that the new mode called ''bookmark'' is returned in the list;+Next the subarray ''substitution'' in the ''$PARSER_MODES'' array in the [[xref>inc/parser/parser.php]] file needs updating so that the new mode called ''bookmark'' is returned in the list;
  
 <code php> <code php>
-function Doku_Parser_Substition() { +global $PARSER_MODES; 
-    $modes = array( +$PARSER_MODES = [ 
-        'acronym','smiley','wordblock','entity','camelcaselink', +    ... 
-        'internallink','media','externallink','linebreak','email', +     
-        'windowssharelink','filelink','notoc','multiplyentity', +    // modes where the token is simply replaced - they can not contain any 
-        'quotes','bookmark', +    // other modes 
-         +    'substition' => [ 
-    ); +        'acronym', 'smiley', 'wordblock', 'entity', 'camelcaselink',  
-    return $modes; +        'internallink', 'media', 'externallink', 'linebreak', 'emaillink',  
-}+        'windowssharelink', 'filelink', 'notoc', 'nocache', 'multiplyentity',  
 +        'quotes', 'rss', 'bookmark' 
 +    ]
 + 
 +    ... 
 +];
 </code> </code>
  
-This function is just to help registering these modes with other modes that accept them (e.g., lists can contain these modes - you can have a link inside a list) without having to list them in full each time they are needed.+This subarray is just to help registering these modes with other modes that accept them (e.g., lists can contain these modes - you can have a link inside a list) without having to list them in full each time they are needed.
  
-**Note:** Similar functions exist, like ''Doku_Parser_Protected'' and ''Doku_Parser_Formatting'' which return different groups of modes. The grouping of different types of syntax is not entirely perfect but still useful to save lines of code.+**Note:** Similar subarrays exist, like ''protected'' and ''formatting'' which return different groups of modes. The grouping of different types of syntax is not entirely perfect but still useful to save lines of code.
  
 With the syntax now described, a new method, which matches the name of the mode (i.e. ''bookmark'') needs to be added to the Handler; With the syntax now described, a new method, which matches the name of the mode (i.e. ''bookmark'') needs to be added to the Handler;
Line 1476: Line 1289:
 <code php> <code php>
 class Doku_Handler { class Doku_Handler {
 +    // ...
  
-    // ... 
-     
     // $match is the string which matched the Lexers regex for bookmarks     // $match is the string which matched the Lexers regex for bookmarks
     // $state identifies the type of match (see the Lexer notes above)     // $state identifies the type of match (see the Lexer notes above)
     // $pos is the byte index in the raw doc of the first character of the match     // $pos is the byte index in the raw doc of the first character of the match
-    function bookmark($match, $state, $pos) { +    public function bookmark($match, $state, $pos) { 
-        +
         // Technically don’t need to worry about the state;         // Technically don’t need to worry about the state;
         // should always be DOKU_LEXER_SPECIAL or there's         // should always be DOKU_LEXER_SPECIAL or there's
         // a very serious bug         // a very serious bug
-        switch ( $state ) { +        switch ($state) {
-        +
             case DOKU_LEXER_SPECIAL:             case DOKU_LEXER_SPECIAL:
-             
                 // Attempt to extract the bookmark name                 // Attempt to extract the bookmark name
-                if ( preg_match('/^BM\{(\w{1,})\}$/', $match, $nameMatch) ) { +                if (preg_match('/^BM\{(\w+)}$/', $match, $nameMatch)) {
-                +
                     $name = $nameMatch[1];                     $name = $nameMatch[1];
-                    +
                     // arg0: name of the Renderer method to call                     // arg0: name of the Renderer method to call
                     // arg1: array of arguments to the Renderer method                     // arg1: array of arguments to the Renderer method
                     // arg2: the byte index as before                     // arg2: the byte index as before
-                    $this->__addCall('bookmark', array($name), $pos); +                    $this->addCall('bookmark', [$name], $pos); 
-                 + 
-                // If the bookmark didn't have a valid name, simply pass it +                    // If the bookmark didn't have a valid name, simply pass it 
-                // through unmodified as plain text (cdata)+                    // through unmodified as plain text (cdata)
                 } else {                 } else {
-                 +                    $this->addCall('cdata', [$match], $pos);
-                    $this->__addCall('cdata', array($match), $pos); +
-                    +
                 }                 }
-            break; +                break;
-            +
         }         }
-         + 
-        // Must return TRUE or the lexer will halt +        // Must return true or the lexer will halt 
-        return TRUE;+        return true;
     }     }
-    +
     // ...     // ...
-     
 } }
 </code> </code>
Line 1525: Line 1330:
 <code php> <code php>
 class Doku_Renderer { class Doku_Renderer {
- 
     // ...     // ...
          
-    function bookmark($name) {}+    public function bookmark($name) {}
  
     // ...     // ...
- 
 } }
 </code> </code>
  
 <code php> <code php>
-class Doku_Renderer_XHTML {+class Doku_Renderer_xhtml { 
 +    // ... 
 + 
 +    public function bookmark($name) { 
 +        $name = $this->_xmlEntities($name);
  
-    // ... 
-     
-    function bookmark($name) { 
-        $name = $this->__xmlEntities($name); 
-         
         // id is required in XHTML while name still supported in 1.0         // id is required in XHTML while name still supported in 1.0
-        echo '<a class="bookmark" name="'.$name.'" id="'.$name.'"></a>'; +        echo '<a class="bookmark" name="' . $name . '" id="' . $name . '"></a>';
-    +
     }     }
  
     // ...     // ...
- 
 } }
 </code> </code>
  
-See the ''tests/parser_replacements.test.php'' script for examples of how you might test this code.+See the ''_test/tests/inc/parser/parser_replacements.test.php'' script for examples of how you might test this code.
  
 ==== Adding Formatting Syntax (with state) ==== ==== Adding Formatting Syntax (with state) ====
Line 1574: Line 1374:
  
 <code php> <code php>
-class Doku_Parser_Mode_TextColors extends Doku_Parser_Mode +namespace dokuwiki\Parsing\ParserMode; 
-     + 
-    var $color; +class TextColors extends AbstractMode 
-     + 
-    var $colors = array('red','green','blue')+    protected $color; 
-     +    protected $colors = ['red', 'green', 'blue']
-    function Doku_Parser_Mode_TextColor($color) { + 
-        +    public function __construct($color) { 
 +        global $PARSER_MODES; 
         // Just to help prevent mistakes using this mode         // Just to help prevent mistakes using this mode
-        if ( !array_key_exists($color, $this->colors) ) { +        if (!array_key_exists($color, $this->colors)) { 
-            trigger_error('Invalid color '.$color, E_USER_WARNING);+            trigger_error('Invalid color ' . $color, E_USER_WARNING);
         }         }
-         
         $this->color = $color;         $this->color = $color;
-        +
         // This mode accepts other modes;         // This mode accepts other modes;
-        $this->allowedModes = array_merge ( +        $this->allowedModes = array_merge( 
-            Doku_Parser_Formatting($color)+            $PARSER_MODES['formatting']
-            Doku_Parser_Substition()+            $PARSER_MODES['substition']
-            Doku_Parser_Disabled()+            $PARSER_MODES['disabled']
         );         );
-        + 
 +        unset($this->allowedModes[array_search($color, $this->allowedModes)]);
     }     }
-    +
     // connectTo is called once for every mode registered with the Lexer     // connectTo is called once for every mode registered with the Lexer
-    function connectTo($mode) { +    public function connectTo($mode) {
-    +
         // The lookahead pattern makes sure there's a closing tag...         // The lookahead pattern makes sure there's a closing tag...
-        $pattern = '<'.$this->color.'>(?=.*</'.$this->color.'>)'; +        $pattern = '<' . $this->color . '>(?=.*</' . $this->color . '>)'; 
-        +
         // arg0: pattern to match to enter this mode         // arg0: pattern to match to enter this mode
         // arg1: other modes where this pattern may match         // arg1: other modes where this pattern may match
         // arg2: name of the this mode         // arg2: name of the this mode
-        $this->Lexer->addEntryPattern($pattern,$mode,$this->color);+        $this->Lexer->addEntryPattern($pattern, $mode, $this->color);
     }     }
-    +
     // post connect is only called once     // post connect is only called once
-    function postConnect() { +    public function postConnect() {
-        +
         // arg0: pattern to match to exit this mode         // arg0: pattern to match to exit this mode
         // arg1: name of mode to exit         // arg1: name of mode to exit
-        $this->Lexer->addExitPattern('</'.$this->color.'>',$this->color); +        $this->Lexer->addExitPattern('</' . $this->color . '>', $this->color); 
-        +    } 
 + 
 +    // if pattern belongs to two or more modes, the one with the lowest sort number wins 
 +    public function getSort() { 
 +        return 158;
     }     }
-     
 } }
 </code> </code>
Line 1626: Line 1429:
   - It actually represents multiple modes, one for each color. The colors need separating into different modes so that ''%%</green>%%'' doesn't end up being the closing tag for ''%%<red>%%'', for example.   - It actually represents multiple modes, one for each color. The colors need separating into different modes so that ''%%</green>%%'' doesn't end up being the closing tag for ''%%<red>%%'', for example.
   - These modes can contain other modes, for example ''%%<red>**Warning**</red>%%'' for bold text which is red. This is registered in the constructor for this class by assigning the accepted mode names to the ''allowedModes'' property.   - These modes can contain other modes, for example ''%%<red>**Warning**</red>%%'' for bold text which is red. This is registered in the constructor for this class by assigning the accepted mode names to the ''allowedModes'' property.
 +  - the constructor unset one of the modes to prevent a formatting mode being nested inside itself (e.g. we don't want ''%%<red>A <red>warning</red> message</red>%%'' to happen).
   - When registering the entry pattern, it's a good idea to check the exit pattern exists (which is done with the lookahead). This should help protect users from themselves, when they forget to add the closing tag.   - When registering the entry pattern, it's a good idea to check the exit pattern exists (which is done with the lookahead). This should help protect users from themselves, when they forget to add the closing tag.
   - The entry pattern needs to be registered for each mode within which the color tags could be used. By contrast we only need one exit pattern, so this is placed in the ''%%postConnect%%'' method, so that is only executed once, after all calls to ''connectTo'' on all modes have been called.   - The entry pattern needs to be registered for each mode within which the color tags could be used. By contrast we only need one exit pattern, so this is placed in the ''%%postConnect%%'' method, so that is only executed once, after all calls to ''connectTo'' on all modes have been called.
  
-With the parsing mode class done, the new modes now need adding to the ''Doku_Parser_Formatting'' function; +With the parsing mode class done, the new modes now need adding to the ''$PARSER_MODES['formatting']'' subarray in inc/parser/parser.php
 <code php> <code php>
-function Doku_Parser_Formatting($remove '') { +global $PARSER_MODES; 
-    $modes = array( +$PARSER_MODES [ 
-        'strong', 'emphasis', 'underline', 'monospace',  +    ... 
-        'subscript', 'superscript', 'deleted', +    // modes for styling text -- footnote behaves similar to styling 
-        'red','yellow','green'+    'formatting' => [ 
-        ); +        'strong', 'emphasis', 'underline', 'monospace', 'subscript',  
-    $key = array_search($remove$modes); +        'superscript', 'deleted', 'footnote', 
-    if ( is_int($key) ) { +        'red','yellow','green' 
-        unset($modes[$key]); +    ]
-    } +    ... 
-     +];
-    return $modes; +
-}+
 </code> </code>
- 
-**Note** this function is primed to unset one of the modes to prevent a formatting mode being nested inside itself (e.g. we don't want ''%%<red>A <red>warning</red> message</red>%%'' to happen). 
  
 Next the Handler needs updating with one method for each color; Next the Handler needs updating with one method for each color;
Line 1653: Line 1452:
 <code php> <code php>
 class Doku_Handler { class Doku_Handler {
- 
     // ...     // ...
          
-    function red($match, $state, $pos) {+    public function red($match, $state, $pos) {
         // The nestingTag method in the Handler is there         // The nestingTag method in the Handler is there
         // to save having to repeat the same code many         // to save having to repeat the same code many
Line 1662: Line 1460:
         // instruction for the entry and exit patterns,         // instruction for the entry and exit patterns,
         // while passing through the rest as cdata         // while passing through the rest as cdata
-        $this->__nestingTag($match, $state, $pos, 'red'); +        $this->nestingTag($match, $state, $pos, 'red'); 
-        return TRUE;+        return true;
     }     }
          
-    function yellow($match, $state, $pos) { +    public function yellow($match, $state, $pos) { 
-        $this->__nestingTag($match, $state, $pos, 'yellow'); +        $this->nestingTag($match, $state, $pos, 'yellow'); 
-        return TRUE;+        return true;
     }     }
          
-    function green($match, $state, $pos) { +    public function green($match, $state, $pos) { 
-        $this->__nestingTag($match, $state, $pos, 'green'); +        $this->nestingTag($match, $state, $pos, 'green'); 
-        return TRUE;+        return true;
     }     }
          
     // ...     // ...
-     
 } }
 </code> </code>
Line 1685: Line 1482:
 <code php> <code php>
 class Doku_Renderer { class Doku_Renderer {
- 
     // ...     // ...
          
-    function red_open() {} +    public function red_open() {} 
-    function red_close() {}+    public function red_close() {}
          
-    function yellow_open() {} +    public function yellow_open() {} 
-    function yellow_close() {}+    public function yellow_close() {}
          
-    function green_open() {} +    public function green_open() {} 
-    function green_close() {}+    public function green_close() {}
  
     // ...     // ...
- 
 } }
 </code> </code>
  
 <code php> <code php>
-class Doku_Renderer_XHTML { +class Doku_Renderer_xhtml {
     // ...     // ...
          
-    function red_open() {+    public function red_open() {
         echo '<span class="red">';         echo '<span class="red">';
     }     }
-    function red_close() {+    public function red_close() {
         echo '</span>';         echo '</span>';
     }     }
          
-    function yellow_open() {+    public function yellow_open() {
         echo '<span class="yellow">';         echo '<span class="yellow">';
     }     }
-    function yellow_close() {+    public function yellow_close() {
         echo '</span>';         echo '</span>';
     }     }
          
-    function green_open() {+    public function green_open() {
         echo '<span class="green">';         echo '<span class="green">';
     }     }
-    function green_close() {+    public function green_close() {
         echo '</span>';         echo '</span>';
     }     }
  
     // ...     // ...
- 
 } }
 </code> </code>
  
-See the ''tests/parser_formatting.test.php'' script for examples of how you might write unit tests for this code.+See the ''_test/tests/inc/parser/parser_i18n.test.php'' script for examples of how you might write unit tests for this code.
  
 ==== Adding Block-Level Syntax ==== ==== Adding Block-Level Syntax ====
Line 1755: Line 1548:
 This syntax might allow a tool to be added to search wiki pages and find things that still need something doing, as well as making it stand out in the document with some eye-catching style. This syntax might allow a tool to be added to search wiki pages and find things that still need something doing, as well as making it stand out in the document with some eye-catching style.
  
-What's different about this syntax is it should be displayed in a separate block in the document (e.g. inside ''<div/>'' so that it can be floated with CSS). This requires modifying the ''Doku_Handler_Block'' class, which loops through all the instructions after all tokens have been seen by the handler and takes care of adding ''<p/>'' tags.+What's different about this syntax is it should be displayed in a separate block in the document (e.g. inside ''<div/>'' so that it can be floated with CSS). This requires modifying the ''dokuwiki\Parsing\Handler\Block'' class, which loops through all the instructions after all tokens have been seen by the handler and takes care of adding ''<p/>'' tags.
  
 The parser mode for this syntax might be; The parser mode for this syntax might be;
  
 <code php> <code php>
-class Doku_Parser_Mode_Todo extends Doku_Parser_Mode {+namespace dokuwiki\Parsing\ParserMode; 
 + 
 +class Todo extends AbstractMode {
          
-    function Doku_Parser_Mode_Todo() { +    public function __construct() {
-        +
         $this->allowedModes = array_merge (         $this->allowedModes = array_merge (
-            Doku_Parser_Formatting()+            $PARSER_MODES['formatting']
-            Doku_Parser_Substition()+            $PARSER_MODES['substition']
-            Doku_Parser_Disabled()+            $PARSER_MODES['disabled']
         );         );
-         
     }     }
          
-    function connectTo($mode) { +    public function connectTo($mode) {
-    +
         $pattern = '<todo>(?=.*</todo>)';         $pattern = '<todo>(?=.*</todo>)';
-        $this->Lexer->addEntryPattern($pattern,$mode,'todo');+        $this->Lexer->addEntryPattern($pattern, $mode, 'todo');
     }     }
          
-    function postConnect() {+    public function postConnect() {
         $this->Lexer->addExitPattern('</todo>','todo');         $this->Lexer->addExitPattern('</todo>','todo');
 +    }
 +    
 +    public function getSort() {
 +        return 150;
     }     }
          
Line 1785: Line 1581:
 </code> </code>
  
-This mode is then added to the ''Doku_Parser_BlockContainers'' function in ''parser.php'';+This mode is then added to the ''container'' entry of ''$PARSER_MODES'' in [[xref>inc/parser/parser.php]];
  
 <code php> <code php>
-function Doku_Parser_BlockContainers() { +global $PARSER_MODES; 
-    $modes array( +$PARSER_MODES [ 
-        'footnote', 'listblock', 'table','quote', +    // containers are complex modes that can contain many other modes 
-        // hr breaks the principle but HRs should not be used in tables / lists  +    // hr breaks the principle but they shouldn'be used in tables / lists 
-        // so put it here +    // so they are put here 
-        'hr', +    'container' => ['listblock', 'table', 'quote', 'hr', 'todo']
-        'todo', +     
-    ); +    ... 
-    return $modes; +];
-}+
 </code> </code>
  
Line 1807: Line 1602:
     // ...     // ...
          
-    function todo($match, $state, $pos) { +    public function todo($match, $state, $pos) { 
-        $this->__nestingTag($match, $state, $pos, 'todo'); +        $this->nestingTag($match, $state, $pos, 'todo'); 
-        return TRUE;+        return true;
     }     }
          
Line 1817: Line 1612:
 </code> </code>
  
-But the ''Doku_Handler_Block'' class (found in ''inc/parser/handler.php''also needs updating, to register the todo opening and closing instructions;+But the [[xref>dokuwiki\Parsing\Handler\Block]] class also needs updating, to register the todo opening and closing instructions;
  
 <code php> <code php>
-class Doku_Handler_Block { +namespace dokuwiki\Parsing\Handler; 
-    + 
 +class Block {
     // ...     // ...
          
     // Blocks don't contain linefeeds     // Blocks don't contain linefeeds
-    var $blockOpen = array( +    protected $blockOpen = [ 
-            'header', +        'header', 
-            'listu_open','listo_open','listitem_open', +        'listu_open','listu_open', 'listo_open', 'listitem_open',  
-            'table_open','tablerow_open','tablecell_open','tableheader_open', +        'listcontent_open', 'table_open', 'tablerow_open', 'tablecell_open',  
-            'quote_open', +        'tableheader_open', 'tablethead_open', 'quote_open', 'code', 'file',  
-            'section_open', // Needed to prevent p_open between header and section_open +        'hr', 'preformatted', 'rss', 'footnote_open
-            'code','file','php','html','hr','preformatted', +        'todo_open' 
-            'todo_open', +    ]
-        )+            
-     +    protected $blockClose = [ 
-    var $blockClose = array( +        'header', 'listu_close', 'listo_close', 'listitem_close',  
-            'header', +        'listcontent_close', 'table_close', 'tablerow_close', 'tablecell_close',  
-            'listu_close','listo_close','listitem_close', +        'tableheader_close', 'tablethead_close', 'quote_close', 'code', 'file', 
-            'table_close','tablerow_close','tablecell_close','tableheader_close', +        'hr', 'preformatted', 'rss', 'footnote_close
-            'quote_close', +        'todo_close' 
-            'section_close', // Needed to prevent p_close after section_close +    ];
-            'code','file','php','html','hr','preformatted', +
-            'todo_close', +
-        );+
                  
 </code> </code>
  
-By registering the ''todo_open'' and ''todo_close'' in the ''%%$blockOpen%%'' and ''%%$blockClose%%'' arrays, it instructs the ''Doku_Handler_Block'' class that any previous open paragraphs should be closed //before// entering the todo section then a new paragraph should start //after// the todo section. Inside the todo, no additional paragraphs should be inserted.+By registering the ''todo_open'' and ''todo_close'' in the ''%%$blockOpen%%'' and ''%%$blockClose%%'' arrays, it instructs the ''dokuwiki\Parsing\Handler\Block'' class that any previous open paragraphs should be closed //before// entering the todo section then a new paragraph should start //after// the todo section. Inside the todo, no additional paragraphs should be inserted.
  
 With that done, the Renderers can be updated; With that done, the Renderers can be updated;
Line 1856: Line 1649:
     // ...     // ...
          
-    function todo_open() {} +    public function todo_open() {} 
-    function todo_close() {}+    public function todo_close() {}
          
     // ...     // ...
Line 1865: Line 1658:
  
 <code php> <code php>
-class Doku_Renderer_XHTML {+class Doku_Renderer_xhtml {
  
     // ...     // ...
          
-    function todo_open() {+    public function todo_open() {
         echo '<div class="todo">';         echo '<div class="todo">';
     }     }
-    function todo_close() {+    public function todo_close() {
         echo '</div>';         echo '</div>';
     }     }
Line 1882: Line 1675:
  
 ==== Serializing the Renderer Instructions ==== ==== Serializing the Renderer Instructions ====
 +
 +FIXME Dokuwiki uses a [[caching]] mechanism inherited from the ''dokuwiki\Cache\Cache''. Rewrite this section.
  
 It is possible to serialize the list of instructions output from the Handler, to eliminate the overhead of re-parsing the original document on each request, if the document itself hasn't changed. It is possible to serialize the list of instructions output from the Handler, to eliminate the overhead of re-parsing the original document on each request, if the document itself hasn't changed.
Line 1888: Line 1683:
  
 <code php> <code php>
-$ID DOKU_DATA . 'wiki/syntax.txt'; +global $conf; 
-$cacheID DOKU_CACHE . $ID.'.cache';+ 
 +$filename $conf['datadir'. 'wiki/syntax.txt'; 
 +$cacheId $conf['cachedir'. $filename . '.cache';
  
 // If there's no cache file or it's out of date // If there's no cache file or it's out of date
 // (the original modified), get a fresh list of instructions // (the original modified), get a fresh list of instructions
-if ( !file_exists($cacheID) || (filemtime($ID) > filemtime($cacheID)) ) { +if (!file_exists($cacheId) || (filemtime($filename) > filemtime($cacheId))) { 
-     +    // Create the Handler 
-    require_once DOKU_INC . 'parser/parser.php'; +    $handler = new Doku_Handler(); 
-     + 
-    // Create the parser +    // Create the parser with the handler 
-    $Parser new Doku_Parser(); +    $parser = new dokuwiki\Parsing\Parser($handler); 
-     +
-    // Add the Handler +
-    $Parser->Handler new Doku_Handler(); +
-    +
     // Load all the modes     // Load all the modes
-    $Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock()); +    $parser->addMode('listblock', new dokuwiki\Parsing\ParserMode\ListBlock()); 
-    $Parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted());  +    $parser->addMode('preformatted', new dokuwiki\Parsing\ParserMode\Preformatted()); 
-    $Parser->addMode('notoc',new Doku_Parser_Mode_NoToc()); +    $parser->addMode('notoc', new dokuwiki\Parsing\ParserMode\NoToc()); 
-    $Parser->addMode('header',new Doku_Parser_Mode_Header()); +    $parser->addMode('header', new dokuwiki\Parsing\ParserMode\Header()); 
-    $Parser->addMode('table',new Doku_Parser_Mode_Table()); +    $parser->addMode('table', new dokuwiki\Parsing\ParserMode\Table()); 
-    +
     // etc. etc.     // etc. etc.
-     + 
-    $instructions = $Parser->parse(file_get_contents($filename)); +    $instructions = $parser->parse(file_get_contents($filename)); 
-    +
     // Serialize and cache      // Serialize and cache 
     $sInstructions = serialize($instructions);     $sInstructions = serialize($instructions);
-     + 
-    if ($fh = @fopen($cacheID, 'a')) { +    if ($fh = @fopen($cacheId, 'a')) { 
-         +        if (fwrite($fh, $sInstructions) === false) { 
-        if (fwrite($fh, $sInstructions) === FALSE) { +            die("Cannot write to file ($cacheId)");
-            die("Cannot write to file ($cacheID)");+
         }         }
-        +
         fclose($fh);         fclose($fh);
     }     }
-     
 } else { } else {
     // Load the serialized instructions and unserialize     // Load the serialized instructions and unserialize
-    $sInstructions = file_get_contents($cacheID);+    $sInstructions = file_get_contents($cacheId);
     $instructions = unserialize($sInstructions);     $instructions = unserialize($sInstructions);
 } }
  
-$Renderer new Doku_Renderer_XHTML();+$renderer = new Doku_Renderer_xhtml();
  
-foreach ( $instructions as $instruction ) {+foreach ($instructions as $instruction) {
     call_user_func_array(     call_user_func_array(
-        array(&$Renderer, $instruction[0]),$instruction[1] +        array($renderer, $instruction[0]), $instruction[1] 
-        );+    );
 } }
  
-echo $Renderer->doc;+echo $renderer->doc;
 </code> </code>
  
Line 1946: Line 1738:
  
 ==== Serializing the Parser ==== ==== Serializing the Parser ====
 +FIXME connecting modes is protected and already called in parse(), but that is outside the cache here. Probably not useful anymore. If still usefull, rewrite with dokuwiki\Cache\Cache
  
 Similar to the above example, it is also possible to serialize the Parser itself, before parsing begins. Because setting up the modes carries a fairly high overhead, this can add a small increase in performance. From loose benchmarking, parsing the wiki:syntax page on a single (slow!) system, what taking around 1.5 seconds to finish //without// serializing the Parser and about 1.25 seconds //with// the a serialized version of the Parser. Similar to the above example, it is also possible to serialize the Parser itself, before parsing begins. Because setting up the modes carries a fairly high overhead, this can add a small increase in performance. From loose benchmarking, parsing the wiki:syntax page on a single (slow!) system, what taking around 1.5 seconds to finish //without// serializing the Parser and about 1.25 seconds //with// the a serialized version of the Parser.
Line 1952: Line 1745:
  
 <code php> <code php>
-$cacheId = DOKU_CACHE . 'parser.cache'; 
  
-if ( !file_exists($cacheId) ) {+global $conf; 
 + 
 +$cacheId = $conf['cachedir'] . 'parser.cache'; 
 +if (!file_exists($cacheId)) { 
 +    // Create the parser with the handler 
 +    $handler = new Doku_Handler(); 
 +    $parser = new dokuwiki\Parsing\Parser($handler);
  
-    // Create the parser... 
-    $Parser = & new Doku_Parser(); 
-    $Parser->Handler = & new Doku_Handler(); 
-     
     // Load all the modes     // Load all the modes
-    $Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock()); +    $parser->addMode('listblock',new dokuwiki\Parsing\ParserMode\ListBlock()); 
-    $Parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted());+    $parser->addMode('preformatted',new dokuwiki\Parsing\ParserMode\Preformatted());
     # etc.     # etc.
-     +
-    // IMPORTANT: call connectModes() +
-    $Parser->connectModes(); +
-    +
     // Serialize     // Serialize
-    $sParser = serialize($Parser); +    $sParser = serialize($parser); 
-    +
     // Write to file     // Write to file
-    if ($fh = @fopen($cacheID, 'a')) { +    if ($fh = @fopen($cacheId, 'a')) { 
-         +        if (fwrite($fh, $sParser) === false) { 
-        if (fwrite($fh, $sParser) === FALSE) { +            die("Cannot write to file ($cacheId)");
-            die("Cannot write to file ($cacheID)");+
         }         }
-         
         fclose($fh);         fclose($fh);
     }     }
Line 1983: Line 1772:
 } else { } else {
     // Otherwise load the serialized version     // Otherwise load the serialized version
-    $sParser = file_get_contents($cacheID); +    $sParser = file_get_contents($cacheId); 
-    $Parser = unserialize($sParser);+    $parser = unserialize($sParser);
 } }
- +$doc = ... 
-$Parser->parse($doc);+$parser->parse($doc);
 </code> </code>
  
Line 1998: Line 1787:
 ===== Testing ===== ===== Testing =====
  
-The [[wp>Unit_testing|unit tests]] provided use [[http://www.lastcraft.com/simple_test.php]]. SimpleTest is an excellent tool for [[wp>Unit_testing|unit testing]] PHP code. In particular, the documentation shines (see http://simpletest.sourceforge.net as well as that found at http://www.lastcraft.com/simple_test.php) and the code is very mature, taking care of many issues transparently (like catching PHP errors and reporting them in the test results).+See [[devel:unittesting]] for setup and details.
  
 For the DokuWiki parser, tests have been provided for all the syntax implemented and I //strongly// recommend writing new tests if additional syntax is added. For the DokuWiki parser, tests have been provided for all the syntax implemented and I //strongly// recommend writing new tests if additional syntax is added.
- 
-To get the tests running, you should only need to modify the file ''tests/testconfig.php'', to point at the correct SimpleTest and DokuWiki directories. 
  
 Some notes / recommendations; Some notes / recommendations;
Line 2012: Line 1799:
 ===== Bugs / Issues ===== ===== Bugs / Issues =====
  
-Some things off the top of my head.+Some things off the top of my head. FIXME move to bug tracker?
  
 ==== Order of adding modes important ==== ==== Order of adding modes important ====
Line 2089: Line 1876:
  
 [[bug>261]] [[bug>261]]
 +
 +NOTE:  See [[https://github.com/dokuwiki/dokuwiki/issues/4054|this GitHub issue]] for further details and a possible workaround.
  
 Because the header, horizontal rule, list, table, quote and preformatted (indented text) syntax relies on linefeed characters to mark their starts and ends, they require regexes which consume linefeed characters. This means users need to add an additional linefeed if a table appears immediately after a list, for example. Because the header, horizontal rule, list, table, quote and preformatted (indented text) syntax relies on linefeed characters to mark their starts and ends, they require regexes which consume linefeed characters. This means users need to add an additional linefeed if a table appears immediately after a list, for example.
devel/parser.1389214917.txt.gz · Last modified: 2014-01-08 22:01 (external edit)

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
CC Attribution-Share Alike 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki