diff options
Diffstat (limited to 'buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc')
-rwxr-xr-x | buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc | 2603 |
1 files changed, 2603 insertions, 0 deletions
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc b/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc new file mode 100755 index 00000000..a474f73c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc @@ -0,0 +1,2603 @@ +<?php +/** + * Source Code Highlighting + * + * The classes in this file are responsible for the dynamic @example, @filesource + * and {@}source} tags output. Using the phpDocumentor_HighlightWordParser, + * the phpDocumentor_HighlightParser retrieves PHP tokens one by one from the + * array generated by {@link phpDocumentorTWordParser} source retrieval functions + * and then highlights them individually. + * + * It accomplishes this highlighting through the assistance of methods in + * the output Converter passed to its parse() method, and then returns the + * fully highlighted source as a string + * + * phpDocumentor :: automatic documentation generator + * + * PHP versions 4 and 5 + * + * Copyright (c) 2002-2008 Gregory Beaver + * + * LICENSE: + * + * This library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General + * Public License as published by the Free Software Foundation; + * either version 2.1 of the License, or (at your option) any + * later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category ToolsAndUtilities + * @package phpDocumentor + * @subpackage Parsers + * @author Gregory Beaver <cellog@php.net> + * @copyright 2002-2008 Gregory Beaver + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @version CVS: $Id: HighlightParser.inc 253641 2008-02-24 02:35:44Z ashnazg $ + * @filesource + * @link http://www.phpdoc.org + * @link http://pear.php.net/PhpDocumentor + * @tutorial tags.example.pkg, tags.filesource.pkg, tags.inlinesource.pkg + * @since 1.2.0beta3 + * @todo CS cleanup - change package to PhpDocumentor + */ + +/** + * Retrieve tokens from an array of tokens organized by line numbers + * + * @category ToolsAndUtilities + * @package phpDocumentor + * @subpackage Parsers + * @author Gregory Beaver <cellog@php.net> + * @copyright 2002-2008 Gregory Beaver + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @version Release: 1.4.3 + * @link http://www.phpdoc.org + * @link http://pear.php.net/PhpDocumentor + * @since 1.2.0beta3 + * @todo CS cleanup - change package to PhpDocumentor + * @todo CS cleanup - change class name to PhpDocumentor_* + */ +class phpDocumentor_HighlightWordParser extends phpDocumentorTWordParser +{ + /** + * Hash used to keep track of line numbers that have already been initialized + * @var array + * @access private + */ + var $_listLineNums = array(); + /** + * Initialize the parser object + * + * @param array &$input the input + * @param phpDocumentor_HighlightParser &$parser the parser + * + * @return void + */ + function setup(&$input, &$parser) + { + $this->_parser = &$parser; + $this->data = &$input; + $this->_all = $input; + $this->_sourceline = 0; + $this->pos = 0; + $this->linenum = 0; + } + + /** + * debugging function + * + * @return void + * @access private + */ + function printState() + { + $linenum = $this->linenum; + $pos = $this->pos; + if (!isset($this->_all[$this->linenum][$this->pos])) { + $linenum++; + $pos = 0; + } + $details = ''; + $token = $this->_all[$linenum][$pos]; + if (is_array($token)) { + $details = token_name($token[0]); + $token = htmlspecialchars($token[1]); + } else { + $token = htmlspecialchars($token); + } + debug('Next Token ' . $this->linenum . '-' . $this->pos . ':' . $details); + var_dump($token); + } + + /** + * Retrieve the position of the next token that will be parsed + * in the internal token array + * + * @return array format: array(line number, position) + */ + function nextToken() + { + $linenum = $this->linenum; + $pos = $this->pos; + if (!isset($this->_all[$this->linenum][$this->pos])) { + $linenum++; + $pos = 0; + } + if (!isset($this->_all[$linenum][$pos])) { + return false; + } + return array($linenum, $pos); + } + + /** + * Retrieve the next token + * + * @return array|string either array(PHP token constant, token) or string + * non-specific separator + */ + function getWord() + { + if (!isset($this->_all[$this->linenum][$this->pos])) { + $this->linenum++; + $this->pos = 0; + if (!isset($this->_all[$this->linenum])) { + return false; + } + $this->_parser->newLineNum(); + return $this->getWord(); + } + $word = $this->_all[$this->linenum][$this->pos++]; + return str_replace("\t", ' ', $word); + } + + /** + * back the word parser to the previous token as defined by $last_token + * + * @param array|string $last_token token, or output from {@link nextToken()} + * @param bool $is_pos if true, backupPos interprets $last_token + * to be the position in the internal token + * array of the last token + * + * @return void + */ + function backupPos($last_token, $is_pos = false) + { + if (!$last_token) { + return; + } + if ($is_pos) { + $this->linenum = $last_token[0]; + $this->pos = $last_token[1]; + return; + } + if ($last_token === false) { + return; + } + + //fancy_debug('before', $this->linenum, $this->pos, + // token_name($this->_all[$this->linenum][$this->pos][0]), + // htmlentities($this->_all[$this->linenum][$this->pos][1]), + // $this->_all[$this->linenum]); + + do { + $this->pos--; + if ($this->pos < 0) { + $this->linenum--; + if ($this->linenum < 0) { + var_dump($last_token); + break; + } + $this->pos = count($this->_all[$this->linenum]) - 1; + } + } while (!$this->tokenEquals($last_token, str_replace("\t", ' ', + $this->_all[$this->linenum][$this->pos]))); + + //fancy_debug('after', $this->linenum, $this->pos, + // token_name($this->_all[$this->linenum][$this->pos][0]), + // htmlentities($this->_all[$this->linenum][$this->pos][1])); + } +} + +/** + * Highlights source code using {@link parse()} + * + * @category ToolsAndUtilities + * @package phpDocumentor + * @subpackage Parsers + * @author Gregory Beaver <cellog@php.net> + * @copyright 2002-2008 Gregory Beaver + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @version Release: 1.4.3 + * @link http://www.phpdoc.org + * @link http://pear.php.net/PhpDocumentor + * @since 1.2.0beta3 + * @todo CS cleanup - change package to PhpDocumentor + * @todo CS cleanup - change class name to PhpDocumentor_* + */ +class phpDocumentor_HighlightParser extends phpDocumentorTParser +{ + /**#@+ + * @access private + */ + + /** + * Highlighted source is built up in this string + * @var string + */ + var $_output; + + /** + * contents of the current source code line as it is parsed + * @var string + */ + var $_line; + + /** + * Used to retrieve highlighted tokens + * @var Converter a descendant of Converter + */ + var $_converter; + + /** + * Path to file being highlighted, if this is from a @filesource tag + * @var false|string full path + */ + var $_filesourcepath; + + /** + * @var array + */ + var $eventHandlers = array( + PARSER_EVENT_ARRAY => 'defaultHandler', + PARSER_EVENT_CLASS => 'handleClass', + PARSER_EVENT_COMMENT => 'handleComment', + PARSER_EVENT_DOCBLOCK_TEMPLATE => 'handleDocBlockTemplate', + PARSER_EVENT_END_DOCBLOCK_TEMPLATE => 'handleEndDocBlockTemplate', + PARSER_EVENT_LOGICBLOCK => 'handleLogicBlock', + PARSER_EVENT_METHOD_LOGICBLOCK => 'handleMethodLogicBlock', + PARSER_EVENT_NOEVENTS => 'defaultHandler', + PARSER_EVENT_OUTPHP => 'defaultHandler', + PARSER_EVENT_CLASS_MEMBER => 'handleClassMember', + PARSER_EVENT_DEFINE => 'defaultHandler', + PARSER_EVENT_DEFINE_PARAMS => 'defaultHandler', + PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS => 'defaultHandler', + PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS => 'defaultHandler', + PARSER_EVENT_DOCBLOCK => 'handleDocBlock', + PARSER_EVENT_TAGS => 'handleTags', + PARSER_EVENT_DESC => 'handleDesc', + PARSER_EVENT_DOCKEYWORD => 'handleTag', + PARSER_EVENT_DOCKEYWORD_EMAIL => 'handleDockeywordEmail', + PARSER_EVENT_EOFQUOTE => 'handleQuote', + PARSER_EVENT_FUNCTION => 'handleFunction', + PARSER_EVENT_METHOD => 'handleMethod', + PARSER_EVENT_FUNCTION_PARAMS => 'handleFunctionParams', + PARSER_EVENT_FUNC_GLOBAL => 'handleFuncGlobal', + PARSER_EVENT_INLINE_DOCKEYWORD => 'handleInlineDockeyword', + PARSER_EVENT_INCLUDE => 'defaultHandler', + PARSER_EVENT_INCLUDE_PARAMS => 'defaultHandler', + PARSER_EVENT_QUOTE => 'handleQuote', + PARSER_EVENT_QUOTE_VAR => 'handleQuoteVar', + PARSER_EVENT_PHPCODE => 'handlePhpCode', + PARSER_EVENT_SINGLEQUOTE => 'handleSingleQuote', + PARSER_EVENT_STATIC_VAR => 'defaultHandler', + PARSER_EVENT_STATIC_VAR_VALUE => 'defaultHandler', + PARSER_EVENT_VAR => 'handleVar', + ); + + /** + * event handlers for @tags + * @tutorial tags.pkg + */ + var $tagHandlers = array( + '*' => 'defaultTagHandler', + 'abstract' => 'coreTagHandler', + 'access' => 'coreTagHandler', + 'author' => 'coreTagHandler', + 'category' => 'coreTagHandler', + 'copyright' => 'coreTagHandler', + 'deprecated' => 'coreTagHandler', + 'example' => 'coreTagHandler', + 'filesource' => 'coreTagHandler', + 'final' => 'coreTagHandler', + 'global' => 'globalTagHandler', + 'ignore' => 'coreTagHandler', + 'license' => 'coreTagHandler', + 'link' => 'coreTagHandler', + 'name' => 'coreTagHandler', + 'package' => 'coreTagHandler', + 'param' => 'paramTagHandler', + 'parameter' => 'paramTagHandler', + 'see' => 'coreTagHandler', + 'since' => 'coreTagHandler', + 'subpackage' => 'coreTagHandler', + 'internal' => 'coreTagHandler', + 'return' => 'returnTagHandler', + 'static' => 'coreTagHandler', + 'staticvar' => 'staticvarTagHandler', + 'throws' => 'coreTagHandler', + 'todo' => 'coreTagHandler', + 'tutorial' => 'coreTagHandler', + 'uses' => 'coreTagHandler', + 'var' => 'varTagHandler', + 'version' => 'coreTagHandler', + 'property' => 'propertyTagHandler', + 'property-read' => 'propertyTagHandler', + 'property-write' => 'propertyTagHandler', + 'method' => 'propertyTagHandler' + ); + /**#@-*/ + + /** + * wraps the current line (via the converter) and resets it to empty + * + * @return void + * @uses Converter::SourceLine() encloses {@link $_line} in a + * converter-specific format + */ + function newLineNum() + { + if ($this->_pf_no_output_yet) { + return; + } + $this->_flush_save(); + $this->_line .= $this->_converter->flushHighlightCache(); + $this->_output .= $this->_converter->SourceLine($this->_wp->linenum, + $this->_line, $this->_path); + $this->_line = ''; + } + + /** + * Start the parsing at a certain line number + * + * @param int $num line number + * + * @return void + */ + function setLineNum($num) + { + $this->_wp->linenum = $num; + } + + /** + * Parse a new file + * + * The parse() method is a do...while() loop that retrieves tokens one by + * one from the {@link $_event_stack}, and uses the token event array set up + * by the class constructor to call event handlers. + * + * The event handlers each process the tokens passed to them, and use the + * {@link _addoutput()} method to append the processed tokens to the + * {@link $_line} variable. The word parser calls {@link newLineNum()} + * every time a line is reached. + * + * In addition, the event handlers use special linking functions + * {@link _link()} and its cousins (_classlink(), etc.) to create in-code + * hyperlinks to the documentation for source code elements that are in the + * source code. + * + * @param array &$parse_data the parse data + * @param Converter &$converter the converter object + * @param bool $inlinesourceparse whether this data is from an + * inline {@}source} tag + * @param string|false $class if a string, it is the name of the + * class whose method we are parsing + * containing a {@}source} tag + * @param false|integer $linenum starting line number from + * {@}source linenum} + * @param false|string $filesourcepath full path to file with @filesource + * tag, if this is a @filesource parse + * + * @staticvar int used for recursion limiting if a handler for + * an event is not found + * @return bool + * @uses setupStates() initialize parser state variables + * @uses configWordParser() pass $parse_data to prepare retrieval of tokens + * @todo CS cleanup - rename tokenizer_ext constant to uppercase + */ + function parse (&$parse_data, &$converter, $inlinesourceparse = false, + $class = false, $linenum = false, $filesourcepath = false) + { + if (!tokenizer_ext) { + if (is_array($parse_data)) { + $parse_data = join($parse_data, ''); + } + $parse_data = explode("\n", $parse_data); + $this->_output = ''; + foreach ($parse_data as $linenum => $line) { + if ($linenum > 0) { + $this->_output .= $converter->SourceLine($linenum, + $line, $filesourcepath); + } + } + return $converter->PreserveWhiteSpace($this->_output); + } + static $endrecur = 0; + $this->_converter = &$converter; + $converter->startHighlight(); + $this->_path = $filesourcepath; + $this->setupStates($inlinesourceparse, $class); + + $this->configWordParser($parse_data); + if ($linenum !== false) { + $this->setLineNum($linenum); + } + // initialize variables so E_ALL error_reporting doesn't complain + $pevent = 0; + $word = 0; + + do { + $lpevent = $pevent; + $pevent = $this->_event_stack->getEvent(); + if ($lpevent != $pevent) { + $this->_last_pevent = $lpevent; + } + + if ($pevent == PARSER_EVENT_CLASS_MEMBER) { + $this->_wp->setWhitespace(true); + } else { + $this->_wp->setWhitespace(false); + } + + if (!is_array($word)) { + $lw = $word; + } + if (is_array($word) && $word[0] != T_WHITESPACE) { + $lw = $word; + } + $dbg_linenum = $this->_wp->linenum; + $dbg_pos = $this->_wp->getPos(); + $word = $this->_wp->getWord(); + if (is_array($word) && ($word[0] == T_WHITESPACE || + $word[0] == T_COMMENT) && + $pevent != PARSER_EVENT_CLASS_MEMBER + ) { + //debug("added " . $this->_wp->linenum . '-' . $this->_wp->pos); + $this->_addoutput($word); + continue; + } else { + $this->_pv_last_word = $lw; + } + if ($pevent != PARSER_EVENT_DOCBLOCK) { + $this->_pv_last_next_word = $this->_pv_next_word; + $this->_pv_next_word = $this->_wp->nextToken(); + } + // in wordparser, have to keep track of lines + //$this->publishEvent(PHPDOCUMENTOR_EVENT_NEWLINENUM, + // $this->_wp->linenum); + if (PHPDOCUMENTOR_DEBUG == true) { + echo "LAST: "; + if (is_array($this->_pv_last_word)) { + echo token_name($this->_pv_last_word[0]) . + ' => |' . + htmlspecialchars($this->_pv_last_word[1]); + } else { + echo "|" . $this->_pv_last_word; + } + echo "|\n"; + echo "PEVENT: " . $this->getParserEventName($pevent) . "\n"; + echo "LASTPEVENT: " . + $this->getParserEventName($this->_last_pevent) . "\n"; + //echo "LINE: " . $this->_line . "\n"; + //echo "OUTPUT: " . $this->_output . "\n"; + echo $dbg_linenum . '-' . $dbg_pos . ": "; + if (is_array($word)) { + echo token_name($word[0]) . ' => |' . htmlspecialchars($word[1]); + } else { + echo '|'.htmlspecialchars($word); + } + echo "|\n"; + $this->_wp->printState(); + echo "NEXT TOKEN: "; + $tok1 = $this->_pv_next_word; + $tok = $this->_wp->_all[$tok1[0]][$tok1[1]]; + if (is_array($tok)) { + echo token_name($tok[0]) . ' => ' . $tok1[0] . '-' . $tok1[1] . + '|' . htmlspecialchars($tok[1]); + } else { + echo "|" . $tok; + } + echo "|\n"; + echo "-------------------\n\n\n"; + flush(); + } + if ($word !== false && isset($this->eventHandlers[$pevent])) { + $handle = $this->eventHandlers[$pevent]; + $this->$handle($word, $pevent); + } elseif ($word !== false) { + debug('WARNING: possible error, no handler for event number ' + . $pevent); + if ($endrecur++ == 25) { + die("FATAL ERROR, recursion limit reached"); + } + } + } while (!($word === false)); + if (strlen($this->_line)) { + $this->newLineNum(); + } + return $this->_output; + } + + /**#@+ + * Event Handlers + * + * All Event Handlers use {@link checkEventPush()} and + * {@link checkEventPop()} to set up the event stack and parser state. + * + * @param string|array $word token value + * @param int $pevent parser event from {@link Parser.inc} + * + * @return void + * @access private + */ + /** + * Most tokens only need highlighting, and this method handles them + */ + function defaultHandler($word, $pevent) + { + $this->_addoutput($word); + if ($this->checkEventPush($word, $pevent)) { + return; + } + $this->checkEventPop($word, $pevent); + } + + /** + * Handles global declarations in a function, like: + * + * <code> + * function foobar() + * { + * global $_phpDocumentor_setting; + * } + * </code> + * + * @uses _globallink() instead of _addoutput(), to link to global variables + * if they are used in a function + */ + function handleFuncGlobal($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) { + return; + } + $this->_globallink($word); + $this->checkEventPop($word, $pevent); + } + + /** + * Handles strings in quotation marks and heredoc + * + * Special handling is needed for strings that contain variables like: + * + * <code>$a = "$test string"</code> + * + * The tokenizer parses out tokens '"',array(T_VARIABLE,'$test'),' string', + * and '"'. Since it is possible to have $this->classvar in a string, + * we save a variable name just in case the next token is -> to allow linking + * to class members. Otherwise, the string is simply highlighted. + * + * constant strings (with no $variables in them) are passed as a single + * entity, and so will be saved in the last token parsed. This means the + * event handler must tell the word parser to re-retrieve the current token + * so that the correct event handler can process it. + */ + function handleQuote($word, $pevent) + { + if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) { + $this->_pv_lastvar = $word; + } + if ($this->checkEventPush($word, $pevent)) { + $this->_addoutput($word); + return; + } + if ($this->_pf_quote_active && + (($this->_pv_last_word == '"' && + $this->_last_pevent != PARSER_EVENT_QUOTE) || + (is_array($this->_pv_last_word) && + $this->_pv_last_word[0] == T_END_HEREDOC && + $this->_last_pevent != PARSER_EVENT_EOFQUOTE)) + ) { + $this->_pf_quote_active = false; + $this->_wp->backupPos($word); + $this->_event_stack->popEvent(); + return; + } + if (!$this->_pf_quote_active && + (($this->_pv_last_word == '"' && + $this->_last_pevent != PARSER_EVENT_QUOTE) || + (is_array($this->_pv_last_word) && + $this->_pv_last_word[0] == T_END_HEREDOC && + $this->_last_pevent != PARSER_EVENT_EOFQUOTE)) + ) { + if (is_array($word) && $word[0] == T_VARIABLE) { + $this->_pv_lastvar = $word; + } + $this->_pf_quote_active = true; + $this->_save_highlight_state = $this->_converter->getHighlightState(); + $this->_converter->startHighlight(); + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + return; + } elseif (is_array($this->_pv_last_word) && + $this->_pv_last_word[0] == T_CONSTANT_ENCAPSED_STRING + ) { + //$this->_pv_quote_data = $this->_pv_last_word[1]; + $this->_event_stack->popEvent(); + $this->_wp->backupPos($word); + return; + } + if ($this->checkEventPop($word, $pevent)) { + $this->_pf_quote_active = false; + } + $this->_addoutput($word); + } + + /** + * Handles {$variable} within a "quote" + * + * This is a simple handler, for a very complex + * array of legal syntax. It is legal to nest control structures + * inside the {}, and other weird stuff. + */ + function handleQuoteVar($word, $pevent) + { + if ($this->checkEventPop($word, $pevent)) { + $this->_pf_quote_active = true; + $this->_addoutput($word); + return; + } + if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) { + $this->_pv_lastvar = $word; + } + if ($this->checkEventPush($word, $pevent)) { + $this->_pf_quote_active = false; + if (is_string($word) && ($word == '{' || $word == '"' || $word == "'") + ) { + $this->_pf_quote_active = true; + $this->_pv_lastvar = false; + } + } + $this->_addoutput($word); + } + + /** + * Handles define() statements + * + * The only thing this handler cares about is retrieving the name of the + * define variable, and the end of the define statement, so after the name + * is found, it simply makes sure parentheses are matched as in this case: + * + * <code> + * define("test",array("hello",6 => 4, 5 => array('there'))); + * </code> + * + * This handler and the DEFINE_PARAMS_PARENTHESIS handler (which is just + * {@link defaultHandler()} in this version, as nothing fancy is needed) + * work together to ensure proper parenthesis matching. + * + * If the define variable is documented, a link will be created to its + * documentation using the Converter passed. + */ + function handleDefine($word, $pevent) + { + static $token_save; + if (!isset($token_save)) { + $token_save = array(); + } + $e = $this->checkEventPush($word, $pevent); + if ($e && $e != PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS) { + return; + } + + if (!isset($this->_pv_define_params_data)) { + $this->_pv_define_params_data = ''; + } + + if ($this->checkEventPop($word, $pevent)) { + unset($token_save); + $this->_addoutput($word); + } + if ($this->_pf_definename_isset) { + $this->_addoutput($word); + } else { + if ($word != ",") { + $token_save[] = $word; + if (is_array($word)) { + $word = $word[1]; + } + $this->_pv_define_params_data .= $word; + } else { + if (substr($this->_pv_define_params_data, 0, 1) == + substr($this->_pv_define_params_data, + strlen($this->_pv_define_params_data) - 1) && + in_array(substr($this->_pv_define_params_data, 0, 1), + array('"', "'")) + ) { + // remove leading and ending quotation marks + // if there are only two + $a = substr($this->_pv_define_params_data, 0, 1); + $b = substr($this->_pv_define_params_data, 1, + strlen($this->_pv_define_params_data) - 2); + if (strpos($b, $a) === false) { + $this->_pv_define_params_data = $b; + } + } + $this->_pf_definename_isset = true; + + $link = $this->_converter->getLink($this->_pv_define_params_data); + foreach ($token_save as $token) { + if (is_object($link)) { + if (is_array($token)) { + $token = $token[1]; + } + $this->_addoutput($this->_converter->returnSee($link, + $token)); + } else { + $this->_addoutput($save, $token); + } + } + $this->_pv_define_params_data = ''; + } + } + } + + /** + * Handles normal global code. Special consideration is taken for DocBlocks + * as they need to retrieve the whole DocBlock before doing any output, so + * the parser flag {@link $_pf_no_output_yet} is set to tell + * {@link _addoutput()} not to spit anything out yet. + * + * @uses _link() make any global code that is a documentable element link + * to the php manual or its documentation + */ + function handlePhpCode($word, $pevent) + { + $test = $this->checkEventPush($word, $pevent); + if ($test == PARSER_EVENT_DOCBLOCK || $test == PARSER_EVENT_COMMENT) { + if (substr($word[1], 0, 2) == '/*' && strpos($word[1], '*/')) { + $this->_pv_last_word = $word; + if ($word[1] == '/**#@-*/') { + $this->_pf_docblock_template = true; + } else { + $this->_pf_docblock = true; + } + return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK); + } + $this->_pf_no_output_yet = true; + $this->_pv_saveline = $this->_wp->linenum + 1; + return; + } + if (is_array($word) && $word[0] == T_DOUBLE_COLON) { + $this->_pf_colon_colon = true; + } + if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) { + $this->_pv_last_string = $word; + } + $this->_link($word); + $this->checkEventPop($word, $pevent); + } + + /** + * Handle the function declaration header + * + * This handler only sees the "function name" portion of the function + * declaration. Handling of the function parameters is by + * {@link handleFunctionParams()}, and the function body is handled by + * {@link handleLogicBlock()} + */ + function handleFunction($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) { + $this->_addoutput($word); + return; + } + if ($this->checkEventPop($word, $pevent)) { + return; + } + $this->_link($word); + } + + /** + * Handle the method declaration header + * + * This handler only sees the "function name" portion of the method + * declaration. Handling of the method parameters is by + * {@link handleFunctionParams()}, and the method body is handled by + * {@link handleMethodLogicBlock()} + */ + function handleMethod($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) { + $this->_addoutput($word); + return; + } + if ($this->checkEventPop($word, $pevent)) { + if ($word == ';') { + $this->_addoutput($word); + } + return; + } + $this->_methodlink($word); + } + + /** + * Handler for the stuff between ( and ) in a function declaration + * + * <code> + * function handles($only,$these,$parameters){...} + * </code> + */ + function handleFunctionParams($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) { + $this->_addoutput($word); + return; + } + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + } + + /** + * Handler for function body. + * + * The function body is checked for php functions, documented constants, + * functions, and indirectly for global statements. It hyperlinks to the + * documentation for detected elements is created. Everything else is + * highlighted normally. + */ + function handleLogicBlock($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) { + $this->_addoutput($word); + return; + } + if (is_array($word) && $word[0] == T_DOUBLE_COLON) { + $this->_pf_colon_colon = true; + } + if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) { + $this->_pv_last_string = $word; + } + $this->_link($word); + if ($this->checkEventPop($word, $pevent)) { + $e = $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent($e); + if ($e == PARSER_EVENT_FUNCTION) { + $this->_wp->backupPos($word); + } + } + } + + /** + * Handler for method body. + * + * Like functions, the method body is checked for php functions, documented + * constants, functions, and indirectly for global statements. It also + * checks for "$this->XXXX" where XXXX is a class variable or method, and + * links to the documentation for detected elements is created. Everything + * else is highlighted normally. + */ + function handleMethodLogicBlock($word, $pevent) + { + if (isset($this->_pv_prev_var_type)) { + //debug('prevtype is set'); + if (!is_array($word)) { + unset($this->_pv_prev_var_type); + } else { + if ($word[0] != T_WHITESPACE && + $word[0] != T_STRING && $word[0] != T_OBJECT_OPERATOR + ) { + //fancy_debug('unset', $word); + unset($this->_pv_prev_var_type); + } + } + } + $this->_pf_inmethod = true; + if ($e = $this->checkEventPush($word, $pevent)) { + $this->_addoutput($word); + if ($e == PARSER_EVENT_CLASS_MEMBER) { + $this->_pf_no_output_yet = true; + } + return; + } + if (is_array($word) && $word[0] == T_DOUBLE_COLON) { + $this->_pf_colon_colon = true; + } + if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) { + $this->_pv_last_string = $word; + } + if (is_array($word) && $word[0] == T_VARIABLE) { + $this->_pv_lastvar = $word; + } + $this->_link($word); + if ($this->checkEventPop($word, $pevent)) { + $this->_pf_inmethod = false; + $e = $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent($e); + if ($e == PARSER_EVENT_METHOD) { + $this->_wp->backupPos($word); + } + } + } + + /** + * Handles $obj->classmember in a method body + * + * This handler is responsible for linking to the documentation of a + * class member when it is used directly in a method body. + * + * There are two methods of determining whether to link: + * - $this->member + * - $this->member->submember + * + * The first case is handled by the $_pv_lastvar variable, and the + * second case is handled by the $_pv_prev_var_type variable. $_pv_lastvar + * is always set to the value of the last T_VARIABLE token, if and only if + * no text has occurred between the variable and a T_OBJECT_OPERATOR token + * "->". handleClassMember will only link if the last variable encountered + * was $this. + * + * When $this->variable is encountered, the variable is looked up to see + * if it can be found, and if so, the contents of its @var tag are processed + * to see if the member variable is defined to have 1 and only 1 class. + * If so, the $_pv_prev_var_type variable is set to this classname. When + * submember is processed, the HighlightParser checks to see if + * $_pv_prev_var_type::submember() or $_pv_prev_var_type::$submember exists, + * and if it does, it is linked to. + */ + function handleClassMember($word, $pevent) + { + if (!isset($this->_pv_lastvar) && !isset($this->_pv_prev_var_type)) { + //fancy_debug('returned from', $word, $this->_pv_prev_var_type); + $this->_pf_no_output_yet = false; + $this->_event_stack->popEvent(); + return $this->defaultHandler($word, $pevent); + } + if (isset($this->_pv_cm_name)) { + $this->_pf_obj_op = false; + $name = $this->_pv_cm_name; + unset($this->_pv_cm_name); + //debug('unset pvcmname'); + $this->_event_stack->popEvent(); + // control variable for _pv_prev_var_type + $setnow = false; + if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') || + isset($this->_pv_prev_var_type) + ) { + if (is_array($word) && $word[0] == T_WHITESPACE) { + // preserve value of _pv_prev_var_type + $setnow = true; + $save = $this->_wp->nextToken(); + $temp = $this->_wp->getWord(); + $this->_wp->backupPos($save, true); + } + if ((is_string($word) && $word == '(') || (isset($temp) && + is_string($temp) && $temp == '(') + ) { + // it's a function + $this->_pf_no_output_yet = false; + $this->_methodlink($name); + unset($this->_pv_prev_var_type); + } else { + // it's a variable + //fancy_debug('name is ', $name); + $this->_pf_no_output_yet = false; + $this->_varlink($name, true); + $templink = + $this->_converter->getLink('object ' . $this->_pv_class); + $class = false; + if (is_object($templink)) { + $class = $this->_converter->classes + ->getClass($templink->name, $templink->path); + } + if ($class) { + $varname = $name; + if (is_array($varname)) { + $varname = $name[1]; + } + if ($varname{0} != '$') { + $varname = '$'.$varname; + } + $var = $class->getVar($this->_converter, $varname); + + if (is_object($var) && $var->docblock->var) { + $type = $var->docblock->var->returnType; + } + if (isset($type)) { + if (strpos($type, 'object') === false) { + $type = 'object '.$type; + } + $type = $this->_converter->getLink($type); + if (phpDocumentor_get_class($type) == 'classlink') { + // the variable's type is a class, + // save it for future -> + //fancy_debug('set prev_var_type!', $type->name); + $setnow = true; + $this->_pv_prev_var_type = $type->name; + } else { + unset($this->_pv_prev_var_type); + } + } else { + unset($this->_pv_prev_var_type); + } + } else { + unset($this->_pv_prev_var_type); + } + } + } else { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($name); + } + if (!$setnow) { + //debug('unset prevtype, no setnow'); + unset($this->_pv_prev_var_type); + } + unset($this->_pv_lastvar); + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + if ($word[0] == T_OBJECT_OPERATOR) { + $this->_wp->backupPos($word); + } else { + $this->_addoutput($word); + } + return; + } + if (!$this->_pf_obj_op && is_array($this->_pv_last_word) && + $this->_pv_last_word[0] == T_OBJECT_OPERATOR + ) { + if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') || + isset($this->_pv_prev_var_type) + ) { + $this->_pf_obj_op = true; + } else { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + $this->_event_stack->popEvent(); + } + } + if (is_array($word) && $word == T_WHITESPACE) { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + return; + } + if ($this->_pf_obj_op) { + if (!(is_array($word) && ($word[0] == T_STRING || + $word[0] == T_WHITESPACE)) + ) { + unset($this->_pv_lastvar); + //debug('unset lastvar'); + $this->_event_stack->popEvent(); + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + return; + } + if ($word[0] == T_STRING) { + //fancy_debug('set pvcmname to', $word); + $this->_pv_cm_name = $word; + } else { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + } + } + } + + /** + * Handles comments + * + * Comments are almost always single-line tokens, and so will be + * in the last word. This handler checks to see if the current token + * is in fact a comment, and if it isn't, it backs up and returns control + * to the parent event handler with that word. + */ + function handleComment($word, $pevent) + { + $w = $this->_pv_last_word; + // don't perform this check if this is a normal comment. Docblocks + // have the _pf_no_output_yet variable set to true + if ($this->_pf_no_output_yet && is_array($w) && + (in_array($w[0], array(T_COMMENT, T_DOC_COMMENT)) && + strpos($w[1], '/**') === 0) + ) { + $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent(PARSER_EVENT_DOCBLOCK); + return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK); + } + if ($this->_pf_no_output_yet) { + $flag = 1; + $this->_pf_no_output_yet = false; + $this->_addoutput($this->_pv_last_word); + } + if (!is_array($word) || + !in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) || + (in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) && + strpos($word[1], '/**') === 0) + ) { + $this->_event_stack->popEvent(); + if (strpos($this->_pv_last_word[1], "\n") !== false) { + //$this->_wp->linenum++; + //$this->newLineNum(); + } + $this->_wp->backupPos($this->_pv_last_word); + $this->_wp->getWord(); + //var_dump($this->_wp->nextToken()); + return; + } elseif (isset($flag)) { + $this->newLineNum(); + } + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + if (strpos($word[1], '*/') === strlen($word[1]) - 2) { + $this->_event_stack->popEvent(); + } + } + + /** + * Handle class declarations + * + * Handles the initial declaration line: + * + * <code>class X</code> + * + * or + * + * <code>class X extends Y implements I</code> + * + * @uses _classlink() to link to documentation for X and for Y class in + * "class X extends Y" + */ + function handleClass($word, $pevent) + { + $this->_pf_in_class = true; + $a = $this->checkEventPush($word, $pevent); + + if (!isset($this->_pv_class) && is_array($word) && $word[0] == T_STRING) { + $this->_pv_class = $this->_converter->class = $word[1]; + $this->_classlink($word); + return; + } + + if (is_array($word) && + in_array($word[0], array(T_PRIVATE, T_PROTECTED, T_PUBLIC)) + ) { + $starttok = $this->_wp->nextToken(); + $test = array(T_WHITESPACE); + while ($test && $test[0] == T_WHITESPACE) { + $tok = $this->_wp->nextToken(); + $test = $this->_wp->getWord(); + } // while + + if (is_array($test) && $test[0] == T_VARIABLE) { + $this->_wp->backupPos($tok, true); + return; + } + $this->_wp->backupPos($starttok, true); + } + + if (@in_array($this->_pv_last_word[0], + array(T_PRIVATE, T_PROTECTED, T_PUBLIC)) + ) { + if (is_array($word) && $word[0] == T_VARIABLE) { + $this->_wp->backupPos($this->_pv_last_word); + $this->_event_stack->pushEvent(PARSER_EVENT_VAR); + return; + } + } + + if ($this->_pf_extends_found && is_array($word) && $word[0] == T_STRING) { + $this->_classlink($word); + return; + } + if (is_array($word) && $word[0] == T_EXTENDS) { + $this->_pf_extends_found = true; + } + if ($a == PARSER_EVENT_DOCBLOCK) { + $this->_pf_no_output_yet = true; + $this->_pv_saveline = $this->_wp->linenum + 1; + return; + } + $this->_addoutput($word); + if ($this->checkEventPop($word, $pevent)) { + $this->_pf_in_class = false; + unset($this->_pv_class); + } + } + + /** + * Handles class variable declaration + * + * <code> + * class X + * { + * var $Y; + * } + * </code> + * + * @uses _varlink() make a link to $Y documentation in class variable + * declaration "var $Y;" + */ + function handleVar($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) { + $this->_addoutput($word); + return; + } + if (is_array($word) && $word[0] == T_VARIABLE) { + return $this->_varlink($word); + } + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + } + + /** + * This handler is responsible for highlighting DocBlocks + * + * handleDocBlock determines whether the docblock is normal or a template, + * and gathers all the lines of the docblock together before doing any + * processing + * + * As it is not possible to distinguish any comment token from a docblock + * token, this handler is also called for comments, and will pass control + * to {@link handleComment()} if the comment is not a DocBlock + * + * @uses commonDocBlock() once all lines of the DocBlock have been retrieved + */ + function handleDocBlock($word, $pevent) + { + if (!($this->_pf_docblock || $this->_pf_docblock_template)) { + if (strpos($this->_pv_last_word[1], '/**') !== 0) { + // not a docblock + $this->_wp->backupPos($this->_pv_last_word); + $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent(PARSER_EVENT_COMMENT); + $this->_pf_no_output_yet = false; + return; + } else { + $this->_pf_no_output_yet = true; + $this->_pv_db_lines = array(); + } + } + $last_word = $this->_pv_last_word[1]; + $dtype = '_pv_docblock'; + if ($last_word == '/**#@-*/') { + // stop using docblock template + $this->_pf_no_output_yet = false; + $this->_addDocBlockoutput('closetemplate', $last_word); + if ($this->_pv_next_word !== false) { + $this->_wp->backupPos($this->_pv_next_word, true); + } + $this->_event_stack->popEvent(); + return; + } + if (!($this->_pf_docblock || $this->_pf_docblock_template)) { + $this->_pv_db_lines = array(); + if (strpos($last_word, '/**#@+') === 0) { + // docblock template definition + $this->_pf_docblock_template = true; + } else { + $this->_pf_docblock = true; + } + $this->_pv_db_lines[] = $last_word; + if (strpos($last_word, '*/') !== false) { + $this->commonDocBlock(); + return; + } + $this->_pv_db_lines[] = $word[1]; + if (strpos($word[1], '*/') !== false) { + $this->commonDocBlock(); + } + } else { + $this->_pv_db_lines[] = $word[1]; + } + if (($this->_pf_docblock || $this->_pf_docblock_template) && + (strpos($word[1], '*/') !== false) + ) { + $this->commonDocBlock(); + } + } + /**#@-*/ + + /** + * This continuation of handleDocBlock splits DocBlock comments up into + * phpDocumentor tokens. It highlights DocBlock templates in a different + * manner from regular DocBlocks, recognizes inline tags, regular tags, + * and distinguishes between standard core tags and other tags, and + * recognizes parameters to tags like @var. + * + * the type in "@var type description" will be highlighted as a php type, + * and the var in "@param type $var description" will be highlighted as a + * php variable. + * + * @return void + * @uses handleDesc() highlight inline tags in the description + * @uses handleTags() highlight all tags + * @access private + */ + function commonDocBlock() + { + $this->_event_stack->popEvent(); + $lines = $this->_pv_db_lines; + $go = count($this->_pv_db_lines); + for ($i=0; $i < $go; $i++) { + if (substr(trim($lines[$i]), 0, 2) == '*/' || + substr(trim($lines[$i]), 0, 1) != '*' && + substr(trim($lines[$i]), 0, 3) != '/**' + ) { + $lines[$i] = array($lines[$i], false); + } elseif (substr(trim($lines[$i]), 0, 3) == '/**') { + $linesi = array(); + // remove leading "/**" + $linesi[1] = substr(trim($lines[$i]), 3); + if (empty($linesi[1])) { + $linesi[0] = $lines[$i]; + } else { + $linesi[0] = + substr($lines[$i], 0, strpos($lines[$i], $linesi[1])); + } + $lines[$i] = $linesi; + } else { + $linesi = array(); + // remove leading "* " + $linesi[1] = substr(trim($lines[$i]), 1); + if (empty($linesi[1])) { + $linesi[0] = $lines[$i]; + } else { + $linesi[0] = + substr($lines[$i], 0, strpos($lines[$i], $linesi[1])); + } + $lines[$i] = $linesi; + } + } + for ($i = 0; $i < count($lines); $i++) { + if ($lines[$i][1] === false) { + continue; + } + if (substr(trim($lines[$i][1]), 0, 1) == '@' && + substr(trim($lines[$i][1]), 0, 2) != '@ ' + ) { + $tagindex = $i; + $i = count($lines); + } + } + if (isset($tagindex)) { + $tags = array_slice($lines, $tagindex); + $desc = array_slice($lines, 0, $tagindex); + } else { + $tags = array(); + $desc = $lines; + } + //var_dump($desc, $tags); + $this->_pf_no_output_yet = false; + $save = $this->_wp->linenum; + $this->_wp->linenum = $this->_pv_saveline; + $this->handleDesc($desc); + $this->handleTags($tags); + $this->_pv_db_lines = array(); + $this->_wp->linenum = $save; + if (strpos($this->_pv_last_word[1], '*/') !== false) { + $this->_wp->backupPos($this->_pv_next_word, true); + } + $this->_pf_docblock = $this->_pf_docblock_template = false; + } + + /** + * Handle the description area of a DocBlock + * + * This method simply finds inline tags and highlights them + * separately from the rest of the description. + * + * @param mixed $desc the description piece(s) + * + * @return void + * @uses getInlineTags() + * @access private + */ + function handleDesc($desc) + { + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + foreach ($desc as $line) { + $this->getInlineTags($line[0] . $line[1]); + if (strpos($line[0], '*/') === false && + !(substr($line[0], 0, 2) == '/*' && + strpos($line[1], '*/') !== false) + ) { + $this->newLineNum(); + $this->_wp->linenum++; + } + } + if ($this->_pf_internal) { + $this->_pf_internal = false; + } + } + + /** + * Handle phpDocumentor tags in a DocBlock + * + * This method uses the {@link $tagHandlers} array to determine which + * method will handle tags found in the docblock, and passes the data to + * the individual handlers one by one + * + * @param array $tags array of tags to handle + * + * @return void + * @access private + */ + function handleTags($tags) + { + $newtags = array(); + $curtag = array(); + for ($i=0; $i < count($tags); $i++) { + $tagsi = trim($tags[$i][1]); + if (substr($tagsi, 0, 1) == '@' && substr($tagsi, 0, 2) != '@ ') { + // start a new tag + $tags[$i][1] = array(substr($tags[$i][1], 0, + strpos($tags[$i][1], $tagsi)), $tagsi); + if (!empty($curtag)) { + $newtags[] = $curtag; + $curtag = array(); + } + $curtag[] = $tags[$i]; + } else { + $curtag[] = $tags[$i]; + } + } + if (!empty($curtag)) { + $newtags[] = $curtag; + } + foreach ($newtags as $tag) { + foreach ($tag as $i => $t) { + if ($t[1] === false) { + continue; + } + if (is_array($t[1])) { + $tag[$i][1][1] + = explode(" ", str_replace("\t", ' ', $t[1][1])); + $x = $tag[$i][1][1]; + } + } + $tagname = substr(array_shift($x), 1); + $restoftag = $tag; + if (isset($this->tagHandlers[$tagname])) { + $handle = $this->tagHandlers[$tagname]; + } else { + $handle = $this->tagHandlers['*']; + } + $this->$handle($tagname, $restoftag); + } + } + + /** + * This handler recognizes all {@}inline} tags + * + * Normal inline tags are simply highlighted. the {@}internal}} inline + * tag {@tutorial tags.inlineinternal.pkg} is highlighted differently + * to distinguish it from other inline tags. + * + * @param mixed $value the tag value + * @param bool $endinternal indicates the end of an @internal tag + * + * @return void + * @access private + */ + function getInlineTags($value, $endinternal = false) + { + if (!$value) { + return; + } + if ($this->_pf_internal && !$endinternal) { + if (strpos($value, '}}') !== false) { + $x = strrpos($value, '}}'); + // add the rest of internal + $this->getInlineTags(substr($value, 0, $x + 3), true); + // strip internal from value + $value = substr($value, strrpos($value, '}}') + 1); + // turn off internal + $this->_pf_internal = false; + } + } + if (!$value) { + return; + } + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + $save = $value; + $value = explode('{@', $value); + $newval = array(); + // everything before the first {@ is normal text + $this->_addDocBlockoutput($dbtype, $value[0]); + for ($i=1; $i < count($value); $i++) { + if (substr($value[$i], 0, 1) == '}') { + $this->_addDocBlockoutput($dbtype, '{@}' . substr($value[$i], 1)); + } else { + $save = $value[$i]; + $value[$i] = str_replace("\t", " ", $value[$i]); + $value[$i] = explode(" ", $value[$i]); + $word = array_shift($value[$i]); + $val = join(' ', $value[$i]); + if ($word == 'internal') { + $this->_pf_internal = true; + $this->_addDocBlockoutput($dbtype, '{@internal '); + $value[$i] = substr($save, strlen('internal') + 1); + // strip internal and cycle as if it were normal text. + $this->_addDocBlockoutput($dbtype, $value[$i]); + continue; + } + if (in_array(str_replace('}', '', $word), $this->allowableInlineTags) + ) { + if (strpos($word, '}')) { + $word = str_replace('}', '', $word); + $val = '} ' . $val; + } + $val = explode('}', $val); + if (count($val) == 1) { + //addError(PDERROR_UNTERMINATED_INLINE_TAG, + // $word, '', $save); + } + $rest = $val; + $val = array_shift($rest); + if ($endinternal) { + $rest = join('}', $rest); + } else { + $rest = join(' ', $rest); + } + if (isset($this->inlineTagHandlers[$word])) { + $handle = $this->inlineTagHandlers[$word]; + } else { + $handle = $this->inlineTagHandlers['*']; + } + $this->$handle($word, $val); + $this->_addDocBlockoutput($dbtype, $rest); + } else { + $val = $word . ' ' . $val; + $this->_addDocBlockoutput($dbtype, '{@' . $val); + } + } + } + } + + + /** + * Handles all inline tags + * + * @param string $name the tag name + * @param mixed $value the tag value + * + * @return void + * @access private + */ + function handleDefaultInlineTag($name, $value) + { + $this->_addDocBlockoutput('inlinetag', '{@' . $name . ' ' . $value . '}'); + } + + /**#@+ + * phpDocumentor DocBlock tag handlers + * + * @param string $name tag name + * @param array $value array of lines contained in the tag description + * + * @return void + * @access private + */ + /** + * Handle normal tags + * + * This handler adds to outpu all comment information before the tag begins + * as in " * " before "@todo" in " * @todo" + * + * Then, it highlights the tag as a regular or coretag based on $coretag. + * Finally, it uses getInlineTags to highlight the description + * + * @param bool $coretag whether this tag is a core tag or not + * + * @uses getInlineTags() highlight a tag description + */ + function defaultTagHandler($name, $value, $coretag = false) + { + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + foreach ($value as $line) { + $this->_addDocBlockoutput($dbtype, $line[0]); + if ($line[1] === false) { + if (trim($line[0]) != '*/') { + $this->newLineNum(); + $this->_wp->linenum++; + } + continue; + } + $this->_addDocBlockoutput($dbtype, $line[1][0]); + $stored = ''; + if (is_array($line[1][1])) { + foreach ($line[1][1] as $i => $tpart) { + if ($tpart == '@' . $name && $i == 0) { + $tagname = 'tag'; + if ($coretag) { + $tagname = 'coretag'; + } + $this->_addDocBlockoutput($tagname, '@' . $name); + continue; + } + $stored .= ' ' . $tpart; + } + } else { + $stored = $line[1]; + } + $this->getInlineTags($stored); + if (strpos($stored, '*/') === false) { + $this->newLineNum(); + $this->_wp->linenum++; + } + } + } + + /** + * main handler for "core" tags + * + * @see defaultTagHandler() + */ + function coreTagHandler($name, $value) + { + return $this->defaultTagHandler($name, $value, true); + } + + /** + * Handles @global + * + * This handler works like {@link defaultTagHandler()} except it highlights + * the type and variable (if present) in "@global type $variable" or + * "@global type description" + */ + function globalTagHandler($name, $value) + { + $this->paramTagHandler($name, $value); + } + + /** + * Handles @param + * + * This handler works like {@link defaultTagHandler()} except it highlights + * the type and variable (if present) in "@param type $variable description" + * or "@param type description" + * + * @param bool $checkforvar private parameter, checks for $var or not + */ + function paramTagHandler($name, $value, $checkforvar = true) + { + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + $ret = $this->retrieveType($value, 0, $checkforvar); + foreach ($value as $num => $line) { + $this->_addDocBlockoutput($dbtype, $line[0]); + if ($line[1] === false) { + if (trim($line[0]) != '*/') { + $this->newLineNum(); + $this->_wp->linenum++; + } + continue; + } + $this->_addDocBlockoutput($dbtype, $line[1][0]); + $stored = ''; + $typeloc = 1; + $varloc = 2; + if (is_array($line[1][1])) { + $this->_addDocBlockoutput('coretag', '@' . $name . ' '); + foreach ($ret[0] as $text) { + if (is_string($text)) { + $this->_addDocBlockoutput($dbtype, $text); + } + if (is_array($text)) { + if ($text[0] != 'desc') { + $this->_addDocBlockoutput($text[0], $text[1]); + } else { + $stored .= $text[1]; + } + } + } + } else { + if (isset($ret[$num])) { + foreach ($ret[$num] as $text) { + if (is_string($text)) { + $this->_addDocBlockoutput($dbtype, $text); + } + if (is_array($text)) { + if ($text[0] != 'desc') { + $this->_addDocBlockoutput($text[0], $text[1]); + } else { + $stored .= $text[1]; + } + } + } + } else { + $stored = $line[1]; + } + } + $this->getInlineTags($stored); + if (strpos($stored, '*/') === false) { + $this->newLineNum(); + $this->_wp->linenum++; + } + } + } + + /** + * handles the @staticvar tag + * + * @see paramTagHandler() + */ + function staticvarTagHandler($name, $value) + { + return $this->paramTagHandler($name, $value); + } + + /** + * handles the @var tag + * + * @see paramTagHandler() + */ + function varTagHandler($name, $value) + { + return $this->paramTagHandler($name, $value); + } + + /** + * Handles @return + * + * This handler works like {@link defaultTagHandler()} except it highlights + * the type in "@return type description" + */ + function returnTagHandler($name, $value) + { + $this->paramTagHandler($name, $value, false); + } + + /** + * Handles @property(-read or -write) and @method magic tags + */ + function propertyTagHandler($name, $value) + { + return $this->paramTagHandler($name, $value, true); + } + + /**#@-*/ + + /** + * Retrieve the type portion of a @tag type description + * + * Tags like @param, @return and @var all have a PHP type portion in their + * description. Since the type may contain the expression "object blah" + * where blah is a classname, it makes parsing out the type field complex. + * + * Even more complicated is the case where a tag variable can contain + * multiple types, such as object blah|object blah2|false, and so this + * method handles these cases. + * + * @param array $value array of words that were separated by spaces + * @param 0|1 $state 0 = find the type, 1 = find the var, if present + * @param bool $checkforvar flag to determine whether to check for the end of a + * type is defined by a $varname + * + * @return array Format: array(state (0 [find type], 1 [var], 2 [done]), + * @access private + */ + function retrieveType($value, $state = 0, $checkforvar = false) + { + $index = 0; + $result = array(); + do { + if (!isset($value[$index][1])) { + return $result; + } + $val = $value[$index][1]; + if (empty($val)) { + return $result; + } + if ($index == 0) { + $val = $val[1]; + array_shift($val); + } else { + $val = explode(' ', $val); + } + $ret = $this->_retrieveType($val, $state, $checkforvar); + $state = $ret[0]; + $result[$index++] = $ret[1]; + } while ((!$checkforvar && $state < 1) || ($state < 2 && $checkforvar)); + return $result; + } + + /** + * used by {@link retrieveType()} in its work + * + * @param array $value array of words that were separated by spaces + * @param 0|1 $state 0 = find the type, 1 = find the var, if present + * @param bool $checkforvar flag to determine whether to check for the end of a + * type is defined by a $varname + * + * @return array + * @access private + */ + function _retrieveType($value, $state, $checkforvar) + { + $result = array(); + $result[] = $this->_removeWhiteSpace($value, 0); + if ($state == 0) { + if (!count($value)) { + return array(2, $result); + } + $types = ''; + $index = 0; + if (trim($value[0]) == 'object') { + $result[] = array('tagphptype', $value[0] . ' '); + $types .= array_shift($value).' '; + $result[] = $this->_removeWhiteSpace($value, 0); + if (!count($value)) { + // was just passed "object" + return array(2, $result); + } + if ($value[0]{0} == '$' || substr($value[0], 0, 2) == '&$') { + // was just passed "object" + // and the next thing is a variable name + if ($checkforvar) { + $result[] = array('tagvarname' , $value[0] . ' '); + array_shift($value); + } + $result[] = array('desc', join(' ', $value)); + return array(2, $result); + } + } + $done = false; + $loop = -1; + do { + // this loop checks for type|type|type and for + // type|object classname|type|object classname2 + if (strpos($value[0], '|')) { + $temptypes = explode('|', $value[0]); + while (count($temptypes)) { + $type = array_shift($temptypes); + $result[] = array('tagphptype', $type); + if (count($temptypes)) { + $result[] = '|'; + } + } + if (trim($type) == 'object') { + $result[] = array('tagphptype', $types . ' '); + $result[] = $this->_removeWhiteSpace($value, 0); + } else { + $done = true; + } + array_shift($value); + if (count($value) && strlen($value[0]) && isset ($value[0]) && + ($value[0]{0} == '$' || substr($value[0], 0, 2) == '&$') + ) { + // was just passed "object" + // and the next thing is a variable name + $result[] = array('tagvarname' , $value[0] . ' '); + array_shift($value); + $result[] = array('desc', join(' ', $value)); + return array(2, $result); + } + } else { + $result[] = array('tagphptype', $value[0] . ' '); + array_shift($value); + $done = true; + } + $loop++; + } while (!$done && count($value)); + if ($loop) { + $result[] = ' '; + } + // still searching for type + if (!$done && !count($value)) { + return array(0, $result); + } + // still searching for var + if ($done && !count($value)) { + return array(1, $result); + } + } + $result[] = $this->_removeWhiteSpace($value, 0); + $state = 1; + if ($checkforvar) { + if (count($value)) { + $state = 2; + if (substr($value[0], 0, 1) == '$' || + substr($value[0], 0, 2) == '&$' + ) { + $result[] = array('tagvarname' , $value[0] . ' '); + array_shift($value); + } + } else { + $state = 1; + } + } + $result[] = array('desc', join(' ', $value)); + return array($state, $result); + } + + /** + * captures trailing whitespace + * + * @param array &$value array of string + * @param int $index index to seek non-whitespace to + * + * @return string whitespace + * @access private + */ + function _removeWhiteSpace(&$value, $index) + { + $result = ''; + if (count($value) > $index && empty($value[$index])) { + $found = false; + for ($i = $index; $i < count($value) && !strlen($value[$i]); $i++) { + $result .= ' '; + } + array_splice($value, $index, $i - $index); + } + return $result; + } + + /**#@+ + * Link generation methods + * + * @param string|array $word token to try to link + * + * @access private + */ + /** + * Generate a link to documentation for an element + * + * This method tries to link to documentation for functions, methods, + * PHP functions, class names, and if found, adds the links to output + * instead of plain text + */ + function _link($word) + { + if (is_array($word) && $word[0] == T_STRING) { + if ($this->_pf_colon_colon) { + $this->_pf_colon_colon = false; + + $combo = $this->_pv_last_string[1] . '::' . $word[1] . '()'; + //debug('testing ' . $combo); + $link = $this->_converter->getLink($combo); + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } + $this->_addoutput($word); + return; + } + $link = $this->_converter->getLink($word[1] . '()'); + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } elseif (is_string($link) && strpos($link, 'ttp://')) { + $this->_addoutput($this->_converter->returnLink($link, + $word[1]), true); + return; + } else { + $link = $this->_converter->getLink($word[1]); + if (is_object($link)) { + $word[1] = $this->_converter->returnSee($link, $word[1]); + } + $this->_addoutput($word, true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to global variables + */ + function _globallink($word) + { + if (!is_array($word)) { + return $this->_addoutput($word); + } + if ($word[0] != T_VARIABLE) { + return $this->_addoutput($word); + } + if (is_array($word) && $word[0] == T_VARIABLE) { + $link = $this->_converter->getLink('global ' . $word[1]); + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to classes + */ + function _classlink($word) + { + //debug("checking class " . $word[1]); + if (is_array($word) && $word[0] == T_STRING) { + $link = $this->_converter->getLink($word[1]); + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to methods + */ + function _methodlink($word) + { + if (is_array($word) && $word[0] == T_STRING) { + //debug("checking method " . $this->_pv_class . '::' . $word[1] . '()'); + if (isset($this->_pv_prev_var_type)) { + $link = $this->_converter->getLink($this->_pv_prev_var_type . '::' . + $word[1] . '()'); + } else { + $link = $this->_converter->getLink($this->_pv_class . '::' . + $word[1] . '()'); + } + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } + if (isset($this->_pv_prev_var_type)) { + $this->_addoutput($word); + return; + } + //debug("checking method " . $word[1] . '()'); + $link = $this->_converter->getLink($word[1] . '()'); + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to class variables + * + * @param bool $justastring true if the $word is only a string + */ + function _varlink($word, $justastring=false) + { + if ($justastring) { + $word[0] = T_VARIABLE; + } + if (is_array($word) && $word[0] == T_VARIABLE) { + $x = ($justastring ? '$' : ''); + //debug("checking var " . $this->_pv_class . '::' . $x . $word[1]); + if (isset($this->_pv_prev_var_type)) { + //debug("checking var " . $this->_pv_prev_var_type . '::' . + // $x . $word[1]); + $link = $this->_converter->getLink($this->_pv_prev_var_type . '::' . + $x . $word[1]); + } else { + $link = $this->_converter->getLink($this->_pv_class . '::' . + $x . $word[1]); + } + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } + //debug("checking var " . $x . $word[1]); + if (isset($this->_pv_prev_var_type)) { + $this->_addoutput($word); + return; + } + $link = $this->_converter->getLink($x . $word[1]); + if (is_object($link)) { + $this->_addoutput($this->_converter->returnSee($link, + $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + /**#@-*/ + + /**#@+ + * Output Methods + * @access private + */ + /** + * This method adds output to {@link $_line} + * + * If a string with variables like "$test this" is present, then special + * handling is used to allow processing of the variable in context. + * + * @param mixed $word the string|array tag token and value + * @param bool $preformatted whether or not the $word is already formatted + * + * @return void + * @see _flush_save() + */ + function _addoutput($word, $preformatted = false) + { + if ($this->_pf_no_output_yet) { + return; + } + if ($this->_pf_quote_active) { + if (is_array($word)) { + $this->_save .= $this->_converter->highlightSource($word[0], + $word[1]); + } else { + $this->_save .= $this->_converter->highlightSource(false, + $word, true); + } + } else { + $this->_flush_save(); + if (is_string($word) && trim($word) == '') { + $this->_line .= $this->_converter->postProcess($word); + return; + } + if (is_array($word) && trim($word[1]) == '') { + $this->_line .= $this->_converter->postProcess($word[1]); + return; + } + if (is_array($word)) { + $this->_line .= $this->_converter->highlightSource($word[0], + $word[1], $preformatted); + } else { + $this->_line .= $this->_converter->highlightSource(false, + $word, $preformatted); + } + } + } + + /** + * Like {@link _output()}, but for DocBlock highlighting + * + * @param mixed $dbtype the docblock type + * @param mixed $word the string|array tag token and value + * @param bool $preformatted whether or not the $word is already formatted + * + * @return void + */ + function _addDocBlockoutput($dbtype, $word, $preformatted = false) + { + if ($this->_pf_internal) { + $this->_line .= $this->_converter->highlightDocBlockSource('internal', + $word, $preformatted); + } else { + $this->_line .= $this->_converter->highlightDocBlockSource($dbtype, + $word, $preformatted); + } + } + + /** + * Flush a saved string variable highlighting + * + * {@source} + * + * @return void + * @todo CS cleanup - rename to _flushSave() for camelCase rule + */ + function _flush_save() + { + if (!empty($this->_save)) { + $this->_save .= $this->_converter->flushHighlightCache(); + // clear the existing cache, reset it to the old value + if (isset($this->_save_highlight_state)) { + $this->_converter-> + _setHighlightCache($this->_save_highlight_state[0], + $this->_save_highlight_state[1]); + } + $this->_line .= $this->_converter-> + highlightSource(T_CONSTANT_ENCAPSED_STRING, $this->_save, true); + $this->_save = ''; + } + } + /**#@-*/ + + /** + * Give the word parser necessary data to begin a new parse + * + * @param array &$data all tokens separated by line number + * + * @return void + */ + function configWordParser(&$data) + { + $this->_wp->setup($data, $this); + $this->_wp->setWhitespace(true); + } + + /** + * Initialize all parser state variables + * + * @param bool $inlinesourceparse true if we are highlighting an inline + * {@}source} tag's output + * @param false|string $class name of class we are going + * to start from + * + * @return void + * @uses $_wp sets to a new {@link phpDocumentor_HighlightWordParser} + */ + function setupStates($inlinesourceparse, $class) + { + $this->_output = ''; + $this->_line = ''; + unset($this->_wp); + $this->_wp = new phpDocumentor_HighlightWordParser; + $this->_event_stack = new EventStack; + if ($inlinesourceparse) { + $this->_event_stack->pushEvent(PARSER_EVENT_PHPCODE); + if ($class) { + $this->_event_stack->pushEvent(PARSER_EVENT_CLASS); + $this->_pv_class = $class; + } + } else { + $this->_pv_class = null; + } + + $this->_pv_define = null; + $this->_pv_define_name = null; + $this->_pv_define_value = null; + $this->_pv_define_params_data = null; + $this->_pv_dtype = null; + $this->_pv_docblock = null; + $this->_pv_dtemplate = null; + $this->_pv_func = null; + $this->_pv_global_name = null; + $this->_pv_global_val = null; + $this->_pv_globals = null; + $this->_pv_global_count = null; + $this->_pv_include_params_data = null; + $this->_pv_include_name = null; + $this->_pv_include_value = null; + $this->_pv_linenum = null; + $this->_pv_periodline = null; + $this->_pv_paren_count = 0; + $this->_pv_statics = null; + $this->_pv_static_count = null; + $this->_pv_static_val = null; + $this->_pv_quote_data = null; + $this->_pv_function_data = null; + $this->_pv_var = null; + $this->_pv_varname = null; + $this->_pf_definename_isset = false; + $this->_pf_extends_found = false; + $this->_pf_includename_isset = false; + $this->_pf_get_source = false; + $this->_pf_getting_source = false; + $this->_pf_in_class = false; + $this->_pf_in_define = false; + $this->_pf_in_global = false; + $this->_pf_in_include = false; + $this->_pf_in_var = false; + $this->_pf_funcparam_val = false; + $this->_pf_quote_active = false; + $this->_pf_reset_quote_data = true; + $this->_pf_useperiod = false; + $this->_pf_var_equals = false; + $this->_pf_obj_op = false; + $this->_pf_docblock = false; + $this->_pf_docblock_template = false; + $this->_pf_colon_colon = false; + $this->_pv_last_string = false; + $this->_pf_inmethod = false; + $this->_pf_no_output_yet = false; + $this->_pv_saveline = 0; + $this->_pv_next_word = false; + $this->_save = ''; + } + + /** + * Initialize the {@link $tokenpushEvent, $wordpushEvent} arrays + * + * @return void + */ + function phpDocumentor_HighlightParser() + { + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + $this->allowableTags + = $GLOBALS['_phpDocumentor_tags_allowed']; + $this->allowableInlineTags + = $GLOBALS['_phpDocumentor_inline_doc_tags_allowed']; + $this->inlineTagHandlers + = array('*' => 'handleDefaultInlineTag'); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_NOEVENTS] = + array( + T_OPEN_TAG => PARSER_EVENT_PHPCODE, + ); + + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_PHPCODE] = + array( + T_FUNCTION => PARSER_EVENT_FUNCTION, + T_CLASS => PARSER_EVENT_CLASS, + T_INTERFACE => PARSER_EVENT_CLASS, + T_INCLUDE_ONCE => PARSER_EVENT_INCLUDE, + T_INCLUDE => PARSER_EVENT_INCLUDE, + T_START_HEREDOC => PARSER_EVENT_EOFQUOTE, + T_REQUIRE => PARSER_EVENT_INCLUDE, + T_REQUIRE_ONCE => PARSER_EVENT_INCLUDE, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_PHPCODE] = + array( + "define" => PARSER_EVENT_DEFINE, + '"' => PARSER_EVENT_QUOTE, + '\'' => PARSER_EVENT_QUOTE, + ); + /**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_FUNCTION] = + array( + '{' => PARSER_EVENT_LOGICBLOCK, + '(' => PARSER_EVENT_FUNCTION_PARAMS, + ); + $this->tokenpushEvent[PARSER_EVENT_FUNCTION] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpopEvent[PARSER_EVENT_FUNCTION] = array("}"); + /**************************************************************/ + + $this->tokenpopEvent[PARSER_EVENT_EOFQUOTE] = array(T_END_HEREDOC); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_FUNCTION_PARAMS] = + array( + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + T_ARRAY => PARSER_EVENT_ARRAY, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_FUNCTION_PARAMS] = + array( + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_FUNCTION_PARAMS] = array(")"); + /**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_LOGICBLOCK] = + array( + "{" => PARSER_EVENT_LOGICBLOCK, + '"' => PARSER_EVENT_QUOTE, + ); + $this->tokenpushEvent[PARSER_EVENT_LOGICBLOCK] = + array( + T_GLOBAL => PARSER_EVENT_FUNC_GLOBAL, + T_STATIC => PARSER_EVENT_STATIC_VAR, + T_START_HEREDOC => PARSER_EVENT_EOFQUOTE, + T_CURLY_OPEN => PARSER_EVENT_LOGICBLOCK, + T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK, + ); + $this->wordpopEvent[PARSER_EVENT_LOGICBLOCK] = array("}"); + $this->tokenpopEvent[PARSER_EVENT_LOGICBLOCK] = array(T_CURLY_OPEN); + + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_ARRAY] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpopEvent[PARSER_EVENT_ARRAY] = array(")"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_FUNC_GLOBAL] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpopEvent[PARSER_EVENT_FUNC_GLOBAL] = array(";"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR] = + array( + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_STATIC_VAR] = + array( + "=" => PARSER_EVENT_STATIC_VAR_VALUE, + ); + $this->wordpopEvent[PARSER_EVENT_STATIC_VAR] = array(";"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] = + array( + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_ARRAY => PARSER_EVENT_ARRAY, + ); + $this->wordpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] = + array( + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_STATIC_VAR_VALUE] = array(";", ","); + /**************************************************************/ + $this->tokenpushEvent[PARSER_EVENT_QUOTE] = + array( + T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER, + T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR, + ); + $this->wordpopEvent[PARSER_EVENT_QUOTE] = array('"'); + /**************************************************************/ + $this->tokenpushEvent[PARSER_EVENT_QUOTE_VAR] = + array( + T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER, + T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR, + ); + $this->wordpushEvent[PARSER_EVENT_QUOTE_VAR] = + array( + "{" => PARSER_EVENT_QUOTE_VAR, + '"' => PARSER_EVENT_QUOTE_VAR, + "'" => PARSER_EVENT_QUOTE_VAR, + ); + $this->wordpopEvent[PARSER_EVENT_QUOTE_VAR] = array('}'); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_DEFINE] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + ); + $this->wordpushEvent[PARSER_EVENT_DEFINE] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS, + ); + $this->wordpopEvent[PARSER_EVENT_DEFINE] = array(";"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS, + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS] = array(")"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS, + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = array(")"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_VAR] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_ARRAY => PARSER_EVENT_ARRAY, + ); + $this->wordpopEvent[PARSER_EVENT_VAR] = array(";"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_CLASS] = + array( + T_FUNCTION => PARSER_EVENT_METHOD, + T_VAR => PARSER_EVENT_VAR, + T_COMMENT => PARSER_EVENT_DOCBLOCK, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_CLOSE_TAG => PARSER_EVENT_OUTPHP, + ); + $this->wordpopEvent[PARSER_EVENT_CLASS] = array("}"); + /**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_METHOD] = + array( + '{' => PARSER_EVENT_METHOD_LOGICBLOCK, + '(' => PARSER_EVENT_FUNCTION_PARAMS, + ); + $this->tokenpushEvent[PARSER_EVENT_METHOD] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpopEvent[PARSER_EVENT_METHOD] = array("}", ";"); + /**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = + array( + "{" => PARSER_EVENT_METHOD_LOGICBLOCK, + '"' => PARSER_EVENT_QUOTE, + ); + $this->tokenpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = + array( + T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER, + T_GLOBAL => PARSER_EVENT_FUNC_GLOBAL, + T_STATIC => PARSER_EVENT_STATIC_VAR, + T_CURLY_OPEN => PARSER_EVENT_LOGICBLOCK, + T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK, + ); + $this->wordpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array("}"); + $this->tokenpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array(T_CURLY_OPEN); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_INCLUDE] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_INCLUDE] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS, + ); + $this->wordpopEvent[PARSER_EVENT_INCLUDE] = array(";"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS, + ); + $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS] = array(")"); + /**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS, + ); + $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = array(")"); + } +} +?> |