fixed some parser bugs
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
index 2ab8088..1bc55b9 100644 (file)
@@ -19,8 +19,9 @@ import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
 import net.sourceforge.phpdt.internal.compiler.util.Util;
+import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
-import net.sourceforge.phpeclipse.internal.compiler.ast.AstNode;
+import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
 import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
 import net.sourceforge.phpeclipse.internal.compiler.ast.ImportReference;
@@ -69,12 +70,15 @@ public class Parser //extends PHPParserSuperclass
   //private boolean phpMode;
   protected int modifiers;
   protected int modifiersSourceStart;
+//  protected IdentifierIndexManager indexManager;
+  
   protected Parser(ProblemReporter problemReporter) {
     this.problemReporter = problemReporter;
     this.options = problemReporter.options;
     this.currentPHPString = 0;
     //         PHPParserSuperclass.fileToParse = fileToParse;
     this.phpList = null;
+//    this.indexManager = null;
     this.str = "";
     this.token = TokenNameEOF;
     //    this.chIndx = 0;
@@ -88,6 +92,7 @@ public class Parser //extends PHPParserSuperclass
     this.currentPHPString = 0;
     //    PHPParserSuperclass.fileToParse = fileToParse;
     this.phpList = null;
+//    this.indexManager = null;
     this.str = "";
     this.token = TokenNameEOF;
     this.phpEnd = false;
@@ -203,6 +208,13 @@ public class Parser //extends PHPParserSuperclass
       }
     } catch (InvalidInputException e) {
       token = TokenNameERROR;
+      String detailedMessage = e.getMessage();
+      
+      if (detailedMessage==Scanner.UNTERMINATED_STRING) {
+        throwSyntaxError("Unterminated string.");
+      } else if (detailedMessage==Scanner.UNTERMINATED_COMMENT) {
+        throwSyntaxError("Unterminated commment.");
+      }
     }
     return;
   }
@@ -219,9 +231,13 @@ public class Parser //extends PHPParserSuperclass
     scanner.setPHPMode(false);
   }
   protected void initialize(boolean phpMode) {
+    initialize(phpMode, null);
+  }
+  protected void initialize(boolean phpMode, IdentifierIndexManager indexManager) {
     compilationUnit = null;
     referenceContext = null;
     includesList = new ArrayList();
+//    this.indexManager = indexManager;
     this.str = "";
     this.token = TokenNameEOF;
     //    this.chIndx = 0;
@@ -851,6 +867,7 @@ public class Parser //extends PHPParserSuperclass
     } else if (token == TokenNamefunction) {
       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
+      methodDecl.modifiers = AccDefault;
       getNextToken();
       functionDefinition(methodDecl);
       return;
@@ -906,6 +923,8 @@ public class Parser //extends PHPParserSuperclass
     } else if (token == TokenNamefinal || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
       TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
       typeDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
+      typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
+      typeDecl.name = new char[]{' '};
       // default super class
       typeDecl.superclass = new SingleTypeReference(TypeConstants.OBJECT, 0);
       compilationUnit.types.add(typeDecl);
@@ -1076,19 +1095,19 @@ public class Parser //extends PHPParserSuperclass
       checkAndSetModifiers(AccInterface);
       getNextToken();
       typeDecl.modifiers = this.modifiers;
+      typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
+      typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
       if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
-        typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
-        typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
         typeDecl.name = scanner.getCurrentIdentifierSource();
         if (token > TokenNameKEYWORD) {
-          throwSyntaxError("Don't use a keyword for interface declaration [" + scanner.toStringAction(token) + "].",
-              typeDecl.sourceStart, typeDecl.sourceEnd);
+          problemReporter.phpKeywordWarning(new String[]{scanner.toStringAction(token)}, scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(),
+              referenceContext, compilationUnit.compilationResult);
+//          throwSyntaxError("Don't use a keyword for interface declaration [" + scanner.toStringAction(token) + "].",
+//              typeDecl.sourceStart, typeDecl.sourceEnd);
         }
         getNextToken();
         interface_extends_list();
       } else {
-        typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
-        typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
         typeDecl.name = new char[]{' '};
         throwSyntaxError("Interface name expected after keyword 'interface'.", typeDecl.sourceStart, typeDecl.sourceEnd);
         return;
@@ -1099,15 +1118,17 @@ public class Parser //extends PHPParserSuperclass
       //               '{' class_statement_list'}'
       class_entry_type();
       typeDecl.modifiers = this.modifiers;
+      typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
+      typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
       //identifier
       //identifier 'extends' identifier
       if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
-        typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
-        typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
         typeDecl.name = scanner.getCurrentIdentifierSource();
         if (token > TokenNameKEYWORD) {
-          throwSyntaxError("Don't use a keyword for class declaration [" + scanner.toStringAction(token) + "].",
-              typeDecl.sourceStart, typeDecl.sourceEnd);
+          problemReporter.phpKeywordWarning(new String[]{scanner.toStringAction(token)}, scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(),
+              referenceContext, compilationUnit.compilationResult);
+//          throwSyntaxError("Don't use a keyword for class declaration [" + scanner.toStringAction(token) + "].",
+//              typeDecl.sourceStart, typeDecl.sourceEnd);
         }
         getNextToken();
         //    extends_from:
@@ -1125,8 +1146,6 @@ public class Parser //extends PHPParserSuperclass
         }
         implements_list();
       } else {
-        typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
-        typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
         typeDecl.name = new char[]{' '};
         throwSyntaxError("Class name expected after keyword 'class'.", typeDecl.sourceStart, typeDecl.sourceEnd);
         return;
@@ -1241,7 +1260,7 @@ public class Parser //extends PHPParserSuperclass
     //    '(' parameter_list ')' method_body
     initializeModifiers();
     int declarationSourceStart = scanner.getCurrentTokenStartPosition();
-    ;
+    
     if (token == TokenNamevar) {
       checkAndSetModifiers(AccPublic);
       problemReporter.phpVarDeprecatedWarning(scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(),
@@ -1249,7 +1268,8 @@ public class Parser //extends PHPParserSuperclass
       getNextToken();
       class_variable_declaration(declarationSourceStart, list);
     } else if (token == TokenNameconst) {
-      class_constant_declaration();
+      checkAndSetModifiers(AccFinal|AccPublic);
+      class_constant_declaration(declarationSourceStart, list);
       if (token != TokenNameSEMICOLON) {
         throwSyntaxError("';' expected after class const declaration.");
       }
@@ -1272,21 +1292,8 @@ public class Parser //extends PHPParserSuperclass
         class_variable_declaration(declarationSourceStart, list);
       }
     }
-    //    if (token == TokenNamefunction) {
-    //      MethodDeclaration methodDecl = new MethodDeclaration(
-    //          this.compilationUnit.compilationResult);
-    //      methodDecl.declarationSourceStart = scanner
-    //          .getCurrentTokenStartPosition();
-    //      getNextToken();
-    //      functionDefinition(methodDecl);
-    //    } else if (token == TokenNamevar) {
-    //      getNextToken();
-    //      classProperty();
-    //    } else {
-    //      throwSyntaxError("'function' or 'var' expected.");
-    //    }
   }
-  private void class_constant_declaration() {
+  private void class_constant_declaration(int declarationSourceStart, ArrayList list) {
     // class_constant_declaration ',' T_STRING '=' static_scalar
     // | T_CONST T_STRING '=' static_scalar
     if (token != TokenNameconst) {
@@ -1298,6 +1305,14 @@ public class Parser //extends PHPParserSuperclass
       if (token != TokenNameIdentifier) {
         throwSyntaxError("Identifier expected in class const declaration.");
       }
+      FieldDeclaration fieldDeclaration = new FieldDeclaration(scanner.getCurrentIdentifierSource(), scanner
+          .getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
+      fieldDeclaration.modifiers = this.modifiers;
+      fieldDeclaration.declarationSourceStart = declarationSourceStart;
+      fieldDeclaration.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
+      fieldDeclaration.modifiersSourceStart = declarationSourceStart;
+      //        fieldDeclaration.type
+      list.add(fieldDeclaration);
       getNextToken();
       if (token != TokenNameEQUAL) {
         throwSyntaxError("'=' expected in class const declaration.");
@@ -1385,9 +1400,12 @@ public class Parser //extends PHPParserSuperclass
     // | class_variable_declaration ',' T_VARIABLE '=' static_scalar
     // | T_VARIABLE
     // | T_VARIABLE '=' static_scalar
+    char[] classVariable;
     do {
       if (token == TokenNameVariable) {
-        FieldDeclaration fieldDeclaration = new FieldDeclaration(scanner.getCurrentIdentifierSource(), scanner
+        classVariable = scanner.getCurrentIdentifierSource();
+      //  indexManager.addIdentifierInformation('v', classVariable, buf, -1, -1);
+        FieldDeclaration fieldDeclaration = new FieldDeclaration(classVariable, scanner
             .getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
         fieldDeclaration.modifiers = this.modifiers;
         fieldDeclaration.declarationSourceStart = declarationSourceStart;
@@ -1422,7 +1440,7 @@ public class Parser //extends PHPParserSuperclass
     if (astPtr == 0) {
       compilationUnit.types.add(methodDecl);
     } else {
-      AstNode node = astStack[astPtr];
+      ASTNode node = astStack[astPtr];
       if (node instanceof TypeDeclaration) {
         TypeDeclaration typeDecl = ((TypeDeclaration) node);
         if (typeDecl.methods == null) {
@@ -1456,10 +1474,16 @@ public class Parser //extends PHPParserSuperclass
     if (token == TokenNameAND) {
       getNextToken();
     }
-    if (token == TokenNameIdentifier) {
-      methodDecl.sourceStart = scanner.getCurrentTokenStartPosition();
-      methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
+    methodDecl.sourceStart = scanner.getCurrentTokenStartPosition();
+    methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
+    if (Scanner.isIdentifierOrKeyword(token)) {
       methodDecl.selector = scanner.getCurrentIdentifierSource();
+      if (token > TokenNameKEYWORD) {
+        problemReporter.phpKeywordWarning(new String[]{scanner.toStringAction(token)}, scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(),
+            referenceContext, compilationUnit.compilationResult);
+//        reportSyntaxWarning("Don't use keyword for function declaration [" + scanner.toStringAction(token) + "].",
+//          scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
+      }
       getNextToken();
       if (token == TokenNameLPAREN) {
         getNextToken();
@@ -1467,7 +1491,7 @@ public class Parser //extends PHPParserSuperclass
         throwSyntaxError("'(' expected in function declaration.");
       }
       if (token != TokenNameRPAREN) {
-        parameter_list();
+        parameter_list(); 
       }
       if (token != TokenNameRPAREN) {
         throwSyntaxError("')' expected in function declaration.");
@@ -1476,9 +1500,7 @@ public class Parser //extends PHPParserSuperclass
         getNextToken();
       }
     } else {
-      if (token > TokenNameKEYWORD) {
-        throwSyntaxError("Don't use keyword for function declaration [" + token + "].");
-      }
+      methodDecl.selector = "<undefined>".toCharArray();
       throwSyntaxError("Function name expected after keyword 'function'.");
     }
   }
@@ -1586,7 +1608,7 @@ public class Parser //extends PHPParserSuperclass
         //          statementList();
         //        }
         else {
-          throwSyntaxError("':' character after 'case' constant expected (Found token: " + scanner.toStringAction(token) + ")");
+          throwSyntaxError("':' character expected after 'case' constant (Found token: " + scanner.toStringAction(token) + ")");
         }
       } else { // TokenNamedefault
         getNextToken();
@@ -1596,9 +1618,11 @@ public class Parser //extends PHPParserSuperclass
             // empty default case
             break;
           }
-          statementList();
+          if (token != TokenNamecase) {
+            statementList();  
+          }
         } else {
-          throwSyntaxError("':' character after 'default' expected.");
+          throwSyntaxError("':' character expected after 'default'.");
         }
       }
     } while (token == TokenNamecase || token == TokenNamedefault);
@@ -2053,8 +2077,8 @@ public class Parser //extends PHPParserSuperclass
         break;
       case TokenNameIntegerLiteral :
       case TokenNameDoubleLiteral :
-      case TokenNameStringLiteral :
-      case TokenNameStringConstant :
+      case TokenNameStringDoubleQuote :
+      case TokenNameStringSingleQuote :
       case TokenNameStringInterpolated :
       case TokenNameFILE :
       case TokenNameLINE :
@@ -2442,14 +2466,23 @@ public class Parser //extends PHPParserSuperclass
     //| class_constant '(' function_call_parameter_list ')'
     //| static_member '(' function_call_parameter_list ')'
     //| variable_without_objects '(' function_call_parameter_list ')'
+    char[] defineName = null;
+    char[] ident = null;
+    int startPos=0;
+    int endPos=0;
     if (Scanner.TRACE) {
       System.out.println("TRACE: function_call()");
     }
     if (token == TokenNameIdentifier) {
+      ident = scanner.getCurrentIdentifierSource();
+      defineName = ident;
+      startPos = scanner.getCurrentTokenStartPosition();
+      endPos = scanner.getCurrentTokenEndPosition();
       getNextToken();
       switch (token) {
         case TokenNamePAAMAYIM_NEKUDOTAYIM :
           // static member:
+          defineName = null;
           getNextToken();
           if (token == TokenNameIdentifier) {
             // class _constant
@@ -2464,6 +2497,45 @@ public class Parser //extends PHPParserSuperclass
       variable_without_objects();
     }
     if (token != TokenNameLPAREN) {
+      if (defineName!=null) {
+        // does this identifier contain only uppercase characters?
+        if (defineName.length==3) {
+          if (defineName[0]=='d' &&
+              defineName[1]=='i' &&
+              defineName[2]=='e' ) {
+            defineName=null;
+          } 
+        } else if (defineName.length==4) {
+          if (defineName[0]=='t' &&
+              defineName[1]=='r' &&
+              defineName[2]=='u' &&
+              defineName[3]=='e' ) {
+            defineName=null;
+          } else if (defineName[0]=='n' &&
+              defineName[1]=='u' &&
+              defineName[2]=='l' &&
+              defineName[3]=='l' ) {
+            defineName=null;
+          }
+        } else if (defineName.length==5) {
+          if (defineName[0]=='f' &&
+              defineName[1]=='a' &&
+              defineName[2]=='l' &&
+              defineName[3]=='s' &&
+              defineName[4]=='e' ) {
+            defineName=null;
+          }
+        }
+        if (defineName!=null) {
+          for (int i=0; i<defineName.length;i++) {
+            if (Character.isLowerCase(defineName[i])) {  
+              problemReporter.phpUppercaseIdentifierWarning(startPos, endPos,
+                referenceContext, compilationUnit.compilationResult);
+              break;
+            }
+          }
+        }
+      }
       // TODO is this ok ?
       return;
       //      throwSyntaxError("'(' expected in function call.");
@@ -2475,7 +2547,13 @@ public class Parser //extends PHPParserSuperclass
     }
     non_empty_function_call_parameter_list();
     if (token != TokenNameRPAREN) {
-      throwSyntaxError("')' expected in function call.");
+      String functionName;
+      if (ident==null) {
+        functionName = new String(" ");
+      } else {
+        functionName = new String(ident);
+      }
+      throwSyntaxError("')' expected in function call ("+functionName+").");
     }
     getNextToken();
   }
@@ -2865,16 +2943,9 @@ public class Parser //extends PHPParserSuperclass
           break;
         case TokenNameVariable :
         case TokenNameDOLLAR_LBRACE :
-        case TokenNameCURLY_OPEN :
+        case TokenNameLBRACE_DOLLAR :
           encaps_var();
           break;
-        //        case TokenNameDOLLAR :
-        //          getNextToken();
-        //          if (token == TokenNameLBRACE) {
-        //            token = TokenNameDOLLAR_LBRACE;
-        //            encaps_var();
-        //          }
-        //          break;
         default :
           char encapsedChar = ((Character) scanner.encapsedStringStack.peek()).charValue();
           if (encapsedChar == '$') {
@@ -2975,7 +3046,9 @@ public class Parser //extends PHPParserSuperclass
         break;
       case TokenNameDOLLAR_LBRACE :
         getNextToken();
-        if (token == TokenNameIdentifier) {
+        if (token == TokenNameDOLLAR_LBRACE) {
+          encaps_var();
+        } else if (token == TokenNameIdentifier) {
           getNextToken();
           if (token == TokenNameLBRACKET) {
             getNextToken();
@@ -2989,23 +3062,19 @@ public class Parser //extends PHPParserSuperclass
             getNextToken();
             //            }
           }
-          if (token != TokenNameRBRACE) {
-            throwSyntaxError("'}' expected after '${'.");
-          }
-          //          scanner.encapsedStringStack.pop();
-          getNextToken();
         } else {
           expr();
-          if (token != TokenNameRBRACE) {
-            throwSyntaxError("'}' expected.");
-          }
-          //          scanner.encapsedStringStack.pop();
-          getNextToken();
         }
+        if (token != TokenNameRBRACE) {
+          throwSyntaxError("'}' expected.");
+        }
+        getNextToken();
         break;
-      case TokenNameCURLY_OPEN :
+      case TokenNameLBRACE_DOLLAR :
         getNextToken();
-        if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
+        if (token == TokenNameLBRACE_DOLLAR) {
+          encaps_var();
+        } else if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
           getNextToken();
           if (token == TokenNameLBRACKET) {
             getNextToken();
@@ -3014,16 +3083,29 @@ public class Parser //extends PHPParserSuperclass
             //            } else {
             expr();
             if (token != TokenNameRBRACKET) {
-              throwSyntaxError("']' expected after '{$'.");
+              throwSyntaxError("']' expected.");
             }
             getNextToken();
             //            }
           } else if (token == TokenNameMINUS_GREATER) {
             getNextToken();
-            if (token != TokenNameIdentifier) {
-              throwSyntaxError("String token expected.");
+            if (token != TokenNameIdentifier &&
+                token != TokenNameVariable) {
+              throwSyntaxError("String or Variable token expected.");
             }
             getNextToken();
+            if (token == TokenNameLBRACKET) {
+              getNextToken();
+              //            if (token == TokenNameRBRACKET) {
+              //              getNextToken();
+              //            } else {
+              expr();
+              if (token != TokenNameRBRACKET) {
+                throwSyntaxError("']' expected after '${'.");
+              }
+              getNextToken();
+              //            }
+            }
           }
           //          if (token != TokenNameRBRACE) {
           //            throwSyntaxError("'}' expected after '{$'.");
@@ -3189,10 +3271,10 @@ public class Parser //extends PHPParserSuperclass
       case TokenNameDoubleLiteral :
         getNextToken();
         return true;
-      case TokenNameStringLiteral :
+      case TokenNameStringDoubleQuote :
         getNextToken();
         return true;
-      case TokenNameStringConstant :
+      case TokenNameStringSingleQuote :
         getNextToken();
         return true;
       case TokenNameStringInterpolated :
@@ -3466,10 +3548,10 @@ public class Parser //extends PHPParserSuperclass
   //ast stack
   final static int AstStackIncrement = 100;
   protected int astPtr;
-  protected AstNode[] astStack = new AstNode[AstStackIncrement];
+  protected ASTNode[] astStack = new ASTNode[AstStackIncrement];
   protected int astLengthPtr;
   protected int[] astLengthStack;
-  AstNode[] noAstNodes = new AstNode[AstStackIncrement];
+  ASTNode[] noAstNodes = new ASTNode[AstStackIncrement];
   public CompilationUnitDeclaration compilationUnit; /*
                                                       * the result from parse()
                                                       */
@@ -3896,7 +3978,7 @@ public class Parser //extends PHPParserSuperclass
       astLengthStack[astLengthPtr] = pos;
     }
   }
-  protected void pushOnAstStack(AstNode node) {
+  protected void pushOnAstStack(ASTNode node) {
     /*
      * add a new obj on top of the ast stack
      */
@@ -3904,8 +3986,8 @@ public class Parser //extends PHPParserSuperclass
       astStack[++astPtr] = node;
     } catch (IndexOutOfBoundsException e) {
       int oldStackLength = astStack.length;
-      AstNode[] oldStack = astStack;
-      astStack = new AstNode[oldStackLength + AstStackIncrement];
+      ASTNode[] oldStack = astStack;
+      astStack = new ASTNode[oldStackLength + AstStackIncrement];
       System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
       astPtr = oldStackLength;
       astStack[astPtr] = node;