PhpDocumentor
[ class tree: PhpDocumentor ] [ index: PhpDocumentor ] [ all elements ]

Source for file Lexer.inc

Documentation is available at Lexer.inc

  1. <?php
  2. define('PHPDOC_LEXER_DESC', 1);
  3. define('PHPDOC_LEXER_TAGS', 2);
  4. define('PHPDOC_LEXER_ESCTAG', 3);
  5. define('PHPDOC_LEXER_INLINETAG', 4);
  6. define('PHPDOC_LEXER_INTERNAL', 5);
  7. define('PHPDOC_LEXER_INTERNALTAG', 6);
  8. define('PHPDOC_LEXER_SIMPLELIST', 7);
  9. define('PHPDOC_DOCBLOCK_TOKEN_NEWLINE', 1);
  10. define('PHPDOC_DOCBLOCK_TOKEN_DESC', 2);
  11. define('PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN', 3);
  12. define('PHPDOC_DOCBLOCK_TOKEN_ESCTAGCLOSE', 4);
  13. define('PHPDOC_DOCBLOCK_TOKEN_TAG', 5);
  14. define('PHPDOC_DOCBLOCK_TOKEN_INLINETAG', 6);
  15. define('PHPDOC_DOCBLOCK_TOKEN_INLINETAGCLOSE', 7);
  16. define('PHPDOC_DOCBLOCK_TOKEN_INTERNAL', 8);
  17. define('PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE', 9);
  18. define('PHPDOC_DOCBLOCK_TOKEN_HTMLTAG', 10);
  19. define('PHPDOC_DOCBLOCK_TOKEN_HTMLTAGCLOSE', 11);
  20. define('PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTSTART', 12);
  21. define('PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND', 13);
  22. define('PHPDOC_DOCBLOCK_TOKEN_UNORDEREDBULLET', 14);
  23. define('PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET', 15);
  24. class PhpDocumentor_DocBlock_Lexer
  25. {
  26.     var $processedline;
  27.     var $tagStack = array();
  28.     var $tokens = array();
  29.     var $simplelist = array();
  30.     var $whitespace = array();
  31.     var $states = array(PHPDOC_LEXER_DESC);
  32.     function tokenName($token)
  33.     {
  34.         $this->tokens = array(
  35.             PHPDOC_DOCBLOCK_TOKEN_NEWLINE => 'PHPDOC_DOCBLOCK_TOKEN_NEWLINE',
  36.             PHPDOC_DOCBLOCK_TOKEN_DESC => 'PHPDOC_DOCBLOCK_TOKEN_DESC',
  37.             PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN => 'PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN',
  38.             PHPDOC_DOCBLOCK_TOKEN_ESCTAGCLOSE => 'PHPDOC_DOCBLOCK_TOKEN_ESCTAGCLOSE',
  39.             PHPDOC_DOCBLOCK_TOKEN_TAG => 'PHPDOC_DOCBLOCK_TOKEN_TAG',
  40.             PHPDOC_DOCBLOCK_TOKEN_INLINETAG => 'PHPDOC_DOCBLOCK_TOKEN_INLINETAG',
  41.             PHPDOC_DOCBLOCK_TOKEN_INLINETAGCLOSE => 'PHPDOC_DOCBLOCK_TOKEN_INLINETAGCLOSE',
  42.             PHPDOC_DOCBLOCK_TOKEN_INTERNAL => 'PHPDOC_DOCBLOCK_TOKEN_INTERNAL',
  43.             PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE => 'PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE',
  44.         );
  45.         if (in_array($token, array_keys($this->tokens))) {
  46.             return $this->tokens[$token];
  47.         }
  48.         return 'UNKNOWN';
  49.     }
  50.  
  51.     function lex($comment)
  52.     {
  53.         $comment = str_replace(array("\r\n", "\r"), array("\n", "\n"), $comment);
  54.         $comment = explode("\n", $comment);
  55.         $this->tokens = array();
  56.         $state = PHPDOC_LEXER_DESC;
  57.         $this->states = array(PHPDOC_LEXER_DESC);
  58.         $tid = 0;
  59.         $token = '';
  60.         $esctag = false;
  61.         $this->exception = false;
  62.         list($lastline,) = each(array_reverse($comment, true));
  63.         foreach ($comment as $this->linenum => $line) {
  64.             if ($this->exception) {
  65.                 $this->tokens = array();
  66.                 return false;
  67.             }
  68.             $linestart = true;
  69.             $this->processedline = trim($line);
  70.             if ($this->processedline == '*/') {
  71.                 break;
  72.             }
  73.             if (!$this->processedline) {
  74.                 continue;
  75.             }
  76.             if (substr($this->processedline, 0, 3) == '/**') {
  77.                 $this->processedline = substr($this->processedline, 3);
  78.                 if (!$this->processedline) {
  79.                     continue;
  80.                 }
  81.                 if (trim($this->processedline) == '*/') {
  82.                     $this->endSimpleList();
  83.                     break;
  84.                 }
  85.             } else {
  86.                 $this->processedline = substr($this->processedline, 1);
  87.             }
  88.             while (true) {
  89.                 switch ($state) {
  90.                     case PHPDOC_LEXER_INTERNALTAG :
  91.                         $internalendpos = strpos($this->processedline, '}}');
  92.                     case PHPDOC_LEXER_TAGS :
  93.                         $trimline = trim($this->processedline);
  94.                         if (strlen($trimline) && $trimline{0} == '@') {
  95.                             if (preg_match('/^(@[^\s]+)\s/', $trimline, $matches) ||
  96.                                   preg_match('/^(@[^\s]+)$/', $trimline, $matches)) {
  97.                                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_TAG,
  98.                                     $matches[1]);
  99.                                 $this->processedline = substr($trimline, strpos($trimline, $matches[1]) +
  100.                                     strlen($matches[1]));
  101.                                 if (!$this->processedline) {
  102.                                     break 2;
  103.                                 }
  104.                                 continue 2; // to while(true)
  105.                             }
  106.                         } elseif (preg_match('/^@/', $trimline, $matches)) {
  107.                             // throw exception for invalid tag
  108.                             return $this->throwException('Invalid tag encountered in line number ' .
  109.                                 $this->linenum . ': "' . $line . '"', 'tag');
  110.                         } else {
  111.                             $tagpos = strpos($this->processedline, '<');
  112.                             $inlinetagpos = strpos($this->processedline, '{@');
  113.                             if (isset($internalendpos) && $internalendpos !== false) {
  114.                                 do {
  115.                                     if ($tagpos !== false && $internalendpos > $tagpos) {
  116.                                         break;
  117.                                     }
  118.                                     if ($inlinetagpos !== false && $internalendpos > $inlinetagpos) {
  119.                                         break;
  120.                                     }
  121.                                     // }} is the next important token
  122.                                     $this->appendDesc(substr($this->processedline, 0,
  123.                                         $internalendpos));
  124.                                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE, '}}');
  125.                                     $this->processedline = substr($this->processedline, $internalendpos
  126.                                         + 2);
  127.                                     array_shift($this->states);
  128.                                     $state = PHPDOC_LEXER_TAGS;
  129.                                     continue 3; // to while(true);
  130.                                 } while (false);
  131.                             }
  132.                             if ($tagpos !== false && $inlinetagpos !== false) {
  133.                                 if ($tagpos > $inlinetagpos) {
  134.                                     $tagpos = false;
  135.                                 } else {
  136.                                     $inlinetagpos = false;
  137.                                 }
  138.                             }
  139.                             if ($tagpos !== false) {
  140.                                 continue $this->searchForHTMLTag($tagpos,
  141.                                     $state, $esctag, $linestart, $trimline);
  142.                             }
  143.                             if ($inlinetagpos !== false) {
  144.                                 $state = $this->searchForInlineTag($inlinetagpos, $comment);
  145.                                 $linestart = false;
  146.                                 continue 2; // to while (true)
  147.                             }
  148.                             if (strpos($this->processedline, '*/')) {
  149.                                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC,
  150.                                     substr($this->processedline,
  151.                                     0, strpos($this->processedline, '*/')));
  152.                                 return $this->tokens;
  153.                             }
  154.                             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC, $this->processedline);
  155.                         }
  156.                     break;
  157.                     case PHPDOC_LEXER_INTERNAL :
  158.                         $internalendpos = strpos($this->processedline, '}}');
  159.                     case PHPDOC_LEXER_SIMPLELIST :
  160.                         if ($linestart && $state == PHPDOC_LEXER_SIMPLELIST) {
  161.                             if (!$this->processSimpleList()) {
  162.                                 while (count($this->simplelist) && !$this->processSimpleList());
  163.                             }
  164.                             if (!count($this->simplelist)) {
  165.                                 array_shift($this->states);
  166.                                 $state = array_shift($this->states);
  167.                                 array_unshift($this->states, $state);
  168.                             }
  169.                         }
  170.                     case PHPDOC_LEXER_DESC :
  171.                         if (strpos($this->processedline, '*/')) {
  172.                             $this->processedline = substr($this->processedline,
  173.                                 0, strpos($this->processedline, '*/'));
  174.                         }
  175.                         if (!$this->processedline) {
  176.                             if ($this->linenum != $lastline) {
  177.                                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n");
  178.                             }
  179.                             continue 3; // to foreach
  180.                         }
  181.                         $trimline = trim($this->processedline);
  182.                         if ($linestart && $state != PHPDOC_LEXER_TAGS && $trimline{0} == '@') {
  183.                             if ($state == PHPDOC_LEXER_INTERNAL) {
  184.                                 // throw exception
  185.                                 return $this->throwException('Cannot start tags in {@internal}} ' .
  186.                                     ' in line number ' .
  187.                                     $this->linenum . ': "' . $line . '"', 'tag');
  188.                             }
  189.                             $this->states = array(PHPDOC_LEXER_TAGS);
  190.                             $state = PHPDOC_LEXER_TAGS;
  191.                             continue 2; // to while(true)
  192.  
  193.                         }
  194.                         if ($state != PHPDOC_LEXER_SIMPLELIST && $linestart && strlen($trimline) > 3 &&
  195.                              ($trimline{0} == '-' || $trimline{0} == '*' ||
  196.                               $trimline{0} == '#' || $trimline{0} == 'o' ||
  197.                               $trimline{0} == '1')) {
  198.                             if ($this->searchForSimplelist($trimline)) {
  199.                                 $state = PHPDOC_LEXER_SIMPLELIST;
  200.                                 $linestart = false;
  201.                                 continue 2; // to while(true)
  202.                             }
  203.                         }
  204.                         $tagpos = strpos($this->processedline, '<');
  205.                         $inlinetagpos = strpos($this->processedline, '{@');
  206.                         if (isset($internalendpos) && $internalendpos !== false) {
  207.                             do {
  208.                                 if ($tagpos !== false && $internalendpos > $tagpos) {
  209.                                     break;
  210.                                 }
  211.                                 if ($inlinetagpos !== false && $internalendpos > $inlinetagpos) {
  212.                                     break;
  213.                                 }
  214.                                 // }} is the next important token
  215.                                 $this->appendDesc(substr($this->processedline, 0, $internalendpos));
  216.                                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE, '}}');
  217.                                 $this->processedline = substr($this->processedline, $internalendpos
  218.                                     + 2);
  219.                                 array_shift($this->states);
  220.                                 $state = PHPDOC_LEXER_DESC;
  221.                                 continue 3; // to while(true);
  222.                             } while (false);
  223.                         }
  224.                         if ($tagpos !== false && $inlinetagpos !== false) {
  225.                             if ($tagpos > $inlinetagpos) {
  226.                                 $tagpos = false;
  227.                             } else {
  228.                                 $inlinetagpos = false;
  229.                             }
  230.                         }
  231.                         if ($tagpos !== false) {
  232.                             continue $this->searchForHTMLTag($tagpos, $state,
  233.                                 $esctag, $linestart, $trimline);
  234.                         }
  235.                         if ($inlinetagpos !== false) {
  236.                             $state = $this->searchForInlineTag($inlinetagpos, $comment);
  237.                             $linestart = false;
  238.                             continue 2; // to while (true)
  239.                         }
  240.                         $this->appendDesc($this->processedline);
  241.                     break;
  242.                     case PHPDOC_LEXER_ESCTAG :
  243.                         if (!$this->processedline) {
  244.                             if ($this->linenum != $lastline) {
  245.                                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n");
  246.                             }
  247.                             continue 3; // to foreach
  248.                         }
  249.                         $endpos = strpos($this->processedline, $esctag);
  250.                         $inlinetagpos = strpos($this->processedline, '{@');
  251.                         if ($endpos !== false && $inlinetagpos !== false) {
  252.                             if ($endpos > $inlinetagpos) {
  253.                                 $endpos = false;
  254.                             } else {
  255.                                 $inlinetagpos = false;
  256.                             }
  257.                         }
  258.                         if ($endpos !== false) {
  259.                             if (strlen(substr($this->processedline, 0, $endpos))) {
  260.                                 $this->appendDesc(substr($this->processedline, 0, $endpos));
  261.                             }
  262.                             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGCLOSE, $esctag);
  263.                             $this->processedline = substr($this->processedline, $endpos +
  264.                                 strlen($esctag));
  265.                             $state = $this->states[0];
  266.                             if (count($this->states) > 1) {
  267.                                 array_shift($this->states);
  268.                             }
  269.                             if (!$this->processedline) {
  270.                                 break 2;
  271.                             }
  272.                         }
  273.                         if ($inlinetagpos !== false) {
  274.                             array_unshift($this->states, PHPDOC_LEXER_ESCTAG);
  275.                             $state = $this->searchForInlineTag($inlinetagpos, $comment);
  276.                             $linestart = false;
  277.                             continue 2; // to while (true)
  278.                         }
  279.                         $this->appendDesc($this->processedline);
  280.                     break;
  281.                     case PHPDOC_LEXER_INLINETAG :
  282.                         if (!$this->processedline) {
  283.                             if ($this->linenum != $lastline) {
  284.                                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n");
  285.                             }
  286.                             continue 3; // to foreach
  287.                         }
  288.                         $endpos = strpos($this->processedline, '}');
  289.                         if ($endpos !== false) {
  290.                             if (strlen(substr($this->processedline, 0, $endpos))) {
  291.                                 $this->appendDesc(substr($this->processedline, 0, $endpos));
  292.                             }
  293.                             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INLINETAGCLOSE, '}');
  294.                             $this->processedline = substr($this->processedline, $endpos + 1); // strlen('}')
  295.                             $state = $this->states[0];
  296.                             if (count($this->states) > 1) {
  297.                                 array_shift($this->states);
  298.                             }
  299.                             if (!$this->processedline) {
  300.                                 break 2;
  301.                             }
  302.                             if ($state != PHPDOC_LEXER_INLINETAG && strlen($this->processedline)) {
  303.                                 $linestart = false;
  304.                                 continue 2; // to while (true)
  305.                             }
  306.                         }
  307.                         $this->appendDesc($this->processedline);
  308.                     break;
  309.                 }
  310.                 break;
  311.             }
  312.             if ($this->linenum != $lastline) {
  313.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n");
  314.             }
  315.         }
  316.         return $this->tokens;
  317.     }
  318.  
  319.     function searchForSimplelist($trimline)
  320.     {
  321.         $whitespace = strpos($this->processedline, $trimline);
  322.         switch ($trimline{0}) {
  323.             case '-' :
  324.             case '*' :
  325.             case '+' :
  326.             case 'o' :
  327.                 if (strlen($trimline) < 3 || $trimline{1} != ' ') {
  328.                     return false;
  329.                 }
  330.                 // unordered lists
  331.                 $this->simplelist[] = 'u' . $trimline{0};
  332.                 $this->whitespace[] = $whitespace;
  333.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTSTART, '');
  334.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_UNORDEREDBULLET, $trimline{0});
  335.                 $this->processedline = substr($this->processedline, strpos($this->processedline,
  336.                     $trimline{0}) + 2);
  337.                 array_unshift($this->states, PHPDOC_LEXER_SIMPLELIST);
  338.                 return true;
  339.             break;
  340.             case '#' :
  341.                 if (strlen($trimline) < 3) {
  342.                     return false;
  343.                 }
  344.                 // ordered lists
  345.                 $this->simplelist[] = '#1';
  346.                 $this->whitespace[] = $whitespace;
  347.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTSTART, '');
  348.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, '#');
  349.                 $this->processedline = substr($this->processedline, strpos($this->processedline,
  350.                     '#') + 2);
  351.                 array_unshift($this->states, PHPDOC_LEXER_SIMPLELIST);
  352.                 return true;
  353.             case '1' :
  354.                 if (strlen($trimline) < 4) {
  355.                     return false;
  356.                 }
  357.                 if ($trimline{1} == ' ') {
  358.                     $this->simplelist[] = 'O1';
  359.                 } elseif ($trimline{1} == '.' && $trimline{2} == ' ') {
  360.                     $this->simplelist[] = 'o1';
  361.                 } else {
  362.                     return false;
  363.                 }
  364.                 $this->whitespace[] = $whitespace;
  365.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTSTART, '');
  366.                 if ($trimline{1} == '.') {
  367.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, '1.');
  368.                     $this->processedline = substr($this->processedline, strpos($this->processedline,
  369.                         '1.') + 3);
  370.                 } else {
  371.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, '1');
  372.                     $this->processedline = substr($this->processedline, strpos($this->processedline,
  373.                         '1') + 2);
  374.                 }
  375.                 array_unshift($this->states, PHPDOC_LEXER_SIMPLELIST);
  376.                 return true;
  377.         }
  378.         return false;
  379.     }
  380.  
  381.     /**
  382.      * @todo process multi-line elements via whitespace
  383.      * @todo process nested simple lists
  384.      */
  385.     function processSimpleList()
  386.     {
  387.         $trimline = trim($this->processedline);
  388.         $index = count($this->simplelist) - 1;
  389.         $whitespace = strpos($this->processedline, $trimline);
  390.         if ($whitespace < $this->whitespace[$index]) {
  391.             while (count($this->whitespace[$index]) && $whitespace < $this->whitespace[$index]) {
  392.                 // the end of the current simplelist
  393.                 $this->tokens = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, '');
  394.                 array_pop($this->simplelist);
  395.                 $index--;
  396.             }
  397.             if ($index == -1) {
  398.                 return false; // all simple lists concluded
  399.             }
  400.         }
  401.         if ($whitespace > $this->whitespace[$index]) {
  402.             // could be a multi-line element or a new list
  403.             if (!$this->searchForSimplelist($trimline)) {
  404.                 // trim off the simple list whitespace if this is multi-line
  405.                 $this->processedline = substr($this->processedline, $this->whitespace[$index] + 2);
  406.             }
  407.             return true;
  408.         }
  409.         // implied: whitespace matches exactly so this is either another
  410.         // bullet point or the end of the simple list
  411.         switch ($this->simplelist[$index]{0}) {
  412.             case 'u' :
  413.                 if (strlen($trimline) < 3 || $trimline{0} != $this->simplelist[$index]{1} ||
  414.                       $trimline{1} != ' ') {
  415.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, '');
  416.                     array_pop($this->simplelist);
  417.                     return false;
  418.                 }
  419.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_UNORDEREDBULLET, $trimline{0});
  420.                 $this->processedline = substr($this->processedline, strpos($this->processedline,
  421.                     $trimline{0}) + 2);
  422.             break;
  423.             case 'o' :
  424.                 if (strlen($trimline) < 4 || ($trimline{0} !=
  425.                       ($this->simplelist[$index]{1} + 1) . '') ||
  426.                       $trimline{1} != '.' || $trimline{2} != ' ') {
  427.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, '');
  428.                     array_pop($this->simplelist);
  429.                     return false;
  430.                 }
  431.                 $this->simplelist[$index] = $this->simplelist[$index]{0} .
  432.                     ($this->simplelist[$index]{1} + 1);
  433.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET,
  434.                     $this->simplelist[$index]{1} . '.');
  435.                 $this->processedline = substr($this->processedline, strpos($this->processedline,
  436.                     $trimline{0} . '.') + 3);
  437.             break;
  438.             case 'O' :
  439.                 if (strlen($trimline) < 3 || $trimline{0} != ($this->simplelist[$index]{1} + 1) . '' ||
  440.                       $trimline{1} != ' ') {
  441.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, '');
  442.                     array_pop($this->simplelist);
  443.                     return false;
  444.                 }
  445.                 $this->simplelist[$index] = $this->simplelist[$index]{0} .
  446.                     ($this->simplelist[$index]{1} + 1);
  447.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET,
  448.                     $this->simplelist[$index]{1});
  449.                 $this->processedline = substr($this->processedline, strpos($this->processedline,
  450.                     $this->simplelist[$index]{1}) + 2);
  451.             break;
  452.             case '#' :
  453.                 if (strlen($trimline) < 3 || $trimline{0} != '#' ||
  454.                       $trimline{1} != ' ') {
  455.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, '');
  456.                     array_pop($this->simplelist);
  457.                     return false;
  458.                 }
  459.                 $this->simplelist[$index] = $this->simplelist[$index]{0} .
  460.                     ($this->simplelist[$index]{1} + 1);
  461.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET,
  462.                     $this->simplelist[$index]{1});
  463.                 $this->processedline = substr($this->processedline, strpos($this->processedline,
  464.                     '#') + 2);
  465.             break;
  466.         }
  467.         return true;
  468.     }
  469.  
  470.     function searchForHTMLTag($tagpos, &$state, &$esctag, &$linestart,
  471.                               &$trimline)
  472.     {
  473.         if (preg_match('/^<(<\/?[a-zA-Z]+ ?\/?>)>/', substr($this->processedline, $tagpos),
  474.               $matches)) {
  475.             if ($tagpos) {
  476.                 $this->appendDesc(substr($this->processedline, 0, $tagpos));
  477.             }
  478.             $this->appendDesc($matches[1]);
  479.             $this->processedline = substr($this->processedline, $tagpos
  480.                 + strlen($matches[1])
  481.                 + 2);
  482.             return 2;
  483.         } elseif (!count($matches) &&
  484.               preg_match('/^<(<\/?[a-zA-Z]+ ?\/?>)>/', substr($this->processedline, $tagpos + 1),
  485.               $matches)) {
  486.             if ($tagpos) {
  487.                 $this->appendDesc(substr($this->processedline, 0, $tagpos));
  488.             }
  489.             $this->appendDesc('<' . $matches[1]);
  490.             $this->processedline = substr($this->processedline, $tagpos
  491.                 + strlen($matches[1])
  492.                 + 3);
  493.             return 2;
  494.         } elseif (preg_match('#^(br>|br/>|br />)#',
  495.               substr($this->processedline, $tagpos + 1), $matches)) {
  496.             if ($tagpos) {
  497.                 $this->appendDesc(substr($this->processedline, 0, $tagpos));
  498.             }
  499.             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAG, 'br');
  500.             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAGCLOSE, 'br');
  501.             $this->processedline = substr($this->processedline, $tagpos
  502.                 + strlen($matches[1])
  503.                 + 1);
  504.             return 2;
  505.         } elseif (preg_match('/^(b>|i>|li>|ol>|ul>|p>|pre>|var>)/',
  506.               substr($this->processedline, $tagpos + 1), $matches)) {
  507.             if ($tagpos) {
  508.                 $this->appendDesc(substr($this->processedline, 0, $tagpos));
  509.             }
  510.             $matches = substr($matches[1], 0, strlen($matches[1]) - 1);
  511.             array_push($this->tagStack, $matches);
  512.             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAG, $matches);
  513.             $this->processedline = substr($this->processedline, $tagpos
  514.                 + strlen($matches)
  515.                 + 2);
  516.             return 2;
  517.         } elseif (preg_match('#^(/b>|/i>|/li>|/ol>|/ul>|/p>|/pre>|/var>)#',
  518.               substr($this->processedline, $tagpos + 1), $matches)) {
  519.             if ($tagpos) {
  520.                 $this->appendDesc(substr($this->processedline, 0, $tagpos));
  521.             }
  522.             $matches = substr($matches[1], 1, strlen($matches[1]) - 2);
  523.             $test = array_pop($this->tagStack);
  524.             if ($matches != $test) {
  525.                 // throw exception
  526.                 $this->throwException('Invalid closing html tag encountered in line number ' .
  527.                     $this->linenum . ': "</' . $matches . '>", expecting "</' . $test . '>"', 'htmltag');
  528.                 return 3;
  529.             }
  530.             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAGCLOSE, $matches);
  531.             $this->processedline = substr($this->processedline, $tagpos
  532.                 + strlen($matches)
  533.                 + 3);
  534.             return 2;
  535.         } elseif (preg_match('/^(code>|pre>|kbd>|samp>)/',
  536.               substr($this->processedline, $tagpos + 1), $matches)) {
  537.             $esctag = '</' . $matches[0];
  538.             if ($tagpos) {
  539.                 $this->appendDesc(substr($this->processedline, 0, $tagpos));
  540.             }
  541.             switch ($matches[0]) {
  542.                 case 'code>' :
  543.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN,
  544.                         '<code>');
  545.                 break;
  546.                 case 'pre>' :
  547.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN,
  548.                         '<pre>');
  549.                 break;
  550.                 case 'kbd>' :
  551.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN,
  552.                         '<kbd>');
  553.                 break;
  554.                 case 'samp>' :
  555.                     $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN,
  556.                         '<samp>');
  557.                 break;
  558.             }
  559.             $this->processedline = $line = substr($this->processedline, $tagpos
  560.                 + strlen($matches[0])
  561.                 + 1);
  562.             $state = PHPDOC_LEXER_ESCTAG;
  563.             if (!$this->processedline) {
  564.                 return 3; // to foreach
  565.             }
  566.             if (strpos($this->processedline, $esctag) !== false) {
  567.                 if (!strpos($this->processedline, $esctag)) {
  568.                     $linestart = false;
  569.                     return 2; // to while (true)
  570.                 }
  571.                 if (strpos($this->processedline, $esctag)) {
  572.                     $this->appendDesc(substr($this->processedline, 0,
  573.                         strpos($this->processedline, $esctag)));
  574.                 }
  575.                 $this->processedline = $trimline =
  576.                     substr($this->processedline, strpos($this->processedline, $esctag));
  577.                 $linestart = false;
  578.                 return 2; // to while(true)
  579.             }
  580.         }
  581.     }
  582.  
  583.     function searchForInlineTag($inlinetagpos, $comment)
  584.     {
  585.         if ($inlinetagpos) {
  586.             $this->appendDesc(substr($this->processedline, 0, $inlinetagpos));
  587.         }
  588.         if ($inlinetagpos === strpos($this->processedline, '{@internal')) {
  589.             $state = array_shift($this->states);
  590.             array_unshift($this->states, $state);
  591.             if ($state == PHPDOC_LEXER_INTERNAL || $state == PHPDOC_LEXER_INTERNALTAG) {
  592.                 // throw exception
  593.                 return $this->throwException('cannot nest {@internal}} in line number ' .
  594.                     $this->linenum . ': "' . $line . '"', 'internaltag');
  595.             }
  596.             $basestate = array_pop($this->states);
  597.             array_push($this->states, $basestate);
  598.             if ($basestate == PHPDOC_LEXER_DESC) {
  599.                 $newstate = PHPDOC_LEXER_INTERNAL;
  600.             } else {
  601.                 $newstate = PHPDOC_LEXER_INTERNALTAG;
  602.             }
  603.             array_unshift($this->states, $newstate);
  604.             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INTERNAL, '{@internal');
  605.             $this->processedline = substr($this->processedline, $inlinetagpos + strlen('{@internal'));
  606.             return $newstate;
  607.         }
  608.         if (!preg_match('/^({@[^}\s]+)\s/', substr($this->processedline, $inlinetagpos), $matches)) {
  609.             if (!preg_match('/^({@[^}\s]+)}/', substr($this->processedline, $inlinetagpos), $matches)) {
  610.                 if ($this->hasEndchar($comment, '}')) {
  611.                     $matches = array(substr($this->processedline, $inlinetagpos),
  612.                         substr($this->processedline, $inlinetagpos));
  613.                 } else {
  614.                     // throw exception if this does not match
  615.                     $this->throwException('Unclosed inline tag encountered on line number ' .
  616.                         $this->linenum . ': "' . $line . '"', 'tag');
  617.                     return PHPDOC_LEXER_DESC;
  618.                 }
  619.             } else {
  620.                 // throw exception if this does not match
  621.                 $this->throwException('Invalid inline tag encountered in line number ' .
  622.                     $this->linenum . ': "' . $line . '"', 'tag');
  623.                 return PHPDOC_LEXER_DESC;
  624.             }
  625.         }
  626.         $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INLINETAG, $matches[1]);
  627.         $this->processedline = substr($this->processedline, $inlinetagpos + strlen($matches[1]));
  628.         return PHPDOC_LEXER_INLINETAG;
  629.     }
  630.  
  631.     function appendDesc($desc)
  632.     {
  633.         if (!strlen($desc)) {
  634.             return;
  635.         }
  636.         if (count($this->tokens)) {
  637.             $last = array_pop($this->tokens);
  638.             if ($last[0] == PHPDOC_DOCBLOCK_TOKEN_DESC) {
  639.                 $last[1] .= $desc;
  640.                 $this->tokens[] = $last;
  641.             } else {
  642.                 $this->tokens[] = $last;
  643.                 $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC, $desc);
  644.             }
  645.         } else {
  646.             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC, $desc);
  647.         }
  648.     }
  649.  
  650.     function hasEndChar($comment, $char)
  651.     {
  652.         $linenum = $this->linenum;
  653.         foreach ($comment as $num => $line) {
  654.             if ($linenum !== false && $num <= $linenum) {
  655.                 continue;
  656.             }
  657.             $linenum = false;
  658.             $processedline = trim($line);
  659.             if ($processedline == '*/') {
  660.                 break;
  661.             }
  662.             if (!$processedline) {
  663.                 continue;
  664.             }
  665.             if (substr($processedline, 0, 3) == '/**') {
  666.                 $processedline = substr($processedline, 3);
  667.                 if (!$processedline) {
  668.                     continue;
  669.                 }
  670.                 if (trim($processedline) == '*/') {
  671.                     break;
  672.                 }
  673.             } else {
  674.                 $processedline = substr($processedline, 1);
  675.             }
  676.             if (strpos($processedline, $char) !== false) {
  677.                 return true;
  678.             }
  679.         }
  680.         return false;
  681.     }
  682.  
  683.     function endSimpleList()
  684.     {
  685.         if (count($this->tagStack)) {
  686.             $this->tokens = array();
  687.             return $this->throwException('Error: unclosed html tags: "' .
  688.                 implode(', ', $this->tagStack) . '"', 'simplelist');
  689.         }
  690.         while (count($this->simplelist)) {
  691.             $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, '');
  692.         }
  693.     }
  694.  
  695.     function throwException($message, $type)
  696.     {
  697.         $this->error = array($message, $this->linenum, $type);
  698.         $this->exception = true;
  699.     }
  700. }
  701. ?>

Documentation generated on Mon, 11 Mar 2019 15:08:16 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.