*** empty log message ***
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / phpparser / PHPParser.java
index 981cd7f..010e977 100644 (file)
@@ -19,6 +19,7 @@ import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
 import net.sourceforge.phpeclipse.phpeditor.PHPString;
 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
+
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.runtime.CoreException;
@@ -34,6 +35,7 @@ public class PHPParser extends PHPKeywords {
   public static final int ERROR = 2;
   public static final int WARNING = 1;
   public static final int INFO = 0;
+  
   private IFile fileToParse;
   private ArrayList phpList;
 
@@ -60,6 +62,12 @@ public class PHPParser extends PHPKeywords {
 
   Long longNumber;
   Double doubleNumber;
+
+  private String stringValue;
+
+  /** Contains the current expression. */
+  private StringBuffer expression;
+
   private boolean phpMode;
 
   final static int TT_EOF = 0;
@@ -171,24 +179,31 @@ public class PHPParser extends PHPKeywords {
   }
 
   public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
-
-    Hashtable attributes = new Hashtable();
-    MarkerUtilities.setMessage(attributes, message);
-    switch (errorLevel) {
-      case ERROR :
-        attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
-        break;
-      case WARNING :
-        attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
-        break;
-      case INFO :
-        attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
-        break;
+    if (file != null) {
+      Hashtable attributes = new Hashtable();
+      MarkerUtilities.setMessage(attributes, message);
+      switch (errorLevel) {
+        case ERROR :
+          attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
+          break;
+        case WARNING :
+          attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
+          break;
+        case INFO :
+          attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
+          break;
+      }
+      MarkerUtilities.setLineNumber(attributes, lineNumber);
+      MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
     }
-    MarkerUtilities.setLineNumber(attributes, lineNumber);
-    MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
   }
 
+  /**
+   * This method will throw the SyntaxError.
+   * It will add the good lines and columns to the Error
+   * @param error the error message
+   * @throws SyntaxError the error raised
+   */
   private void throwSyntaxError(String error) {
 
     if (str.length() < chIndx) {
@@ -206,8 +221,13 @@ public class PHPParser extends PHPKeywords {
     throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
   }
 
+  /**
+   * This method will throw the SyntaxError.
+   * It will add the good lines and columns to the Error
+   * @param error the error message
+   * @throws SyntaxError the error raised
+   */
   private void throwSyntaxError(String error, int startRow) {
-
     throw new SyntaxError(startRow, 0, " ", error);
   }
 
@@ -361,7 +381,6 @@ public class PHPParser extends PHPKeywords {
           if (openString) {
             throwSyntaxError("Open string character \"`\" at end of file.", startRow);
           }
-          setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
           token = TT_STRING_CONSTANT;
           return;
         }
@@ -751,27 +770,15 @@ public class PHPParser extends PHPKeywords {
             if (ch2 == '?') {
               ch2 = str.charAt(chIndx++);
               if (Character.isWhitespace(ch2)) {
-                // php start 
+                // php start
                 phpMode = true;
                 phpFound = true;
                 break;
-              } else if (ch2 == 'p') {
-                ch2 = str.charAt(chIndx++);
-                if (ch2 == 'h') {
-                  ch2 = str.charAt(chIndx++);
-                  if (ch2 == 'p') {
-                    phpMode = true;
-                    phpFound = true;
-                    break;
-                  }
-                  chIndx--;
-                }
-                chIndx--;
-              } else if (ch2 == 'P') {
+              } else if (ch2 == 'p' || ch2 == 'P') {
                 ch2 = str.charAt(chIndx++);
-                if (ch2 == 'H') {
+                if (ch2 == 'h' || ch2 == 'H') {
                   ch2 = str.charAt(chIndx++);
-                  if (ch2 == 'P') {
+                  if (ch2 == 'p' || ch2 == 'P') {
                     phpMode = true;
                     phpFound = true;
                     break;
@@ -880,73 +887,14 @@ public class PHPParser extends PHPKeywords {
               continue;
 
             } else if (ch == '"') {
-              // read string until end
-              boolean openString = true;
-              while (str.length() > chIndx) {
-                ch = str.charAt(chIndx++);
-                if (ch == '\\') {
-                  if (str.length() > chIndx) {
-                    ch = str.charAt(chIndx++);
-                  }
-                } else if (ch == '"') {
-                  openString = false;
-                  break;
-                } else if (ch == '\n') {
-                  rowCount++;
-                  columnCount = chIndx;
-                }
-              }
-              if (openString) {
-                throwSyntaxError("Open string character '\"' at end of file.");
-              }
-              token = TT_INTERPOLATED_STRING;
+              getString('"',TT_INTERPOLATED_STRING,"Open string character '\"' at end of file.");
               return;
             } else if (ch == '\'') {
-              // read string until end
-              boolean openString = true;
-              int startRow = rowCount;
-              while (str.length() > chIndx) {
-                ch = str.charAt(chIndx++);
-                if (ch == '\\') {
-                  if (str.length() > chIndx) {
-                    ch = str.charAt(chIndx++);
-                  }
-                } else if (ch == '\'') {
-                  openString = false;
-                  break;
-                } else if (ch == '\n') {
-                  rowCount++;
-                  columnCount = chIndx;
-                }
-              }
-              if (openString) {
-                throwSyntaxError("Open string character \"'\" at end of file.", startRow);
-              }
-              token = TT_STRING_CONSTANT;
+              getString('\'',TT_STRING_CONSTANT,"Open string character \"'\" at end of file.");
               return;
             } else if (ch == '`') {
-              // read string until end
-              boolean openString = true;
-              int startRow = rowCount;
-              while (str.length() > chIndx) {
-                ch = str.charAt(chIndx++);
-                if (ch == '\\') {
-                  if (str.length() > chIndx) {
-                    ch = str.charAt(chIndx++);
-                  }
-                } else if (ch == '`') {
-                  openString = false;
-                  break;
-                } else if (ch == '\n') {
-                  rowCount++;
-                  columnCount = chIndx;
-                }
-              }
-              if (openString) {
-                throwSyntaxError("Open string character \"`\" at end of file.", startRow);
-              }
+              getString('`',TT_STRING_CONSTANT,"Open string character \"`\" at end of file.");
               setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
-              token = TT_STRING_CONSTANT;
               return;
             }
 
@@ -1328,29 +1276,51 @@ public class PHPParser extends PHPKeywords {
     //    }
   }
 
+  /**
+   * Get an identifier.
+   */
   private void getIdentifier() {
-    StringBuffer ident = new StringBuffer();
-
-    ident.append(ch);
+  //  StringBuffer ident = new StringBuffer();
+    int startPosition = chIndx - 1;
+//    ident.append(ch);
     if (ch == '$') {
+      getChar();
+      // attention recursive call:
+      getIdentifier();
       token = TT_VARIABLE;
+      return;
     } else {
       token = TT_IDENTIFIER;
     }
+
     getChar();
+
+    //this will read the buffer until the next character is a forbidden character for identifier
     while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
-      ident.append(ch);
+  //    ident.append(ch);
       getChar();
     }
-    identifier = ident.toString();
-    chIndx--;
-
+    int endPosition = chIndx--;
+    int length = (--endPosition) - startPosition;
+
+    identifier = str.substring(startPosition, endPosition);
+    // System.out.println(identifier);
+    
+    // determine if this identitfer is a keyword
+    // @todo improve this in future version
     Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
     if (i != null) {
       token = i.intValue();
     }
   }
 
+  /**
+   * Get a number.
+   * if it's a <code>double</code> the number will be stored in <code>doubleNumber</code> and the token will have the
+   * value {@link PHPParser#TT_DOUBLE_NUMBER}<br />
+   * if it's a <code>double</code> the number will be stored in <code>longNumber</code> and the token will have the
+   * value {@link PHPParser#TT_INT_NUMBER}
+   */
   private void getNumber() {
     StringBuffer inum = new StringBuffer();
     char dFlag = ' ';
@@ -1436,6 +1406,45 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
+  /**
+   * Get a String.
+   * @param openChar the opening char ('\'', '"', '`')
+   * @param typeString the type of string {@link #TT_STRING_CONSTANT},{@link #TT_INTERPOLATED_STRING}
+   * @param errorMsg the error message in case of parse error in the string
+   */
+  private void getString(final char openChar, final int typeString, final String errorMsg) {
+    StringBuffer sBuffer = new StringBuffer();
+    boolean openString = true;
+    int startRow = rowCount;
+    while (str.length() > chIndx) {
+      ch = str.charAt(chIndx++);
+      if (ch == '\\') {
+        sBuffer.append(ch);
+        if (str.length() > chIndx) {
+          ch = str.charAt(chIndx++);
+          sBuffer.append(ch);
+        }
+      } else if (ch == openChar) {
+        openString = false;
+        break;
+      } else if (ch == '\n') {
+        rowCount++;
+        columnCount = chIndx;
+      } else {
+        sBuffer.append(ch);
+      }
+    }
+    if (openString) {
+      if (typeString == TT_STRING_CONSTANT) {
+        throwSyntaxError(errorMsg, startRow);
+      } else {
+        throwSyntaxError(errorMsg);
+      }
+    }
+    token = typeString;
+    stringValue = sBuffer.toString();
+  }
+
   public void htmlParserTester(String input) {
     int lineNumber = 1;
     int startLineNumber = 1;
@@ -1460,7 +1469,7 @@ public class PHPParser extends PHPKeywords {
           if (ch2 == '?') {
             ch2 = input.charAt(i++);
             if (Character.isWhitespace(ch2)) {
-              // php start 
+              // php start
               phpMode = true;
               phpFound = true;
               startIndex = i;
@@ -1609,7 +1618,7 @@ public class PHPParser extends PHPKeywords {
         //          String temp = ((PHPString)phpList.get(j)).getPHPString();
         //          int startIndx = temp.length()-10;
         //          if (startIndx<0) {
-        //            startIndx = 0; 
+        //            startIndx = 0;
         //          }
         //          System.out.println(temp.substring(startIndx)+"?>");
         //        }
@@ -1618,7 +1627,7 @@ public class PHPParser extends PHPKeywords {
         //        for(int j=0;j<phpList.size();j++) {
         //          temp = (PHPString) phpList.get(j);
         //          parser.start(temp.getPHPString(), temp.getLineNumber());
-        //        } 
+        //        }
       }
     } catch (CoreException e) {
     }
@@ -1673,7 +1682,7 @@ public class PHPParser extends PHPKeywords {
         } else {
           setMarker(err.getMessage(), err.getLine(), ERROR);
         }
-        // if an error occured, 
+        // if an error occured,
         // try to find keywords 'class' or 'function'
         // to parse the rest of the string
         while (token != TT_EOF && token != TT_UNDEFINED) {
@@ -1691,7 +1700,7 @@ public class PHPParser extends PHPKeywords {
   }
 
   /**
-   * Parses a string with php tAGS
+   * Parses a string with php tags
    * i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
    */
   public void parse(String s) throws CoreException {
@@ -1735,7 +1744,7 @@ public class PHPParser extends PHPKeywords {
       } catch (SyntaxError sytaxErr1) {
         setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
         try {
-          // if an error occured, 
+          // if an error occured,
           // try to find keywords 'class' or 'function'
           // to parse the rest of the string
           while (token != TT_EOF && token != TT_UNDEFINED) {
@@ -1756,6 +1765,121 @@ public class PHPParser extends PHPKeywords {
     while (true);
   }
 
+  public PHPOutlineInfo parseInfo(Object parent, String s) {
+    PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
+    //    Stack stack = new Stack();
+    //    stack.push(outlineInfo.getDeclarations());
+
+    this.str = s;
+    this.token = TT_EOF;
+    this.chIndx = 0;
+    this.rowCount = 1;
+    this.columnCount = 0;
+    this.phpEnd = false;
+    this.phpMode = false;
+
+    try {
+      getNextToken();
+      parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
+    } catch (CoreException e) {
+    }
+    return outlineInfo;
+  }
+
+  private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPSegmentWithChildren current, boolean goBack) {
+    //   PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
+    PHPSegmentWithChildren temp;
+    int counter = 0;
+    String oldIdentifier;
+    IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+    try {
+      while (token != TT_EOF && token != TT_UNDEFINED) {
+        if (token == TT_VARIABLE) {
+          outlineInfo.addVariable(identifier);
+          getNextToken();
+        } else if (token == TT_var) {
+          getNextToken();
+          if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
+            getNextToken();
+            outlineInfo.addVariable(identifier);
+            if (token != TT_SEMICOLON) {
+              oldIdentifier = identifier;
+              getNextToken();
+              switch (token) {
+                case TT_VARIABLE            : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
+                                              break;
+                case TT_IDENTIFIER          : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
+                                              break;
+                case TT_DOUBLE_NUMBER       : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
+                                              break;
+                case TT_INT_NUMBER          : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
+                                              break;
+                case TT_INTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
+                                              break;
+                case TT_STRING_CONSTANT     : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
+                                              break;
+                default                     : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
+                                              break;
+              }
+            } else {
+              current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
+            }
+          }
+        } else if (token == TT_function) {
+          getNextToken();
+          if (token == TT_AMPERSAND) {
+            getNextToken();
+          }
+          if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
+            outlineInfo.addVariable(identifier);
+            temp = new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length());
+            current.add(temp);
+            getNextToken();
+            parseDeclarations(outlineInfo, temp, true);
+          }
+        } else if (token == TT_class) {
+          getNextToken();
+          if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
+            outlineInfo.addVariable(identifier);
+            temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
+            current.add(temp);
+            //        stack.push(temp);
+            getNextToken();
+
+            //skip tokens for classname, extends and others until we have the opening '{'
+            while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
+              getNextToken();
+            }
+            parseDeclarations(outlineInfo, temp, true);
+            //        stack.pop();
+          }
+        } else if (token == TT_LISTOPEN) {
+          getNextToken();
+          counter++;
+        } else if (token == TT_LISTCLOSE) {
+          getNextToken();
+          --counter;
+          if (counter == 0 && goBack) {
+            return;
+          }
+        } else if (token == TT_require || token == TT_require_once || token == TT_include || token == TT_include_once) {
+          expression();
+          outlineInfo.addVariable(identifier);
+          current.add(new PHPReqIncDeclaration(current, identifier, chIndx - identifier.length(),expression.toString()));
+          getNextToken();
+        } else {
+          getNextToken();
+        }
+      }
+    } catch (CoreException e) {
+    } catch (SyntaxError sytaxErr) {
+      try {
+        setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
+      } catch (CoreException e) {
+      }
+    }
+  }
+
   private void statementList() throws CoreException {
     do {
       statement();
@@ -2299,7 +2423,7 @@ public class PHPParser extends PHPKeywords {
         } else {
           throwSyntaxError("':' character after 'case' constant expected.");
         }
-      } else { // TT_default 
+      } else { // TT_default
         getNextToken();
         if (token == TT_DDOT) {
           getNextToken();
@@ -2575,6 +2699,14 @@ public class PHPParser extends PHPKeywords {
   }
 
   private void expression() throws CoreException {
+    //todo: find a better way to get the expression
+    expression = new StringBuffer();
+    for (int i = chIndx;i<str.length();i++) {
+      if (str.charAt(i) == ';') {
+        break;
+      }
+      expression.append(str.charAt(i));
+    }
     //    if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
     //      getNextToken();
     //    } else {
@@ -2864,7 +2996,7 @@ public class PHPParser extends PHPKeywords {
         getNextToken();
         unaryExpression();
         break;
-        // '@' '&' '*' '+' '-' '~' '!' 
+        // '@' '&' '*' '+' '-' '~' '!'
       case TT_AT :
         getNextToken();
         castExpression();
@@ -3189,6 +3321,10 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
+  /**
+   * It will look for a value (after a '=' for example)
+   * @throws CoreException
+   */
   private void constant() throws CoreException {
     String ident;
     switch (token) {