d251b188a5a4ce265e6ed0625ffcf198ec1275c4
[atutor.git] / mods / phpdoc2 / PhpDocumentor / phpDocumentor / HighlightParser.inc
1 <?php\r
2 /**\r
3  * Source Code Highlighting\r
4  *\r
5  * The classes in this file are responsible for the dynamic @example, @filesource\r
6  * and {@}source} tags output.  Using the phpDocumentor_HighlightWordParser,\r
7  * the phpDocumentor_HighlightParser retrieves PHP tokens one by one from the\r
8  * array generated by {@link phpDocumentorTWordParser} source retrieval functions\r
9  * and then highlights them individually.\r
10  *\r
11  * It accomplishes this highlighting through the assistance of methods in\r
12  * the output Converter passed to its parse() method, and then returns the\r
13  * fully highlighted source as a string\r
14  *\r
15  * phpDocumentor :: automatic documentation generator\r
16  * \r
17  * PHP versions 4 and 5\r
18  *\r
19  * Copyright (c) 2002-2007 Gregory Beaver\r
20  * \r
21  * LICENSE:\r
22  * \r
23  * This library is free software; you can redistribute it\r
24  * and/or modify it under the terms of the GNU Lesser General\r
25  * Public License as published by the Free Software Foundation;\r
26  * either version 2.1 of the License, or (at your option) any\r
27  * later version.\r
28  * \r
29  * This library is distributed in the hope that it will be useful,\r
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
32  * Lesser General Public License for more details.\r
33  * \r
34  * You should have received a copy of the GNU Lesser General Public\r
35  * License along with this library; if not, write to the Free Software\r
36  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
37  *\r
38  * @category   ToolsAndUtilities\r
39  * @package    phpDocumentor\r
40  * @subpackage Parsers\r
41  * @author     Gregory Beaver <cellog@php.net>\r
42  * @copyright  2002-2007 Gregory Beaver\r
43  * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL\r
44  * @version    CVS: $Id: HighlightParser.inc,v 1.15 2007/11/18 17:44:15 ashnazg Exp $\r
45  * @filesource\r
46  * @link       http://www.phpdoc.org\r
47  * @link       http://pear.php.net/PhpDocumentor\r
48  * @tutorial   tags.example.pkg, tags.filesource.pkg, tags.inlinesource.pkg\r
49  * @since      1.2.0beta3\r
50  * @todo       CS cleanup - change package to PhpDocumentor\r
51  */\r
52 \r
53 /**\r
54  * Retrieve tokens from an array of tokens organized by line numbers\r
55  *\r
56  * @category   ToolsAndUtilities\r
57  * @package    phpDocumentor\r
58  * @subpackage Parsers\r
59  * @author     Gregory Beaver <cellog@php.net>\r
60  * @copyright  2002-2007 Gregory Beaver\r
61  * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL\r
62  * @version    Release: 1.4.1\r
63  * @link       http://www.phpdoc.org\r
64  * @link       http://pear.php.net/PhpDocumentor\r
65  * @since      1.2.0beta3\r
66  * @todo       CS cleanup - change package to PhpDocumentor\r
67  * @todo       CS cleanup - change class name to PhpDocumentor_*\r
68  */\r
69 class phpDocumentor_HighlightWordParser extends phpDocumentorTWordParser\r
70 {\r
71     /**\r
72      * Hash used to keep track of line numbers that have already been initialized\r
73      * @var array\r
74      * @access private\r
75      */\r
76     var $_listLineNums = array();\r
77     /**\r
78      * Initialize the parser object\r
79      *\r
80      * @param array                         &$input  the input\r
81      * @param phpDocumentor_HighlightParser &$parser the parser\r
82      *\r
83      * @return void\r
84      */\r
85     function setup(&$input, &$parser)\r
86     {\r
87         $this->_parser     = &$parser;\r
88         $this->data        = &$input;\r
89         $this->_all        = $input;\r
90         $this->_sourceline = 0;\r
91         $this->pos         = 0;\r
92         $this->linenum     = 0;\r
93     }\r
94     \r
95     /**\r
96      * debugging function\r
97      *\r
98      * @return void\r
99      * @access private\r
100      */\r
101     function printState()\r
102     {\r
103         $linenum = $this->linenum;\r
104         $pos     = $this->pos;\r
105         if (!isset($this->_all[$this->linenum][$this->pos])) {\r
106             $linenum++;\r
107             $pos = 0;\r
108         }\r
109         $details = '';\r
110         $token   = $this->_all[$linenum][$pos];\r
111         if (is_array($token)) {\r
112             $details = token_name($token[0]);\r
113             $token   = htmlspecialchars($token[1]);\r
114         } else {\r
115             $token = htmlspecialchars($token);\r
116         }\r
117         debug('Next Token ' . $this->linenum . '-' . $this->pos . ':' . $details);\r
118         var_dump($token);\r
119     }\r
120     \r
121     /**\r
122      * Retrieve the position of the next token that will be parsed\r
123      * in the internal token array\r
124      *\r
125      * @return array format: array(line number, position)\r
126      */\r
127     function nextToken()\r
128     {\r
129         $linenum = $this->linenum;\r
130         $pos     = $this->pos;\r
131         if (!isset($this->_all[$this->linenum][$this->pos])) {\r
132             $linenum++;\r
133             $pos = 0;\r
134         }\r
135         if (!isset($this->_all[$linenum][$pos])) {\r
136             return false;\r
137         }\r
138         return array($linenum, $pos);\r
139     }\r
140     \r
141     /**\r
142      * Retrieve the next token\r
143      *\r
144      * @return array|string either array(PHP token constant, token) or string\r
145      *                      non-specific separator\r
146      */\r
147     function getWord()\r
148     {\r
149         if (!isset($this->_all[$this->linenum][$this->pos])) {\r
150             $this->linenum++;\r
151             $this->pos = 0;\r
152             if (!isset($this->_all[$this->linenum])) {\r
153                 return false;\r
154             }\r
155             $this->_parser->newLineNum();\r
156             return $this->getWord();\r
157         }\r
158         $word = $this->_all[$this->linenum][$this->pos++];\r
159         return str_replace("\t", '    ', $word);\r
160     }\r
161 \r
162     /**\r
163      * back the word parser to the previous token as defined by $last_token\r
164      *\r
165      * @param array|string $last_token token, or output from {@link nextToken()}\r
166      * @param bool         $is_pos     if true, backupPos interprets $last_token \r
167      *                                 to be the position in the internal token\r
168      *                                 array of the last token\r
169      *\r
170      * @return void\r
171      */\r
172     function backupPos($last_token, $is_pos = false)\r
173     {\r
174         if (!$last_token) {\r
175             return;\r
176         }\r
177         if ($is_pos) {\r
178             $this->linenum = $last_token[0];\r
179             $this->pos     = $last_token[1];\r
180             return;\r
181         }\r
182         if ($last_token === false) {\r
183             return;\r
184         }\r
185 \r
186         //fancy_debug('before', $this->linenum, $this->pos, \r
187         //    token_name($this->_all[$this->linenum][$this->pos][0]),\r
188         //    htmlentities($this->_all[$this->linenum][$this->pos][1]),\r
189         //    $this->_all[$this->linenum]);\r
190 \r
191         do {\r
192             $this->pos--;\r
193             if ($this->pos < 0) {\r
194                 $this->linenum--;\r
195                 if ($this->linenum < 0) {\r
196                     var_dump($last_token);\r
197                     break;\r
198                 }\r
199                 $this->pos = count($this->_all[$this->linenum]) - 1;\r
200             }\r
201         } while (!$this->tokenEquals($last_token, str_replace("\t", '    ', \r
202             $this->_all[$this->linenum][$this->pos])));\r
203 \r
204         //fancy_debug('after', $this->linenum, $this->pos,\r
205         //    token_name($this->_all[$this->linenum][$this->pos][0]),\r
206         //    htmlentities($this->_all[$this->linenum][$this->pos][1]));\r
207     }\r
208 }\r
209 \r
210 /**\r
211  * Highlights source code using {@link parse()}\r
212  *\r
213  * @category   ToolsAndUtilities\r
214  * @package    phpDocumentor\r
215  * @subpackage Parsers\r
216  * @author     Gregory Beaver <cellog@php.net>\r
217  * @copyright  2002-2007 Gregory Beaver\r
218  * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL\r
219  * @version    Release: 1.4.1\r
220  * @link       http://www.phpdoc.org\r
221  * @link       http://pear.php.net/PhpDocumentor\r
222  * @since      1.2.0beta3\r
223  * @todo       CS cleanup - change package to PhpDocumentor\r
224  * @todo       CS cleanup - change class name to PhpDocumentor_*\r
225  */\r
226 class phpDocumentor_HighlightParser extends phpDocumentorTParser\r
227 {\r
228     /**#@+\r
229      * @access private\r
230      */\r
231 \r
232     /**\r
233      * Highlighted source is built up in this string\r
234      * @var string\r
235      */\r
236     var $_output;\r
237 \r
238     /**\r
239      * contents of the current source code line as it is parsed\r
240      * @var string\r
241      */\r
242     var $_line;\r
243 \r
244     /**\r
245      * Used to retrieve highlighted tokens\r
246      * @var Converter a descendant of Converter\r
247      */\r
248     var $_converter;\r
249 \r
250     /**\r
251      * Path to file being highlighted, if this is from a @filesource tag\r
252      * @var false|string full path\r
253      */\r
254     var $_filesourcepath;\r
255 \r
256     /**\r
257      * @var array\r
258      */\r
259     var $eventHandlers = array(\r
260         PARSER_EVENT_ARRAY                      => 'defaultHandler',\r
261         PARSER_EVENT_CLASS                      => 'handleClass',\r
262         PARSER_EVENT_COMMENT                    => 'handleComment',\r
263         PARSER_EVENT_DOCBLOCK_TEMPLATE          => 'handleDocBlockTemplate',\r
264         PARSER_EVENT_END_DOCBLOCK_TEMPLATE      => 'handleEndDocBlockTemplate',\r
265         PARSER_EVENT_LOGICBLOCK                 => 'handleLogicBlock',\r
266         PARSER_EVENT_METHOD_LOGICBLOCK          => 'handleMethodLogicBlock',\r
267         PARSER_EVENT_NOEVENTS                   => 'defaultHandler',\r
268         PARSER_EVENT_OUTPHP                     => 'defaultHandler',\r
269         PARSER_EVENT_CLASS_MEMBER               => 'handleClassMember',\r
270         PARSER_EVENT_DEFINE                     => 'defaultHandler',\r
271         PARSER_EVENT_DEFINE_PARAMS              => 'defaultHandler',\r
272         PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS  => 'defaultHandler',\r
273         PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS => 'defaultHandler',\r
274         PARSER_EVENT_DOCBLOCK                   => 'handleDocBlock',\r
275         PARSER_EVENT_TAGS                       => 'handleTags',\r
276         PARSER_EVENT_DESC                       => 'handleDesc',\r
277         PARSER_EVENT_DOCKEYWORD                 => 'handleTag',\r
278         PARSER_EVENT_DOCKEYWORD_EMAIL           => 'handleDockeywordEmail',\r
279         PARSER_EVENT_EOFQUOTE                   => 'handleQuote',\r
280         PARSER_EVENT_FUNCTION                   => 'handleFunction',\r
281         PARSER_EVENT_METHOD                     => 'handleMethod',\r
282         PARSER_EVENT_FUNCTION_PARAMS            => 'handleFunctionParams',\r
283         PARSER_EVENT_FUNC_GLOBAL                => 'handleFuncGlobal',\r
284         PARSER_EVENT_INLINE_DOCKEYWORD          => 'handleInlineDockeyword',\r
285         PARSER_EVENT_INCLUDE                    => 'defaultHandler',\r
286         PARSER_EVENT_INCLUDE_PARAMS             => 'defaultHandler',\r
287         PARSER_EVENT_QUOTE                      => 'handleQuote',\r
288         PARSER_EVENT_QUOTE_VAR                  => 'handleQuoteVar',\r
289         PARSER_EVENT_PHPCODE                    => 'handlePhpCode',\r
290         PARSER_EVENT_SINGLEQUOTE                => 'handleSingleQuote',\r
291         PARSER_EVENT_STATIC_VAR                 => 'defaultHandler',\r
292         PARSER_EVENT_STATIC_VAR_VALUE           => 'defaultHandler',\r
293         PARSER_EVENT_VAR                        => 'handleVar',\r
294     );\r
295 \r
296     /**\r
297      * event handlers for @tags\r
298      * @tutorial tags.pkg\r
299      */\r
300     var $tagHandlers = array(\r
301         '*'              => 'defaultTagHandler',\r
302         'abstract'       => 'coreTagHandler',\r
303         'access'         => 'coreTagHandler',\r
304         'author'         => 'coreTagHandler',\r
305         'category'       => 'coreTagHandler',\r
306         'copyright'      => 'coreTagHandler',\r
307         'deprecated'     => 'coreTagHandler',\r
308         'example'        => 'coreTagHandler',\r
309         'filesource'     => 'coreTagHandler',\r
310         'final'          => 'coreTagHandler',\r
311         'global'         => 'globalTagHandler',\r
312         'ignore'         => 'coreTagHandler',\r
313         'license'        => 'coreTagHandler',\r
314         'link'           => 'coreTagHandler',\r
315         'name'           => 'coreTagHandler',\r
316         'package'        => 'coreTagHandler',\r
317         'param'          => 'paramTagHandler',\r
318         'parameter'      => 'paramTagHandler',\r
319         'see'            => 'coreTagHandler',\r
320         'since'          => 'coreTagHandler',\r
321         'subpackage'     => 'coreTagHandler',\r
322         'internal'       => 'coreTagHandler',\r
323         'return'         => 'returnTagHandler',\r
324         'static'         => 'coreTagHandler',\r
325         'staticvar'      => 'staticvarTagHandler',\r
326         'throws'         => 'coreTagHandler',\r
327         'todo'           => 'coreTagHandler',\r
328         'tutorial'       => 'coreTagHandler',\r
329         'uses'           => 'coreTagHandler',\r
330         'var'            => 'varTagHandler',\r
331         'version'        => 'coreTagHandler',\r
332         'property'       => 'propertyTagHandler',\r
333         'property-read'  => 'propertyTagHandler',\r
334         'property-write' => 'propertyTagHandler',\r
335         'method'         => 'propertyTagHandler'\r
336     );\r
337     /**#@-*/\r
338     \r
339     /**\r
340      * wraps the current line (via the converter) and resets it to empty\r
341      *\r
342      * @return void\r
343      * @uses Converter::SourceLine() encloses {@link $_line} in a\r
344      *                               converter-specific format\r
345      */\r
346     function newLineNum()\r
347     {\r
348         if ($this->_pf_no_output_yet) {\r
349             return;\r
350         }\r
351         $this->_flush_save();\r
352         $this->_line   .= $this->_converter->flushHighlightCache();\r
353         $this->_output .= $this->_converter->SourceLine($this->_wp->linenum,\r
354             $this->_line, $this->_path);\r
355         $this->_line    = '';\r
356     }\r
357     \r
358     /**\r
359      * Start the parsing at a certain line number\r
360      *\r
361      * @param int $num line number\r
362      *\r
363      * @return void\r
364      */\r
365     function setLineNum($num)\r
366     {\r
367         $this->_wp->linenum = $num;\r
368     }\r
369     \r
370     /**\r
371      * Parse a new file\r
372      *\r
373      * The parse() method is a do...while() loop that retrieves tokens one by\r
374      * one from the {@link $_event_stack}, and uses the token event array set up\r
375      * by the class constructor to call event handlers.\r
376      *\r
377      * The event handlers each process the tokens passed to them, and use the\r
378      * {@link _addoutput()} method to append the processed tokens to the\r
379      * {@link $_line} variable.  The word parser calls {@link newLineNum()}\r
380      * every time a line is reached.\r
381      *\r
382      * In addition, the event handlers use special linking functions\r
383      * {@link _link()} and its cousins (_classlink(), etc.) to create in-code\r
384      * hyperlinks to the documentation for source code elements that are in the\r
385      * source code.\r
386      *\r
387      * @param array         &$parse_data       the parse data\r
388      * @param Converter     &$converter        the converter object\r
389      * @param bool          $inlinesourceparse whether this data is from an\r
390      *                                         inline {@}source} tag\r
391      * @param string|false  $class             if a string, it is the name of the \r
392      *                                         class whose method we are parsing\r
393      *                                         containing a {@}source} tag\r
394      * @param false|integer $linenum           starting line number from\r
395      *                                         {@}source linenum}\r
396      * @param false|string  $filesourcepath    full path to file with @filesource\r
397      *                                         tag, if this is a @filesource parse\r
398      *\r
399      * @staticvar int used for recursion limiting if a handler for\r
400      *                an event is not found\r
401      * @return bool\r
402      * @uses setupStates() initialize parser state variables\r
403      * @uses configWordParser() pass $parse_data to prepare retrieval of tokens\r
404      * @todo CS cleanup - rename tokenizer_ext constant to uppercase\r
405      */\r
406     function parse (&$parse_data, &$converter, $inlinesourceparse = false,\r
407         $class = false, $linenum = false, $filesourcepath = false)\r
408     {\r
409         if (!tokenizer_ext) {\r
410             if (is_array($parse_data)) {\r
411                 $parse_data = join($parse_data, '');\r
412             }\r
413             $parse_data    = explode("\n", $parse_data);\r
414             $this->_output = '';\r
415             foreach ($parse_data as $linenum => $line) {\r
416                 if ($linenum > 0) {\r
417                     $this->_output .= $converter->SourceLine($linenum,\r
418                         $line, $filesourcepath);\r
419                 }\r
420             }\r
421             return $converter->PreserveWhiteSpace($this->_output);\r
422         }\r
423         static $endrecur  = 0;\r
424         $this->_converter = &$converter;\r
425         $converter->startHighlight();\r
426         $this->_path = $filesourcepath;\r
427         $this->setupStates($inlinesourceparse, $class);\r
428 \r
429         $this->configWordParser($parse_data);\r
430         if ($linenum !== false) {\r
431             $this->setLineNum($linenum);\r
432         }\r
433         // initialize variables so E_ALL error_reporting doesn't complain\r
434         $pevent = 0;\r
435         $word   = 0;\r
436 \r
437         do {\r
438             $lpevent = $pevent;\r
439             $pevent  = $this->_event_stack->getEvent();\r
440             if ($lpevent != $pevent) {\r
441                 $this->_last_pevent = $lpevent;\r
442             }\r
443 \r
444             if ($pevent == PARSER_EVENT_CLASS_MEMBER) {\r
445                 $this->_wp->setWhitespace(true);\r
446             } else {\r
447                 $this->_wp->setWhitespace(false);\r
448             }\r
449 \r
450             if (!is_array($word)) {\r
451                 $lw = $word;\r
452             }\r
453             if (is_array($word) && $word[0] != T_WHITESPACE) {\r
454                 $lw = $word;\r
455             }\r
456             $dbg_linenum = $this->_wp->linenum;\r
457             $dbg_pos     = $this->_wp->getPos();\r
458             $word        = $this->_wp->getWord();\r
459             if (is_array($word) && ($word[0] == T_WHITESPACE || \r
460                 $word[0] == T_COMMENT) && \r
461                 $pevent != PARSER_EVENT_CLASS_MEMBER\r
462             ) {\r
463                 //debug("added " . $this->_wp->linenum . '-' . $this->_wp->pos);\r
464                 $this->_addoutput($word);\r
465                 continue;\r
466             } else {\r
467                 $this->_pv_last_word = $lw;\r
468             }\r
469             if ($pevent != PARSER_EVENT_DOCBLOCK) {\r
470                 $this->_pv_last_next_word = $this->_pv_next_word;\r
471                 $this->_pv_next_word      = $this->_wp->nextToken();\r
472             }\r
473             // in wordparser, have to keep track of lines\r
474             //$this->publishEvent(PHPDOCUMENTOR_EVENT_NEWLINENUM, \r
475             //    $this->_wp->linenum);\r
476             if (PHPDOCUMENTOR_DEBUG == true) {\r
477                 echo "LAST: ";\r
478                 if (is_array($this->_pv_last_word)) {\r
479                     echo token_name($this->_pv_last_word[0]) . \r
480                         ' => |' .\r
481                         htmlspecialchars($this->_pv_last_word[1]);\r
482                 } else {\r
483                     echo "|" . $this->_pv_last_word;\r
484                 }\r
485                 echo "|\n";\r
486                 echo "PEVENT: " . $this->getParserEventName($pevent) . "\n";\r
487                 echo "LASTPEVENT: " .\r
488                     $this->getParserEventName($this->_last_pevent) . "\n";\r
489                 //echo "LINE: "   . $this->_line   . "\n";\r
490                 //echo "OUTPUT: " . $this->_output . "\n";\r
491                 echo $dbg_linenum . '-' . $dbg_pos . ": ";\r
492                 if (is_array($word)) {\r
493                     echo token_name($word[0]) . ' => |' . htmlspecialchars($word[1]);\r
494                 } else {\r
495                     echo '|'.htmlspecialchars($word);\r
496                 }\r
497                 echo "|\n";\r
498                 $this->_wp->printState();\r
499                 echo "NEXT TOKEN: ";\r
500                 $tok1 = $this->_pv_next_word;\r
501                 $tok  = $this->_wp->_all[$tok1[0]][$tok1[1]];\r
502                 if (is_array($tok)) {\r
503                     echo token_name($tok[0]) . ' => ' . $tok1[0] . '-' . $tok1[1] .\r
504                         '|' . htmlspecialchars($tok[1]);\r
505                 } else {\r
506                     echo "|" . $tok;\r
507                 }\r
508                 echo "|\n";\r
509                 echo "-------------------\n\n\n";\r
510                 flush();\r
511             }\r
512             if ($word !== false && isset($this->eventHandlers[$pevent])) {\r
513                 $handle = $this->eventHandlers[$pevent];\r
514                 $this->$handle($word, $pevent);\r
515             } elseif ($word !== false) {\r
516                 debug('WARNING: possible error, no handler for event number '\r
517                      . $pevent);\r
518                 if ($endrecur++ == 25) {\r
519                     die("FATAL ERROR, recursion limit reached");\r
520                 }\r
521             }\r
522         } while (!($word === false));\r
523         if (strlen($this->_line)) {\r
524             $this->newLineNum();\r
525         }\r
526         return $this->_output;\r
527     }\r
528 \r
529     /**#@+\r
530      * Event Handlers\r
531      *\r
532      * All Event Handlers use {@link checkEventPush()} and\r
533      * {@link checkEventPop()} to set up the event stack and parser state.\r
534      *\r
535      * @param string|array $word   token value\r
536      * @param int          $pevent parser event from {@link Parser.inc}\r
537      *\r
538      * @return void\r
539      * @access private\r
540      */\r
541     /**\r
542      * Most tokens only need highlighting, and this method handles them\r
543      */\r
544     function defaultHandler($word, $pevent)\r
545     {\r
546         $this->_addoutput($word);\r
547         if ($this->checkEventPush($word, $pevent)) {\r
548             return;\r
549         }\r
550         $this->checkEventPop($word, $pevent);\r
551     }\r
552     \r
553     /**\r
554      * Handles global declarations in a function, like:\r
555      *\r
556      * <code>\r
557      * function foobar()\r
558      * {\r
559      *     global $_phpDocumentor_setting;\r
560      * }\r
561      * </code>\r
562      *\r
563      * @uses _globallink() instead of _addoutput(), to link to global variables\r
564      *       if they are used in a function\r
565      */\r
566     function handleFuncGlobal($word, $pevent)\r
567     {\r
568         if ($this->checkEventPush($word, $pevent)) {\r
569             return;\r
570         }\r
571         $this->_globallink($word);\r
572         $this->checkEventPop($word, $pevent);\r
573     }\r
574     \r
575     /**\r
576      * Handles strings in quotation marks and heredoc\r
577      *\r
578      * Special handling is needed for strings that contain variables like:\r
579      *\r
580      * <code>$a = "$test string"</code>\r
581      *\r
582      * The tokenizer parses out tokens '"',array(T_VARIABLE,'$test'),' string',\r
583      * and '"'.  Since it is possible to have $this->classvar in a string,\r
584      * we save a variable name just in case the next token is -> to allow linking\r
585      * to class members.  Otherwise, the string is simply highlighted.\r
586      *\r
587      * constant strings (with no $variables in them) are passed as a single\r
588      * entity, and so will be saved in the last token parsed.  This means the\r
589      * event handler must tell the word parser to re-retrieve the current token\r
590      * so that the correct event handler can process it.\r
591      */\r
592     function handleQuote($word, $pevent)\r
593     {\r
594         if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) {\r
595             $this->_pv_lastvar = $word;\r
596         }\r
597         if ($this->checkEventPush($word, $pevent)) {\r
598             $this->_addoutput($word);\r
599             return;\r
600         }\r
601         if ($this->_pf_quote_active &&\r
602             (($this->_pv_last_word == '"' && \r
603             $this->_last_pevent != PARSER_EVENT_QUOTE) ||\r
604             (is_array($this->_pv_last_word) && \r
605             $this->_pv_last_word[0] == T_END_HEREDOC &&\r
606             $this->_last_pevent != PARSER_EVENT_EOFQUOTE))\r
607         ) {\r
608             $this->_pf_quote_active = false;\r
609             $this->_wp->backupPos($word);\r
610             $this->_event_stack->popEvent();\r
611             return;\r
612         }\r
613         if (!$this->_pf_quote_active && \r
614             (($this->_pv_last_word == '"' && \r
615             $this->_last_pevent != PARSER_EVENT_QUOTE) ||\r
616             (is_array($this->_pv_last_word) && \r
617             $this->_pv_last_word[0] == T_END_HEREDOC &&\r
618             $this->_last_pevent != PARSER_EVENT_EOFQUOTE))\r
619         ) {\r
620             if (is_array($word) && $word[0] == T_VARIABLE) {\r
621                 $this->_pv_lastvar = $word;\r
622             }\r
623             $this->_pf_quote_active      = true;\r
624             $this->_save_highlight_state = $this->_converter->getHighlightState();\r
625             $this->_converter->startHighlight();\r
626             $this->_addoutput($word);\r
627             $this->checkEventPop($word, $pevent);\r
628             return;\r
629         } elseif (is_array($this->_pv_last_word) && \r
630             $this->_pv_last_word[0] == T_CONSTANT_ENCAPSED_STRING\r
631         ) {\r
632             //$this->_pv_quote_data = $this->_pv_last_word[1];\r
633             $this->_event_stack->popEvent();\r
634             $this->_wp->backupPos($word);\r
635             return;\r
636         }\r
637         if ($this->checkEventPop($word, $pevent)) {\r
638             $this->_pf_quote_active = false;\r
639         }\r
640         $this->_addoutput($word);\r
641     }\r
642     \r
643     /**\r
644      * Handles {$variable} within a "quote"\r
645      *\r
646      * This is a simple handler, for a very complex\r
647      * array of legal syntax.  It is legal to nest control structures\r
648      * inside the {}, and other weird stuff.\r
649      */\r
650     function handleQuoteVar($word, $pevent)\r
651     {\r
652         if ($this->checkEventPop($word, $pevent)) {\r
653             $this->_pf_quote_active = true;\r
654             $this->_addoutput($word);\r
655             return;\r
656         }\r
657         if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) {\r
658             $this->_pv_lastvar = $word;\r
659         }\r
660         if ($this->checkEventPush($word, $pevent)) {\r
661             $this->_pf_quote_active = false;\r
662             if (is_string($word) && ($word == '{' || $word == '"' || $word == "'")\r
663             ) {\r
664                 $this->_pf_quote_active = true;\r
665                 $this->_pv_lastvar      = false;\r
666             }\r
667         }\r
668         $this->_addoutput($word);\r
669     }\r
670     \r
671     /**\r
672      * Handles define() statements\r
673      *\r
674      * The only thing this handler cares about is retrieving the name of the\r
675      * define variable, and the end of the define statement, so after the name\r
676      * is found, it simply makes sure parentheses are matched as in this case:\r
677      *\r
678      * <code>\r
679      * define("test",array("hello",6 => 4, 5 => array('there')));\r
680      * </code>\r
681      *\r
682      * This handler and the DEFINE_PARAMS_PARENTHESIS handler (which is just\r
683      * {@link defaultHandler()} in this version, as nothing fancy is needed)\r
684      * work together to ensure proper parenthesis matching.\r
685      *\r
686      * If the define variable is documented, a link will be created to its\r
687      * documentation using the Converter passed.\r
688      */\r
689     function handleDefine($word, $pevent)\r
690     {\r
691         static $token_save;\r
692         if (!isset($token_save)) {\r
693             $token_save = array();\r
694         }\r
695         $e = $this->checkEventPush($word, $pevent);\r
696         if ($e && $e != PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS) {\r
697             return;\r
698         }\r
699         \r
700         if (!isset($this->_pv_define_params_data)) {\r
701             $this->_pv_define_params_data = '';\r
702         }\r
703         \r
704         if ($this->checkEventPop($word, $pevent)) {\r
705             unset($token_save);\r
706             $this->_addoutput($word);\r
707         }\r
708         if ($this->_pf_definename_isset) {\r
709             $this->_addoutput($word);\r
710         } else {\r
711             if ($word != ",") {\r
712                 $token_save[] = $word;\r
713                 if (is_array($word)) {\r
714                     $word = $word[1];\r
715                 }\r
716                 $this->_pv_define_params_data .= $word;\r
717             } else {\r
718                 if (substr($this->_pv_define_params_data, 0, 1) ==\r
719                     substr($this->_pv_define_params_data,\r
720                         strlen($this->_pv_define_params_data) - 1) &&\r
721                     in_array(substr($this->_pv_define_params_data, 0, 1), \r
722                         array('"', "'"))\r
723                 ) {\r
724                     // remove leading and ending quotation marks \r
725                     // if there are only two\r
726                     $a = substr($this->_pv_define_params_data, 0, 1);\r
727                     $b = substr($this->_pv_define_params_data, 1, \r
728                         strlen($this->_pv_define_params_data) - 2);\r
729                     if (strpos($b, $a) === false) {\r
730                         $this->_pv_define_params_data = $b;\r
731                     }\r
732                 }\r
733                 $this->_pf_definename_isset = true;\r
734 \r
735                 $link = $this->_converter->getLink($this->_pv_define_params_data);\r
736                 foreach ($token_save as $token) {\r
737                     if (is_object($link)) {\r
738                         if (is_array($token)) {\r
739                             $token = $token[1];\r
740                         }\r
741                         $this->_addoutput($this->_converter->returnSee($link,\r
742                             $token));\r
743                     } else {\r
744                         $this->_addoutput($save, $token);\r
745                     }\r
746                 }\r
747                 $this->_pv_define_params_data = '';\r
748             }\r
749         }\r
750     }\r
751     \r
752     /**\r
753      * Handles normal global code.  Special consideration is taken for DocBlocks\r
754      * as they need to retrieve the whole DocBlock before doing any output, so\r
755      * the parser flag {@link $_pf_no_output_yet} is set to tell\r
756      * {@link _addoutput()} not to spit anything out yet.\r
757      *\r
758      * @uses _link() make any global code that is a documentable element link\r
759      *       to the php manual or its documentation\r
760      */\r
761     function handlePhpCode($word, $pevent)\r
762     {\r
763         $test = $this->checkEventPush($word, $pevent);\r
764         if ($test == PARSER_EVENT_DOCBLOCK || $test == PARSER_EVENT_COMMENT) {\r
765             if (substr($word[1], 0, 2) == '/*' && strpos($word[1], '*/')) {\r
766                 $this->_pv_last_word = $word;\r
767                 if ($word[1] == '/**#@-*/') {\r
768                     $this->_pf_docblock_template = true;\r
769                 } else {\r
770                     $this->_pf_docblock = true;\r
771                 }\r
772                 return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK);\r
773             }\r
774             $this->_pf_no_output_yet = true;\r
775             $this->_pv_saveline      = $this->_wp->linenum + 1;\r
776             return;\r
777         }\r
778         if (is_array($word) && $word[0] == T_DOUBLE_COLON) {\r
779             $this->_pf_colon_colon = true;\r
780         }\r
781         if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {\r
782             $this->_pv_last_string = $word;\r
783         }\r
784         $this->_link($word);\r
785         $this->checkEventPop($word, $pevent);\r
786     }\r
787     \r
788     /**\r
789      * Handle the function declaration header\r
790      *\r
791      * This handler only sees the "function name" portion of the function\r
792      * declaration.  Handling of the function parameters is by\r
793      * {@link handleFunctionParams()}, and the function body is handled by\r
794      * {@link handleLogicBlock()}\r
795      */\r
796     function handleFunction($word, $pevent)\r
797     {\r
798         if ($this->checkEventPush($word, $pevent)) {\r
799             $this->_addoutput($word);\r
800             return;\r
801         }\r
802         if ($this->checkEventPop($word, $pevent)) {\r
803             return;\r
804         }\r
805         $this->_link($word);\r
806     }\r
807     \r
808     /**\r
809      * Handle the method declaration header\r
810      *\r
811      * This handler only sees the "function name" portion of the method\r
812      * declaration.  Handling of the method parameters is by\r
813      * {@link handleFunctionParams()}, and the method body is handled by\r
814      * {@link handleMethodLogicBlock()}\r
815      */\r
816     function handleMethod($word, $pevent)\r
817     {\r
818         if ($this->checkEventPush($word, $pevent)) {\r
819             $this->_addoutput($word);\r
820             return;\r
821         }\r
822         if ($this->checkEventPop($word, $pevent)) {\r
823             if ($word == ';') {\r
824                 $this->_addoutput($word);\r
825             }\r
826             return;\r
827         }\r
828         $this->_methodlink($word);\r
829     }\r
830     \r
831     /**\r
832      * Handler for the stuff between ( and ) in a function declaration\r
833      *\r
834      * <code>\r
835      * function handles($only,$these,$parameters){...}\r
836      * </code>\r
837      */\r
838     function handleFunctionParams($word, $pevent)\r
839     {\r
840         if ($this->checkEventPush($word, $pevent)) {\r
841             $this->_addoutput($word);\r
842             return;\r
843         }\r
844         $this->_addoutput($word);\r
845         $this->checkEventPop($word, $pevent);\r
846     }\r
847     \r
848     /**\r
849      * Handler for function body.\r
850      *\r
851      * The function body is checked for php functions, documented constants,\r
852      * functions, and indirectly for global statements.  It hyperlinks to the\r
853      * documentation for detected elements is created.  Everything else is\r
854      * highlighted normally.\r
855      */\r
856     function handleLogicBlock($word, $pevent)\r
857     {\r
858         if ($this->checkEventPush($word, $pevent)) {\r
859             $this->_addoutput($word);\r
860             return;\r
861         }\r
862         if (is_array($word) && $word[0] == T_DOUBLE_COLON) {\r
863             $this->_pf_colon_colon = true;\r
864         }\r
865         if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {\r
866             $this->_pv_last_string = $word;\r
867         }\r
868         $this->_link($word);\r
869         if ($this->checkEventPop($word, $pevent)) {\r
870             $e = $this->_event_stack->popEvent();\r
871             $this->_event_stack->pushEvent($e);\r
872             if ($e == PARSER_EVENT_FUNCTION) {\r
873                 $this->_wp->backupPos($word); \r
874             }\r
875         }\r
876     }\r
877     \r
878     /**\r
879      * Handler for method body.\r
880      *\r
881      * Like functions, the method body is checked for php functions, documented\r
882      * constants, functions, and indirectly for global statements.  It also\r
883      * checks for "$this->XXXX" where XXXX is a class variable or method, and\r
884      * links to the documentation for detected elements is created.  Everything\r
885      * else is highlighted normally.\r
886      */\r
887     function handleMethodLogicBlock($word, $pevent)\r
888     {\r
889         if (isset($this->_pv_prev_var_type)) {\r
890             //debug('prevtype is set');\r
891             if (!is_array($word)) {\r
892                 unset($this->_pv_prev_var_type);\r
893             } else {\r
894                 if ($word[0] != T_WHITESPACE && \r
895                     $word[0] != T_STRING && $word[0] != T_OBJECT_OPERATOR\r
896                 ) {\r
897                     //fancy_debug('unset', $word);\r
898                     unset($this->_pv_prev_var_type);\r
899                 }\r
900             }\r
901         }\r
902         $this->_pf_inmethod = true;\r
903         if ($e = $this->checkEventPush($word, $pevent)) {\r
904             $this->_addoutput($word);\r
905             if ($e == PARSER_EVENT_CLASS_MEMBER) {\r
906                 $this->_pf_no_output_yet = true;\r
907             }\r
908             return;\r
909         }\r
910         if (is_array($word) && $word[0] == T_DOUBLE_COLON) {\r
911             $this->_pf_colon_colon = true;\r
912         }\r
913         if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {\r
914             $this->_pv_last_string = $word;\r
915         }\r
916         if (is_array($word) && $word[0] == T_VARIABLE) {\r
917             $this->_pv_lastvar = $word;\r
918         }\r
919         $this->_link($word);\r
920         if ($this->checkEventPop($word, $pevent)) {\r
921             $this->_pf_inmethod = false;\r
922             $e                  = $this->_event_stack->popEvent();\r
923             $this->_event_stack->pushEvent($e);\r
924             if ($e == PARSER_EVENT_METHOD) {\r
925                 $this->_wp->backupPos($word); \r
926             }\r
927         }\r
928     }\r
929     \r
930     /**\r
931      * Handles $obj->classmember in a method body\r
932      *\r
933      * This handler is responsible for linking to the documentation of a\r
934      * class member when it is used directly in a method body.\r
935      * \r
936      * There are two methods of determining whether to link:\r
937      * - $this->member\r
938      * - $this->member->submember\r
939      *\r
940      * The first case is handled by the $_pv_lastvar variable, and the\r
941      * second case is handled by the $_pv_prev_var_type variable.  $_pv_lastvar\r
942      * is always set to the value of the last T_VARIABLE token, if and only if\r
943      * no text has occurred between the variable and a T_OBJECT_OPERATOR token\r
944      * "->".  handleClassMember will only link if the last variable encountered\r
945      * was $this.\r
946      *\r
947      * When $this->variable is encountered, the variable is looked up to see\r
948      * if it can be found, and if so, the contents of its @var tag are processed\r
949      * to see if the member variable is defined to have 1 and only 1 class.\r
950      * If so, the $_pv_prev_var_type variable is set to this classname.  When\r
951      * submember is processed, the HighlightParser checks to see if \r
952      * $_pv_prev_var_type::submember() or $_pv_prev_var_type::$submember exists,\r
953      * and if it does, it is linked to.\r
954      */\r
955     function handleClassMember($word, $pevent)\r
956     {\r
957         if (!isset($this->_pv_lastvar) && !isset($this->_pv_prev_var_type)) {\r
958             //fancy_debug('returned from', $word, $this->_pv_prev_var_type);\r
959             $this->_pf_no_output_yet = false;\r
960             $this->_event_stack->popEvent();\r
961             return $this->defaultHandler($word, $pevent);\r
962         }\r
963         if (isset($this->_pv_cm_name)) {\r
964             $this->_pf_obj_op = false;\r
965             $name             = $this->_pv_cm_name;\r
966             unset($this->_pv_cm_name);\r
967             //debug('unset pvcmname');\r
968             $this->_event_stack->popEvent();\r
969             // control variable for _pv_prev_var_type\r
970             $setnow = false;\r
971             if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') ||\r
972                 isset($this->_pv_prev_var_type)\r
973             ) {\r
974                 if (is_array($word) && $word[0] == T_WHITESPACE) {\r
975                     // preserve value of _pv_prev_var_type\r
976                     $setnow = true;\r
977                     $save   = $this->_wp->nextToken();\r
978                     $temp   = $this->_wp->getWord();\r
979                     $this->_wp->backupPos($save, true);\r
980                 }\r
981                 if ((is_string($word) && $word == '(') || (isset($temp) && \r
982                     is_string($temp) && $temp == '(')\r
983                 ) {\r
984                     // it's a function\r
985                     $this->_pf_no_output_yet = false;\r
986                     $this->_methodlink($name);\r
987                     unset($this->_pv_prev_var_type);\r
988                 } else {\r
989                     // it's a variable\r
990                     //fancy_debug('name is ', $name);\r
991                     $this->_pf_no_output_yet = false;\r
992                     $this->_varlink($name, true);\r
993                     $templink = \r
994                         $this->_converter->getLink('object ' . $this->_pv_class);\r
995                     $class    = false;\r
996                     if (is_object($templink)) {\r
997                         $class = $this->_converter->classes\r
998                             ->getClass($templink->name, $templink->path);\r
999                     }\r
1000                     if ($class) {\r
1001                         $varname = $name;\r
1002                         if (is_array($varname)) {\r
1003                             $varname = $name[1];\r
1004                         }\r
1005                         if ($varname{0} != '$') {\r
1006                             $varname = '$'.$varname;\r
1007                         }\r
1008                         $var = $class->getVar($this->_converter, $varname);\r
1009                         \r
1010                         if (is_object($var) && $var->docblock->var) {\r
1011                             $type = $var->docblock->var->returnType;\r
1012                         }\r
1013                         if (isset($type)) {\r
1014                             if (strpos($type, 'object') === false) {\r
1015                                 $type = 'object '.$type;\r
1016                             }\r
1017                             $type = $this->_converter->getLink($type);\r
1018                             if (phpDocumentor_get_class($type) == 'classlink') {\r
1019                                 // the variable's type is a class, \r
1020                                 // save it for future ->\r
1021                                 //fancy_debug('set prev_var_type!', $type->name);\r
1022                                 $setnow                  = true;\r
1023                                 $this->_pv_prev_var_type = $type->name;\r
1024                             } else {\r
1025                                 unset($this->_pv_prev_var_type);\r
1026                             }\r
1027                         } else {\r
1028                             unset($this->_pv_prev_var_type);\r
1029                         }\r
1030                     } else {\r
1031                         unset($this->_pv_prev_var_type);\r
1032                     }\r
1033                 }\r
1034             } else {\r
1035                 $this->_pf_no_output_yet = false;\r
1036                 // this does NewLinenum if necessary\r
1037                 $this->_wp->backupPos($word);\r
1038                 $this->_wp->getWord();\r
1039                 $this->_addoutput($name);\r
1040             }\r
1041             if (!$setnow) {\r
1042                 //debug('unset prevtype, no setnow');\r
1043                 unset($this->_pv_prev_var_type);\r
1044             }\r
1045             unset($this->_pv_lastvar);\r
1046             $this->_pf_no_output_yet = false;\r
1047             // this does NewLinenum if necessary\r
1048             $this->_wp->backupPos($word);\r
1049             $this->_wp->getWord();\r
1050             if ($word[0] == T_OBJECT_OPERATOR) {\r
1051                 $this->_wp->backupPos($word);\r
1052             } else {\r
1053                 $this->_addoutput($word);\r
1054             }\r
1055             return;\r
1056         }\r
1057         if (!$this->_pf_obj_op && is_array($this->_pv_last_word) && \r
1058             $this->_pv_last_word[0] == T_OBJECT_OPERATOR\r
1059         ) {\r
1060             if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') ||\r
1061                 isset($this->_pv_prev_var_type)\r
1062             ) {\r
1063                 $this->_pf_obj_op = true;\r
1064             } else {\r
1065                 $this->_pf_no_output_yet = false;\r
1066                 // this does NewLinenum if necessary\r
1067                 $this->_wp->backupPos($word);\r
1068                 $this->_wp->getWord();\r
1069                 $this->_addoutput($word);\r
1070                 $this->_event_stack->popEvent();\r
1071             }\r
1072         }\r
1073         if (is_array($word) && $word == T_WHITESPACE) {\r
1074             $this->_pf_no_output_yet = false;\r
1075             // this does NewLinenum if necessary\r
1076             $this->_wp->backupPos($word);\r
1077             $this->_wp->getWord();\r
1078             $this->_addoutput($word);\r
1079             return;\r
1080         }\r
1081         if ($this->_pf_obj_op) {\r
1082             if (!(is_array($word) && ($word[0] == T_STRING || \r
1083                 $word[0] == T_WHITESPACE))\r
1084             ) {\r
1085                 unset($this->_pv_lastvar);\r
1086                 //debug('unset lastvar');\r
1087                 $this->_event_stack->popEvent();\r
1088                 $this->_pf_no_output_yet = false;\r
1089                 // this does NewLinenum if necessary\r
1090                 $this->_wp->backupPos($word);\r
1091                 $this->_wp->getWord();\r
1092                 $this->_addoutput($word);\r
1093                 return;\r
1094             }\r
1095             if ($word[0] == T_STRING) {\r
1096                 //fancy_debug('set pvcmname to', $word);\r
1097                 $this->_pv_cm_name = $word;\r
1098             } else {\r
1099                 $this->_pf_no_output_yet = false;\r
1100                 // this does NewLinenum if necessary\r
1101                 $this->_wp->backupPos($word);\r
1102                 $this->_wp->getWord();\r
1103                 $this->_addoutput($word);\r
1104             }\r
1105         }\r
1106     }\r
1107     \r
1108     /**\r
1109      * Handles comments\r
1110      *\r
1111      * Comments are almost always single-line tokens, and so will be\r
1112      * in the last word.  This handler checks to see if the current token\r
1113      * is in fact a comment, and if it isn't, it backs up and returns control\r
1114      * to the parent event handler with that word.\r
1115      */\r
1116     function handleComment($word, $pevent)\r
1117     {\r
1118         $w = $this->_pv_last_word;\r
1119         // don't perform this check if this is a normal comment.  Docblocks\r
1120         // have the _pf_no_output_yet variable set to true\r
1121         if ($this->_pf_no_output_yet && is_array($w) && \r
1122             (in_array($w[0], array(T_COMMENT, T_DOC_COMMENT)) && \r
1123             strpos($w[1], '/**') === 0)\r
1124         ) {\r
1125             $this->_event_stack->popEvent();\r
1126             $this->_event_stack->pushEvent(PARSER_EVENT_DOCBLOCK);\r
1127             return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK);\r
1128         }\r
1129         if ($this->_pf_no_output_yet) {\r
1130             $flag                    = 1;\r
1131             $this->_pf_no_output_yet = false;\r
1132             $this->_addoutput($this->_pv_last_word);\r
1133         }\r
1134         if (!is_array($word) || \r
1135             !in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) ||\r
1136             (in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) && \r
1137             strpos($word[1], '/**') === 0)\r
1138         ) {\r
1139             $this->_event_stack->popEvent();\r
1140             if (strpos($this->_pv_last_word[1], "\n") !== false) {\r
1141                 //$this->_wp->linenum++;\r
1142                 //$this->newLineNum();\r
1143             }\r
1144             $this->_wp->backupPos($this->_pv_last_word);\r
1145             $this->_wp->getWord();\r
1146             //var_dump($this->_wp->nextToken());\r
1147             return;\r
1148         } elseif (isset($flag)) {\r
1149             $this->newLineNum();\r
1150         }\r
1151         $this->_addoutput($word);\r
1152         $this->checkEventPop($word, $pevent);\r
1153         if (strpos($word[1], '*/') === strlen($word[1]) - 2) {\r
1154             $this->_event_stack->popEvent();\r
1155         }\r
1156     }\r
1157     \r
1158     /**\r
1159      * Handle class declarations\r
1160      *\r
1161      * Handles the initial declaration line:\r
1162      *\r
1163      * <code>class X</code>\r
1164      * \r
1165      * or\r
1166      * \r
1167      * <code>class X extends Y implements I</code>\r
1168      *\r
1169      * @uses _classlink() to link to documentation for X and for Y class in\r
1170      *                    "class X extends Y"\r
1171      */\r
1172     function handleClass($word, $pevent)\r
1173     {\r
1174         $this->_pf_in_class = true;\r
1175         $a                  = $this->checkEventPush($word, $pevent);\r
1176 \r
1177         if (!isset($this->_pv_class) && is_array($word) && $word[0] == T_STRING) {\r
1178             $this->_pv_class = $this->_converter->class = $word[1];\r
1179             $this->_classlink($word);\r
1180             return;\r
1181         }\r
1182         \r
1183         if (is_array($word) && \r
1184             in_array($word[0], array(T_PRIVATE, T_PROTECTED, T_PUBLIC))\r
1185         ) {\r
1186             $starttok = $this->_wp->nextToken();\r
1187             $test     = array(T_WHITESPACE);\r
1188             while ($test && $test[0] == T_WHITESPACE) {\r
1189                 $tok  = $this->_wp->nextToken();\r
1190                 $test = $this->_wp->getWord();\r
1191             } // while\r
1192             \r
1193             if (is_array($test) && $test[0] == T_VARIABLE) {\r
1194                 $this->_wp->backupPos($tok, true);\r
1195                 return;\r
1196             }\r
1197             $this->_wp->backupPos($starttok, true);\r
1198         }\r
1199         \r
1200         if (@in_array($this->_pv_last_word[0], \r
1201             array(T_PRIVATE, T_PROTECTED, T_PUBLIC))\r
1202         ) {\r
1203             if (is_array($word) && $word[0] == T_VARIABLE) {\r
1204                 $this->_wp->backupPos($this->_pv_last_word);\r
1205                 $this->_event_stack->pushEvent(PARSER_EVENT_VAR);\r
1206                 return;\r
1207             }\r
1208         }\r
1209 \r
1210         if ($this->_pf_extends_found && is_array($word) && $word[0] == T_STRING) {\r
1211             $this->_classlink($word);\r
1212             return;\r
1213         }\r
1214         if (is_array($word) && $word[0] == T_EXTENDS) {\r
1215             $this->_pf_extends_found = true;\r
1216         }\r
1217         if ($a == PARSER_EVENT_DOCBLOCK) {\r
1218             $this->_pf_no_output_yet = true;\r
1219             $this->_pv_saveline      = $this->_wp->linenum + 1;\r
1220             return;\r
1221         }\r
1222         $this->_addoutput($word);\r
1223         if ($this->checkEventPop($word, $pevent)) {\r
1224             $this->_pf_in_class = false;\r
1225             unset($this->_pv_class);\r
1226         }\r
1227     }\r
1228     \r
1229     /**\r
1230      * Handles class variable declaration\r
1231      *\r
1232      * <code>\r
1233      * class X\r
1234      * {\r
1235      *     var $Y;\r
1236      * }\r
1237      * </code>\r
1238      *\r
1239      * @uses _varlink() make a link to $Y documentation in class variable\r
1240      *                  declaration "var $Y;"\r
1241      */\r
1242     function handleVar($word, $pevent)\r
1243     {\r
1244         if ($this->checkEventPush($word, $pevent)) {\r
1245             $this->_addoutput($word);\r
1246             return;\r
1247         }\r
1248         if (is_array($word) && $word[0] == T_VARIABLE) {\r
1249             return $this->_varlink($word);\r
1250         }\r
1251         $this->_addoutput($word);\r
1252         $this->checkEventPop($word, $pevent);\r
1253     }\r
1254     \r
1255     /**\r
1256      * This handler is responsible for highlighting DocBlocks\r
1257      *\r
1258      * handleDocBlock determines whether the docblock is normal or a template,\r
1259      * and gathers all the lines of the docblock together before doing any\r
1260      * processing\r
1261      *\r
1262      * As it is not possible to distinguish any comment token from a docblock\r
1263      * token, this handler is also called for comments, and will pass control\r
1264      * to {@link handleComment()} if the comment is not a DocBlock\r
1265      *\r
1266      * @uses commonDocBlock() once all lines of the DocBlock have been retrieved\r
1267      */\r
1268     function handleDocBlock($word, $pevent)\r
1269     {\r
1270         if (!($this->_pf_docblock || $this->_pf_docblock_template)) {\r
1271             if (strpos($this->_pv_last_word[1], '/**') !== 0) {\r
1272                 // not a docblock\r
1273                 $this->_wp->backupPos($this->_pv_last_word);\r
1274                 $this->_event_stack->popEvent();\r
1275                 $this->_event_stack->pushEvent(PARSER_EVENT_COMMENT);\r
1276                 $this->_pf_no_output_yet = false;\r
1277                 return;\r
1278             } else {\r
1279                 $this->_pf_no_output_yet = true;\r
1280                 $this->_pv_db_lines      = array();\r
1281             }\r
1282         }\r
1283         $last_word = $this->_pv_last_word[1];\r
1284         $dtype     = '_pv_docblock';\r
1285         if ($last_word == '/**#@-*/') {\r
1286             // stop using docblock template\r
1287             $this->_pf_no_output_yet = false;\r
1288             $this->_addDocBlockoutput('closetemplate', $last_word);\r
1289             if ($this->_pv_next_word !== false) {\r
1290                 $this->_wp->backupPos($this->_pv_next_word, true);\r
1291             }\r
1292             $this->_event_stack->popEvent();\r
1293             return;\r
1294         }\r
1295         if (!($this->_pf_docblock || $this->_pf_docblock_template)) {\r
1296             $this->_pv_db_lines = array();\r
1297             if (strpos($last_word, '/**#@+') === 0) {\r
1298                 // docblock template definition\r
1299                 $this->_pf_docblock_template = true;\r
1300             } else {\r
1301                 $this->_pf_docblock = true;\r
1302             }\r
1303             $this->_pv_db_lines[] = $last_word;\r
1304             if (strpos($last_word, '*/') !== false) {\r
1305                 $this->commonDocBlock();\r
1306                 return;\r
1307             }\r
1308             $this->_pv_db_lines[] = $word[1];\r
1309             if (strpos($word[1], '*/') !== false) {\r
1310                 $this->commonDocBlock();\r
1311             }\r
1312         } else {\r
1313             $this->_pv_db_lines[] = $word[1];\r
1314         }\r
1315         if (($this->_pf_docblock || $this->_pf_docblock_template) && \r
1316             (strpos($word[1], '*/') !== false)\r
1317         ) {\r
1318             $this->commonDocBlock();\r
1319         }\r
1320     }\r
1321     /**#@-*/\r
1322 \r
1323     /**\r
1324      * This continuation of handleDocBlock splits DocBlock comments up into\r
1325      * phpDocumentor tokens.  It highlights DocBlock templates in a different\r
1326      * manner from regular DocBlocks, recognizes inline tags, regular tags,\r
1327      * and distinguishes between standard core tags and other tags, and\r
1328      * recognizes parameters to tags like @var.\r
1329      *\r
1330      * the type in "@var type description" will be highlighted as a php type,\r
1331      * and the var in "@param type $var description" will be highlighted as a\r
1332      * php variable.\r
1333      *\r
1334      * @return void\r
1335      * @uses handleDesc() highlight inline tags in the description\r
1336      * @uses handleTags() highlight all tags\r
1337      * @access private\r
1338      */\r
1339     function commonDocBlock()\r
1340     {\r
1341         $this->_event_stack->popEvent();\r
1342         $lines = $this->_pv_db_lines;\r
1343         $go    = count($this->_pv_db_lines);\r
1344         for ($i=0; $i < $go; $i++) {\r
1345             if (substr(trim($lines[$i]), 0, 2) == '*/' || \r
1346                 substr(trim($lines[$i]), 0, 1) != '*' && \r
1347                 substr(trim($lines[$i]), 0, 3) != '/**'\r
1348             ) {\r
1349                 $lines[$i] = array($lines[$i], false);\r
1350             } elseif (substr(trim($lines[$i]), 0, 3) == '/**') {\r
1351                 $linesi = array();\r
1352                 // remove leading "/**"\r
1353                 $linesi[1] = substr(trim($lines[$i]), 3);\r
1354                 if (empty($linesi[1])) {\r
1355                     $linesi[0] = $lines[$i];\r
1356                 } else {\r
1357                     $linesi[0] = \r
1358                         substr($lines[$i], 0, strpos($lines[$i], $linesi[1]));\r
1359                 }\r
1360                 $lines[$i] = $linesi;\r
1361             } else {\r
1362                 $linesi = array();\r
1363                 // remove leading "* "\r
1364                 $linesi[1] = substr(trim($lines[$i]), 1);\r
1365                 if (empty($linesi[1])) {\r
1366                     $linesi[0] = $lines[$i];\r
1367                 } else {\r
1368                     $linesi[0] = \r
1369                         substr($lines[$i], 0, strpos($lines[$i], $linesi[1]));\r
1370                 }\r
1371                 $lines[$i] = $linesi;\r
1372             }\r
1373         }\r
1374         for ($i = 0; $i < count($lines); $i++) {\r
1375             if ($lines[$i][1] === false) {\r
1376                 continue;\r
1377             }\r
1378             if (substr(trim($lines[$i][1]), 0, 1) == '@' && \r
1379                 substr(trim($lines[$i][1]), 0, 2) != '@ '\r
1380             ) {\r
1381                 $tagindex = $i;\r
1382                 $i        = count($lines);\r
1383             }\r
1384         }\r
1385         if (isset($tagindex)) {\r
1386             $tags = array_slice($lines, $tagindex);\r
1387             $desc = array_slice($lines, 0, $tagindex);\r
1388         } else {\r
1389             $tags = array();\r
1390             $desc = $lines;\r
1391         }\r
1392         //var_dump($desc, $tags);\r
1393         $this->_pf_no_output_yet = false;\r
1394         $save                    = $this->_wp->linenum;\r
1395         $this->_wp->linenum      = $this->_pv_saveline;\r
1396         $this->handleDesc($desc);\r
1397         $this->handleTags($tags);\r
1398         $this->_pv_db_lines = array();\r
1399         $this->_wp->linenum = $save;\r
1400         if (strpos($this->_pv_last_word[1], '*/') !== false) {\r
1401             $this->_wp->backupPos($this->_pv_next_word, true);\r
1402         }\r
1403         $this->_pf_docblock = $this->_pf_docblock_template = false;\r
1404     }\r
1405     \r
1406     /**\r
1407      * Handle the description area of a DocBlock\r
1408      *\r
1409      * This method simply finds inline tags and highlights them\r
1410      * separately from the rest of the description.\r
1411      *\r
1412      * @param mixed $desc the description piece(s)\r
1413      *\r
1414      * @return void\r
1415      * @uses getInlineTags()\r
1416      * @access private\r
1417      */\r
1418     function handleDesc($desc)\r
1419     {\r
1420         $dbtype  = 'docblock';\r
1421         $dbtype .= ($this->_pf_docblock ? '' : 'template');\r
1422         foreach ($desc as $line) {\r
1423             $this->getInlineTags($line[0] . $line[1]);\r
1424             if (strpos($line[0], '*/') === false &&\r
1425                 !(substr($line[0], 0, 2) == '/*' && \r
1426                 strpos($line[1], '*/') !== false)\r
1427             ) {\r
1428                 $this->newLineNum();\r
1429                 $this->_wp->linenum++;\r
1430             }\r
1431         }\r
1432         if ($this->_pf_internal) {\r
1433             $this->_pf_internal = false;\r
1434         }\r
1435     }\r
1436     \r
1437     /**\r
1438      * Handle phpDocumentor tags in a DocBlock\r
1439      *\r
1440      * This method uses the {@link $tagHandlers} array to determine which\r
1441      * method will handle tags found in the docblock, and passes the data to\r
1442      * the individual handlers one by one\r
1443      *\r
1444      * @param array $tags array of tags to handle\r
1445      *\r
1446      * @return void\r
1447      * @access private\r
1448      */\r
1449     function handleTags($tags)\r
1450     {\r
1451         $newtags = array();\r
1452         $curtag  = array();\r
1453         for ($i=0; $i < count($tags); $i++) {\r
1454             $tagsi = trim($tags[$i][1]);\r
1455             if (substr($tagsi, 0, 1) == '@' && substr($tagsi, 0, 2) != '@ ') {\r
1456                 // start a new tag\r
1457                 $tags[$i][1] = array(substr($tags[$i][1], 0, \r
1458                     strpos($tags[$i][1], $tagsi)), $tagsi);\r
1459                 if (!empty($curtag)) {\r
1460                     $newtags[] = $curtag;\r
1461                     $curtag    = array();\r
1462                 }\r
1463                 $curtag[] = $tags[$i];\r
1464             } else {\r
1465                 $curtag[] = $tags[$i];\r
1466             }\r
1467         }\r
1468         if (!empty($curtag)) {\r
1469             $newtags[] = $curtag;\r
1470         }\r
1471         foreach ($newtags as $tag) {\r
1472             foreach ($tag as $i => $t) {\r
1473                 if ($t[1] === false) {\r
1474                     continue;\r
1475                 }\r
1476                 if (is_array($t[1])) {\r
1477                     $tag[$i][1][1]\r
1478                         = explode(" ", str_replace("\t", '    ', $t[1][1]));\r
1479                     $x = $tag[$i][1][1];\r
1480                 }\r
1481             }\r
1482             $tagname   = substr(array_shift($x), 1);\r
1483             $restoftag = $tag;\r
1484             if (isset($this->tagHandlers[$tagname])) {\r
1485                 $handle = $this->tagHandlers[$tagname];\r
1486             } else {\r
1487                 $handle = $this->tagHandlers['*'];\r
1488             }\r
1489             $this->$handle($tagname, $restoftag);\r
1490         }\r
1491     }\r
1492     \r
1493     /**\r
1494      * This handler recognizes all {@}inline} tags\r
1495      *\r
1496      * Normal inline tags are simply highlighted.  the {@}internal}} inline\r
1497      * tag {@tutorial tags.inlineinternal.pkg} is highlighted differently\r
1498      * to distinguish it from other inline tags.\r
1499      *\r
1500      * @param mixed $value       the tag value\r
1501      * @param bool  $endinternal indicates the end of an @internal tag\r
1502      *\r
1503      * @return void\r
1504      * @access private\r
1505      */\r
1506     function getInlineTags($value, $endinternal = false)\r
1507     {\r
1508         if (!$value) {\r
1509             return;\r
1510         }\r
1511         if ($this->_pf_internal && !$endinternal) {\r
1512             if (strpos($value, '}}') !== false) {\r
1513                 $x = strrpos($value, '}}');\r
1514                 // add the rest of internal\r
1515                 $this->getInlineTags(substr($value, 0, $x + 3), true);\r
1516                 // strip internal from value\r
1517                 $value = substr($value, strrpos($value, '}}') + 1);\r
1518                 // turn off internal\r
1519                 $this->_pf_internal = false;\r
1520             }\r
1521         }\r
1522         if (!$value) {\r
1523             return;\r
1524         }\r
1525         $dbtype  = 'docblock';\r
1526         $dbtype .= ($this->_pf_docblock ? '' : 'template');\r
1527         $save    = $value;\r
1528         $value   = explode('{@', $value);\r
1529         $newval  = array();\r
1530         // everything before the first {@ is normal text\r
1531         $this->_addDocBlockoutput($dbtype, $value[0]);\r
1532         for ($i=1; $i < count($value); $i++) {\r
1533             if (substr($value[$i], 0, 1) == '}') {\r
1534                 $this->_addDocBlockoutput($dbtype, '{@}' . substr($value[$i], 1));\r
1535             } else {\r
1536                 $save      = $value[$i];\r
1537                 $value[$i] = str_replace("\t", "    ", $value[$i]);\r
1538                 $value[$i] = explode(" ", $value[$i]);\r
1539                 $word      = array_shift($value[$i]);\r
1540                 $val       = join(' ', $value[$i]);\r
1541                 if ($word == 'internal') {\r
1542                     $this->_pf_internal = true;\r
1543                     $this->_addDocBlockoutput($dbtype, '{@internal ');\r
1544                     $value[$i] = substr($save, strlen('internal') + 1);\r
1545                     // strip internal and cycle as if it were normal text.\r
1546                     $this->_addDocBlockoutput($dbtype, $value[$i]);\r
1547                     continue;\r
1548                 }\r
1549                 if (in_array(str_replace('}', '', $word), $this->allowableInlineTags)\r
1550                 ) {\r
1551                     if (strpos($word, '}')) {\r
1552                         $word = str_replace('}', '', $word);\r
1553                         $val  = '} ' . $val;\r
1554                     }\r
1555                     $val = explode('}', $val);\r
1556                     if (count($val) == 1) {\r
1557                          //addError(PDERROR_UNTERMINATED_INLINE_TAG,\r
1558                          //    $word, '', $save);\r
1559                     }\r
1560                     $rest = $val;\r
1561                     $val  = array_shift($rest);\r
1562                     if ($endinternal) {\r
1563                         $rest = join('}', $rest);\r
1564                     } else {\r
1565                         $rest = join(' ', $rest);\r
1566                     }\r
1567                     if (isset($this->inlineTagHandlers[$word])) {\r
1568                         $handle = $this->inlineTagHandlers[$word];\r
1569                     } else {\r
1570                         $handle = $this->inlineTagHandlers['*'];\r
1571                     }\r
1572                     $this->$handle($word, $val);\r
1573                     $this->_addDocBlockoutput($dbtype, $rest);\r
1574                 } else {\r
1575                     $val = $word . ' ' . $val;\r
1576                     $this->_addDocBlockoutput($dbtype, '{@' . $val);\r
1577                 }\r
1578             }\r
1579         }\r
1580     }\r
1581 \r
1582     \r
1583     /**\r
1584      * Handles all inline tags\r
1585      *\r
1586      * @param string $name  the tag name\r
1587      * @param mixed  $value the tag value\r
1588      *\r
1589      * @return void\r
1590      * @access private\r
1591      */\r
1592     function handleDefaultInlineTag($name, $value)\r
1593     {\r
1594         $this->_addDocBlockoutput('inlinetag', '{@' . $name . ' ' . $value . '}');\r
1595     }\r
1596 \r
1597     /**#@+\r
1598      * phpDocumentor DocBlock tag handlers\r
1599      *\r
1600      * @param string $name    tag name\r
1601      * @param array  $value   array of lines contained in the tag description\r
1602      *\r
1603      * @return void\r
1604      * @access private\r
1605      */\r
1606     /**\r
1607      * Handle normal tags\r
1608      *\r
1609      * This handler adds to outpu all comment information before the tag begins\r
1610      * as in " * " before "@todo" in " * @todo"\r
1611      *\r
1612      * Then, it highlights the tag as a regular or coretag based on $coretag.\r
1613      * Finally, it uses getInlineTags to highlight the description\r
1614      *\r
1615      * @param bool $coretag whether this tag is a core tag or not\r
1616      *\r
1617      * @uses getInlineTags() highlight a tag description\r
1618      */\r
1619     function defaultTagHandler($name, $value, $coretag = false)\r
1620     {\r
1621         $dbtype  = 'docblock';\r
1622         $dbtype .= ($this->_pf_docblock ? '' : 'template');\r
1623         foreach ($value as $line) {\r
1624             $this->_addDocBlockoutput($dbtype, $line[0]);\r
1625             if ($line[1] === false) {\r
1626                 if (trim($line[0]) != '*/') {\r
1627                     $this->newLineNum();\r
1628                     $this->_wp->linenum++;\r
1629                 }\r
1630                 continue;\r
1631             }\r
1632             $this->_addDocBlockoutput($dbtype, $line[1][0]);\r
1633             $stored = '';\r
1634             if (is_array($line[1][1])) {\r
1635                 foreach ($line[1][1] as $i => $tpart) {\r
1636                     if ($tpart == '@' . $name && $i == 0) {\r
1637                         $tagname = 'tag';\r
1638                         if ($coretag) {\r
1639                             $tagname = 'coretag';\r
1640                         }\r
1641                         $this->_addDocBlockoutput($tagname, '@' . $name);\r
1642                         continue;\r
1643                     }\r
1644                     $stored .= ' ' . $tpart;\r
1645                 }\r
1646             } else {\r
1647                 $stored = $line[1];\r
1648             }\r
1649             $this->getInlineTags($stored);\r
1650             if (strpos($stored, '*/') === false) {\r
1651                 $this->newLineNum();\r
1652                 $this->_wp->linenum++;\r
1653             }\r
1654         }\r
1655     }\r
1656     \r
1657     /**\r
1658      * main handler for "core" tags\r
1659      *\r
1660      * @see defaultTagHandler()\r
1661      */\r
1662     function coreTagHandler($name, $value)\r
1663     {\r
1664         return $this->defaultTagHandler($name, $value, true);\r
1665     }\r
1666     \r
1667     /**\r
1668      * Handles @global\r
1669      *\r
1670      * This handler works like {@link defaultTagHandler()} except it highlights\r
1671      * the type and variable (if present) in "@global type $variable" or\r
1672      * "@global type description"\r
1673      */\r
1674     function globalTagHandler($name, $value)\r
1675     {\r
1676         $this->paramTagHandler($name, $value);\r
1677     }\r
1678     \r
1679     /**\r
1680      * Handles @param\r
1681      *\r
1682      * This handler works like {@link defaultTagHandler()} except it highlights\r
1683      * the type and variable (if present) in "@param type $variable description"\r
1684      * or "@param type description"\r
1685      *\r
1686      * @param bool $checkforvar private parameter, checks for $var or not\r
1687      */\r
1688     function paramTagHandler($name, $value, $checkforvar = true)\r
1689     {\r
1690         $dbtype  = 'docblock';\r
1691         $dbtype .= ($this->_pf_docblock ? '' : 'template');\r
1692         $ret     = $this->retrieveType($value, 0, $checkforvar);\r
1693         foreach ($value as $num => $line) {\r
1694             $this->_addDocBlockoutput($dbtype, $line[0]);\r
1695             if ($line[1] === false) {\r
1696                 if (trim($line[0]) != '*/') {\r
1697                     $this->newLineNum();\r
1698                     $this->_wp->linenum++;\r
1699                 }\r
1700                 continue;\r
1701             }\r
1702             $this->_addDocBlockoutput($dbtype, $line[1][0]);\r
1703             $stored  = '';\r
1704             $typeloc = 1;\r
1705             $varloc  = 2;\r
1706             if (is_array($line[1][1])) {\r
1707                 $this->_addDocBlockoutput('coretag', '@' . $name . ' ');\r
1708                 foreach ($ret[0] as $text) {\r
1709                     if (is_string($text)) {\r
1710                         $this->_addDocBlockoutput($dbtype, $text);\r
1711                     }\r
1712                     if (is_array($text)) {\r
1713                         if ($text[0] != 'desc') {\r
1714                             $this->_addDocBlockoutput($text[0], $text[1]);\r
1715                         } else {\r
1716                             $stored .= $text[1];\r
1717                         }\r
1718                     }\r
1719                 }\r
1720             } else {\r
1721                 if (isset($ret[$num])) {\r
1722                     foreach ($ret[$num] as $text) {\r
1723                         if (is_string($text)) {\r
1724                             $this->_addDocBlockoutput($dbtype, $text);\r
1725                         }\r
1726                         if (is_array($text)) {\r
1727                             if ($text[0] != 'desc') {\r
1728                                 $this->_addDocBlockoutput($text[0], $text[1]);\r
1729                             } else {\r
1730                                 $stored .= $text[1];\r
1731                             }\r
1732                         }\r
1733                     }\r
1734                 } else {\r
1735                     $stored = $line[1];\r
1736                 }\r
1737             }\r
1738             $this->getInlineTags($stored);\r
1739             if (strpos($stored, '*/') === false) {\r
1740                 $this->newLineNum();\r
1741                 $this->_wp->linenum++;\r
1742             }\r
1743         }\r
1744     }\r
1745     \r
1746     /**\r
1747      * handles the @staticvar tag\r
1748      *\r
1749      * @see paramTagHandler()\r
1750      */\r
1751     function staticvarTagHandler($name, $value)\r
1752     {\r
1753         return $this->paramTagHandler($name, $value);\r
1754     }\r
1755     \r
1756     /**\r
1757      * handles the @var tag\r
1758      *\r
1759      * @see paramTagHandler()\r
1760      */\r
1761     function varTagHandler($name, $value)\r
1762     {\r
1763         return $this->paramTagHandler($name, $value);\r
1764     }\r
1765     \r
1766     /**\r
1767      * Handles @return\r
1768      *\r
1769      * This handler works like {@link defaultTagHandler()} except it highlights\r
1770      * the type in "@return type description"\r
1771      */\r
1772     function returnTagHandler($name, $value)\r
1773     {\r
1774         $this->paramTagHandler($name, $value, false);\r
1775     }\r
1776 \r
1777     /**\r
1778      * Handles @property(-read or -write) and @method magic tags\r
1779      */\r
1780     function propertyTagHandler($name, $value)\r
1781     {\r
1782         return $this->paramTagHandler($name, $value, true);\r
1783     }\r
1784 \r
1785     /**#@-*/\r
1786     \r
1787     /**\r
1788      * Retrieve the type portion of a @tag type description\r
1789      *\r
1790      * Tags like @param, @return and @var all have a PHP type portion in their\r
1791      * description.  Since the type may contain the expression "object blah"\r
1792      * where blah is a classname, it makes parsing out the type field complex.\r
1793      *\r
1794      * Even more complicated is the case where a tag variable can contain\r
1795      * multiple types, such as object blah|object blah2|false, and so this\r
1796      * method handles these cases.\r
1797      *\r
1798      * @param array $value       array of words that were separated by spaces\r
1799      * @param 0|1   $state       0 = find the type, 1 = find the var, if present\r
1800      * @param bool  $checkforvar flag to determine whether to check for the end of a\r
1801      *                           type is defined by a $varname\r
1802      *\r
1803      * @return array Format: array(state (0 [find type], 1 [var], 2 [done]),\r
1804      * @access private\r
1805      */\r
1806     function retrieveType($value, $state = 0, $checkforvar = false)\r
1807     {\r
1808         $index  = 0;\r
1809         $result = array();\r
1810         do {\r
1811             if (!isset($value[$index][1])) {\r
1812                 return $result;\r
1813             }\r
1814             $val = $value[$index][1];\r
1815             if (empty($val)) {\r
1816                 return $result;\r
1817             }\r
1818             if ($index == 0) {\r
1819                 $val = $val[1];\r
1820                 array_shift($val);\r
1821             } else {\r
1822                 $val = explode(' ', $val);\r
1823             }\r
1824             $ret              = $this->_retrieveType($val, $state, $checkforvar);\r
1825             $state            = $ret[0];\r
1826             $result[$index++] = $ret[1];\r
1827         } while ((!$checkforvar && $state < 1) || ($state < 2 && $checkforvar));\r
1828         return $result;\r
1829     }\r
1830 \r
1831     /**\r
1832      * used by {@link retrieveType()} in its work\r
1833      *\r
1834      * @param array $value       array of words that were separated by spaces\r
1835      * @param 0|1   $state       0 = find the type, 1 = find the var, if present\r
1836      * @param bool  $checkforvar flag to determine whether to check for the end of a\r
1837      *                           type is defined by a $varname\r
1838      *\r
1839      * @return array \r
1840      * @access private\r
1841      */    \r
1842     function _retrieveType($value, $state, $checkforvar)\r
1843     {\r
1844         $result   = array();\r
1845         $result[] = $this->_removeWhiteSpace($value, 0);\r
1846         if ($state == 0) {\r
1847             if (!count($value)) {\r
1848                 return array(2, $result);\r
1849             }\r
1850             $types = '';\r
1851             $index = 0;\r
1852             if (trim($value[0]) == 'object') {\r
1853                 $result[] = array('tagphptype', $value[0] . ' ');\r
1854                 $types   .= array_shift($value).' ';\r
1855                 $result[] = $this->_removeWhiteSpace($value, 0);\r
1856                 if (!count($value)) {\r
1857                     // was just passed "object"\r
1858                     return array(2, $result);\r
1859                 }\r
1860                 if ($value[0]{0} == '$' || substr($value[0], 0, 2) == '&$') {\r
1861                     // was just passed "object"\r
1862                     // and the next thing is a variable name\r
1863                     if ($checkforvar) {\r
1864                         $result[] = array('tagvarname' , $value[0] . ' ');\r
1865                         array_shift($value);\r
1866                     }\r
1867                     $result[] = array('desc', join(' ', $value));\r
1868                     return array(2, $result);\r
1869                 }\r
1870             }\r
1871             $done = false;\r
1872             $loop = -1;\r
1873             do {\r
1874                 // this loop checks for type|type|type and for\r
1875                 // type|object classname|type|object classname2\r
1876                 if (strpos($value[0], '|')) {\r
1877                     $temptypes = explode('|', $value[0]);\r
1878                     while (count($temptypes)) {\r
1879                         $type     = array_shift($temptypes);\r
1880                         $result[] = array('tagphptype', $type);\r
1881                         if (count($temptypes)) {\r
1882                             $result[] = '|';\r
1883                         }\r
1884                     }\r
1885                     if (trim($type) == 'object') {\r
1886                         $result[] = array('tagphptype', $types . ' ');\r
1887                         $result[] = $this->_removeWhiteSpace($value, 0);\r
1888                     } else {\r
1889                         $done = true;\r
1890                     }\r
1891                     array_shift($value);\r
1892                     if (count($value) && strlen($value[0]) && isset ($value[0]) && \r
1893                         ($value[0]{0} == '$' || substr($value[0], 0, 2) == '&$')\r
1894                     ) {\r
1895                         // was just passed "object"\r
1896                         // and the next thing is a variable name\r
1897                         $result[] = array('tagvarname' , $value[0] . ' ');\r
1898                         array_shift($value);\r
1899                         $result[] = array('desc', join(' ', $value));\r
1900                         return array(2, $result);\r
1901                     }\r
1902                 } else {\r
1903                     $result[] = array('tagphptype', $value[0] . ' ');\r
1904                     array_shift($value);\r
1905                     $done = true;\r
1906                 }\r
1907                 $loop++;\r
1908             } while (!$done && count($value));\r
1909             if ($loop) {\r
1910                 $result[] = ' ';\r
1911             }\r
1912             // still searching for type\r
1913             if (!$done && !count($value)) {\r
1914                 return array(0, $result);\r
1915             }\r
1916             // still searching for var\r
1917             if ($done && !count($value)) {\r
1918                 return array(1, $result);\r
1919             }\r
1920         }\r
1921         $result[] = $this->_removeWhiteSpace($value, 0);\r
1922         $state    = 1;\r
1923         if ($checkforvar) {\r
1924             if (count($value)) {\r
1925                 $state = 2;\r
1926                 if (substr($value[0], 0, 1) == '$' || \r
1927                     substr($value[0], 0, 2) == '&$'\r
1928                 ) {\r
1929                     $result[] = array('tagvarname' , $value[0] . ' ');\r
1930                     array_shift($value);\r
1931                 }\r
1932             } else {\r
1933                 $state = 1;\r
1934             }\r
1935         }\r
1936         $result[] = array('desc', join(' ', $value));\r
1937         return array($state, $result);\r
1938     }\r
1939     \r
1940     /**\r
1941      * captures trailing whitespace\r
1942      *\r
1943      * @param array &$value array of string\r
1944      * @param int   $index  index to seek non-whitespace to\r
1945      *\r
1946      * @return string whitespace\r
1947      * @access private\r
1948      */\r
1949     function _removeWhiteSpace(&$value, $index)\r
1950     {\r
1951         $result = '';\r
1952         if (count($value) > $index && empty($value[$index])) {\r
1953             $found = false;\r
1954             for ($i = $index; $i < count($value) && !strlen($value[$i]); $i++) {\r
1955                 $result .= ' ';\r
1956             }\r
1957             array_splice($value, $index, $i - $index);\r
1958         }\r
1959         return $result;\r
1960     }\r
1961 \r
1962     /**#@+\r
1963      * Link generation methods\r
1964      *\r
1965      * @param string|array $word token to try to link\r
1966      *\r
1967      * @access private\r
1968      */\r
1969     /**\r
1970      * Generate a link to documentation for an element\r
1971      *\r
1972      * This method tries to link to documentation for functions, methods,\r
1973      * PHP functions, class names, and if found, adds the links to output\r
1974      * instead of plain text\r
1975      */\r
1976     function _link($word)\r
1977     {\r
1978         if (is_array($word) && $word[0] == T_STRING) {\r
1979             if ($this->_pf_colon_colon) {\r
1980                 $this->_pf_colon_colon = false;\r
1981 \r
1982                 $combo = $this->_pv_last_string[1] . '::' . $word[1] . '()';\r
1983                 //debug('testing ' . $combo);\r
1984                 $link = $this->_converter->getLink($combo);\r
1985                 if (is_object($link)) {\r
1986                     $this->_addoutput($this->_converter->returnSee($link,\r
1987                         $word[1]), true);\r
1988                     return;\r
1989                 }\r
1990                 $this->_addoutput($word);\r
1991                 return;\r
1992             }\r
1993             $link = $this->_converter->getLink($word[1] . '()');\r
1994             if (is_object($link)) {\r
1995                 $this->_addoutput($this->_converter->returnSee($link,\r
1996                     $word[1]), true);\r
1997                 return;\r
1998             } elseif (is_string($link) && strpos($link, 'ttp://')) {\r
1999                 $this->_addoutput($this->_converter->returnLink($link,\r
2000                     $word[1]), true);\r
2001                 return;\r
2002             } else {\r
2003                 $link = $this->_converter->getLink($word[1]);\r
2004                 if (is_object($link)) {\r
2005                     $word[1] = $this->_converter->returnSee($link, $word[1]);\r
2006                 }\r
2007                 $this->_addoutput($word, true);\r
2008                 return;\r
2009             }\r
2010         }\r
2011         $this->_addoutput($word);\r
2012     }\r
2013     \r
2014     /**\r
2015      * Works like {@link _link()} except it only links to global variables\r
2016      */\r
2017     function _globallink($word)\r
2018     {\r
2019         if (!is_array($word)) {\r
2020             return $this->_addoutput($word);\r
2021         }\r
2022         if ($word[0] != T_VARIABLE) {\r
2023             return $this->_addoutput($word);\r
2024         }\r
2025         if (is_array($word) && $word[0] == T_VARIABLE) {\r
2026             $link = $this->_converter->getLink('global ' . $word[1]);\r
2027             if (is_object($link)) {\r
2028                 $this->_addoutput($this->_converter->returnSee($link,\r
2029                     $word[1]), true);\r
2030                 return;\r
2031             }\r
2032         }\r
2033         $this->_addoutput($word);\r
2034     }\r
2035     \r
2036     /**\r
2037      * Works like {@link _link()} except it only links to classes\r
2038      */\r
2039     function _classlink($word)\r
2040     {\r
2041         //debug("checking class " . $word[1]);\r
2042         if (is_array($word) && $word[0] == T_STRING) {\r
2043             $link = $this->_converter->getLink($word[1]);\r
2044             if (is_object($link)) {\r
2045                 $this->_addoutput($this->_converter->returnSee($link,\r
2046                     $word[1]), true);\r
2047                 return;\r
2048             }\r
2049         }\r
2050         $this->_addoutput($word);\r
2051     }\r
2052     \r
2053     /**\r
2054      * Works like {@link _link()} except it only links to methods\r
2055      */\r
2056     function _methodlink($word)\r
2057     {\r
2058         if (is_array($word) && $word[0] == T_STRING) {\r
2059             //debug("checking method " . $this->_pv_class . '::' . $word[1] . '()');\r
2060             if (isset($this->_pv_prev_var_type)) {\r
2061                 $link = $this->_converter->getLink($this->_pv_prev_var_type . '::' .\r
2062                     $word[1] . '()');\r
2063             } else {\r
2064                 $link = $this->_converter->getLink($this->_pv_class . '::' . \r
2065                     $word[1] . '()');\r
2066             }\r
2067             if (is_object($link)) {\r
2068                 $this->_addoutput($this->_converter->returnSee($link,\r
2069                     $word[1]), true);\r
2070                 return;\r
2071             }\r
2072             if (isset($this->_pv_prev_var_type)) {\r
2073                 $this->_addoutput($word);\r
2074                 return;\r
2075             }\r
2076             //debug("checking method " . $word[1] . '()');\r
2077             $link = $this->_converter->getLink($word[1] . '()');\r
2078             if (is_object($link)) {\r
2079                 $this->_addoutput($this->_converter->returnSee($link,\r
2080                     $word[1]), true);\r
2081                 return;\r
2082             }\r
2083         }\r
2084         $this->_addoutput($word);\r
2085     }\r
2086     \r
2087     /**\r
2088      * Works like {@link _link()} except it only links to class variables\r
2089      *\r
2090      * @param bool $justastring true if the $word is only a string\r
2091      */\r
2092     function _varlink($word, $justastring=false)\r
2093     {\r
2094         if ($justastring) {\r
2095             $word[0] = T_VARIABLE;\r
2096         }\r
2097         if (is_array($word) && $word[0] == T_VARIABLE) {\r
2098             $x = ($justastring ? '$' : '');\r
2099             //debug("checking var " . $this->_pv_class . '::' . $x . $word[1]);\r
2100             if (isset($this->_pv_prev_var_type)) {\r
2101                 //debug("checking var " . $this->_pv_prev_var_type . '::' .\r
2102                 //    $x . $word[1]);\r
2103                 $link = $this->_converter->getLink($this->_pv_prev_var_type . '::' .\r
2104                     $x . $word[1]);\r
2105             } else {\r
2106                 $link = $this->_converter->getLink($this->_pv_class . '::' . \r
2107                     $x . $word[1]);\r
2108             }\r
2109             if (is_object($link)) {\r
2110                 $this->_addoutput($this->_converter->returnSee($link,\r
2111                     $word[1]), true);\r
2112                 return;\r
2113             }\r
2114             //debug("checking var " . $x . $word[1]);\r
2115             if (isset($this->_pv_prev_var_type)) {\r
2116                 $this->_addoutput($word);\r
2117                 return;\r
2118             }\r
2119             $link = $this->_converter->getLink($x . $word[1]);\r
2120             if (is_object($link)) {\r
2121                 $this->_addoutput($this->_converter->returnSee($link,\r
2122                     $word[1]), true);\r
2123                 return;\r
2124             }\r
2125         }\r
2126         $this->_addoutput($word);\r
2127     }\r
2128     /**#@-*/\r
2129     \r
2130     /**#@+\r
2131      * Output Methods\r
2132      * @access private\r
2133      */\r
2134     /**\r
2135      * This method adds output to {@link $_line}\r
2136      *\r
2137      * If a string with variables like "$test this" is present, then special\r
2138      * handling is used to allow processing of the variable in context.\r
2139      *\r
2140      * @param mixed $word         the string|array tag token and value\r
2141      * @param bool  $preformatted whether or not the $word is already formatted\r
2142      *\r
2143      * @return void\r
2144      * @see _flush_save()\r
2145      */\r
2146     function _addoutput($word, $preformatted = false)\r
2147     {\r
2148         if ($this->_pf_no_output_yet) {\r
2149             return;\r
2150         }\r
2151         if ($this->_pf_quote_active) {\r
2152             if (is_array($word)) {\r
2153                 $this->_save .= $this->_converter->highlightSource($word[0],\r
2154                     $word[1]);\r
2155             } else {\r
2156                 $this->_save .= $this->_converter->highlightSource(false,\r
2157                     $word, true);\r
2158             }\r
2159         } else {\r
2160             $this->_flush_save();\r
2161             if (is_string($word) && trim($word) == '') {\r
2162                 $this->_line .= $this->_converter->postProcess($word);\r
2163                 return;\r
2164             }\r
2165             if (is_array($word) && trim($word[1]) == '') {\r
2166                 $this->_line .= $this->_converter->postProcess($word[1]);\r
2167                 return;\r
2168             }\r
2169             if (is_array($word)) {\r
2170                 $this->_line .= $this->_converter->highlightSource($word[0],\r
2171                     $word[1], $preformatted);\r
2172             } else {\r
2173                 $this->_line .= $this->_converter->highlightSource(false,\r
2174                     $word, $preformatted);\r
2175             }\r
2176         }\r
2177     }\r
2178     \r
2179     /** \r
2180      * Like {@link _output()}, but for DocBlock highlighting\r
2181      *\r
2182      * @param mixed $dbtype       the docblock type\r
2183      * @param mixed $word         the string|array tag token and value\r
2184      * @param bool  $preformatted whether or not the $word is already formatted\r
2185      *\r
2186      * @return void\r
2187      */\r
2188     function _addDocBlockoutput($dbtype, $word, $preformatted = false)\r
2189     {\r
2190         if ($this->_pf_internal) {\r
2191             $this->_line .= $this->_converter->highlightDocBlockSource('internal',\r
2192                 $word, $preformatted);\r
2193         } else {\r
2194             $this->_line .= $this->_converter->highlightDocBlockSource($dbtype,\r
2195                 $word, $preformatted);\r
2196         }\r
2197     }\r
2198     \r
2199     /**\r
2200      * Flush a saved string variable highlighting\r
2201      *\r
2202      * {@source}\r
2203      *\r
2204      * @return void\r
2205      * @todo CS cleanup - rename to _flushSave() for camelCase rule\r
2206      */\r
2207     function _flush_save()\r
2208     {\r
2209         if (!empty($this->_save)) {\r
2210             $this->_save .= $this->_converter->flushHighlightCache();\r
2211             // clear the existing cache, reset it to the old value\r
2212             if (isset($this->_save_highlight_state)) {\r
2213                 $this->_converter->\r
2214                     _setHighlightCache($this->_save_highlight_state[0],\r
2215                          $this->_save_highlight_state[1]);\r
2216             }\r
2217             $this->_line .= $this->_converter->\r
2218                 highlightSource(T_CONSTANT_ENCAPSED_STRING, $this->_save, true);\r
2219             $this->_save  = '';\r
2220         }\r
2221     }\r
2222     /**#@-*/\r
2223     \r
2224     /**\r
2225      * Give the word parser necessary data to begin a new parse\r
2226      *\r
2227      * @param array &$data all tokens separated by line number\r
2228      *\r
2229      * @return void\r
2230      */\r
2231     function configWordParser(&$data)\r
2232     {\r
2233         $this->_wp->setup($data, $this);\r
2234         $this->_wp->setWhitespace(true);\r
2235     }\r
2236 \r
2237     /**\r
2238      * Initialize all parser state variables\r
2239      *\r
2240      * @param bool         $inlinesourceparse true if we are highlighting an inline \r
2241      *                                        {@}source} tag's output\r
2242      * @param false|string $class             name of class we are going \r
2243      *                                        to start from\r
2244      *\r
2245      * @return void\r
2246      * @uses $_wp sets to a new {@link phpDocumentor_HighlightWordParser}\r
2247      */\r
2248     function setupStates($inlinesourceparse, $class)\r
2249     {\r
2250         $this->_output = '';\r
2251         $this->_line   = '';\r
2252         unset($this->_wp);\r
2253         $this->_wp          = new phpDocumentor_HighlightWordParser;\r
2254         $this->_event_stack = new EventStack;\r
2255         if ($inlinesourceparse) {\r
2256             $this->_event_stack->pushEvent(PARSER_EVENT_PHPCODE);\r
2257             if ($class) {\r
2258                 $this->_event_stack->pushEvent(PARSER_EVENT_CLASS);\r
2259                 $this->_pv_class = $class;\r
2260             }\r
2261         } else {\r
2262             $this->_pv_class = null;\r
2263         }\r
2264 \r
2265         $this->_pv_define              = null;\r
2266         $this->_pv_define_name         = null;\r
2267         $this->_pv_define_value        = null;\r
2268         $this->_pv_define_params_data  = null;\r
2269         $this->_pv_dtype               = null;\r
2270         $this->_pv_docblock            = null;\r
2271         $this->_pv_dtemplate           = null;\r
2272         $this->_pv_func                = null;\r
2273         $this->_pv_global_name         = null;\r
2274         $this->_pv_global_val          = null;\r
2275         $this->_pv_globals             = null;\r
2276         $this->_pv_global_count        = null;\r
2277         $this->_pv_include_params_data = null;\r
2278         $this->_pv_include_name        = null;\r
2279         $this->_pv_include_value       = null;\r
2280         $this->_pv_linenum             = null;\r
2281         $this->_pv_periodline          = null;\r
2282         $this->_pv_paren_count         = 0;\r
2283         $this->_pv_statics             = null;\r
2284         $this->_pv_static_count        = null;\r
2285         $this->_pv_static_val          = null;\r
2286         $this->_pv_quote_data          = null;\r
2287         $this->_pv_function_data       = null;\r
2288         $this->_pv_var                 = null;\r
2289         $this->_pv_varname             = null;\r
2290         $this->_pf_definename_isset    = false;\r
2291         $this->_pf_extends_found       = false;\r
2292         $this->_pf_includename_isset   = false;\r
2293         $this->_pf_get_source          = false;\r
2294         $this->_pf_getting_source      = false;\r
2295         $this->_pf_in_class            = false;\r
2296         $this->_pf_in_define           = false;\r
2297         $this->_pf_in_global           = false;\r
2298         $this->_pf_in_include          = false;\r
2299         $this->_pf_in_var              = false;\r
2300         $this->_pf_funcparam_val       = false;\r
2301         $this->_pf_quote_active        = false;\r
2302         $this->_pf_reset_quote_data    = true;\r
2303         $this->_pf_useperiod           = false;\r
2304         $this->_pf_var_equals          = false;\r
2305         $this->_pf_obj_op              = false;\r
2306         $this->_pf_docblock            = false;\r
2307         $this->_pf_docblock_template   = false;\r
2308         $this->_pf_colon_colon         = false;\r
2309         $this->_pv_last_string         = false;\r
2310         $this->_pf_inmethod            = false;\r
2311         $this->_pf_no_output_yet       = false;\r
2312         $this->_pv_saveline            = 0;\r
2313         $this->_pv_next_word           = false;\r
2314         $this->_save                   = '';\r
2315     }\r
2316 \r
2317     /**\r
2318      * Initialize the {@link $tokenpushEvent, $wordpushEvent} arrays\r
2319      *\r
2320      * @return void\r
2321      */\r
2322     function phpDocumentor_HighlightParser()\r
2323     {\r
2324         if (!defined('T_INTERFACE')) {\r
2325             define('T_INTERFACE', -1);\r
2326         }\r
2327         $this->allowableTags\r
2328             = $GLOBALS['_phpDocumentor_tags_allowed'];\r
2329         $this->allowableInlineTags\r
2330             = $GLOBALS['_phpDocumentor_inline_doc_tags_allowed'];\r
2331         $this->inlineTagHandlers\r
2332             = array('*' => 'handleDefaultInlineTag');\r
2333         /**************************************************************/\r
2334 \r
2335         $this->tokenpushEvent[PARSER_EVENT_NOEVENTS] = \r
2336             array(\r
2337                 T_OPEN_TAG => PARSER_EVENT_PHPCODE,\r
2338             );\r
2339 \r
2340         /**************************************************************/\r
2341 \r
2342         $this->tokenpushEvent[PARSER_EVENT_PHPCODE] = \r
2343             array(\r
2344                 T_FUNCTION      => PARSER_EVENT_FUNCTION,\r
2345                 T_CLASS         => PARSER_EVENT_CLASS,\r
2346                 T_INTERFACE     => PARSER_EVENT_CLASS,\r
2347                 T_INCLUDE_ONCE  => PARSER_EVENT_INCLUDE,\r
2348                 T_INCLUDE       => PARSER_EVENT_INCLUDE,\r
2349                 T_START_HEREDOC => PARSER_EVENT_EOFQUOTE,\r
2350                 T_REQUIRE       => PARSER_EVENT_INCLUDE,\r
2351                 T_REQUIRE_ONCE  => PARSER_EVENT_INCLUDE,\r
2352                 T_COMMENT       => PARSER_EVENT_COMMENT,\r
2353                 T_DOC_COMMENT   => PARSER_EVENT_DOCBLOCK,\r
2354             );\r
2355         $this->wordpushEvent[PARSER_EVENT_PHPCODE]  =\r
2356             array(\r
2357                 "define" => PARSER_EVENT_DEFINE,\r
2358                 '"'      => PARSER_EVENT_QUOTE,\r
2359                 '\''     => PARSER_EVENT_QUOTE,\r
2360             );\r
2361         /**************************************************************/\r
2362 \r
2363         $this->wordpushEvent[PARSER_EVENT_FUNCTION]  =\r
2364             array(\r
2365                 '{' => PARSER_EVENT_LOGICBLOCK,\r
2366                 '(' => PARSER_EVENT_FUNCTION_PARAMS,\r
2367             );\r
2368         $this->tokenpushEvent[PARSER_EVENT_FUNCTION] =\r
2369             array(\r
2370                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2371                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2372             );\r
2373         $this->wordpopEvent[PARSER_EVENT_FUNCTION]   = array("}");\r
2374         /**************************************************************/\r
2375 \r
2376         $this->tokenpopEvent[PARSER_EVENT_EOFQUOTE] = array(T_END_HEREDOC);\r
2377         /**************************************************************/\r
2378 \r
2379         $this->tokenpushEvent[PARSER_EVENT_FUNCTION_PARAMS] =\r
2380             array(\r
2381                 T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,\r
2382                 T_ARRAY                    => PARSER_EVENT_ARRAY,\r
2383                 T_COMMENT                  => PARSER_EVENT_COMMENT,\r
2384                 T_DOC_COMMENT              => PARSER_EVENT_DOCBLOCK,\r
2385             );\r
2386         $this->wordpushEvent[PARSER_EVENT_FUNCTION_PARAMS]  =\r
2387             array(\r
2388                 '"' => PARSER_EVENT_QUOTE,\r
2389                 "'" => PARSER_EVENT_QUOTE,\r
2390             );\r
2391         $this->wordpopEvent[PARSER_EVENT_FUNCTION_PARAMS]   = array(")");\r
2392         /**************************************************************/\r
2393 \r
2394         $this->wordpushEvent[PARSER_EVENT_LOGICBLOCK]  = \r
2395             array(\r
2396                 "{" => PARSER_EVENT_LOGICBLOCK,\r
2397                 '"' => PARSER_EVENT_QUOTE,\r
2398             );\r
2399         $this->tokenpushEvent[PARSER_EVENT_LOGICBLOCK] =\r
2400             array(\r
2401                 T_GLOBAL                   => PARSER_EVENT_FUNC_GLOBAL,\r
2402                 T_STATIC                   => PARSER_EVENT_STATIC_VAR,\r
2403                 T_START_HEREDOC            => PARSER_EVENT_EOFQUOTE,\r
2404                 T_CURLY_OPEN               => PARSER_EVENT_LOGICBLOCK,\r
2405                 T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK,\r
2406             );\r
2407         $this->wordpopEvent[PARSER_EVENT_LOGICBLOCK]   = array("}");\r
2408         $this->tokenpopEvent[PARSER_EVENT_LOGICBLOCK]  = array(T_CURLY_OPEN);\r
2409 \r
2410         /**************************************************************/\r
2411 \r
2412         $this->tokenpushEvent[PARSER_EVENT_ARRAY] = \r
2413             array(\r
2414                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2415                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2416             );\r
2417         $this->wordpopEvent[PARSER_EVENT_ARRAY]   = array(")");\r
2418         /**************************************************************/\r
2419 \r
2420         $this->tokenpushEvent[PARSER_EVENT_FUNC_GLOBAL] =\r
2421             array(\r
2422                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2423                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2424             );\r
2425         $this->wordpopEvent[PARSER_EVENT_FUNC_GLOBAL]   = array(";");\r
2426         /**************************************************************/\r
2427 \r
2428         $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR] =\r
2429             array(\r
2430                 T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,\r
2431                 T_COMMENT                  => PARSER_EVENT_COMMENT,\r
2432                 T_DOC_COMMENT              => PARSER_EVENT_DOCBLOCK,\r
2433             );\r
2434         $this->wordpushEvent[PARSER_EVENT_STATIC_VAR]  =\r
2435             array(\r
2436                 "=" => PARSER_EVENT_STATIC_VAR_VALUE,\r
2437             );\r
2438         $this->wordpopEvent[PARSER_EVENT_STATIC_VAR]   = array(";");\r
2439         /**************************************************************/\r
2440 \r
2441         $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] = \r
2442             array(\r
2443                 T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,\r
2444                 T_COMMENT                  => PARSER_EVENT_COMMENT,\r
2445                 T_DOC_COMMENT              => PARSER_EVENT_DOCBLOCK,\r
2446                 T_ARRAY                    => PARSER_EVENT_ARRAY,\r
2447             );\r
2448         $this->wordpushEvent[PARSER_EVENT_STATIC_VAR_VALUE]  =\r
2449             array(\r
2450                 '"' => PARSER_EVENT_QUOTE,\r
2451                 "'" => PARSER_EVENT_QUOTE,\r
2452             );\r
2453         $this->wordpopEvent[PARSER_EVENT_STATIC_VAR_VALUE]   = array(";", ",");\r
2454         /**************************************************************/\r
2455         $this->tokenpushEvent[PARSER_EVENT_QUOTE] = \r
2456             array(\r
2457                 T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,\r
2458                 T_CURLY_OPEN      => PARSER_EVENT_QUOTE_VAR,\r
2459             );\r
2460         $this->wordpopEvent[PARSER_EVENT_QUOTE]   = array('"');\r
2461         /**************************************************************/\r
2462         $this->tokenpushEvent[PARSER_EVENT_QUOTE_VAR] = \r
2463             array(\r
2464                 T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,\r
2465                 T_CURLY_OPEN      => PARSER_EVENT_QUOTE_VAR,\r
2466             );\r
2467         $this->wordpushEvent[PARSER_EVENT_QUOTE_VAR]  =\r
2468             array(\r
2469                 "{" => PARSER_EVENT_QUOTE_VAR,\r
2470                 '"' => PARSER_EVENT_QUOTE_VAR,\r
2471                 "'" => PARSER_EVENT_QUOTE_VAR,\r
2472             );\r
2473         $this->wordpopEvent[PARSER_EVENT_QUOTE_VAR]   = array('}');\r
2474         /**************************************************************/\r
2475 \r
2476         $this->tokenpushEvent[PARSER_EVENT_DEFINE] = \r
2477             array(\r
2478                 T_COMMENT                  => PARSER_EVENT_COMMENT,\r
2479                 T_DOC_COMMENT              => PARSER_EVENT_DOCBLOCK,\r
2480                 T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,\r
2481             );\r
2482         $this->wordpushEvent[PARSER_EVENT_DEFINE]  = \r
2483             array(\r
2484                 "(" => PARSER_EVENT_DEFINE_PARAMS,\r
2485             );\r
2486         $this->wordpopEvent[PARSER_EVENT_DEFINE]   = array(";");\r
2487         /**************************************************************/\r
2488 \r
2489         $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS] = \r
2490             array(\r
2491                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2492                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2493             );\r
2494         $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS]  = \r
2495             array(\r
2496                 "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,\r
2497                 '"' => PARSER_EVENT_QUOTE,\r
2498                 "'" => PARSER_EVENT_QUOTE,\r
2499             );\r
2500         $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS]   = array(")");\r
2501         /**************************************************************/\r
2502 \r
2503         $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] =\r
2504             array(\r
2505                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2506                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2507             );\r
2508         $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS]  =\r
2509             array(\r
2510                 "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,\r
2511                 '"' => PARSER_EVENT_QUOTE,\r
2512                 "'" => PARSER_EVENT_QUOTE,\r
2513             );\r
2514         $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS]   = array(")");\r
2515         /**************************************************************/\r
2516 \r
2517         $this->tokenpushEvent[PARSER_EVENT_VAR] = \r
2518             array(\r
2519                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2520                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2521                 T_ARRAY       => PARSER_EVENT_ARRAY,\r
2522             );\r
2523         $this->wordpopEvent[PARSER_EVENT_VAR]   = array(";");\r
2524         /**************************************************************/\r
2525 \r
2526         $this->tokenpushEvent[PARSER_EVENT_CLASS] = \r
2527             array(\r
2528                 T_FUNCTION    => PARSER_EVENT_METHOD,\r
2529                 T_VAR         => PARSER_EVENT_VAR,\r
2530                 T_COMMENT     => PARSER_EVENT_DOCBLOCK,\r
2531                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2532                 T_CLOSE_TAG   => PARSER_EVENT_OUTPHP,\r
2533             );\r
2534         $this->wordpopEvent[PARSER_EVENT_CLASS]   = array("}");\r
2535         /**************************************************************/\r
2536 \r
2537         $this->wordpushEvent[PARSER_EVENT_METHOD]  =\r
2538             array(\r
2539                 '{' => PARSER_EVENT_METHOD_LOGICBLOCK,\r
2540                 '(' => PARSER_EVENT_FUNCTION_PARAMS,\r
2541             );\r
2542         $this->tokenpushEvent[PARSER_EVENT_METHOD] =\r
2543             array(\r
2544                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2545                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2546             );\r
2547         $this->wordpopEvent[PARSER_EVENT_METHOD]   = array("}", ";");\r
2548         /**************************************************************/\r
2549 \r
2550         $this->wordpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK]  = \r
2551             array(\r
2552                 "{" => PARSER_EVENT_METHOD_LOGICBLOCK,\r
2553                 '"' => PARSER_EVENT_QUOTE,\r
2554             );\r
2555         $this->tokenpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] =\r
2556             array(\r
2557                 T_OBJECT_OPERATOR          => PARSER_EVENT_CLASS_MEMBER,\r
2558                 T_GLOBAL                   => PARSER_EVENT_FUNC_GLOBAL,\r
2559                 T_STATIC                   => PARSER_EVENT_STATIC_VAR,\r
2560                 T_CURLY_OPEN               => PARSER_EVENT_LOGICBLOCK,\r
2561                 T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK,\r
2562             );\r
2563         $this->wordpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK]   = array("}");\r
2564         $this->tokenpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK]  = array(T_CURLY_OPEN);\r
2565         /**************************************************************/\r
2566 \r
2567         $this->tokenpushEvent[PARSER_EVENT_INCLUDE] = \r
2568             array(\r
2569                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2570                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2571             );\r
2572         $this->wordpushEvent[PARSER_EVENT_INCLUDE]  = \r
2573             array(\r
2574                 "(" => PARSER_EVENT_INCLUDE_PARAMS,\r
2575             );\r
2576         $this->wordpopEvent[PARSER_EVENT_INCLUDE]   = array(";");\r
2577         /**************************************************************/\r
2578 \r
2579         $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS] = \r
2580             array(\r
2581                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2582                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2583             );\r
2584         $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS]  = \r
2585             array(\r
2586                 "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,\r
2587             );\r
2588         $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS]   = array(")");\r
2589         /**************************************************************/\r
2590 \r
2591         $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] =\r
2592             array(\r
2593                 T_COMMENT     => PARSER_EVENT_COMMENT,\r
2594                 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,\r
2595             );\r
2596         $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS]  =\r
2597             array(\r
2598                 "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,\r
2599             );\r
2600         $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS]   = array(")");\r
2601     }\r
2602 }\r
2603 ?>\r