fixed parser bug;
[phpeclipse.git] / net.sourceforge.phpeclipse / src / test / PHPParser.jj
index afc5890..f2cd08d 100644 (file)
@@ -87,7 +87,7 @@ public final class PHPParser extends PHPParserSuperclass {
   /** The cursor in expression stack. */
   private static int nodePtr;
 
-  public static final boolean PARSER_DEBUG = true;
+  public static final boolean PARSER_DEBUG = false;
 
   public final void setFileToParse(final IFile fileToParse) {
     PHPParser.fileToParse = fileToParse;
@@ -589,19 +589,79 @@ MORE :
 |
   <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
 |
-  <STRING_LITERAL: (<STRING_1> | <STRING_2> | <STRING_3>)>
-|   <STRING_1: "\"" ( ~["\"","\\"] | "\\" ~[] )* "\"">
+  <STRING_LITERAL: (<STRING_2> | <STRING_3>)>
+//|   <STRING_1: "\"" ( ~["\"","\\"] | "\\" ~[] )* "\"">
 |   <STRING_2: "'"  ( ~["'","\\"]  | "\\" ~[] )* "'">
 |   <STRING_3: "`"  ( ~["`","\\"]  | "\\" ~[] )* "`">
 }
 
+<IN_STRING,DOLLAR_IN_STRING> SKIP :
+{
+  <ESCAPED : ("\\" ~[])> : IN_STRING
+}
+
+<PHPPARSING> TOKEN :
+{
+  <DOUBLEQUOTE : "\""> : IN_STRING
+}
+
+
+<IN_STRING> TOKEN :
+{
+  <DOLLARS : "$"> : DOLLAR_IN_STRING
+}
+
+<IN_STRING,DOLLAR_IN_STRING> TOKEN :
+{
+  <DOUBLEQUOTE2 : "\""> : PHPPARSING
+}
+
+<DOLLAR_IN_STRING> TOKEN :
+{
+  <LBRACE1 : "{"> : DOLLAR_IN_STRING_EXPR
+}
+
+<IN_STRING> SPECIAL_TOKEN :
+{
+    <"{"> : SKIPSTRING
+}
+
+<SKIPSTRING> SPECIAL_TOKEN :
+{
+    <"}"> : IN_STRING
+}
+
+<SKIPSTRING> SKIP :
+{
+    <~[]>
+}
+
+<DOLLAR_IN_STRING_EXPR> TOKEN :
+{
+  <RBRACE1 : "}"> : DOLLAR_IN_STRING
+}
+
+<DOLLAR_IN_STRING_EXPR> TOKEN :
+{
+  <ID : (~["}"])*>
+}
+
+<IN_STRING> SKIP :
+{
+  <~[]>
+}
+
+<DOLLAR_IN_STRING_EXPR,IN_STRING> SKIP :
+{
+  <~[]>
+}
 /* IDENTIFIERS */
 
 
 <PHPPARSING,IN_VARIABLE> TOKEN : {<DOLLAR : "$"> : IN_VARIABLE}
 
 
-<PHPPARSING, IN_VARIABLE> TOKEN :
+<PHPPARSING, IN_VARIABLE, DOLLAR_IN_STRING> TOKEN :
 {
   <IDENTIFIER: (<LETTER>|<SPECIAL>) (<LETTER>|<DIGIT>|<SPECIAL>)* >
 |
@@ -618,6 +678,10 @@ MORE :
   >
 }
 
+<DOLLAR_IN_STRING> SPECIAL_TOKEN :
+{
+ < ~[] > : IN_STRING
+}
 /* SEPARATORS */
 
 <PHPPARSING,IN_VARIABLE> TOKEN :
@@ -724,8 +788,8 @@ void PhpBlock() :
   } catch (ParseException e) {
     errorMessage = "'?>' expected";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
   }
 }
@@ -830,8 +894,8 @@ Token token;
   } catch (ParseException e) {
     errorMessage = "unexpected token : '"+ e.currentToken.next.image + "'. '{' expected";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
   }
   ( ClassBodyDeclaration(classDeclaration) )*
@@ -841,8 +905,8 @@ Token token;
   } catch (ParseException e) {
     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. 'var', 'function' or '}' expected";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
     return PHPParser.token.sourceEnd;
   }
@@ -879,7 +943,6 @@ FieldDeclaration FieldDeclaration() :
   token = <VAR> variableDeclaration = VariableDeclaratorNoSuffix()
   {
     arrayList.add(variableDeclaration);
-    outlineInfo.addVariable(variableDeclaration.name());
     pos = variableDeclaration.sourceEnd;
   }
   (
@@ -1024,8 +1087,8 @@ AbstractVariable VariableDeclaratorId() :
   } catch (ParseException e) {
     errorMessage = "'$' expected for variable identifier";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     throw e;
   }
 }
@@ -1036,13 +1099,13 @@ Variable Variable() :
   final Token token;
 }
 {
-  token = <DOLLAR> variable = Var(token)
+  token = <DOLLAR> variable = Var()
   {
-    return new Variable(variable,token.sourceEnd,variable.sourceEnd);
+    return variable;
   }
 }
 
-Variable Var(final Token dollar) :
+Variable Var() :
 {
   Variable variable = null;
   final Token token,token2;
@@ -1050,18 +1113,21 @@ Variable Var(final Token dollar) :
   Expression expression;
 }
 {
-  token = <DOLLAR> variable = Var(token)
-  {return new Variable(variable,dollar.sourceEnd,variable.sourceEnd);}
+  token = <DOLLAR> variable = Var()
+  {return new Variable(variable,variable.sourceStart,variable.sourceEnd);}
 |
   token = <LBRACE> expression = Expression() token2 = <RBRACE>
   {
    return new Variable(expression,
-                       dollar.sourceStart,
+                       token.sourceStart,
                        token2.sourceEnd);
   }
 |
   token = <IDENTIFIER>
-  {return new Variable(token.image,dollar.sourceStart,token.sourceEnd);}
+  {
+   outlineInfo.addVariable("$" + token.image);
+   return new Variable(token.image,token.sourceStart,token.sourceEnd);
+  }
 }
 
 Expression VariableInitializer() :
@@ -1147,8 +1213,8 @@ MethodDeclaration MethodDeclaration() :
     if (errorMessage != null)  throw e;
     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     throw e;
   }
   {currentSegment = functionDeclaration;}
@@ -1167,7 +1233,7 @@ MethodDeclaration MethodDeclarator(final int start) :
 {
   Token identifier = null;
   Token reference = null;
-  final Hashtable formalParameters = new Hashtable();
+  final ArrayList formalParameters = new ArrayList();
   String identifierChar = SYNTAX_ERROR_CHAR;
   int end = start;
 }
@@ -1216,7 +1282,7 @@ MethodDeclaration MethodDeclarator(final int start) :
  * FormalParameters follows method identifier.
  * (FormalParameter())
  */
-int FormalParameters(final Hashtable parameters) :
+int FormalParameters(final ArrayList parameters) :
 {
   VariableDeclaration var;
   final Token token;
@@ -1236,10 +1302,10 @@ int FormalParameters(final Hashtable parameters) :
   }
   [
     var = FormalParameter()
-    {parameters.put(var.name(),var);end = var.sourceEnd;}
+    {parameters.add(var);end = var.sourceEnd;}
     (
       <COMMA> var = FormalParameter()
-      {parameters.put(var.name(),var);end = var.sourceEnd;}
+      {parameters.add(var);end = var.sourceEnd;}
     )*
   ]
   try {
@@ -1267,6 +1333,7 @@ VariableDeclaration FormalParameter() :
 {
   [token = <BIT_AND>] variableDeclaration = VariableDeclaratorNoSuffix()
   {
+    outlineInfo.addVariable("$"+variableDeclaration.name());
     if (token != null) {
       variableDeclaration.setReference(true);
     }
@@ -1914,6 +1981,7 @@ AbstractVariable VariableSuffix(final AbstractVariable prefix) :
 Literal Literal() :
 {
   final Token token;
+  StringLiteral literal;
 }
 {
   token = <INTEGER_LITERAL>        {return new NumberLiteral(token);}
@@ -1922,26 +1990,70 @@ Literal Literal() :
 | token = <TRUE>                   {return new TrueLiteral(token);}
 | token = <FALSE>                  {return new FalseLiteral(token);}
 | token = <NULL>                   {return new NullLiteral(token);}
+| literal = evaluableString()        {return literal;}
+}
+
+StringLiteral evaluableString() :
+{
+  ArrayList list = new ArrayList();
+  Token start,end;
+  Token token,lbrace,rbrace;
+  AbstractVariable var;
+  Expression expr;
+}
+{
+  start = <DOUBLEQUOTE>
+  (
+   <DOLLARS>
+       (
+        token = <IDENTIFIER> {list.add(new Variable(token.image,
+                                                    token.sourceStart,
+                                                    token.sourceEnd));}
+        |
+         lbrace = <LBRACE1>
+         token = <ID>
+         {list.add(new Variable(token.image,
+                                token.sourceStart,
+                                token.sourceEnd));}
+         rbrace = <RBRACE1>
+       )
+   )*
+  end = <DOUBLEQUOTE2>
+  {
+  AbstractVariable[] vars = new AbstractVariable[list.size()];
+  list.toArray(vars);
+  return new StringLiteral(SimpleCharStream.currentBuffer.substring(start.sourceEnd,end.sourceStart),
+                           start.sourceStart,
+                           end.sourceEnd,
+                           vars);
+  }
 }
 
 FunctionCall Arguments(final Expression func) :
 {
 Expression[] args = null;
-final Token token;
+final Token token,lparen;
 }
 {
-  <LPAREN> [ args = ArgumentList() ]
+  lparen = <LPAREN> [ args = ArgumentList() ]
   try {
     token = <RPAREN>
     {return new FunctionCall(func,args,token.sourceEnd);}
   } catch (ParseException e) {
     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list";
     errorLevel   = ERROR;
-    errorStart = args[args.length-1].sourceEnd+1;
-    errorEnd   = args[args.length-1].sourceEnd+1;
+    if (args == null) {
+        errorStart = lparen.sourceEnd+1;
+        errorEnd   = lparen.sourceEnd+2;
+    } else {
+        errorStart = args[args.length-1].sourceEnd+1;
+        errorEnd   = args[args.length-1].sourceEnd+2;
+    }
     processParseExceptionDebug(e);
   }
-  {return new FunctionCall(func,args,args[args.length-1].sourceEnd);}
+  {
+  int sourceEnd = (args == null && args.length != 0) ? lparen.sourceEnd+1 : args[args.length-1].sourceEnd;
+  return new FunctionCall(func,args,sourceEnd);}
 }
 
 /**
@@ -2141,8 +2253,8 @@ HTMLBlock htmlBlock() :
   } catch (ParseException e) {
     errorMessage = "unexpected end of file , '<?php' expected";
     errorLevel   = ERROR;
-    errorStart   = SimpleCharStream.getPosition();
-    errorEnd     = SimpleCharStream.getPosition();
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     throw e;
   }
   {
@@ -2691,6 +2803,7 @@ AbstractCase switchLabel0() :
   Statement statement;
   final ArrayList stmts = new ArrayList();
   final Token token = PHPParser.token;
+  final int start = PHPParser.token.next.sourceStart;
 }
 {
   expr = SwitchLabel()
@@ -2703,7 +2816,8 @@ AbstractCase switchLabel0() :
     final Statement[] stmtsArray = new Statement[listSize];
     stmts.toArray(stmtsArray);
     if (expr == null) {//it's a default
-      return new DefaultCase(stmtsArray,token.sourceStart,stmtsArray[listSize-1].sourceEnd);
+      final int end = PHPParser.token.next.sourceStart;
+      return new DefaultCase(stmtsArray,start,end);
     }
     if (listSize != 0) {
       return new Case(expr,stmtsArray,expr.sourceStart,stmtsArray[listSize-1].sourceEnd);
@@ -2737,7 +2851,6 @@ Expression SwitchLabel() :
   }
   try {
     token = <COLON>
-    {return expr;}
   } catch (ParseException e) {
     errorMessage = "':' expected after case expression";
     errorLevel   = ERROR;
@@ -2745,11 +2858,11 @@ Expression SwitchLabel() :
     errorEnd   = expr.sourceEnd+1;
     processParseExceptionDebug(e);
   }
+  {return expr;}
 |
   token = <_DEFAULT>
   try {
     <COLON>
-    {return null;}
   } catch (ParseException e) {
     errorMessage = "':' expected after 'default' keyword";
     errorLevel   = ERROR;
@@ -2757,6 +2870,7 @@ Expression SwitchLabel() :
     errorEnd   = token.sourceEnd+1;
     processParseExceptionDebug(e);
   }
+  {return null;}
 }
 
 Break BreakStatement() :
@@ -2858,8 +2972,8 @@ IfStatement IfStatement0(final Expression condition, final int start,final int e
   } catch (ParseException e) {
     errorMessage = "'endif' expected";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     throw e;
   }
   try {
@@ -2867,8 +2981,8 @@ IfStatement IfStatement0(final Expression condition, final int start,final int e
   } catch (ParseException e) {
     errorMessage = "';' expected after 'endif' keyword";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     throw e;
   }
     {
@@ -2908,8 +3022,8 @@ IfStatement IfStatement0(final Expression condition, final int start,final int e
       }
       errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected";
       errorLevel   = ERROR;
-      errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-      errorEnd   = SimpleCharStream.getPosition() + 1;
+      errorStart = e.currentToken.sourceStart;
+      errorEnd   = e.currentToken.sourceEnd;
       throw e;
     }
   ]
@@ -3009,8 +3123,8 @@ Statement WhileStatement0(final int start, final int end) :
   } catch (ParseException e) {
     errorMessage = "'endwhile' expected";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     throw e;
   }
   try {
@@ -3022,8 +3136,8 @@ Statement WhileStatement0(final int start, final int end) :
   } catch (ParseException e) {
     errorMessage = "';' expected after 'endwhile' keyword";
     errorLevel   = ERROR;
-    errorStart = SimpleCharStream.getPosition() - e.currentToken.next.image.length() + 1;
-    errorEnd   = SimpleCharStream.getPosition() + 1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     throw e;
   }
 |
@@ -3076,8 +3190,8 @@ ForeachStatement ForeachStatement() :
   } catch (ParseException e) {
     errorMessage = "'(' expected after 'foreach' keyword";
     errorLevel   = ERROR;
-    errorStart = foreachToken.sourceEnd+1;
-    errorEnd   = foreachToken.sourceEnd+1;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
     {pos = foreachToken.sourceEnd+1;}
   }
@@ -3087,8 +3201,8 @@ ForeachStatement ForeachStatement() :
   } catch (ParseException e) {
     errorMessage = "variable expected";
     errorLevel   = ERROR;
-    errorStart = pos;
-    errorEnd   = pos;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
   }
   try {
@@ -3097,8 +3211,8 @@ ForeachStatement ForeachStatement() :
   } catch (ParseException e) {
     errorMessage = "'as' expected";
     errorLevel   = ERROR;
-    errorStart = pos;
-    errorEnd   = pos;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
   }
   try {
@@ -3108,8 +3222,8 @@ ForeachStatement ForeachStatement() :
     if (errorMessage != null) throw e;
     errorMessage = "variable expected";
     errorLevel   = ERROR;
-    errorStart = pos;
-    errorEnd   = pos;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
   }
   try {
@@ -3118,8 +3232,8 @@ ForeachStatement ForeachStatement() :
   } catch (ParseException e) {
     errorMessage = "')' expected after 'foreach' keyword";
     errorLevel   = ERROR;
-    errorStart = pos;
-    errorEnd   = pos;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
   }
   try {
@@ -3129,8 +3243,8 @@ ForeachStatement ForeachStatement() :
     if (errorMessage != null) throw e;
     errorMessage = "statement expected";
     errorLevel   = ERROR;
-    errorStart = pos;
-    errorEnd   = pos;
+    errorStart = e.currentToken.sourceStart;
+    errorEnd   = e.currentToken.sourceEnd;
     processParseExceptionDebug(e);
   }
   {return new ForeachStatement(expression,