Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/spikephpcoverage/src/parser/PHPParser.php
Go to the documentation of this file.
00001 <?php
00002     /*
00003     *  $Id: PHPParser.php,v 1.3 2010/12/14 17:36:00 moodlerobot Exp $
00004     *  
00005     *  Copyright(c) 2004-2006, SpikeSource Inc. All Rights Reserved.
00006     *  Licensed under the Open Software License version 2.1
00007     *  (See http://www.spikesource.com/license.html)
00008     */
00009 ?>
00010 <?php
00011 
00012     if(!defined("__PHPCOVERAGE_HOME")) {
00013         define("__PHPCOVERAGE_HOME", dirname(dirname(__FILE__)));
00014     }
00015     require_once __PHPCOVERAGE_HOME . "/parser/Parser.php";
00016 
00024     class PHPParser extends Parser {
00025         /*{{{ Members */
00026 
00027         private $inHereDoc = false;
00028         private $inFunction = false;
00029         private $phpStarters = array('<?php', '<?', '<?=');
00030         private $phpFinisher = '?>';
00031         private $inComment = false;
00032         private $lastLineEndTokenType = "";
00033         private $fileToken = null;
00034         private $currFileToken = 0;
00035         private $lineNb = 0;
00036         private $multiLineTok = null;
00037         // If one of these tokens occur as the last token of a line
00038         // then the next line can be treated as a continuation line
00039         // depending on how it starts.
00040         public static $contTypes = array(
00041             "(",
00042             ",",
00043             ".",
00044             "=",
00045             T_LOGICAL_XOR,
00046             T_LOGICAL_AND,
00047             T_LOGICAL_OR,
00048             T_PLUS_EQUAL,
00049             T_MINUS_EQUAL,
00050             T_MUL_EQUAL,
00051             T_DIV_EQUAL,
00052             T_CONCAT_EQUAL,
00053             T_MOD_EQUAL,
00054             T_AND_EQUAL,
00055             T_OR_EQUAL,
00056             T_XOR_EQUAL,
00057             T_BOOLEAN_AND,
00058             T_BOOLEAN_OR,
00059             T_OBJECT_OPERATOR, 
00060             T_DOUBLE_ARROW, 
00061             "[", 
00062             "]",
00063             T_LOGICAL_OR, 
00064             T_LOGICAL_XOR, 
00065             T_LOGICAL_AND,
00066             T_STRING
00067         );
00068         /*}}}*/
00069 
00070         /*{{{ protected function openFileReadOnly() */
00071 
00079         protected function openFileReadOnly() {
00080             $this->fileToken = @token_get_all(file_get_contents($this->filename));
00081             return parent::openFileReadOnly();
00082         }
00083 
00084         /*}}}*/
00085         /*{{{ protected function getNextToken() */
00086 
00098         protected function getNextToken($line, &$pos) {
00099             $lineLen = strlen($line);
00100             if($pos >= $lineLen) {
00101                 return null;
00102             }
00103             if($this->multiLineTok != null) {
00104                 list($tok, $lnb, $posnl) = $this->multiLineTok;
00105                 if(is_string($tok)) {
00106                     $str = $tok;
00107                 } else {
00108                     $str = $tok[1];
00109                 }
00110                 if($posnl >= strlen($str)) {
00111                     $this->multiLineTok = null;
00112                 } else {
00113                     if(substr($str, $posnl + 1, $lineLen) == $line) {
00114                         $pos += $lineLen;
00115                         $newPosnl = $posnl + $lineLen;
00116                     } else {
00117                         $newPosnl = strpos($str, "\n", $posnl + 1);
00118                         if($newPosnl === false) {
00119                             $newPosnl = strlen($str);
00120                         }
00121                         $len = $newPosnl - $posnl - 1;
00122                         //if(substr($str, $posnl + 1, $len) != substr($line, $pos, $len)) {
00123                         //}
00124                         $pos += $len;
00125                     }
00126                     $this->multiLineTok[1]++;
00127                     $this->multiLineTok[2] = $newPosnl;
00128                     return $tok;
00129                 }
00130             }
00131             if(!isset($this->fileToken[$this->currFileToken])) {
00132                 return null;
00133             }
00134             $tok = &$this->fileToken[$this->currFileToken];
00135             if(is_string($tok)) {
00136                 $str = $tok;
00137             } else {
00138                 $str = $tok[1];
00139             }
00140             $nbnl = substr_count($str, "\n");
00141             if($nbnl > 0 && ($posnl = strpos($str, "\n")) != strlen($str) - 1) {
00142                 $this->multiLineTok = array($tok, 1, $posnl);
00143                 $str = substr($str, 0, $posnl + 1);
00144             }
00145             if(substr($line, $pos, strlen($str)) == $str) {
00146                 $this->currFileToken++;
00147                 $pos += strlen($str);
00148                 return $tok;
00149             } else {
00150                 return null;
00151             }
00152         }
00153 
00154         /*}}}*/
00155         /*{{{ protected function isMultiLineCont() */
00156 
00166         protected function isMultiLineCont() {
00167             if($this->multiLineTok == null
00168                || $this->multiLineTok[1] <= 1) {
00169                 return false;
00170             }
00171             switch ($this->getTokenType($this->multiLineTok[0])) {
00172             case T_COMMENT:
00173             case T_INLINE_HTML:             // <br/><b>jhsk</b>
00174                 return false;
00175             }
00176             return true;
00177         }
00178 
00179         /*}}}*/
00180         /*{{{ protected function processLine() */
00181 
00192         protected function processLine($line) {
00193 
00194             // Default values
00195             $prevLineType = $this->lineType; 
00196             $this->lineType = LINE_TYPE_NOEXEC;
00197             $tokenCnt = 0;
00198             $this->lineNb++;
00199             $pos = 0;
00200             $seeMore = false;
00201             $seenEnough = false;
00202             $lastToken = null;
00203             
00204             while (($token = $this->getNextToken($line, $pos))) {
00205                 if (!is_string($token)) {
00206                     $stoken = token_name($token[0]) . ' "'
00207                         . str_replace(array("\\", "\"", "\n", "\r")
00208                                       , array("\\\\", "\\\"", "\\n", "\\r")
00209                                       , $token[1]) . '"';
00210                     if (isset($token[2])) {
00211                         $stoken .= '[' . $token[2] . ']';
00212                         if ($token[2] != $this->lineNb) {
00213                             $stoken .= ' != [' . $this->lineNb . ']';
00214                         }
00215                     }
00216                 } else {
00217                     $stoken = $token;
00218                 }
00219                 $this->logger->debug("Token $stoken", __FILE__, __LINE__);
00220                 if (!is_string($token) && $token[0] == T_WHITESPACE) {
00221                     continue;
00222                 }
00223                 $lastToken = $token;
00224                 $tokenCnt ++;
00225                 if ($this->inHereDoc) {
00226                     $this->lineType = LINE_TYPE_CONT;
00227                     $this->logger->debug("Here doc Continuation! Token: $token",
00228                                          __FILE__, __LINE__);
00229                     
00230                     if ($this->getTokenType($token) == T_END_HEREDOC) {
00231                         $this->inHereDoc = false;
00232                     }
00233                     continue;
00234                 }
00235                 if ($this->inFunction) {
00236                     $this->lineType = LINE_TYPE_NOEXEC;
00237                     $this->logger->debug("Function! Token: $token",
00238                                          __FILE__, __LINE__);
00239                     if ($this->getTokenType($token) == '{') {
00240                         $this->inFunction = false;
00241                     }
00242                     continue;
00243                 }
00244                 
00245                 if($tokenCnt == 1 && $prevLineType != LINE_TYPE_NOEXEC
00246                    && ($this->isMultiLineCont()
00247                        || $this->isContinuation($token))) {
00248                     $this->lineType = LINE_TYPE_CONT;
00249                     $this->logger->debug("Continuation! Token: ".print_r($token, true),
00250                                          __FILE__, __LINE__);
00251                     $seenEnough = true;
00252                     continue;
00253                 }
00254                 if ($seenEnough) {
00255                     continue;
00256                 }
00257                 if(is_string($token)) {
00258                     // FIXME: Add more cases, if needed
00259                     switch($token) {
00260                         // Any of these things, are non-executable.
00261                         // And so do not change the status of the line
00262                     case '{':
00263                     case '}':
00264                     case '(':
00265                     case ')':
00266                     case ';':
00267                         break; 
00268                         
00269                         // Everything else by default is executable.
00270                     default:
00271                         $this->logger->debug("Other string: $token",
00272                                              __FILE__, __LINE__);
00273                         if($this->lineType == LINE_TYPE_NOEXEC) {
00274                             $this->lineType = LINE_TYPE_EXEC;
00275                         }
00276                         break;
00277                     }
00278                     $this->logger->debug("Status: " . $this->getLineTypeStr($this->lineType) . "\t\tToken: $token",
00279                                          __FILE__, __LINE__);
00280                 }
00281                 else {
00282                     // The token is an array
00283                     list($tokenType, $text) = $token;
00284                     switch($tokenType) {
00285                     case T_COMMENT:
00286                     case T_DOC_COMMENT:
00287                     case T_WHITESPACE:              // white space
00288                     case T_OPEN_TAG:                // < ?
00289                     case T_OPEN_TAG_WITH_ECHO:      // < ? =
00290                     case T_CURLY_OPEN:              // 
00291                     case T_INLINE_HTML:             // <br/><b>jhsk</b>
00292                         //case T_STRING:                  // 
00293                     case T_EXTENDS:                 // extends
00294                     case T_STATIC:                  // static
00295                     case T_STRING_VARNAME:          // string varname?
00296                     case T_CHARACTER:               // character
00297                     case T_ELSE:                    // else
00298                     case T_CONSTANT_ENCAPSED_STRING:   // "some str"
00299                     case T_ARRAY:                   // array
00300                         // Any of these things, are non-executable.
00301                         // And so do not change the status of the line
00302                         // as the line starts as non-executable.
00303                         break;
00304                     case T_START_HEREDOC:
00305                         $this->inHereDoc = true;
00306                         break;
00307                     case T_PRIVATE:                 // private
00308                     case T_PUBLIC:                  // public
00309                     case T_PROTECTED:               // protected
00310                     case T_VAR:                     // var
00311                     case T_GLOBAL:                  // global
00312                     case T_ABSTRACT:                // abstract (Moodle added)
00313                     case T_CLASS:                   // class
00314                     case T_INTERFACE:               // interface
00315                     case T_REQUIRE:                 // require
00316                     case T_REQUIRE_ONCE:            // require_once
00317                     case T_INCLUDE:                 // include
00318                     case T_INCLUDE_ONCE:            // include_once
00319                     case T_SWITCH:                  // switch
00320                     case T_CONST:                   // const
00321                     case T_TRY:                     // try
00322                         $this->lineType = LINE_TYPE_NOEXEC;
00323                         // No need to see any further
00324                         $seenEnough = true;
00325                         break; 
00326                     case T_FUNCTION:                // function
00327                         $this->lineType = LINE_TYPE_NOEXEC;
00328                         $this->inFunction = true;
00329                         // No need to see any further
00330                         $seenEnough = true;
00331                         break; 
00332                     case T_VARIABLE:                // $foo
00333                         $seeMore = true;
00334                         if($this->lineType == LINE_TYPE_NOEXEC) {
00335                             $this->lineType = LINE_TYPE_EXEC;
00336                         }
00337                         break;
00338                     case T_CLOSE_TAG:
00339                         if($this->lineType != LINE_TYPE_EXEC) {
00340                             $this->lineType = LINE_TYPE_NOEXEC;
00341                         }
00342                         break;
00343                     default:
00344                         $this->logger->debug("Other token: " . token_name($tokenType),
00345                                              __FILE__, __LINE__);
00346                         $seeMore = false;
00347                         if($this->lineType == LINE_TYPE_NOEXEC) {
00348                             $this->lineType = LINE_TYPE_EXEC;
00349                         }
00350                         break;
00351                     }
00352                     $this->logger->debug("Status: " . $this->getLineTypeStr($this->lineType) . "\t\tToken type: $tokenType \tText: $text",
00353                                          __FILE__, __LINE__);
00354                 }
00355                 if(($this->lineType == LINE_TYPE_EXEC && !$seeMore) 
00356                    || $seenEnough) {
00357                     // start moodle modification: comment debug line causing notices
00358                     //$this->logger->debug("Made a decision! Exiting. Token Type: $tokenType & Text: $text",
00359                     //                     __FILE__, __LINE__);
00360                     // end moodle modification
00361                     if($seenEnough) {
00362                         $this->logger->debug("Seen enough at Token Type: $tokenType & Text: $text",
00363                                              __FILE__, __LINE__);
00364                     } else {
00365                         $seenEnough = true;
00366                     }
00367                 }
00368             } // end while
00369             $this->logger->debug("Line Type: " . $this->getLineTypeStr($this->lineType),
00370                                  __FILE__, __LINE__);
00371             $this->lastLineEndTokenType = $this->getTokenType($lastToken);
00372             $this->logger->debug("Last End Token: " . $this->lastLineEndTokenType,
00373                                  __FILE__, __LINE__);
00374         }
00375 
00376         /*}}}*/
00377         /*{{{ public function getLineType() */
00378 
00385         public function getLineType() {
00386             return $this->lineType;
00387         }
00388         /*}}}*/
00389         /*{{{ protected function isContinuation() */
00390 
00398         protected function isContinuation(&$token) {
00399             if(is_string($token)) {
00400                 switch($token) {
00401                 case ".":
00402                 case ",";
00403                 case "]":
00404                 case "[":
00405                 case "(":
00406                 case ")":
00407                 case "=":
00408                     return true;
00409                 }
00410             }
00411             else {
00412                 list($tokenType, $text) = $token;               
00413                 switch($tokenType) {
00414                 case T_CONSTANT_ENCAPSED_STRING:
00415                 case T_ARRAY:
00416                 case T_DOUBLE_ARROW:
00417                 case T_OBJECT_OPERATOR:
00418                 case T_LOGICAL_XOR:
00419                 case T_LOGICAL_AND:
00420                 case T_LOGICAL_OR:
00421                 case T_PLUS_EQUAL:
00422                 case T_MINUS_EQUAL:
00423                 case T_MUL_EQUAL:
00424                 case T_DIV_EQUAL:
00425                 case T_CONCAT_EQUAL:
00426                 case T_MOD_EQUAL:
00427                 case T_AND_EQUAL:
00428                 case T_OR_EQUAL:
00429                 case T_XOR_EQUAL:
00430                 case T_BOOLEAN_AND:
00431                 case T_BOOLEAN_OR:
00432                 case T_LNUMBER:
00433                 case T_DNUMBER:
00434                     return true;
00435 
00436                 case T_STRING:
00437                 case T_VARIABLE:
00438                     return in_array($this->lastLineEndTokenType, PHPParser::$contTypes);
00439                 }
00440             }
00441 
00442             return false;
00443         }
00444         /*}}}*/
00445         /*{{{ protected function getTokenType() */
00446 
00455         protected function getTokenType($token) {
00456             if(is_string($token)) {
00457                 return $token;
00458             }
00459             else {
00460                 list($tokenType, $text) = $token;
00461                 return $tokenType;
00462             }
00463         }
00464         /*}}}*/
00465         /*
00466         // Main
00467         $obj = new PHPParser();
00468         $obj->parse("test.php");
00469         while(($line = $obj->getLine()) !== false) {
00470             echo "#########################\n";
00471             echo "[" . $line . "] Type: [" . $obj->getLineTypeStr($obj->getLineType()) . "]\n";
00472             echo "#########################\n";
00473     }
00474     */
00475 
00476     }
00477 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations