* Added browser like links (Ctrl+Mouseclick on identifier; same as F3 shortcut)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Scanner.java
index a8232c2..a1127f5 100644 (file)
@@ -16,6 +16,7 @@ import net.sourceforge.phpdt.core.compiler.CharOperation;
 import net.sourceforge.phpdt.core.compiler.IScanner;
 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
+import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
 import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteral;
 
 public class Scanner implements IScanner, ITerminalSymbols {
@@ -191,20 +192,25 @@ public class Scanner implements IScanner, ITerminalSymbols {
   public char[][] taskTags = null;
 
   public char[][] taskPriorities = null;
-
+  public boolean isTaskCaseSensitive = true;
   public static final boolean DEBUG = false;
 
   public static final boolean TRACE = false;
 
+  public ICompilationUnit compilationUnit = null;
   /**
-   * Determines if the specified character is permissible as the first character in a PHP identifier
+   * Determines if the specified character is permissible 
+   * as the first character in a PHP identifier.
+   * 
+   * The '$' character for HP variables isn't regarded as the first character !
    */
   public static boolean isPHPIdentifierStart(char ch) {
     return Character.isLetter(ch) || (ch == '_') || (0x7F <= ch && ch <= 0xFF);
   }
 
   /**
-   * Determines if the specified character may be part of a PHP identifier as other than the first character
+   * Determines if the specified character may be part of a PHP 
+   * identifier as other than the first character
    */
   public static boolean isPHPIdentifierPart(char ch) {
     return Character.isLetterOrDigit(ch) || (ch == '_') || (0x7F <= ch && ch <= 0xFF);
@@ -311,6 +317,9 @@ public class Scanner implements IScanner, ITerminalSymbols {
 
   public final char[] getCurrentStringLiteralSource() {
     // Return the token REAL source (aka unicodes are precomputed)
+    if (startPosition + 1 >= currentPosition) {
+      return new char[0];
+    }
     char[] result;
     int length;
     System.arraycopy(source, startPosition + 1, result = new char[length = currentPosition - startPosition - 2], 0, length);
@@ -318,6 +327,14 @@ public class Scanner implements IScanner, ITerminalSymbols {
     return result;
   }
 
+  public final char[] getCurrentStringLiteralSource(int startPos) {
+    // Return the token REAL source (aka unicodes are precomputed)
+    char[] result;
+    int length;
+    System.arraycopy(source, startPos + 1, result = new char[length = currentPosition - startPos - 2], 0, length);
+    //    }
+    return result;
+  }
   /*
    * Search the source position corresponding to the end of a given line number
    * 
@@ -1515,7 +1532,7 @@ public class Scanner implements IScanner, ITerminalSymbols {
           case '#':
           case '/': {
             char startChar = currentCharacter;
-            if (getNextChar('=')) {
+            if (getNextChar('=') && startChar=='/') {
               return TokenNameDIVIDE_EQUAL;
             }
             int test;
@@ -1738,6 +1755,10 @@ public class Scanner implements IScanner, ITerminalSymbols {
                     return TokenNameCOMMENT_PHPDOC;
                   return TokenNameCOMMENT_BLOCK;
                 }
+                
+                if (this.taskTags != null) {
+                  checkTaskTag(this.startPosition, this.currentPosition);
+                }
               } catch (IndexOutOfBoundsException e) {
                 //                  reset end position for error reporting
                 currentPosition -= 2;
@@ -3143,7 +3164,7 @@ public class Scanner implements IScanner, ITerminalSymbols {
         if ((data[++index] == 'n') && (data[++index] == 'd') && (data[++index] == 'd') && (data[++index] == 'e')
             && (data[++index] == 'c') && (data[++index] == 'l') && (data[++index] == 'a') && (data[++index] == 'r')
             && (data[++index] == 'e'))
-          return TokenNameendforeach;
+          return TokenNameenddeclare;
         index = 0;
         if ((data[++index] == 'n') // endforeach
             && (data[++index] == 'd') && (data[++index] == 'f') && (data[++index] == 'o') && (data[++index] == 'r')
@@ -3626,7 +3647,12 @@ public class Scanner implements IScanner, ITerminalSymbols {
   }
 
   public final void setSource(char[] source) {
+    setSource(null, source);
+  }
+  
+  public final void setSource(ICompilationUnit compilationUnit, char[] source) {
     //the source-buffer is set to sourceString
+    this.compilationUnit = compilationUnit;
     if (source == null) {
       this.source = new char[0];
     } else {
@@ -3966,11 +3992,15 @@ public class Scanner implements IScanner, ITerminalSymbols {
 
   public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean checkNonExternalizedStringLiterals,
       boolean assertMode) {
-    this(tokenizeComments, tokenizeWhiteSpace, checkNonExternalizedStringLiterals, assertMode, false, null, null);
+    this(tokenizeComments, tokenizeWhiteSpace, checkNonExternalizedStringLiterals, assertMode, false, null, null,true);
   }
 
-  public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean checkNonExternalizedStringLiterals,
-      boolean assertMode, boolean tokenizeStrings, char[][] taskTags, char[][] taskPriorities) {
+  public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, 
+      boolean checkNonExternalizedStringLiterals,
+      boolean assertMode, boolean tokenizeStrings, 
+      char[][] taskTags, 
+      char[][] taskPriorities,
+      boolean isTaskCaseSensitive) {
     this.eofPosition = Integer.MAX_VALUE;
     this.tokenizeComments = tokenizeComments;
     this.tokenizeWhiteSpace = tokenizeWhiteSpace;
@@ -4114,86 +4144,203 @@ public class Scanner implements IScanner, ITerminalSymbols {
     }
   }
 
+//chech presence of task: tags
+//TODO (frederic) see if we need to take unicode characters into account...
+public void checkTaskTag(int commentStart, int commentEnd) {
+       char[] src = this.source;
+       
+       // only look for newer task: tags
+       if (this.foundTaskCount > 0
+               && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
+               return;
+       }
+       int foundTaskIndex = this.foundTaskCount;
+       char previous = src[commentStart+1]; // should be '*' or '/'
+       nextChar : for (
+               int i = commentStart + 2; i < commentEnd && i < this.eofPosition; i++) {
+               char[] tag = null;
+               char[] priority = null;
+               // check for tag occurrence only if not ambiguous with javadoc tag
+               if (previous != '@') {
+                       nextTag : for (int itag = 0; itag < this.taskTags.length; itag++) {
+                               tag = this.taskTags[itag];
+                               int tagLength = tag.length;
+                               if (tagLength == 0) continue nextTag;
+       
+                               // ensure tag is not leaded with letter if tag starts with a letter
+                               if (Character.isJavaIdentifierStart(tag[0])) {
+                                       if (Character.isJavaIdentifierPart(previous)) {
+                                               continue nextTag;
+                                       }
+                               }
+       
+                               for (int t = 0; t < tagLength; t++) {
+                                       char sc, tc;
+                                       int x = i+t;
+                                       if (x >= this.eofPosition || x >= commentEnd) continue nextTag;
+                                       if ((sc = src[i + t]) != (tc = tag[t])) {                                                                                                                                                                       // case sensitive check
+                                               if (this.isTaskCaseSensitive || (Character.toLowerCase(sc) != Character.toLowerCase(tc))) {     // case insensitive check
+                                                       continue nextTag;
+                                               }
+                                       }
+                               }
+                               // ensure tag is not followed with letter if tag finishes with a letter
+                               if (i+tagLength < commentEnd && Character.isJavaIdentifierPart(src[i+tagLength-1])) {
+                                       if (Character.isJavaIdentifierPart(src[i + tagLength]))
+                                               continue nextTag;
+                               }
+                               if (this.foundTaskTags == null) {
+                                       this.foundTaskTags = new char[5][];
+                                       this.foundTaskMessages = new char[5][];
+                                       this.foundTaskPriorities = new char[5][];
+                                       this.foundTaskPositions = new int[5][];
+                               } else if (this.foundTaskCount == this.foundTaskTags.length) {
+                                       System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                                       System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                                       System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                                       System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                               }
+                               
+                               priority = this.taskPriorities != null && itag < this.taskPriorities.length
+                                                       ? this.taskPriorities[itag]
+                                                       : null;
+                               
+                               this.foundTaskTags[this.foundTaskCount] = tag;
+                               this.foundTaskPriorities[this.foundTaskCount] = priority;
+                               this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
+                               this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
+                               this.foundTaskCount++;
+                               i += tagLength - 1; // will be incremented when looping
+                               break nextTag;
+                       }
+               }
+               previous = src[i];
+       }
+       for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
+               // retrieve message start and end positions
+               int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
+               int max_value = i + 1 < this.foundTaskCount
+                               ? this.foundTaskPositions[i + 1][0] - 1
+                               : commentEnd - 1;
+               // at most beginning of next task
+               if (max_value < msgStart) {
+                       max_value = msgStart; // would only occur if tag is before EOF.
+               }
+               int end = -1;
+               char c;
+               for (int j = msgStart; j < max_value; j++) {
+                       if ((c = src[j]) == '\n' || c == '\r') {
+                               end = j - 1;
+                               break;
+                       }
+               }
+               if (end == -1) {
+                       for (int j = max_value; j > msgStart; j--) {
+                               if ((c = src[j]) == '*') {
+                                       end = j - 1;
+                                       break;
+                               }
+                       }
+                       if (end == -1)
+                               end = max_value;
+               }
+               if (msgStart == end)
+                       continue; // empty
+               // trim the message
+               while (CharOperation.isWhitespace(src[end]) && msgStart <= end)
+                       end--;
+               while (CharOperation.isWhitespace(src[msgStart]) && msgStart <= end)
+                       msgStart++;
+               // update the end position of the task
+               this.foundTaskPositions[i][1] = end;
+               // get the message source
+               final int messageLength = end - msgStart + 1;
+               char[] message = new char[messageLength];
+               System.arraycopy(src, msgStart, message, 0, messageLength);
+               this.foundTaskMessages[i] = message;
+       }
+}
+
   // chech presence of task: tags
-  public void checkTaskTag(int commentStart, int commentEnd) {
-    // only look for newer task: tags
-    if (this.foundTaskCount > 0 && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
-      return;
-    }
-    int foundTaskIndex = this.foundTaskCount;
-    nextChar: for (int i = commentStart; i < commentEnd && i < this.eofPosition; i++) {
-      char[] tag = null;
-      char[] priority = null;
-      // check for tag occurrence
-      nextTag: for (int itag = 0; itag < this.taskTags.length; itag++) {
-        tag = this.taskTags[itag];
-        priority = this.taskPriorities != null && itag < this.taskPriorities.length ? this.taskPriorities[itag] : null;
-        int tagLength = tag.length;
-        for (int t = 0; t < tagLength; t++) {
-          if (this.source[i + t] != tag[t])
-            continue nextTag;
-        }
-        if (this.foundTaskTags == null) {
-          this.foundTaskTags = new char[5][];
-          this.foundTaskMessages = new char[5][];
-          this.foundTaskPriorities = new char[5][];
-          this.foundTaskPositions = new int[5][];
-        } else if (this.foundTaskCount == this.foundTaskTags.length) {
-          System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
-          System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0,
-              this.foundTaskCount);
-          System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0,
-              this.foundTaskCount);
-          System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0,
-              this.foundTaskCount);
-        }
-        this.foundTaskTags[this.foundTaskCount] = tag;
-        this.foundTaskPriorities[this.foundTaskCount] = priority;
-        this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
-        this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
-        this.foundTaskCount++;
-        i += tagLength - 1; // will be incremented when looping
-      }
-    }
-    for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
-      // retrieve message start and end positions
-      int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
-      int max_value = i + 1 < this.foundTaskCount ? this.foundTaskPositions[i + 1][0] - 1 : commentEnd - 1;
-      // at most beginning of next task
-      if (max_value < msgStart)
-        max_value = msgStart; // would only occur if tag is before EOF.
-      int end = -1;
-      char c;
-      for (int j = msgStart; j < max_value; j++) {
-        if ((c = this.source[j]) == '\n' || c == '\r') {
-          end = j - 1;
-          break;
-        }
-      }
-      if (end == -1) {
-        for (int j = max_value; j > msgStart; j--) {
-          if ((c = this.source[j]) == '*') {
-            end = j - 1;
-            break;
-          }
-        }
-        if (end == -1)
-          end = max_value;
-      }
-      if (msgStart == end)
-        continue; // empty
-      // trim the message
-      while (CharOperation.isWhitespace(source[end]) && msgStart <= end)
-        end--;
-      while (CharOperation.isWhitespace(source[msgStart]) && msgStart <= end)
-        msgStart++;
-      // update the end position of the task
-      this.foundTaskPositions[i][1] = end;
-      // get the message source
-      final int messageLength = end - msgStart + 1;
-      char[] message = new char[messageLength];
-      System.arraycopy(source, msgStart, message, 0, messageLength);
-      this.foundTaskMessages[i] = message;
-    }
-  }
+//  public void checkTaskTag(int commentStart, int commentEnd) {
+//    // only look for newer task: tags
+//    if (this.foundTaskCount > 0 && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
+//      return;
+//    }
+//    int foundTaskIndex = this.foundTaskCount;
+//    nextChar: for (int i = commentStart; i < commentEnd && i < this.eofPosition; i++) {
+//      char[] tag = null;
+//      char[] priority = null;
+//      // check for tag occurrence
+//      nextTag: for (int itag = 0; itag < this.taskTags.length; itag++) {
+//        tag = this.taskTags[itag];
+//        priority = this.taskPriorities != null && itag < this.taskPriorities.length ? this.taskPriorities[itag] : null;
+//        int tagLength = tag.length;
+//        for (int t = 0; t < tagLength; t++) {
+//          if (this.source[i + t] != tag[t])
+//            continue nextTag;
+//        }
+//        if (this.foundTaskTags == null) {
+//          this.foundTaskTags = new char[5][];
+//          this.foundTaskMessages = new char[5][];
+//          this.foundTaskPriorities = new char[5][];
+//          this.foundTaskPositions = new int[5][];
+//        } else if (this.foundTaskCount == this.foundTaskTags.length) {
+//          System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+//          System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0,
+//              this.foundTaskCount);
+//          System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0,
+//              this.foundTaskCount);
+//          System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0,
+//              this.foundTaskCount);
+//        }
+//        this.foundTaskTags[this.foundTaskCount] = tag;
+//        this.foundTaskPriorities[this.foundTaskCount] = priority;
+//        this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
+//        this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
+//        this.foundTaskCount++;
+//        i += tagLength - 1; // will be incremented when looping
+//      }
+//    }
+//    for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
+//      // retrieve message start and end positions
+//      int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
+//      int max_value = i + 1 < this.foundTaskCount ? this.foundTaskPositions[i + 1][0] - 1 : commentEnd - 1;
+//      // at most beginning of next task
+//      if (max_value < msgStart)
+//        max_value = msgStart; // would only occur if tag is before EOF.
+//      int end = -1;
+//      char c;
+//      for (int j = msgStart; j < max_value; j++) {
+//        if ((c = this.source[j]) == '\n' || c == '\r') {
+//          end = j - 1;
+//          break;
+//        }
+//      }
+//      if (end == -1) {
+//        for (int j = max_value; j > msgStart; j--) {
+//          if ((c = this.source[j]) == '*') {
+//            end = j - 1;
+//            break;
+//          }
+//        }
+//        if (end == -1)
+//          end = max_value;
+//      }
+//      if (msgStart == end)
+//        continue; // empty
+//      // trim the message
+//      while (CharOperation.isWhitespace(source[end]) && msgStart <= end)
+//        end--;
+//      while (CharOperation.isWhitespace(source[msgStart]) && msgStart <= end)
+//        msgStart++;
+//      // update the end position of the task
+//      this.foundTaskPositions[i][1] = end;
+//      // get the message source
+//      final int messageLength = end - msgStart + 1;
+//      char[] message = new char[messageLength];
+//      System.arraycopy(source, msgStart, message, 0, messageLength);
+//      this.foundTaskMessages[i] = message;
+//    }
+//  }
 }
\ No newline at end of file