1) Moved net.sourceforge.phpeclipse.ui\src\net\sourceforge\phpdt back to net.sourcefo...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / PHPCodeReader.java
index 1b16749..96d65c8 100644 (file)
@@ -13,239 +13,318 @@ import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
 
 /**
- * Reads from a document either forwards or backwards. May be configured to skip comments and strings.
+ * Reads from a document either forwards or backwards. May be configured to skip
+ * comments and strings.
  */
 public class PHPCodeReader extends SingleCharReader {
 
-  /** The EOF character */
-  public static final int EOF = -1;
-
-  private boolean fSkipComments = false;
-
-  private boolean fSkipStrings = false;
-
-  private boolean fForward = false;
-
-  private IDocument fDocument;
-
-  private int fOffset;
-
-  private int fEnd = -1;
-
-  private int fCachedLineNumber = -1;
-
-  private int fCachedLineOffset = -1;
-
-  public PHPCodeReader() {
-  }
-
-  /**
-   * Returns the offset of the last read character. Should only be called after read has been called.
-   */
-  public int getOffset() {
-    return fForward ? fOffset - 1 : fOffset;
-  }
-
-  public void configureForwardReader(IDocument document, int offset, int length, boolean skipComments, boolean skipStrings)
-      throws IOException {
-    fDocument = document;
-    fOffset = offset;
-    fSkipComments = skipComments;
-    fSkipStrings = skipStrings;
-
-    fForward = true;
-    fEnd = Math.min(fDocument.getLength(), fOffset + length);
-  }
-
-  public void configureBackwardReader(IDocument document, int offset, boolean skipComments, boolean skipStrings) throws IOException {
-    fDocument = document;
-    fOffset = offset;
-    fSkipComments = skipComments;
-    fSkipStrings = skipStrings;
-
-    fForward = false;
-    try {
-      fCachedLineNumber = fDocument.getLineOfOffset(fOffset);
-    } catch (BadLocationException x) {
-      throw new IOException(x.getMessage());
-    }
-  }
-
-  /*
-   * @see Reader#close()
-   */
-  public void close() throws IOException {
-    fDocument = null;
-  }
-
-  /*
-   * @see SingleCharReader#read()
-   */
-  public int read() throws IOException {
-    try {
-      return fForward ? readForwards() : readBackwards();
-    } catch (BadLocationException x) {
-      throw new IOException(x.getMessage());
-    }
-  }
-
-  private void gotoCommentEnd() throws BadLocationException {
-    while (fOffset < fEnd) {
-      char current = fDocument.getChar(fOffset++);
-      if (current == '*') {
-        if (fOffset < fEnd && fDocument.getChar(fOffset) == '/') {
-          ++fOffset;
-          return;
-        }
-      }
-    }
-  }
-
-  private void gotoStringEnd(char delimiter) throws BadLocationException {
-    while (fOffset < fEnd) {
-      char current = fDocument.getChar(fOffset++);
-      if (current == '\\') {
-        // ignore escaped characters
-        ++fOffset;
-      } else if (current == delimiter) {
-        return;
-      }
-    }
-  }
-
-  private void gotoLineEnd() throws BadLocationException {
-    int line = fDocument.getLineOfOffset(fOffset);
-    fOffset = fDocument.getLineOffset(line + 1);
-  }
-
-  private int readForwards() throws BadLocationException {
-    while (fOffset < fEnd) {
-      char current = fDocument.getChar(fOffset++);
-
-      switch (current) {
-      case '"':
-      case '\'':
-
-        if (fSkipStrings) {
-          gotoStringEnd(current);
-          continue;
-        }
-
-        return current;
-      case '#':
-
-        if (fSkipComments && fOffset < fEnd) {
-          gotoLineEnd();
-          continue;
-        }
-
-        return current;
-
-      case '/':
-
-        if (fSkipComments && fOffset < fEnd) {
-          char next = fDocument.getChar(fOffset);
-          if (next == '*') {
-            // a comment starts, advance to the comment end
-            ++fOffset;
-            gotoCommentEnd();
-            continue;
-          } else if (next == '/') {
-            // '//'-comment starts, advance to the line end
-            gotoLineEnd();
-            continue;
-          }
-        }
-
-        return current;
-
-      }
-
-      return current;
-    }
-
-    return EOF;
-  }
-
-  private void handleSingleLineComment() throws BadLocationException {
-    int line = fDocument.getLineOfOffset(fOffset);
-    if (line < fCachedLineNumber) {
-      fCachedLineNumber = line;
-      fCachedLineOffset = fDocument.getLineOffset(line);
-      int offset = fOffset;
-      while (fCachedLineOffset < offset) {
-        char current = fDocument.getChar(offset--);
-
-        if (current == '/' && fCachedLineOffset <= offset && fDocument.getChar(offset) == '/') {
-          fOffset = offset;
-          return;
-        }
-
-        if (current == '#' && fCachedLineOffset <= offset) {
-          fOffset = offset;
-          return;
-        }
-      }
-    }
-  }
-
-  private void gotoCommentStart() throws BadLocationException {
-    while (0 < fOffset) {
-      char current = fDocument.getChar(fOffset--);
-      if (current == '*' && 0 <= fOffset && fDocument.getChar(fOffset) == '/')
-        return;
-    }
-  }
-
-  private void gotoStringStart(char delimiter) throws BadLocationException {
-    while (0 < fOffset) {
-      char current = fDocument.getChar(fOffset);
-      if (current == delimiter) {
-        if (!(0 <= fOffset && fDocument.getChar(fOffset - 1) == '\\'))
-          return;
-      }
-      --fOffset;
-    }
-  }
-
-  private int readBackwards() throws BadLocationException {
-
-    while (0 < fOffset) {
-      --fOffset;
-
-      handleSingleLineComment();
-
-      char current = fDocument.getChar(fOffset);
-      switch (current) {
-      case '/':
-
-        if (fSkipComments && fOffset > 1) {
-          char next = fDocument.getChar(fOffset - 1);
-          if (next == '*') {
-            // a comment ends, advance to the comment start
-            fOffset -= 2;
-            gotoCommentStart();
-            continue;
-          }
-        }
-
-        return current;
-      case '"':
-      case '\'':
-
-        if (fSkipStrings) {
-          --fOffset;
-          gotoStringStart(current);
-          continue;
-        }
-
-        return current;
-      }
-
-      return current;
-    }
-
-    return EOF;
-  }
+       /** The EOF character */
+       public static final int EOF = -1;
+       private boolean fSkipComments = false;
+       private boolean fSkipStrings  = false;
+       private boolean fForward      = false;
+       
+       private IDocument fDocument;
+       
+       private int fOffset;                           // The current text position within the editor's text
+       private int fEnd              = -1;
+       private int fCachedLineNumber = -1;            // Holds the last line we checked for single line comments
+
+       public PHPCodeReader() {
+       }
+
+       /**
+        * Returns the offset of the last read character. Should only be called
+        * after read has been called.
+        */
+       public int getOffset() {
+               return fForward ? fOffset - 1 : fOffset;
+       }
+
+       public void configureForwardReader(IDocument document, int offset,
+                       int length, boolean skipComments, boolean skipStrings)
+                       throws IOException {
+               fDocument = document;
+               fOffset = offset;
+               fSkipComments = skipComments;
+               fSkipStrings = skipStrings;
+
+               fForward = true;
+               fEnd = Math.min(fDocument.getLength(), fOffset + length);
+       }
+
+       public void configureBackwardReader(IDocument document, int offset,
+                       boolean skipComments, boolean skipStrings) throws IOException {
+               fDocument = document;
+               fOffset = offset;
+               fSkipComments = skipComments;
+               fSkipStrings = skipStrings;
+
+               fForward = false;
+               try {
+                       fCachedLineNumber = fDocument.getLineOfOffset(fOffset);
+               } catch (BadLocationException x) {
+                       throw new IOException(x.getMessage());
+               }
+       }
+
+       /*
+        * @see Reader#close()
+        */
+       public void close() throws IOException {
+               fDocument = null;
+       }
+
+       /*
+        * @see SingleCharReader#read()
+        */
+       public int read() throws IOException {
+               try {
+                       return fForward ? readForwards() : readBackwards();
+               } catch (BadLocationException x) {
+                       throw new IOException(x.getMessage());
+               }
+       }
+
+       private int gotoCommentEnd (int nTextPos) throws BadLocationException {
+               while (nTextPos < fEnd) {
+                       char current = fDocument.getChar (nTextPos++);
+                       
+                       if (current == '*') {
+                               if ((nTextPos < fEnd) && 
+                                   (fDocument.getChar (nTextPos) == '/')) {
+                                       ++nTextPos;
+                                       
+                                       return nTextPos;
+                               }
+                       }
+               }
+               
+               return nTextPos;
+       }
+
+       /**
+        * 
+        * @param delimiter
+        * @throws BadLocationException
+        */
+       private int gotoStringEnd (int nTextPos, char delimiter) throws BadLocationException {
+               while (nTextPos < fEnd) {               // If long as we are not at the end of text
+                       char current = fDocument.getChar (nTextPos++);
+                       
+                       if (current == '\\') {                          // ignore escaped characters
+                               ++nTextPos;
+                       } 
+                       else if (current == delimiter) {
+                               return nTextPos;
+                       }
+               }
+               
+               return nTextPos;                        // End position
+       }
+
+       /**
+        * 
+        * @param nTextPos               The current text position
+        * 
+        * @return                       The position of the start of next line
+        * 
+        * @throws BadLocationException
+        */
+       private int gotoLineEnd (int nTextPos) throws BadLocationException {
+               int line = fDocument.getLineOfOffset (nTextPos); // Get the line number of the current text position
+               
+               return fDocument.getLineOffset (line + 1);
+       }
+
+       private int readForwards () throws BadLocationException {
+               while (fOffset < fEnd) {
+                       char current = fDocument.getChar(fOffset++);
+
+                       switch (current) {
+                           case '"':
+                           case '\'':
+                               if (fSkipStrings) {
+                                   fOffset = gotoStringEnd (fOffset, current);
+                                   continue;
+                               }
+                               return current;
+                               
+                           case '#':
+                               if (fSkipComments && fOffset < fEnd) {
+                                   fOffset = gotoLineEnd (fOffset);
+                                   continue;
+                               }
+                               return current;
+
+                           case '/':
+                               if (fSkipComments && fOffset < fEnd) {
+                                   char next = fDocument.getChar(fOffset);
+                                   
+                                   if (next == '*') {                                  // A comment starts, advance to the comment end
+                                       ++fOffset;
+                                       fOffset = gotoCommentEnd (fOffset);
+                                       continue;
+                                   } else if (next == '/') {                   // '//'-comment starts, advance to the line end
+                                       fOffset = gotoLineEnd (fOffset);
+                                       continue;
+                                   }
+                               }    
+                               return current;
+                       }
+
+                       return current;
+               }
+
+               return EOF;
+       }
+
+       /**
+        * Check whether the current line contains a single line comment.
+        * If it contains a single line comment (// or #), than set fOffset (the global character index)
+        * to the character just before the single line comment.
+        * 
+        * @throws BadLocationException
+        */
+       
+       private void handleSingleLineComment () throws BadLocationException {
+           char current;
+               int  line = fDocument.getLineOfOffset (fOffset);         // Get the line number which belongs to the current text position fOffset
+               
+               if (line < fCachedLineNumber) {                          // If we didn't parse this line already
+                       fCachedLineNumber = line;                            // Remember this line for the next time (so we don't search again!)   
+                       int nOffset       = fDocument.getLineOffset (line);  // Get the start position of current line      
+                       
+                       while (nOffset < fOffset) {                          // As long as the text position is within the current line 
+                               current = fDocument.getChar (nOffset);           // Get the character from the current text position
+
+                               switch (current) {
+                                   case '/':
+                                       if (fDocument.getChar (nOffset + 1) == '/') { // If the following character is '/'
+                                           fOffset = nOffset - 1;
+                                           
+                                           return;
+                                       }
+                                       break;    
+                                   
+                                   case '#':
+                        fOffset = nOffset - 1;
+                        return;
+                                   
+                                   case '"':                                           // It's a string start quote
+                                   case '\'':
+                                       nOffset++;                                      // Set to next character
+                                       
+                                       while (nOffset < fOffset) {                     // As long as we are within the same line
+                                           char cChar = fDocument.getChar (nOffset++);
+                                           
+                                           if (cChar == '\\') {                        // Ignore escaped characters
+                                               ++nOffset;
+                                           } 
+                                           else if (cChar == current) {                // If end of string found 
+                                               break;
+                                           }
+                                       }
+                                       break;
+                               }
+                               
+                               nOffset++;                                              // Go for the next character
+                       }
+               }
+       }
+
+       /**
+        * We search the for the block comment start sequence "/*"
+        * 
+        * The returned value points to the '/'
+        * 
+        * @throws BadLocationException
+        * 
+        * @return The new text position
+        */
+       
+       private int gotoCommentStart (int nTextPos) throws BadLocationException {
+               while (0 < nTextPos) {                                // As long as we are not at the start of the editor text
+                   char current = fDocument.getChar (nTextPos--);    // Get the character from the current text position        
+                       
+                       if ((current == '*') &&                           // If current character is a '*' 
+                           (0 <= nTextPos) &&                            // and if we are not yet at the start of the editor text 
+                           (fDocument.getChar (nTextPos) == '/')) {      // and the previous character is a '/', 
+                               return nTextPos;                              // We found the block comment start "/*"
+                       }
+               }
+               
+               return nTextPos;
+       }
+
+       /**
+        * The string closing quote has been found, when reading the editor text backwards.
+        * So we have to search for the start of the string
+        * 
+        * The returned value points to '"' or '''
+        * 
+        * @param delimiter The string double quote '"' or single ''' quote we search for
+        * 
+        * @throws BadLocationException
+        */
+       private int gotoStringStart (int nTextPos, char delimiter) throws BadLocationException {
+               while (0 < nTextPos) {                              // As long as we are not at the start of the editor text
+                       char current = fDocument.getChar (nTextPos);    // Get the character from the current text position 
+                                                                       
+                       if (current == delimiter) {                     // If we found the same character ('"' or ''') again, we have found the string start
+                               if (!(0 <= nTextPos &&                        
+                                     fDocument.getChar (nTextPos - 1) == '\\')) // If the character before the string quote is not an '/' 
+                               return nTextPos;                                 // we found the string start
+                       }
+                                                                           
+                       --nTextPos;                                          // Go one character back
+               }
+               
+               return nTextPos;
+       }
+
+       /**
+        * Read the editor text backwards
+        * 
+        */
+       
+       private int readBackwards() throws BadLocationException {
+           char current;                                                // The character on position fOffset
+           
+               while (0 < fOffset) {                                        // As long as we are not at the beginning of the editor text
+                       --fOffset;                                               // Step back one character
+
+                       handleSingleLineComment ();                              // Search for a single line comment within the current line
+                                                                                // If there is a single line comment, fOffset is set to position just before the single line comment
+
+                       current = fDocument.getChar (fOffset);                   // Read the current character
+                       switch (current) {                                       // Process the current character
+                           case '/':                                            // Is it a single line comment? 
+                               if (fSkipComments &&                             // When comments should be skipped when parsing
+                                   fOffset > 1) {                               // and if there is indeed an additional character before that '/'
+                                   char prev = fDocument.getChar (fOffset - 1); // Look at the character in front of the '/'
+                                   
+                                   if (prev == '*') {                           // If '*' than a block comment ends here, advance to the comment start
+                                       fOffset -= 2;                            // Set character pointer to character before "*/"
+                                       fOffset  = gotoCommentStart (fOffset);   // and search for the starting "/*" of the block comment
+                                       continue;
+                                   }
+                               }
+                               return current;                                  // No block comment end, so return the current character
+                               
+                           case '"':                                            // Is it a string double quote closing '"'?                                                
+                           case '\'':                                           // or a string single quote closing '''?
+                               if (fSkipStrings) {                              // If we should skip strings when parsing
+                                   --fOffset;                                   // Set pointer one before the string closing quote 
+                                   fOffset = gotoStringStart (fOffset, current);// and search the start of string ('"' or ''')
+                                   continue;
+                               }
+                               return current;                                  // No string skip, so return the current character
+                       }
+
+                       return current;                                          // No string and no comment
+               }
+
+               return EOF;                                                  // When the start of the text has been found
+       }
 }
-