.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
index 12e3dfb..69dfdcf 100644 (file)
@@ -14,6 +14,33 @@ import java.util.HashSet;
 import net.sourceforge.phpdt.core.compiler.CharOperation;
 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
+import net.sourceforge.phpdt.internal.compiler.ast.AND_AND_Expression;
+import net.sourceforge.phpdt.internal.compiler.ast.ASTNode;
+import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
+import net.sourceforge.phpdt.internal.compiler.ast.BinaryExpression;
+import net.sourceforge.phpdt.internal.compiler.ast.Block;
+import net.sourceforge.phpdt.internal.compiler.ast.BreakStatement;
+import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
+import net.sourceforge.phpdt.internal.compiler.ast.ConditionalExpression;
+import net.sourceforge.phpdt.internal.compiler.ast.ContinueStatement;
+import net.sourceforge.phpdt.internal.compiler.ast.EqualExpression;
+import net.sourceforge.phpdt.internal.compiler.ast.Expression;
+import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
+import net.sourceforge.phpdt.internal.compiler.ast.FieldReference;
+import net.sourceforge.phpdt.internal.compiler.ast.IfStatement;
+import net.sourceforge.phpdt.internal.compiler.ast.ImportReference;
+import net.sourceforge.phpdt.internal.compiler.ast.InstanceOfExpression;
+import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
+import net.sourceforge.phpdt.internal.compiler.ast.OR_OR_Expression;
+import net.sourceforge.phpdt.internal.compiler.ast.OperatorIds;
+import net.sourceforge.phpdt.internal.compiler.ast.ReturnStatement;
+import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference;
+import net.sourceforge.phpdt.internal.compiler.ast.Statement;
+import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral;
+import net.sourceforge.phpdt.internal.compiler.ast.StringLiteralDQ;
+import net.sourceforge.phpdt.internal.compiler.ast.StringLiteralSQ;
+import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
+import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
@@ -23,33 +50,6 @@ import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
 import net.sourceforge.phpdt.internal.compiler.util.Util;
 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
 import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
-import net.sourceforge.phpeclipse.internal.compiler.ast.AND_AND_Expression;
-import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
-import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
-import net.sourceforge.phpeclipse.internal.compiler.ast.BinaryExpression;
-import net.sourceforge.phpeclipse.internal.compiler.ast.Block;
-import net.sourceforge.phpeclipse.internal.compiler.ast.BreakStatement;
-import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
-import net.sourceforge.phpeclipse.internal.compiler.ast.ConditionalExpression;
-import net.sourceforge.phpeclipse.internal.compiler.ast.ContinueStatement;
-import net.sourceforge.phpeclipse.internal.compiler.ast.EqualExpression;
-import net.sourceforge.phpeclipse.internal.compiler.ast.Expression;
-import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
-import net.sourceforge.phpeclipse.internal.compiler.ast.FieldReference;
-import net.sourceforge.phpeclipse.internal.compiler.ast.IfStatement;
-import net.sourceforge.phpeclipse.internal.compiler.ast.ImportReference;
-import net.sourceforge.phpeclipse.internal.compiler.ast.InstanceOfExpression;
-import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration;
-import net.sourceforge.phpeclipse.internal.compiler.ast.OR_OR_Expression;
-import net.sourceforge.phpeclipse.internal.compiler.ast.OperatorIds;
-import net.sourceforge.phpeclipse.internal.compiler.ast.ReturnStatement;
-import net.sourceforge.phpeclipse.internal.compiler.ast.SingleTypeReference;
-import net.sourceforge.phpeclipse.internal.compiler.ast.Statement;
-import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteral;
-import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteralDQ;
-import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteralSQ;
-import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
-import net.sourceforge.phpeclipse.internal.compiler.ast.TypeReference;
 import net.sourceforge.phpeclipse.ui.overlaypages.ProjectPrefUtil;
 
 import org.eclipse.core.resources.IFile;
@@ -422,6 +422,9 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                        try {
                                statement = statement();
                                blockStatements.add(statement);
+                               if (token == TokenNameEOF) {
+                                       return null;
+                               }
                                if (branchStatement && statement != null) {
                                        // reportSyntaxError("Unreachable code", statement.sourceStart,
                                        // statement.sourceEnd);
@@ -453,10 +456,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                }
                                                if (token == TokenNameif || token == TokenNameswitch || token == TokenNamefor || token == TokenNamewhile
                                                                || token == TokenNamedo || token == TokenNameforeach || token == TokenNamecontinue || token == TokenNamebreak
-                                                               || token == TokenNamereturn || token == TokenNameexit || token == TokenNameecho || token == TokenNameglobal
-                                                               || token == TokenNamestatic || token == TokenNameunset || token == TokenNamefunction || token == TokenNamedeclare
-                                                               || token == TokenNametry || token == TokenNamecatch || token == TokenNamethrow || token == TokenNamefinal
-                                                               || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
+                                                               || token == TokenNamereturn || token == TokenNameexit || token == TokenNameecho || token == TokenNameECHO_INVISIBLE
+                                                               || token == TokenNameglobal || token == TokenNamestatic || token == TokenNameunset || token == TokenNamefunction
+                                                               || token == TokenNamedeclare || token == TokenNametry || token == TokenNamecatch || token == TokenNamethrow
+                                                               || token == TokenNamefinal || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
                                                        break;
                                                }
                                                // System.out.println(scanner.toStringAction(token));
@@ -748,33 +751,26 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                getNextToken();
                        }
                        return statement;
-               } else if (token == TokenNameINLINE_HTML) {
-                       if (scanner.phpExpressionTag) {
-                               // start of <?= ... ?> block
+               } else if (token == TokenNameECHO_INVISIBLE) {
+                       // 0-length token directly after PHP short tag &lt;?=
+                       getNextToken();
+                       expressionList();
+                       if (token == TokenNameSEMICOLON) {
                                getNextToken();
-                               expr();
-                               if (token == TokenNameSEMICOLON) {
-                                       getNextToken();
-                               }
+//                             if (token != TokenNameINLINE_HTML) {
+//                                     // TODO should this become a configurable warning?
+//                                     reportSyntaxError("Probably '?>' expected  after PHP short tag expression (only the first expression will be echoed).");
+//                             }
+                       } else {
                                if (token != TokenNameINLINE_HTML) {
-                                       throwSyntaxError("Missing '?>' for open PHP expression block ('<?=').");
+                                       throwSyntaxError("';' expected after PHP short tag '<?=' expression.");
                                }
-                       } else {
                                getNextToken();
                        }
                        return statement;
-                       // } else if (token == TokenNameprint) {
-                       // getNextToken();
-                       // expression();
-                       // if (token == TokenNameSEMICOLON) {
-                       // getNextToken();
-                       // } else {
-                       // if (token != TokenNameStopPHP) {
-                       // throwSyntaxError("';' expected after 'print' statement.");
-                       // }
-                       // getNextToken();
-                       // }
-                       // return;
+               } else if (token == TokenNameINLINE_HTML) {
+                       getNextToken();
+                       return statement;
                } else if (token == TokenNameglobal) {
                        getNextToken();
                        global_var_list();
@@ -1746,6 +1742,11 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                expr(); // constant();
                                if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
                                        getNextToken();
+                                       if (token == TokenNameRBRACE) {
+                                               // empty case; assumes that the '}' token belongs to the wrapping
+                                               // switch statement - #1371992
+                                               break;
+                                       }
                                        if (token == TokenNamecase || token == TokenNamedefault) {
                                                // empty case statement ?
                                                continue;
@@ -1773,7 +1774,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
                                        getNextToken();
                                        if (token == TokenNameRBRACE) {
-                                               // empty default case
+                                               // empty default case; ; assumes that the '}' token belongs to the
+                                               // wrapping switch statement - #1371992
                                                break;
                                        }
                                        if (token != TokenNamecase) {
@@ -2502,37 +2504,33 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                        // | rw_variable T_INC
                        // | rw_variable T_DEC
                        case TokenNameIdentifier:
-                               char[] ident = scanner.getCurrentTokenSource();
-                               Expression lhsIdentifier = identifier(true, true);
-                               if (lhsIdentifier != null) {
-                                       expression = lhsIdentifier;
-                               }
-                               if (token == TokenNameEQUAL || token == TokenNamePLUS_EQUAL
-                                               || token == TokenNameMINUS_EQUAL || token == TokenNameMULTIPLY_EQUAL || token == TokenNameDIVIDE_EQUAL
-                                               || token == TokenNameDOT_EQUAL || token == TokenNameREMAINDER_EQUAL || token == TokenNameAND_EQUAL
-                                               || token == TokenNameOR_EQUAL || token == TokenNameXOR_EQUAL || token == TokenNameRIGHT_SHIFT_EQUAL
-                                               || token == TokenNameLEFT_SHIFT_EQUAL) {
-                                       String error = "Assignment operator '"+scanner.toStringAction(token)+"' not allowed after identifier '"+new String(ident)+"' (use 'define(...)' to define constants).";
-                                       throwSyntaxError(error);
-                               }
-                               break;
                        case TokenNameVariable:
                        case TokenNameDOLLAR:
+                               Expression lhs = null;
                                boolean rememberedVar = false;
-                               Expression lhs = variable(true, true);
-                               if (lhs != null && lhs instanceof FieldReference && token != TokenNameEQUAL && token != TokenNamePLUS_EQUAL
-                                               && token != TokenNameMINUS_EQUAL && token != TokenNameMULTIPLY_EQUAL && token != TokenNameDIVIDE_EQUAL
-                                               && token != TokenNameDOT_EQUAL && token != TokenNameREMAINDER_EQUAL && token != TokenNameAND_EQUAL
-                                               && token != TokenNameOR_EQUAL && token != TokenNameXOR_EQUAL && token != TokenNameRIGHT_SHIFT_EQUAL
-                                               && token != TokenNameLEFT_SHIFT_EQUAL) {
-                                       FieldReference ref = (FieldReference) lhs;
-                                       if (!containsVariableSet(ref.token)) {
-                                               problemReporter.uninitializedLocalVariable(new String(ref.token), ref.sourceStart(), ref.sourceEnd(), referenceContext,
-                                                               compilationUnit.compilationResult);
-                                               addVariableSet(ref.token);
+                               if (token == TokenNameIdentifier) {
+                                       lhs = identifier(true, true);
+                                       if (lhs != null) {
+                                               expression = lhs;
+                                       }
+                               } else {
+                                       lhs = variable(true, true);
+                                       if (lhs != null) {
+                                               expression = lhs;
+                                       }
+                                       if (lhs != null && lhs instanceof FieldReference && token != TokenNameEQUAL && token != TokenNamePLUS_EQUAL
+                                                       && token != TokenNameMINUS_EQUAL && token != TokenNameMULTIPLY_EQUAL && token != TokenNameDIVIDE_EQUAL
+                                                       && token != TokenNameDOT_EQUAL && token != TokenNameREMAINDER_EQUAL && token != TokenNameAND_EQUAL
+                                                       && token != TokenNameOR_EQUAL && token != TokenNameXOR_EQUAL && token != TokenNameRIGHT_SHIFT_EQUAL
+                                                       && token != TokenNameLEFT_SHIFT_EQUAL) {
+                                               FieldReference ref = (FieldReference) lhs;
+                                               if (!containsVariableSet(ref.token)) {
+                                                       problemReporter.uninitializedLocalVariable(new String(ref.token), ref.sourceStart(), ref.sourceEnd(),
+                                                                       referenceContext, compilationUnit.compilationResult);
+                                                       addVariableSet(ref.token);
+                                               }
                                        }
                                }
-
                                switch (token) {
                                case TokenNameEQUAL:
                                        if (lhs != null && lhs instanceof FieldReference) {
@@ -2788,7 +2786,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                if (Scanner.TRACE) {
                        System.out.println("TRACE: dynamic_class_name_reference()");
                }
-               base_variable();
+               base_variable(true);
                if (token == TokenNameMINUS_GREATER) {
                        getNextToken();
                        object_property();
@@ -3014,26 +3012,24 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                        }
                                }
                        }
-                       // TODO is this ok ?
-                       return ref;
-                       // throwSyntaxError("'(' expected in function call.");
-               }
-               getNextToken();
-               if (token == TokenNameRPAREN) {
+               } else {
                        getNextToken();
-                       return ref;
-               }
-               non_empty_function_call_parameter_list();
-               if (token != TokenNameRPAREN) {
-                       String functionName;
-                       if (ident == null) {
-                               functionName = new String(" ");
-                       } else {
-                               functionName = new String(ident);
+                       if (token == TokenNameRPAREN) {
+                               getNextToken();
+                               return ref;
+                       }
+                       non_empty_function_call_parameter_list();
+                       if (token != TokenNameRPAREN) {
+                               String functionName;
+                               if (ident == null) {
+                                       functionName = new String(" ");
+                               } else {
+                                       functionName = new String(ident);
+                               }
+                               throwSyntaxError("')' expected in function call (" + functionName + ").");
                        }
-                       throwSyntaxError("')' expected in function call (" + functionName + ").");
+                       getNextToken();
                }
-               getNextToken();
                return ref;
        }
 
@@ -3106,7 +3102,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                return function_call(lefthandside, ignoreVar);
        }
 
-       private Expression base_variable() {
+       private Expression base_variable(boolean lefthandside) {
                // base_variable:
                // reference_variable
                // | simple_indirect_reference reference_variable
@@ -3121,7 +3117,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                        while (token == TokenNameDOLLAR) {
                                getNextToken();
                        }
-                       reference_variable(false, false);
+                       reference_variable(lefthandside, false);
                }
                return ref;
        }
@@ -3151,11 +3147,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                }
                                getNextToken();
                        } else if (token == TokenNameLBRACKET) {
-                               if (ref != null && ref instanceof FieldReference) {
-                                       FieldReference fref = (FieldReference) ref;
-                                       addVariableSet(fref.token);
-                               }
-                               ref = null;
+                               // To remove "ref = null;" here, is probably better than the patch
+                               // commented in #1368081 - axelcl
                                getNextToken();
                                if (token != TokenNameRBRACKET) {
                                        expr();
@@ -3349,7 +3342,105 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                // base_variable_with_function_calls T_OBJECT_OPERATOR
                // object_property method_or_not variable_properties
                // | base_variable_with_function_calls
-               Expression ref = base_variable_with_function_calls(lefthandside, ignoreVar);
+
+               // Expression ref = function_call(lefthandside, ignoreVar);
+
+               // function_call:
+               // T_STRING '(' function_call_parameter_list ')'
+               // | 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;
+               Expression ref = null;
+               if (Scanner.TRACE) {
+                       System.out.println("TRACE: function_call()");
+               }
+               if (token == TokenNameIdentifier) {
+                       ident = scanner.getCurrentIdentifierSource();
+                       defineName = ident;
+                       startPos = scanner.getCurrentTokenStartPosition();
+                       endPos = scanner.getCurrentTokenEndPosition();
+                       getNextToken();
+
+                       if (token == TokenNameEQUAL || token == TokenNamePLUS_EQUAL || token == TokenNameMINUS_EQUAL
+                                       || token == TokenNameMULTIPLY_EQUAL || token == TokenNameDIVIDE_EQUAL || token == TokenNameDOT_EQUAL
+                                       || token == TokenNameREMAINDER_EQUAL || token == TokenNameAND_EQUAL || token == TokenNameOR_EQUAL
+                                       || token == TokenNameXOR_EQUAL || token == TokenNameRIGHT_SHIFT_EQUAL || token == TokenNameLEFT_SHIFT_EQUAL) {
+                               String error = "Assignment operator '" + scanner.toStringAction(token) + "' not allowed after identifier '"
+                                               + new String(ident) + "' (use 'define(...)' to define constants).";
+                               reportSyntaxError(error);
+                       }
+
+                       switch (token) {
+                       case TokenNamePAAMAYIM_NEKUDOTAYIM:
+                               // static member:
+                               defineName = null;
+                               getNextToken();
+                               if (token == TokenNameIdentifier) {
+                                       // class _constant
+                                       getNextToken();
+                               } else {
+                                       // static member:
+                                       variable_without_objects(true, false);
+                               }
+                               break;
+                       }
+               } else {
+                       ref = variable_without_objects(lefthandside, ignoreVar);
+               }
+               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 ref;
+                       // throwSyntaxError("'(' expected in function call.");
+               } else {
+                       getNextToken();
+
+                       if (token == TokenNameRPAREN) {
+                               getNextToken();
+                               ref = null;
+                       } else {
+                               non_empty_function_call_parameter_list();
+                               if (token != TokenNameRPAREN) {
+                                       String functionName;
+                                       if (ident == null) {
+                                               functionName = new String(" ");
+                                       } else {
+                                               functionName = new String(ident);
+                                       }
+                                       throwSyntaxError("')' expected in function call (" + functionName + ").");
+                               }
+                               getNextToken();
+                       }
+               }
                if (token == TokenNameMINUS_GREATER) {
                        ref = null;
                        getNextToken();