3 * Source Code Highlighting
\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
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
15 * phpDocumentor :: automatic documentation generator
\r
17 * PHP versions 4 and 5
\r
19 * Copyright (c) 2002-2007 Gregory Beaver
\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
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
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
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
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
50 * @todo CS cleanup - change package to PhpDocumentor
\r
54 * Retrieve tokens from an array of tokens organized by line numbers
\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
66 * @todo CS cleanup - change package to PhpDocumentor
\r
67 * @todo CS cleanup - change class name to PhpDocumentor_*
\r
69 class phpDocumentor_HighlightWordParser extends phpDocumentorTWordParser
\r
72 * Hash used to keep track of line numbers that have already been initialized
\r
76 var $_listLineNums = array();
\r
78 * Initialize the parser object
\r
80 * @param array &$input the input
\r
81 * @param phpDocumentor_HighlightParser &$parser the parser
\r
85 function setup(&$input, &$parser)
\r
87 $this->_parser = &$parser;
\r
88 $this->data = &$input;
\r
89 $this->_all = $input;
\r
90 $this->_sourceline = 0;
\r
96 * debugging function
\r
101 function printState()
\r
103 $linenum = $this->linenum;
\r
105 if (!isset($this->_all[$this->linenum][$this->pos])) {
\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
115 $token = htmlspecialchars($token);
\r
117 debug('Next Token ' . $this->linenum . '-' . $this->pos . ':' . $details);
\r
122 * Retrieve the position of the next token that will be parsed
\r
123 * in the internal token array
\r
125 * @return array format: array(line number, position)
\r
127 function nextToken()
\r
129 $linenum = $this->linenum;
\r
131 if (!isset($this->_all[$this->linenum][$this->pos])) {
\r
135 if (!isset($this->_all[$linenum][$pos])) {
\r
138 return array($linenum, $pos);
\r
142 * Retrieve the next token
\r
144 * @return array|string either array(PHP token constant, token) or string
\r
145 * non-specific separator
\r
149 if (!isset($this->_all[$this->linenum][$this->pos])) {
\r
152 if (!isset($this->_all[$this->linenum])) {
\r
155 $this->_parser->newLineNum();
\r
156 return $this->getWord();
\r
158 $word = $this->_all[$this->linenum][$this->pos++];
\r
159 return str_replace("\t", ' ', $word);
\r
163 * back the word parser to the previous token as defined by $last_token
\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
172 function backupPos($last_token, $is_pos = false)
\r
174 if (!$last_token) {
\r
178 $this->linenum = $last_token[0];
\r
179 $this->pos = $last_token[1];
\r
182 if ($last_token === false) {
\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
193 if ($this->pos < 0) {
\r
195 if ($this->linenum < 0) {
\r
196 var_dump($last_token);
\r
199 $this->pos = count($this->_all[$this->linenum]) - 1;
\r
201 } while (!$this->tokenEquals($last_token, str_replace("\t", ' ',
\r
202 $this->_all[$this->linenum][$this->pos])));
\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
211 * Highlights source code using {@link parse()}
\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
226 class phpDocumentor_HighlightParser extends phpDocumentorTParser
\r
233 * Highlighted source is built up in this string
\r
239 * contents of the current source code line as it is parsed
\r
245 * Used to retrieve highlighted tokens
\r
246 * @var Converter a descendant of Converter
\r
251 * Path to file being highlighted, if this is from a @filesource tag
\r
252 * @var false|string full path
\r
254 var $_filesourcepath;
\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
297 * event handlers for @tags
\r
298 * @tutorial tags.pkg
\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
340 * wraps the current line (via the converter) and resets it to empty
\r
343 * @uses Converter::SourceLine() encloses {@link $_line} in a
\r
344 * converter-specific format
\r
346 function newLineNum()
\r
348 if ($this->_pf_no_output_yet) {
\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
359 * Start the parsing at a certain line number
\r
361 * @param int $num line number
\r
365 function setLineNum($num)
\r
367 $this->_wp->linenum = $num;
\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
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
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
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
399 * @staticvar int used for recursion limiting if a handler for
\r
400 * an event is not found
\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
406 function parse (&$parse_data, &$converter, $inlinesourceparse = false,
\r
407 $class = false, $linenum = false, $filesourcepath = false)
\r
409 if (!tokenizer_ext) {
\r
410 if (is_array($parse_data)) {
\r
411 $parse_data = join($parse_data, '');
\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
421 return $converter->PreserveWhiteSpace($this->_output);
\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
429 $this->configWordParser($parse_data);
\r
430 if ($linenum !== false) {
\r
431 $this->setLineNum($linenum);
\r
433 // initialize variables so E_ALL error_reporting doesn't complain
\r
438 $lpevent = $pevent;
\r
439 $pevent = $this->_event_stack->getEvent();
\r
440 if ($lpevent != $pevent) {
\r
441 $this->_last_pevent = $lpevent;
\r
444 if ($pevent == PARSER_EVENT_CLASS_MEMBER) {
\r
445 $this->_wp->setWhitespace(true);
\r
447 $this->_wp->setWhitespace(false);
\r
450 if (!is_array($word)) {
\r
453 if (is_array($word) && $word[0] != T_WHITESPACE) {
\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
463 //debug("added " . $this->_wp->linenum . '-' . $this->_wp->pos);
\r
464 $this->_addoutput($word);
\r
467 $this->_pv_last_word = $lw;
\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
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
478 if (is_array($this->_pv_last_word)) {
\r
479 echo token_name($this->_pv_last_word[0]) .
\r
481 htmlspecialchars($this->_pv_last_word[1]);
\r
483 echo "|" . $this->_pv_last_word;
\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
495 echo '|'.htmlspecialchars($word);
\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
509 echo "-------------------\n\n\n";
\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
518 if ($endrecur++ == 25) {
\r
519 die("FATAL ERROR, recursion limit reached");
\r
522 } while (!($word === false));
\r
523 if (strlen($this->_line)) {
\r
524 $this->newLineNum();
\r
526 return $this->_output;
\r
532 * All Event Handlers use {@link checkEventPush()} and
\r
533 * {@link checkEventPop()} to set up the event stack and parser state.
\r
535 * @param string|array $word token value
\r
536 * @param int $pevent parser event from {@link Parser.inc}
\r
542 * Most tokens only need highlighting, and this method handles them
\r
544 function defaultHandler($word, $pevent)
\r
546 $this->_addoutput($word);
\r
547 if ($this->checkEventPush($word, $pevent)) {
\r
550 $this->checkEventPop($word, $pevent);
\r
554 * Handles global declarations in a function, like:
\r
557 * function foobar()
\r
559 * global $_phpDocumentor_setting;
\r
563 * @uses _globallink() instead of _addoutput(), to link to global variables
\r
564 * if they are used in a function
\r
566 function handleFuncGlobal($word, $pevent)
\r
568 if ($this->checkEventPush($word, $pevent)) {
\r
571 $this->_globallink($word);
\r
572 $this->checkEventPop($word, $pevent);
\r
576 * Handles strings in quotation marks and heredoc
\r
578 * Special handling is needed for strings that contain variables like:
\r
580 * <code>$a = "$test string"</code>
\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
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
592 function handleQuote($word, $pevent)
\r
594 if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) {
\r
595 $this->_pv_lastvar = $word;
\r
597 if ($this->checkEventPush($word, $pevent)) {
\r
598 $this->_addoutput($word);
\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
608 $this->_pf_quote_active = false;
\r
609 $this->_wp->backupPos($word);
\r
610 $this->_event_stack->popEvent();
\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
620 if (is_array($word) && $word[0] == T_VARIABLE) {
\r
621 $this->_pv_lastvar = $word;
\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
629 } elseif (is_array($this->_pv_last_word) &&
\r
630 $this->_pv_last_word[0] == T_CONSTANT_ENCAPSED_STRING
\r
632 //$this->_pv_quote_data = $this->_pv_last_word[1];
\r
633 $this->_event_stack->popEvent();
\r
634 $this->_wp->backupPos($word);
\r
637 if ($this->checkEventPop($word, $pevent)) {
\r
638 $this->_pf_quote_active = false;
\r
640 $this->_addoutput($word);
\r
644 * Handles {$variable} within a "quote"
\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
650 function handleQuoteVar($word, $pevent)
\r
652 if ($this->checkEventPop($word, $pevent)) {
\r
653 $this->_pf_quote_active = true;
\r
654 $this->_addoutput($word);
\r
657 if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) {
\r
658 $this->_pv_lastvar = $word;
\r
660 if ($this->checkEventPush($word, $pevent)) {
\r
661 $this->_pf_quote_active = false;
\r
662 if (is_string($word) && ($word == '{' || $word == '"' || $word == "'")
\r
664 $this->_pf_quote_active = true;
\r
665 $this->_pv_lastvar = false;
\r
668 $this->_addoutput($word);
\r
672 * Handles define() statements
\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
679 * define("test",array("hello",6 => 4, 5 => array('there')));
\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
686 * If the define variable is documented, a link will be created to its
\r
687 * documentation using the Converter passed.
\r
689 function handleDefine($word, $pevent)
\r
691 static $token_save;
\r
692 if (!isset($token_save)) {
\r
693 $token_save = array();
\r
695 $e = $this->checkEventPush($word, $pevent);
\r
696 if ($e && $e != PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS) {
\r
700 if (!isset($this->_pv_define_params_data)) {
\r
701 $this->_pv_define_params_data = '';
\r
704 if ($this->checkEventPop($word, $pevent)) {
\r
705 unset($token_save);
\r
706 $this->_addoutput($word);
\r
708 if ($this->_pf_definename_isset) {
\r
709 $this->_addoutput($word);
\r
711 if ($word != ",") {
\r
712 $token_save[] = $word;
\r
713 if (is_array($word)) {
\r
716 $this->_pv_define_params_data .= $word;
\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
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
733 $this->_pf_definename_isset = true;
\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
741 $this->_addoutput($this->_converter->returnSee($link,
\r
744 $this->_addoutput($save, $token);
\r
747 $this->_pv_define_params_data = '';
\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
758 * @uses _link() make any global code that is a documentable element link
\r
759 * to the php manual or its documentation
\r
761 function handlePhpCode($word, $pevent)
\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
770 $this->_pf_docblock = true;
\r
772 return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK);
\r
774 $this->_pf_no_output_yet = true;
\r
775 $this->_pv_saveline = $this->_wp->linenum + 1;
\r
778 if (is_array($word) && $word[0] == T_DOUBLE_COLON) {
\r
779 $this->_pf_colon_colon = true;
\r
781 if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {
\r
782 $this->_pv_last_string = $word;
\r
784 $this->_link($word);
\r
785 $this->checkEventPop($word, $pevent);
\r
789 * Handle the function declaration header
\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
796 function handleFunction($word, $pevent)
\r
798 if ($this->checkEventPush($word, $pevent)) {
\r
799 $this->_addoutput($word);
\r
802 if ($this->checkEventPop($word, $pevent)) {
\r
805 $this->_link($word);
\r
809 * Handle the method declaration header
\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
816 function handleMethod($word, $pevent)
\r
818 if ($this->checkEventPush($word, $pevent)) {
\r
819 $this->_addoutput($word);
\r
822 if ($this->checkEventPop($word, $pevent)) {
\r
823 if ($word == ';') {
\r
824 $this->_addoutput($word);
\r
828 $this->_methodlink($word);
\r
832 * Handler for the stuff between ( and ) in a function declaration
\r
835 * function handles($only,$these,$parameters){...}
\r
838 function handleFunctionParams($word, $pevent)
\r
840 if ($this->checkEventPush($word, $pevent)) {
\r
841 $this->_addoutput($word);
\r
844 $this->_addoutput($word);
\r
845 $this->checkEventPop($word, $pevent);
\r
849 * Handler for function body.
\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
856 function handleLogicBlock($word, $pevent)
\r
858 if ($this->checkEventPush($word, $pevent)) {
\r
859 $this->_addoutput($word);
\r
862 if (is_array($word) && $word[0] == T_DOUBLE_COLON) {
\r
863 $this->_pf_colon_colon = true;
\r
865 if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {
\r
866 $this->_pv_last_string = $word;
\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
879 * Handler for method body.
\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
887 function handleMethodLogicBlock($word, $pevent)
\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
894 if ($word[0] != T_WHITESPACE &&
\r
895 $word[0] != T_STRING && $word[0] != T_OBJECT_OPERATOR
\r
897 //fancy_debug('unset', $word);
\r
898 unset($this->_pv_prev_var_type);
\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
910 if (is_array($word) && $word[0] == T_DOUBLE_COLON) {
\r
911 $this->_pf_colon_colon = true;
\r
913 if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {
\r
914 $this->_pv_last_string = $word;
\r
916 if (is_array($word) && $word[0] == T_VARIABLE) {
\r
917 $this->_pv_lastvar = $word;
\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
931 * Handles $obj->classmember in a method body
\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
936 * There are two methods of determining whether to link:
\r
938 * - $this->member->submember
\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
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
955 function handleClassMember($word, $pevent)
\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
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
971 if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') ||
\r
972 isset($this->_pv_prev_var_type)
\r
974 if (is_array($word) && $word[0] == T_WHITESPACE) {
\r
975 // preserve value of _pv_prev_var_type
\r
977 $save = $this->_wp->nextToken();
\r
978 $temp = $this->_wp->getWord();
\r
979 $this->_wp->backupPos($save, true);
\r
981 if ((is_string($word) && $word == '(') || (isset($temp) &&
\r
982 is_string($temp) && $temp == '(')
\r
985 $this->_pf_no_output_yet = false;
\r
986 $this->_methodlink($name);
\r
987 unset($this->_pv_prev_var_type);
\r
990 //fancy_debug('name is ', $name);
\r
991 $this->_pf_no_output_yet = false;
\r
992 $this->_varlink($name, true);
\r
994 $this->_converter->getLink('object ' . $this->_pv_class);
\r
996 if (is_object($templink)) {
\r
997 $class = $this->_converter->classes
\r
998 ->getClass($templink->name, $templink->path);
\r
1002 if (is_array($varname)) {
\r
1003 $varname = $name[1];
\r
1005 if ($varname{0} != '$') {
\r
1006 $varname = '$'.$varname;
\r
1008 $var = $class->getVar($this->_converter, $varname);
\r
1010 if (is_object($var) && $var->docblock->var) {
\r
1011 $type = $var->docblock->var->returnType;
\r
1013 if (isset($type)) {
\r
1014 if (strpos($type, 'object') === false) {
\r
1015 $type = 'object '.$type;
\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
1023 $this->_pv_prev_var_type = $type->name;
\r
1025 unset($this->_pv_prev_var_type);
\r
1028 unset($this->_pv_prev_var_type);
\r
1031 unset($this->_pv_prev_var_type);
\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
1042 //debug('unset prevtype, no setnow');
\r
1043 unset($this->_pv_prev_var_type);
\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
1053 $this->_addoutput($word);
\r
1057 if (!$this->_pf_obj_op && is_array($this->_pv_last_word) &&
\r
1058 $this->_pv_last_word[0] == T_OBJECT_OPERATOR
\r
1060 if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') ||
\r
1061 isset($this->_pv_prev_var_type)
\r
1063 $this->_pf_obj_op = true;
\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
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
1081 if ($this->_pf_obj_op) {
\r
1082 if (!(is_array($word) && ($word[0] == T_STRING ||
\r
1083 $word[0] == T_WHITESPACE))
\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
1095 if ($word[0] == T_STRING) {
\r
1096 //fancy_debug('set pvcmname to', $word);
\r
1097 $this->_pv_cm_name = $word;
\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
1109 * Handles comments
\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
1116 function handleComment($word, $pevent)
\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
1125 $this->_event_stack->popEvent();
\r
1126 $this->_event_stack->pushEvent(PARSER_EVENT_DOCBLOCK);
\r
1127 return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK);
\r
1129 if ($this->_pf_no_output_yet) {
\r
1131 $this->_pf_no_output_yet = false;
\r
1132 $this->_addoutput($this->_pv_last_word);
\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
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
1144 $this->_wp->backupPos($this->_pv_last_word);
\r
1145 $this->_wp->getWord();
\r
1146 //var_dump($this->_wp->nextToken());
\r
1148 } elseif (isset($flag)) {
\r
1149 $this->newLineNum();
\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
1159 * Handle class declarations
\r
1161 * Handles the initial declaration line:
\r
1163 * <code>class X</code>
\r
1167 * <code>class X extends Y implements I</code>
\r
1169 * @uses _classlink() to link to documentation for X and for Y class in
\r
1170 * "class X extends Y"
\r
1172 function handleClass($word, $pevent)
\r
1174 $this->_pf_in_class = true;
\r
1175 $a = $this->checkEventPush($word, $pevent);
\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
1183 if (is_array($word) &&
\r
1184 in_array($word[0], array(T_PRIVATE, T_PROTECTED, T_PUBLIC))
\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
1193 if (is_array($test) && $test[0] == T_VARIABLE) {
\r
1194 $this->_wp->backupPos($tok, true);
\r
1197 $this->_wp->backupPos($starttok, true);
\r
1200 if (@in_array($this->_pv_last_word[0],
\r
1201 array(T_PRIVATE, T_PROTECTED, T_PUBLIC))
\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
1210 if ($this->_pf_extends_found && is_array($word) && $word[0] == T_STRING) {
\r
1211 $this->_classlink($word);
\r
1214 if (is_array($word) && $word[0] == T_EXTENDS) {
\r
1215 $this->_pf_extends_found = true;
\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
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
1230 * Handles class variable declaration
\r
1239 * @uses _varlink() make a link to $Y documentation in class variable
\r
1240 * declaration "var $Y;"
\r
1242 function handleVar($word, $pevent)
\r
1244 if ($this->checkEventPush($word, $pevent)) {
\r
1245 $this->_addoutput($word);
\r
1248 if (is_array($word) && $word[0] == T_VARIABLE) {
\r
1249 return $this->_varlink($word);
\r
1251 $this->_addoutput($word);
\r
1252 $this->checkEventPop($word, $pevent);
\r
1256 * This handler is responsible for highlighting DocBlocks
\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
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
1266 * @uses commonDocBlock() once all lines of the DocBlock have been retrieved
\r
1268 function handleDocBlock($word, $pevent)
\r
1270 if (!($this->_pf_docblock || $this->_pf_docblock_template)) {
\r
1271 if (strpos($this->_pv_last_word[1], '/**') !== 0) {
\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
1279 $this->_pf_no_output_yet = true;
\r
1280 $this->_pv_db_lines = array();
\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
1292 $this->_event_stack->popEvent();
\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
1301 $this->_pf_docblock = true;
\r
1303 $this->_pv_db_lines[] = $last_word;
\r
1304 if (strpos($last_word, '*/') !== false) {
\r
1305 $this->commonDocBlock();
\r
1308 $this->_pv_db_lines[] = $word[1];
\r
1309 if (strpos($word[1], '*/') !== false) {
\r
1310 $this->commonDocBlock();
\r
1313 $this->_pv_db_lines[] = $word[1];
\r
1315 if (($this->_pf_docblock || $this->_pf_docblock_template) &&
\r
1316 (strpos($word[1], '*/') !== false)
\r
1318 $this->commonDocBlock();
\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
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
1335 * @uses handleDesc() highlight inline tags in the description
\r
1336 * @uses handleTags() highlight all tags
\r
1339 function commonDocBlock()
\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
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
1358 substr($lines[$i], 0, strpos($lines[$i], $linesi[1]));
\r
1360 $lines[$i] = $linesi;
\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
1369 substr($lines[$i], 0, strpos($lines[$i], $linesi[1]));
\r
1371 $lines[$i] = $linesi;
\r
1374 for ($i = 0; $i < count($lines); $i++) {
\r
1375 if ($lines[$i][1] === false) {
\r
1378 if (substr(trim($lines[$i][1]), 0, 1) == '@' &&
\r
1379 substr(trim($lines[$i][1]), 0, 2) != '@ '
\r
1382 $i = count($lines);
\r
1385 if (isset($tagindex)) {
\r
1386 $tags = array_slice($lines, $tagindex);
\r
1387 $desc = array_slice($lines, 0, $tagindex);
\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
1403 $this->_pf_docblock = $this->_pf_docblock_template = false;
\r
1407 * Handle the description area of a DocBlock
\r
1409 * This method simply finds inline tags and highlights them
\r
1410 * separately from the rest of the description.
\r
1412 * @param mixed $desc the description piece(s)
\r
1415 * @uses getInlineTags()
\r
1418 function handleDesc($desc)
\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
1428 $this->newLineNum();
\r
1429 $this->_wp->linenum++;
\r
1432 if ($this->_pf_internal) {
\r
1433 $this->_pf_internal = false;
\r
1438 * Handle phpDocumentor tags in a DocBlock
\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
1444 * @param array $tags array of tags to handle
\r
1449 function handleTags($tags)
\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
1463 $curtag[] = $tags[$i];
\r
1465 $curtag[] = $tags[$i];
\r
1468 if (!empty($curtag)) {
\r
1469 $newtags[] = $curtag;
\r
1471 foreach ($newtags as $tag) {
\r
1472 foreach ($tag as $i => $t) {
\r
1473 if ($t[1] === false) {
\r
1476 if (is_array($t[1])) {
\r
1478 = explode(" ", str_replace("\t", ' ', $t[1][1]));
\r
1479 $x = $tag[$i][1][1];
\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
1487 $handle = $this->tagHandlers['*'];
\r
1489 $this->$handle($tagname, $restoftag);
\r
1494 * This handler recognizes all {@}inline} tags
\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
1500 * @param mixed $value the tag value
\r
1501 * @param bool $endinternal indicates the end of an @internal tag
\r
1506 function getInlineTags($value, $endinternal = false)
\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
1525 $dbtype = 'docblock';
\r
1526 $dbtype .= ($this->_pf_docblock ? '' : 'template');
\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
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
1549 if (in_array(str_replace('}', '', $word), $this->allowableInlineTags)
\r
1551 if (strpos($word, '}')) {
\r
1552 $word = str_replace('}', '', $word);
\r
1553 $val = '} ' . $val;
\r
1555 $val = explode('}', $val);
\r
1556 if (count($val) == 1) {
\r
1557 //addError(PDERROR_UNTERMINATED_INLINE_TAG,
\r
1558 // $word, '', $save);
\r
1561 $val = array_shift($rest);
\r
1562 if ($endinternal) {
\r
1563 $rest = join('}', $rest);
\r
1565 $rest = join(' ', $rest);
\r
1567 if (isset($this->inlineTagHandlers[$word])) {
\r
1568 $handle = $this->inlineTagHandlers[$word];
\r
1570 $handle = $this->inlineTagHandlers['*'];
\r
1572 $this->$handle($word, $val);
\r
1573 $this->_addDocBlockoutput($dbtype, $rest);
\r
1575 $val = $word . ' ' . $val;
\r
1576 $this->_addDocBlockoutput($dbtype, '{@' . $val);
\r
1584 * Handles all inline tags
\r
1586 * @param string $name the tag name
\r
1587 * @param mixed $value the tag value
\r
1592 function handleDefaultInlineTag($name, $value)
\r
1594 $this->_addDocBlockoutput('inlinetag', '{@' . $name . ' ' . $value . '}');
\r
1598 * phpDocumentor DocBlock tag handlers
\r
1600 * @param string $name tag name
\r
1601 * @param array $value array of lines contained in the tag description
\r
1607 * Handle normal tags
\r
1609 * This handler adds to outpu all comment information before the tag begins
\r
1610 * as in " * " before "@todo" in " * @todo"
\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
1615 * @param bool $coretag whether this tag is a core tag or not
\r
1617 * @uses getInlineTags() highlight a tag description
\r
1619 function defaultTagHandler($name, $value, $coretag = false)
\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
1632 $this->_addDocBlockoutput($dbtype, $line[1][0]);
\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
1639 $tagname = 'coretag';
\r
1641 $this->_addDocBlockoutput($tagname, '@' . $name);
\r
1644 $stored .= ' ' . $tpart;
\r
1647 $stored = $line[1];
\r
1649 $this->getInlineTags($stored);
\r
1650 if (strpos($stored, '*/') === false) {
\r
1651 $this->newLineNum();
\r
1652 $this->_wp->linenum++;
\r
1658 * main handler for "core" tags
\r
1660 * @see defaultTagHandler()
\r
1662 function coreTagHandler($name, $value)
\r
1664 return $this->defaultTagHandler($name, $value, true);
\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
1674 function globalTagHandler($name, $value)
\r
1676 $this->paramTagHandler($name, $value);
\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
1686 * @param bool $checkforvar private parameter, checks for $var or not
\r
1688 function paramTagHandler($name, $value, $checkforvar = true)
\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
1702 $this->_addDocBlockoutput($dbtype, $line[1][0]);
\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
1712 if (is_array($text)) {
\r
1713 if ($text[0] != 'desc') {
\r
1714 $this->_addDocBlockoutput($text[0], $text[1]);
\r
1716 $stored .= $text[1];
\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
1726 if (is_array($text)) {
\r
1727 if ($text[0] != 'desc') {
\r
1728 $this->_addDocBlockoutput($text[0], $text[1]);
\r
1730 $stored .= $text[1];
\r
1735 $stored = $line[1];
\r
1738 $this->getInlineTags($stored);
\r
1739 if (strpos($stored, '*/') === false) {
\r
1740 $this->newLineNum();
\r
1741 $this->_wp->linenum++;
\r
1747 * handles the @staticvar tag
\r
1749 * @see paramTagHandler()
\r
1751 function staticvarTagHandler($name, $value)
\r
1753 return $this->paramTagHandler($name, $value);
\r
1757 * handles the @var tag
\r
1759 * @see paramTagHandler()
\r
1761 function varTagHandler($name, $value)
\r
1763 return $this->paramTagHandler($name, $value);
\r
1769 * This handler works like {@link defaultTagHandler()} except it highlights
\r
1770 * the type in "@return type description"
\r
1772 function returnTagHandler($name, $value)
\r
1774 $this->paramTagHandler($name, $value, false);
\r
1778 * Handles @property(-read or -write) and @method magic tags
\r
1780 function propertyTagHandler($name, $value)
\r
1782 return $this->paramTagHandler($name, $value, true);
\r
1788 * Retrieve the type portion of a @tag type description
\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
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
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
1803 * @return array Format: array(state (0 [find type], 1 [var], 2 [done]),
\r
1806 function retrieveType($value, $state = 0, $checkforvar = false)
\r
1809 $result = array();
\r
1811 if (!isset($value[$index][1])) {
\r
1814 $val = $value[$index][1];
\r
1815 if (empty($val)) {
\r
1818 if ($index == 0) {
\r
1820 array_shift($val);
\r
1822 $val = explode(' ', $val);
\r
1824 $ret = $this->_retrieveType($val, $state, $checkforvar);
\r
1826 $result[$index++] = $ret[1];
\r
1827 } while ((!$checkforvar && $state < 1) || ($state < 2 && $checkforvar));
\r
1832 * used by {@link retrieveType()} in its work
\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
1842 function _retrieveType($value, $state, $checkforvar)
\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
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
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
1867 $result[] = array('desc', join(' ', $value));
\r
1868 return array(2, $result);
\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
1885 if (trim($type) == 'object') {
\r
1886 $result[] = array('tagphptype', $types . ' ');
\r
1887 $result[] = $this->_removeWhiteSpace($value, 0);
\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
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
1903 $result[] = array('tagphptype', $value[0] . ' ');
\r
1904 array_shift($value);
\r
1908 } while (!$done && count($value));
\r
1912 // still searching for type
\r
1913 if (!$done && !count($value)) {
\r
1914 return array(0, $result);
\r
1916 // still searching for var
\r
1917 if ($done && !count($value)) {
\r
1918 return array(1, $result);
\r
1921 $result[] = $this->_removeWhiteSpace($value, 0);
\r
1923 if ($checkforvar) {
\r
1924 if (count($value)) {
\r
1926 if (substr($value[0], 0, 1) == '$' ||
\r
1927 substr($value[0], 0, 2) == '&$'
\r
1929 $result[] = array('tagvarname' , $value[0] . ' ');
\r
1930 array_shift($value);
\r
1936 $result[] = array('desc', join(' ', $value));
\r
1937 return array($state, $result);
\r
1941 * captures trailing whitespace
\r
1943 * @param array &$value array of string
\r
1944 * @param int $index index to seek non-whitespace to
\r
1946 * @return string whitespace
\r
1949 function _removeWhiteSpace(&$value, $index)
\r
1952 if (count($value) > $index && empty($value[$index])) {
\r
1954 for ($i = $index; $i < count($value) && !strlen($value[$i]); $i++) {
\r
1957 array_splice($value, $index, $i - $index);
\r
1963 * Link generation methods
\r
1965 * @param string|array $word token to try to link
\r
1970 * Generate a link to documentation for an element
\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
1976 function _link($word)
\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
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
1990 $this->_addoutput($word);
\r
1993 $link = $this->_converter->getLink($word[1] . '()');
\r
1994 if (is_object($link)) {
\r
1995 $this->_addoutput($this->_converter->returnSee($link,
\r
1998 } elseif (is_string($link) && strpos($link, 'ttp://')) {
\r
1999 $this->_addoutput($this->_converter->returnLink($link,
\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
2007 $this->_addoutput($word, true);
\r
2011 $this->_addoutput($word);
\r
2015 * Works like {@link _link()} except it only links to global variables
\r
2017 function _globallink($word)
\r
2019 if (!is_array($word)) {
\r
2020 return $this->_addoutput($word);
\r
2022 if ($word[0] != T_VARIABLE) {
\r
2023 return $this->_addoutput($word);
\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
2033 $this->_addoutput($word);
\r
2037 * Works like {@link _link()} except it only links to classes
\r
2039 function _classlink($word)
\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
2050 $this->_addoutput($word);
\r
2054 * Works like {@link _link()} except it only links to methods
\r
2056 function _methodlink($word)
\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
2064 $link = $this->_converter->getLink($this->_pv_class . '::' .
\r
2067 if (is_object($link)) {
\r
2068 $this->_addoutput($this->_converter->returnSee($link,
\r
2072 if (isset($this->_pv_prev_var_type)) {
\r
2073 $this->_addoutput($word);
\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
2084 $this->_addoutput($word);
\r
2088 * Works like {@link _link()} except it only links to class variables
\r
2090 * @param bool $justastring true if the $word is only a string
\r
2092 function _varlink($word, $justastring=false)
\r
2094 if ($justastring) {
\r
2095 $word[0] = T_VARIABLE;
\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
2106 $link = $this->_converter->getLink($this->_pv_class . '::' .
\r
2109 if (is_object($link)) {
\r
2110 $this->_addoutput($this->_converter->returnSee($link,
\r
2114 //debug("checking var " . $x . $word[1]);
\r
2115 if (isset($this->_pv_prev_var_type)) {
\r
2116 $this->_addoutput($word);
\r
2119 $link = $this->_converter->getLink($x . $word[1]);
\r
2120 if (is_object($link)) {
\r
2121 $this->_addoutput($this->_converter->returnSee($link,
\r
2126 $this->_addoutput($word);
\r
2135 * This method adds output to {@link $_line}
\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
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
2144 * @see _flush_save()
\r
2146 function _addoutput($word, $preformatted = false)
\r
2148 if ($this->_pf_no_output_yet) {
\r
2151 if ($this->_pf_quote_active) {
\r
2152 if (is_array($word)) {
\r
2153 $this->_save .= $this->_converter->highlightSource($word[0],
\r
2156 $this->_save .= $this->_converter->highlightSource(false,
\r
2160 $this->_flush_save();
\r
2161 if (is_string($word) && trim($word) == '') {
\r
2162 $this->_line .= $this->_converter->postProcess($word);
\r
2165 if (is_array($word) && trim($word[1]) == '') {
\r
2166 $this->_line .= $this->_converter->postProcess($word[1]);
\r
2169 if (is_array($word)) {
\r
2170 $this->_line .= $this->_converter->highlightSource($word[0],
\r
2171 $word[1], $preformatted);
\r
2173 $this->_line .= $this->_converter->highlightSource(false,
\r
2174 $word, $preformatted);
\r
2180 * Like {@link _output()}, but for DocBlock highlighting
\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
2188 function _addDocBlockoutput($dbtype, $word, $preformatted = false)
\r
2190 if ($this->_pf_internal) {
\r
2191 $this->_line .= $this->_converter->highlightDocBlockSource('internal',
\r
2192 $word, $preformatted);
\r
2194 $this->_line .= $this->_converter->highlightDocBlockSource($dbtype,
\r
2195 $word, $preformatted);
\r
2200 * Flush a saved string variable highlighting
\r
2205 * @todo CS cleanup - rename to _flushSave() for camelCase rule
\r
2207 function _flush_save()
\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
2217 $this->_line .= $this->_converter->
\r
2218 highlightSource(T_CONSTANT_ENCAPSED_STRING, $this->_save, true);
\r
2219 $this->_save = '';
\r
2225 * Give the word parser necessary data to begin a new parse
\r
2227 * @param array &$data all tokens separated by line number
\r
2231 function configWordParser(&$data)
\r
2233 $this->_wp->setup($data, $this);
\r
2234 $this->_wp->setWhitespace(true);
\r
2238 * Initialize all parser state variables
\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
2246 * @uses $_wp sets to a new {@link phpDocumentor_HighlightWordParser}
\r
2248 function setupStates($inlinesourceparse, $class)
\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
2258 $this->_event_stack->pushEvent(PARSER_EVENT_CLASS);
\r
2259 $this->_pv_class = $class;
\r
2262 $this->_pv_class = null;
\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
2318 * Initialize the {@link $tokenpushEvent, $wordpushEvent} arrays
\r
2322 function phpDocumentor_HighlightParser()
\r
2324 if (!defined('T_INTERFACE')) {
\r
2325 define('T_INTERFACE', -1);
\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
2335 $this->tokenpushEvent[PARSER_EVENT_NOEVENTS] =
\r
2337 T_OPEN_TAG => PARSER_EVENT_PHPCODE,
\r
2340 /**************************************************************/
\r
2342 $this->tokenpushEvent[PARSER_EVENT_PHPCODE] =
\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
2355 $this->wordpushEvent[PARSER_EVENT_PHPCODE] =
\r
2357 "define" => PARSER_EVENT_DEFINE,
\r
2358 '"' => PARSER_EVENT_QUOTE,
\r
2359 '\'' => PARSER_EVENT_QUOTE,
\r
2361 /**************************************************************/
\r
2363 $this->wordpushEvent[PARSER_EVENT_FUNCTION] =
\r
2365 '{' => PARSER_EVENT_LOGICBLOCK,
\r
2366 '(' => PARSER_EVENT_FUNCTION_PARAMS,
\r
2368 $this->tokenpushEvent[PARSER_EVENT_FUNCTION] =
\r
2370 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2371 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2373 $this->wordpopEvent[PARSER_EVENT_FUNCTION] = array("}");
\r
2374 /**************************************************************/
\r
2376 $this->tokenpopEvent[PARSER_EVENT_EOFQUOTE] = array(T_END_HEREDOC);
\r
2377 /**************************************************************/
\r
2379 $this->tokenpushEvent[PARSER_EVENT_FUNCTION_PARAMS] =
\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
2386 $this->wordpushEvent[PARSER_EVENT_FUNCTION_PARAMS] =
\r
2388 '"' => PARSER_EVENT_QUOTE,
\r
2389 "'" => PARSER_EVENT_QUOTE,
\r
2391 $this->wordpopEvent[PARSER_EVENT_FUNCTION_PARAMS] = array(")");
\r
2392 /**************************************************************/
\r
2394 $this->wordpushEvent[PARSER_EVENT_LOGICBLOCK] =
\r
2396 "{" => PARSER_EVENT_LOGICBLOCK,
\r
2397 '"' => PARSER_EVENT_QUOTE,
\r
2399 $this->tokenpushEvent[PARSER_EVENT_LOGICBLOCK] =
\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
2407 $this->wordpopEvent[PARSER_EVENT_LOGICBLOCK] = array("}");
\r
2408 $this->tokenpopEvent[PARSER_EVENT_LOGICBLOCK] = array(T_CURLY_OPEN);
\r
2410 /**************************************************************/
\r
2412 $this->tokenpushEvent[PARSER_EVENT_ARRAY] =
\r
2414 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2415 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2417 $this->wordpopEvent[PARSER_EVENT_ARRAY] = array(")");
\r
2418 /**************************************************************/
\r
2420 $this->tokenpushEvent[PARSER_EVENT_FUNC_GLOBAL] =
\r
2422 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2423 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2425 $this->wordpopEvent[PARSER_EVENT_FUNC_GLOBAL] = array(";");
\r
2426 /**************************************************************/
\r
2428 $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR] =
\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
2434 $this->wordpushEvent[PARSER_EVENT_STATIC_VAR] =
\r
2436 "=" => PARSER_EVENT_STATIC_VAR_VALUE,
\r
2438 $this->wordpopEvent[PARSER_EVENT_STATIC_VAR] = array(";");
\r
2439 /**************************************************************/
\r
2441 $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] =
\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
2448 $this->wordpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] =
\r
2450 '"' => PARSER_EVENT_QUOTE,
\r
2451 "'" => PARSER_EVENT_QUOTE,
\r
2453 $this->wordpopEvent[PARSER_EVENT_STATIC_VAR_VALUE] = array(";", ",");
\r
2454 /**************************************************************/
\r
2455 $this->tokenpushEvent[PARSER_EVENT_QUOTE] =
\r
2457 T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
\r
2458 T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR,
\r
2460 $this->wordpopEvent[PARSER_EVENT_QUOTE] = array('"');
\r
2461 /**************************************************************/
\r
2462 $this->tokenpushEvent[PARSER_EVENT_QUOTE_VAR] =
\r
2464 T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
\r
2465 T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR,
\r
2467 $this->wordpushEvent[PARSER_EVENT_QUOTE_VAR] =
\r
2469 "{" => PARSER_EVENT_QUOTE_VAR,
\r
2470 '"' => PARSER_EVENT_QUOTE_VAR,
\r
2471 "'" => PARSER_EVENT_QUOTE_VAR,
\r
2473 $this->wordpopEvent[PARSER_EVENT_QUOTE_VAR] = array('}');
\r
2474 /**************************************************************/
\r
2476 $this->tokenpushEvent[PARSER_EVENT_DEFINE] =
\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
2482 $this->wordpushEvent[PARSER_EVENT_DEFINE] =
\r
2484 "(" => PARSER_EVENT_DEFINE_PARAMS,
\r
2486 $this->wordpopEvent[PARSER_EVENT_DEFINE] = array(";");
\r
2487 /**************************************************************/
\r
2489 $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS] =
\r
2491 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2492 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2494 $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS] =
\r
2496 "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,
\r
2497 '"' => PARSER_EVENT_QUOTE,
\r
2498 "'" => PARSER_EVENT_QUOTE,
\r
2500 $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS] = array(")");
\r
2501 /**************************************************************/
\r
2503 $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] =
\r
2505 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2506 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2508 $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] =
\r
2510 "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,
\r
2511 '"' => PARSER_EVENT_QUOTE,
\r
2512 "'" => PARSER_EVENT_QUOTE,
\r
2514 $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = array(")");
\r
2515 /**************************************************************/
\r
2517 $this->tokenpushEvent[PARSER_EVENT_VAR] =
\r
2519 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2520 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2521 T_ARRAY => PARSER_EVENT_ARRAY,
\r
2523 $this->wordpopEvent[PARSER_EVENT_VAR] = array(";");
\r
2524 /**************************************************************/
\r
2526 $this->tokenpushEvent[PARSER_EVENT_CLASS] =
\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
2534 $this->wordpopEvent[PARSER_EVENT_CLASS] = array("}");
\r
2535 /**************************************************************/
\r
2537 $this->wordpushEvent[PARSER_EVENT_METHOD] =
\r
2539 '{' => PARSER_EVENT_METHOD_LOGICBLOCK,
\r
2540 '(' => PARSER_EVENT_FUNCTION_PARAMS,
\r
2542 $this->tokenpushEvent[PARSER_EVENT_METHOD] =
\r
2544 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2545 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2547 $this->wordpopEvent[PARSER_EVENT_METHOD] = array("}", ";");
\r
2548 /**************************************************************/
\r
2550 $this->wordpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] =
\r
2552 "{" => PARSER_EVENT_METHOD_LOGICBLOCK,
\r
2553 '"' => PARSER_EVENT_QUOTE,
\r
2555 $this->tokenpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] =
\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
2563 $this->wordpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array("}");
\r
2564 $this->tokenpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array(T_CURLY_OPEN);
\r
2565 /**************************************************************/
\r
2567 $this->tokenpushEvent[PARSER_EVENT_INCLUDE] =
\r
2569 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2570 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2572 $this->wordpushEvent[PARSER_EVENT_INCLUDE] =
\r
2574 "(" => PARSER_EVENT_INCLUDE_PARAMS,
\r
2576 $this->wordpopEvent[PARSER_EVENT_INCLUDE] = array(";");
\r
2577 /**************************************************************/
\r
2579 $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS] =
\r
2581 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2582 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2584 $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS] =
\r
2586 "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,
\r
2588 $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS] = array(")");
\r
2589 /**************************************************************/
\r
2591 $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] =
\r
2593 T_COMMENT => PARSER_EVENT_COMMENT,
\r
2594 T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
\r
2596 $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] =
\r
2598 "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,
\r
2600 $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = array(")");
\r