ugly syntax supported (endif, endwhile endfor)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / test / PHPParser.jj
index 7c68a46..2a86a45 100644 (file)
@@ -127,7 +127,12 @@ public class PHPParser extends PHPParserSuperclass {
    */
   private static void setMarker(ParseException e) {
     try {
-      setMarker(fileToParse, errorMessage, jj_input_stream.tokenBegin,jj_input_stream.tokenBegin+e.currentToken.image.length(), errorLevel);
+      setMarker(fileToParse,
+                errorMessage,
+                jj_input_stream.tokenBegin,
+                jj_input_stream.tokenBegin + e.currentToken.image.length(),
+                errorLevel,
+                "Line " + e.currentToken.beginLine);
     } catch (CoreException e2) {
       PHPeclipsePlugin.log(e2);
     }
@@ -197,7 +202,11 @@ public class PHPParser extends PHPParserSuperclass {
   }
 
   public void parse(String s) throws CoreException {
-    ReInit(new StringReader(s));
+    StringReader stream = new StringReader(s);
+    if (jj_input_stream == null) {
+      jj_input_stream = new SimpleCharStream(stream, 1, 1);
+    }
+    ReInit(stream);
     try {
       parse();
     } catch (ParseException e) {
@@ -272,10 +281,14 @@ PARSER_END(PHPParser)
   "/*" : IN_MULTI_LINE_COMMENT
 }
 
-<IN_SINGLE_LINE_COMMENT>
-SPECIAL_TOKEN :
+<IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
 {
-  <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" | "?>" > : PHPPARSING
+  <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : PHPPARSING
+}
+
+<IN_SINGLE_LINE_COMMENT> TOKEN :
+{
+  <SINGLE_LINE_COMMENT_PHPEND : "?>" > : DEFAULT
 }
 
 <IN_FORMAL_COMMENT>
@@ -347,6 +360,10 @@ MORE :
 | < TRUE: "true" >
 | < WHILE: "while" >
 | < ENDWHILE : "endwhile" >
+| <ENDIF : "endif" >
+| <ENDFOR : "endfor" >
+| <FOREACH : "foreach" >
+| <AS : "as" >
 }
 
 /* TYPES */
@@ -398,20 +415,30 @@ MORE :
   < STRING_LITERAL: (<STRING_1> | <STRING_2> | <STRING_3>)>
 |    < STRING_1:
       "\""
-      (   (~["\""])
-        | "\\\""
+      (
+        ~["\""]
+        |
+        "\\\""
       )*
       "\""
     >
 |    < STRING_2:
       "'"
-      (   (~["'"]))*
+      (
+      ~["'"]
+       |
+       "\\'"
+      )*
 
       "'"
     >
 |   < STRING_3:
       "`"
-      (   (~["`"]))*
+      (
+        ~["`"]
+      |
+        "\\`"
+      )*
       "`"
     >
 }
@@ -431,7 +458,7 @@ MORE :
   >
 |
   < #SPECIAL:
-    "_"
+    "_" | ["\u007f"-"\u00ff"]
   >
 }
 
@@ -456,43 +483,46 @@ MORE :
 {
   <AT     : "@">
 | <DOLLAR : "$">
-| < ASSIGN: "=" >
-| < GT: ">" >
-| < LT: "<" >
-| < BANG: "!" >
-| < HOOK: "?" >
-| < COLON: ":" >
-| < EQ: "==" >
-| < LE: "<=" >
-| < GE: ">=" >
-| < NE: "!=" >
-| < SC_OR: "||" >
-| < SC_AND: "&&" >
-| < INCR: "++" >
-| < DECR: "--" >
-| < PLUS: "+" >
-| < MINUS: "-" >
-| < STAR: "*" >
-| < SLASH: "/" >
-| < BIT_AND: "&" >
-| < BIT_OR: "|" >
-| < XOR: "^" >
-| < REM: "%" >
-| < LSHIFT: "<<" >
-| < RSIGNEDSHIFT: ">>" >
-| < RUNSIGNEDSHIFT: ">>>" >
-| < PLUSASSIGN: "+=" >
-| < MINUSASSIGN: "-=" >
-| < STARASSIGN: "*=" >
-| < SLASHASSIGN: "/=" >
-| < ANDASSIGN: "&=" >
-| < ORASSIGN: "|=" >
-| < XORASSIGN: "^=" >
-| < DOTASSIGN: ".=" >
-| < REMASSIGN: "%=" >
-| < LSHIFTASSIGN: "<<=" >
-| < RSIGNEDSHIFTASSIGN: ">>=" >
-| < RUNSIGNEDSHIFTASSIGN: ">>>=" >
+| <ASSIGN: "=" >
+| <GT: ">" >
+| <LT: "<" >
+| <BANG: "!" >
+| <HOOK: "?" >
+| <COLON: ":" >
+| <EQ: "==" >
+| <LE: "<=" >
+| <GE: ">=" >
+| <NE: "!=" >
+| <DIF: "<>" >
+| <SC_OR: "||" >
+| <SC_AND: "&&" >
+| <INCR: "++" >
+| <DECR: "--" >
+| <PLUS: "+" >
+| <MINUS: "-" >
+| <STAR: "*" >
+| <SLASH: "/" >
+| <BIT_AND: "&" >
+| <BIT_OR: "|" >
+| <XOR: "^" >
+| <REM: "%" >
+| <LSHIFT: "<<" >
+| <RSIGNEDSHIFT: ">>" >
+| <RUNSIGNEDSHIFT: ">>>" >
+| <PLUSASSIGN: "+=" >
+| <MINUSASSIGN: "-=" >
+| <STARASSIGN: "*=" >
+| <SLASHASSIGN: "/=" >
+| <ANDASSIGN: "&=" >
+| <ORASSIGN: "|=" >
+| <XORASSIGN: "^=" >
+| <DOTASSIGN: ".=" >
+| <REMASSIGN: "%=" >
+| <LSHIFTASSIGN: "<<=" >
+| <RSIGNEDSHIFTASSIGN: ">>=" >
+| <BANGDOUBLEEQUAL: "!==" >
+| <TRIPLEEQUAL: "===" >
+| <TILDEEQUAL: "~=" >
 }
 
 <PHPPARSING> TOKEN :
@@ -518,8 +548,14 @@ void phpTest() :
 void phpFile() :
 {}
 {
+  try {
   (<PHPSTART> Php() <PHPEND>)*
   <EOF>
+  } catch (TokenMgrError e) {
+    errorMessage = e.getMessage();
+    errorLevel   = ERROR;
+    throw generateParseException();
+  }
 }
 
 void Php() :
@@ -537,13 +573,17 @@ void ClassDeclaration() :
 {
   <CLASS> className = <IDENTIFIER> [ <EXTENDS> <IDENTIFIER> ]
   {
-    classDeclaration = new PHPClassDeclaration(currentSegment,className.image,pos);
-    currentSegment.add(classDeclaration);
-    currentSegment = classDeclaration;
+    if (currentSegment != null) {
+      classDeclaration = new PHPClassDeclaration(currentSegment,className.image,pos);
+      currentSegment.add(classDeclaration);
+      currentSegment = classDeclaration;
+    }
   }
   ClassBody()
   {
-    currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
+    if (currentSegment != null) {
+      currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
+    }
   }
 }
 
@@ -581,10 +621,18 @@ void FieldDeclaration() :
 }
 {
   <VAR> variableDeclaration = VariableDeclarator()
-  {currentSegment.add(variableDeclaration);}
+  {
+    if (currentSegment != null) {
+      currentSegment.add(variableDeclaration);
+    }
+  }
   ( <COMMA>
-    variableDeclaration = VariableDeclarator()
-    {currentSegment.add(variableDeclaration);}
+      variableDeclaration = VariableDeclarator()
+      {
+      if (currentSegment != null) {
+        currentSegment.add(variableDeclaration);
+      }
+      }
   )*
   try {
     <SEMICOLON>
@@ -599,11 +647,10 @@ PHPVarDeclaration VariableDeclarator() :
 {
   String varName;
   String varValue = null;
-  int pos;
+  int pos = jj_input_stream.bufpos;
 }
 {
   varName = VariableDeclaratorId()
-  {pos = jj_input_stream.tokenBegin;}
   [
     <ASSIGN>
     try {
@@ -692,10 +739,23 @@ Token token;
 String VariableInitializer() :
 {
   String expr;
+  Token token;
 }
 {
   expr = Literal()
   {return expr;}
+|
+  <MINUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
+  {return "-" + token.image;}
+|
+  <PLUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
+  {return "+" + token.image;}
+|
+  expr = ArrayDeclarator()
+  {return expr;}
+|
+  token = <IDENTIFIER>
+  {return token.image;}
 }
 
 String ArrayVariable() :
@@ -736,12 +796,16 @@ void MethodDeclaration() :
 {
   <FUNCTION> functionDeclaration = MethodDeclarator()
   {
-    currentSegment.add(functionDeclaration);
-    currentSegment = functionDeclaration;
+    if (currentSegment != null) {
+      currentSegment.add(functionDeclaration);
+      currentSegment = functionDeclaration;
+    }
   }
   Block()
   {
-    currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
+    if (currentSegment != null) {
+      currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
+    }
   }
 }
 
@@ -835,6 +899,9 @@ String Type() :
 |
   <INTEGER>
   {return "integer";}
+|
+  <OBJECT>
+  {return "object";}
 }
 
 String Expression() :
@@ -850,7 +917,13 @@ String Expression() :
   expr = ConditionalExpression()
   [
     assignOperator = AssignmentOperator()
-    expr2 = Expression()
+    try {
+      expr2 = Expression()
+    } catch (ParseException e) {
+      errorMessage = "expression expected";
+      errorLevel   = ERROR;
+      throw e;
+    }
   ]
   {
     if (expr2 == null) {
@@ -862,9 +935,7 @@ String Expression() :
 }
 
 String AssignmentOperator() :
-{
-  Token assignOperator;
-}
+{}
 {
   <ASSIGN>
 {return "=";}
@@ -882,8 +953,6 @@ String AssignmentOperator() :
 {return "<<=";}
 | <RSIGNEDSHIFTASSIGN>
 {return ">>=";}
-| <RUNSIGNEDSHIFTASSIGN>
-{return ">>>=";}
 | <ANDASSIGN>
 {return "&=";}
 | <XORASSIGN>
@@ -892,6 +961,8 @@ String AssignmentOperator() :
 {return "|=";}
 | <DOTASSIGN>
 {return ".=";}
+| <TILDEEQUAL>
+{return "~=";}
 }
 
 String ConditionalExpression() :
@@ -1062,7 +1133,13 @@ String EqualityExpression() :
   expr = RelationalExpression()
   {buff.append(expr);}
   (
-  ( operator = <EQ> | operator = <NE> ) expr2 = RelationalExpression()
+  (   operator = <EQ>
+    | operator = <DIF>
+    | operator = <NE>
+    | operator = <BANGDOUBLEEQUAL>
+    | operator = <TRIPLEEQUAL>
+  )
+  expr2 = RelationalExpression()
   {
     buff.append(operator.image);
     buff.append(expr2);
@@ -1149,19 +1226,37 @@ String MultiplicativeExpression() :
   {return buff.toString();}
 }
 
+/**
+ * An unary expression starting with @, & or nothing
+ */
 String UnaryExpression() :
 {
   String expr;
+  Token token;
   final StringBuffer buff = new StringBuffer();
 }
 {
-  <AT> expr = UnaryExpression()
-  {return "@" + expr;}
+  token = <BIT_AND> expr = UnaryExpressionNoPrefix()
+  {
+    if (token == null) {
+      return expr;
+    }
+    return token.image + expr;
+  }
 |
-  ( <PLUS> {buff.append("+");}| <MINUS> {buff.append("-");}) expr = UnaryExpression()
+  (<AT> {buff.append("@");})* expr = UnaryExpressionNoPrefix()
+  {return buff.append(expr).toString();}
+}
+
+String UnaryExpressionNoPrefix() :
+{
+  String expr;
+  Token token;
+}
+{
+  ( token = <PLUS> | token = <MINUS> ) expr = UnaryExpression()
   {
-    buff.append(expr);
-    return buff.toString();
+    return token.image + expr;
   }
 |
   expr = PreIncrementExpression()
@@ -1174,6 +1269,7 @@ String UnaryExpression() :
   {return expr;}
 }
 
+
 String PreIncrementExpression() :
 {
 String expr;
@@ -1259,6 +1355,15 @@ String PrimaryExpression() :
   ( expr = PrimarySuffix()  {buff.append(expr);} )*
   {return buff.toString();}
 |
+  expr = ArrayDeclarator()
+  {return "array" + expr;}
+}
+
+String ArrayDeclarator() :
+{
+  String expr;
+}
+{
   <ARRAY> expr = ArrayInitializer()
   {return "array" + expr;}
 }
@@ -1272,12 +1377,9 @@ String PrimaryPrefix() :
   token = <IDENTIFIER>
   {return token.image;}
 |
-  [token = <BIT_AND>] <NEW> expr = ClassIdentifier()
+  <NEW> expr = ClassIdentifier()
   {
-    if (token == null) {
-      return "new " + expr;
-    }
-    return "new &" + expr;
+    return "new " + expr;
   }
 |  
   expr = VariableDeclaratorId()
@@ -1317,7 +1419,14 @@ String VariableSuffix() :
   <CLASSACCESS> expr = VariableName()
   {return "->" + expr;}
 | 
-  <LBRACKET> [ expr = Expression() ] <RBRACKET>
+  <LBRACKET> [ expr = Expression() ]
+  try {
+    <RBRACKET>
+  } catch (ParseException e) {
+    errorMessage = "']' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
   {
     if(expr == null) {
       return "[]";
@@ -1338,14 +1447,8 @@ String Literal() :
   token = <FLOATING_POINT_LITERAL>
   {return token.image;}
 |
-  try {
-    token = <STRING_LITERAL>
+  token = <STRING_LITERAL>
   {return token.image;}
-  } catch (TokenMgrError e) {
-    errorMessage = "unterminated string";
-    errorLevel   = ERROR;
-    throw generateParseException();
-  }
 |
   expr = BooleanLiteral()
   {return expr;}
@@ -1423,7 +1526,14 @@ void Statement() :
 {}
 {
   LOOKAHEAD(2)
-  Expression()  (<SEMICOLON> | "?>")
+  Expression()
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
 |
   LOOKAHEAD(2)
   LabeledStatement()
@@ -1451,6 +1561,8 @@ void Statement() :
 |
   ForStatement()
 |
+  ForeachStatement()
+|
   BreakStatement()
 |
   ContinueStatement()
@@ -1468,34 +1580,69 @@ void Statement() :
 
 void IncludeStatement() :
 {
-  Token token;
   String expr;
-  int pos;
+  int pos = jj_input_stream.bufpos;
 }
 {
-  token = <REQUIRE>
-  {pos = token.beginLine;}
+  <REQUIRE>
   expr = Expression()
-  {currentSegment.add(new PHPReqIncDeclaration(currentSegment, "require",pos,expr));}
-  (<SEMICOLON> | "?>")
+  {
+    if (currentSegment != null) {
+      currentSegment.add(new PHPReqIncDeclaration(currentSegment, "require",pos,expr));
+    }
+  }
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
 |
-  token = <REQUIRE_ONCE>
-  {pos = token.beginLine;}
+  <REQUIRE_ONCE>
   expr = Expression()
-  {currentSegment.add(new PHPReqIncDeclaration(currentSegment, "require_once",pos,expr));}
-  (<SEMICOLON> | "?>")
+  {
+    if (currentSegment != null) {
+      currentSegment.add(new PHPReqIncDeclaration(currentSegment, "require_once",pos,expr));
+    }
+  }
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
 |
-  token = <INCLUDE>
-  {pos = token.beginLine;}
+  <INCLUDE>
   expr = Expression()
-  {currentSegment.add(new PHPReqIncDeclaration(currentSegment, "include",pos,expr));}
-  (<SEMICOLON> | "?>")
+  {
+    if (currentSegment != null) {
+      currentSegment.add(new PHPReqIncDeclaration(currentSegment, "include",pos,expr));
+    }
+  }
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
 |
-  token = <INCLUDE_ONCE>
-  {pos = token.beginLine;}
+  <INCLUDE_ONCE>
   expr = Expression()
-  {currentSegment.add(new PHPReqIncDeclaration(currentSegment, "include_once",pos,expr));}
-  (<SEMICOLON> | "?>")
+  {
+    if (currentSegment != null) {
+      currentSegment.add(new PHPReqIncDeclaration(currentSegment, "include_once",pos,expr));
+    }
+  }
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
 }
 
 String PrintExpression() :
@@ -1527,13 +1674,27 @@ void EchoStatement() :
 void GlobalStatement() :
 {}
 {
-  <GLOBAL> VariableDeclaratorId() (<COMMA> VariableDeclaratorId())* (<SEMICOLON> | "?>")
+  <GLOBAL> VariableDeclaratorId() (<COMMA> VariableDeclaratorId())*
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
 }
 
 void StaticStatement() :
 {}
 {
-  <STATIC> VariableDeclarator() (<COMMA> VariableDeclarator())* (<SEMICOLON> | "?>")
+  <STATIC> VariableDeclarator() (<COMMA> VariableDeclarator())*
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
 }
 
 void LabeledStatement() :
@@ -1579,11 +1740,6 @@ void EmptyStatement() :
 }
 
 void StatementExpression() :
-/*
- * The last expansion of this production accepts more than the legal
- * Java expansions for StatementExpression.  This expansion does not
- * use PostfixExpression for performance reasons.
- */
 {}
 {
   PreIncrementExpression()
@@ -1624,7 +1780,7 @@ void IfStatement() :
  */
 {}
 {
-  <IF> Condition("if") Statement() ( LOOKAHEAD(1) ElseIfStatement() )* [ LOOKAHEAD(1) <ELSE> Statement() ]
+  <IF> Condition("if") IfStatement0()
 }
 
 void Condition(String keyword) :
@@ -1647,6 +1803,39 @@ void Condition(String keyword) :
   }
 }
 
+void IfStatement0() :
+{}
+{
+  <COLON> (Statement())* (ElseIfStatementColon())* [ElseStatementColon()] <ENDIF>
+  try {
+    <SEMICOLON>
+  } catch (ParseException e) {
+    errorMessage = "';' expected 'endif' keyword";
+    errorLevel   = ERROR;
+    throw e;
+  }
+|
+  Statement() ( LOOKAHEAD(1) ElseIfStatement() )* [ LOOKAHEAD(1) <ELSE> Statement() ]
+}
+
+void ElseIfStatementColon() :
+{}
+{
+  <ELSEIF> Condition("elseif") <COLON> (Statement())*
+}
+
+void ElseStatement() :
+{}
+{
+  <ELSE> Statement()
+}
+
+void ElseStatementColon() :
+{}
+{
+  <ELSE> <COLON> (Statement())*
+}
+
 void ElseIfStatement() :
 {}
 {
@@ -1662,7 +1851,14 @@ void WhileStatement() :
 void WhileStatement0() :
 {}
 {
-  <COLON> (Statement())* <ENDWHILE> (<SEMICOLON> | "?>")
+  <COLON> (Statement())* <ENDWHILE>
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected after 'endwhile' keyword";
+    errorLevel   = ERROR;
+    throw e;
+  }
 |
   Statement()
 }
@@ -1670,13 +1866,38 @@ void WhileStatement0() :
 void DoStatement() :
 {}
 {
-  <DO> Statement() <WHILE> Condition("while") (<SEMICOLON> | "?>")
+  <DO> Statement() <WHILE> Condition("while")
+  try {
+    (<SEMICOLON> | "?>")
+  } catch (ParseException e) {
+    errorMessage = "';' expected";
+    errorLevel   = ERROR;
+    throw e;
+  }
+}
+
+void ForeachStatement() :
+{}
+{
+  <FOREACH> <LPAREN> Variable() <AS> Variable() [ <ARRAYASSIGN> Expression() ] <RPAREN> Statement()
 }
 
 void ForStatement() :
 {}
 {
-  <FOR> <LPAREN> [ ForInit() ] <SEMICOLON> [ Expression() ] <SEMICOLON> [ ForUpdate() ] <RPAREN> Statement()
+  <FOR> <LPAREN> [ ForInit() ] <SEMICOLON> [ Expression() ] <SEMICOLON> [ ForUpdate() ] <RPAREN>
+    (
+      Statement()
+    |
+      <COLON> (Statement())* <ENDFOR>
+      try {
+        <SEMICOLON>
+      } catch (ParseException e) {
+        errorMessage = "';' expected 'endfor' keyword";
+        errorLevel   = ERROR;
+        throw e;
+      }
+    )
 }
 
 void ForInit() :