TestCase and Mockobject for PHPPartitionScanner Junit testing.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / test / PHPParser.jj
1 options {
2   LOOKAHEAD = 1;
3   CHOICE_AMBIGUITY_CHECK = 2;
4   OTHER_AMBIGUITY_CHECK = 1;
5   STATIC = true;
6   DEBUG_PARSER = false;
7   DEBUG_LOOKAHEAD = false;
8   DEBUG_TOKEN_MANAGER = false;
9   OPTIMIZE_TOKEN_MANAGER = false;
10   ERROR_REPORTING = true;
11   JAVA_UNICODE_ESCAPE = false;
12   UNICODE_INPUT = false;
13   IGNORE_CASE = true;
14   USER_TOKEN_MANAGER = false;
15   USER_CHAR_STREAM = false;
16   BUILD_PARSER = true;
17   BUILD_TOKEN_MANAGER = true;
18   SANITY_CHECK = true;
19   FORCE_LA_CHECK = false;
20 }
21
22 PARSER_BEGIN(PHPParser)
23 package test;
24
25 import org.eclipse.core.resources.IFile;
26 import org.eclipse.core.resources.IMarker;
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.ui.texteditor.MarkerUtilities;
29 import org.eclipse.jface.preference.IPreferenceStore;
30
31 import java.util.Hashtable;
32 import java.util.Enumeration;
33 import java.io.StringReader;
34 import java.io.*;
35 import java.text.MessageFormat;
36
37 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
38 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
39 import net.sourceforge.phpdt.internal.compiler.parser.*;
40 import net.sourceforge.phpdt.internal.compiler.ast.*;
41
42 /**
43  * A new php parser.
44  * This php parser is inspired by the Java 1.2 grammar example
45  * given with JavaCC. You can get JavaCC at http://www.webgain.com
46  * You can test the parser with the PHPParserTestCase2.java
47  * @author Matthieu Casanova
48  */
49 public final class PHPParser extends PHPParserSuperclass {
50
51   /** The file that is parsed. */
52   private static IFile fileToParse;
53
54   /** The current segment. */
55   private static PHPSegmentWithChildren currentSegment;
56
57   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
58   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
59   static PHPOutlineInfo outlineInfo;
60
61   private static PHPFunctionDeclaration currentFunction;
62   private static boolean assigning;
63
64   /** The error level of the current ParseException. */
65   private static int errorLevel = ERROR;
66   /** The message of the current ParseException. If it's null it's because the parse exception wasn't handled */
67   private static String errorMessage;
68
69   private static int errorStart = -1;
70   private static int errorEnd = -1;
71
72   //ast stack
73   private final static int AstStackIncrement = 100;
74   /** The stack of node. */
75   private static AstNode[] astStack;
76   /** The cursor in expression stack. */
77         private static int expressionPtr;
78
79   public final void setFileToParse(final IFile fileToParse) {
80     this.fileToParse = fileToParse;
81   }
82
83   public PHPParser() {
84   }
85
86   public PHPParser(final IFile fileToParse) {
87     this(new StringReader(""));
88     this.fileToParse = fileToParse;
89   }
90
91   public static final void phpParserTester(final String strEval) throws CoreException, ParseException {
92     PHPParserTokenManager.SwitchTo(PHPParserTokenManager.PHPPARSING);
93     final StringReader stream = new StringReader(strEval);
94     if (jj_input_stream == null) {
95       jj_input_stream = new SimpleCharStream(stream, 1, 1);
96     }
97     ReInit(new StringReader(strEval));
98     astStack = new AstNode[AstStackIncrement];
99     phpTest();
100   }
101
102   public static final void htmlParserTester(final File fileName) throws CoreException, ParseException {
103     try {
104       final Reader stream = new FileReader(fileName);
105       if (jj_input_stream == null) {
106         jj_input_stream = new SimpleCharStream(stream, 1, 1);
107       }
108       ReInit(stream);
109       astStack = new AstNode[AstStackIncrement];
110       phpFile();
111     } catch (FileNotFoundException e) {
112       e.printStackTrace();  //To change body of catch statement use Options | File Templates.
113     }
114   }
115
116   public static final void htmlParserTester(final String strEval) throws CoreException, ParseException {
117     final StringReader stream = new StringReader(strEval);
118     if (jj_input_stream == null) {
119       jj_input_stream = new SimpleCharStream(stream, 1, 1);
120     }
121     ReInit(stream);
122     astStack = new AstNode[AstStackIncrement];
123     phpFile();
124   }
125
126   public final PHPOutlineInfo parseInfo(final Object parent, final String s) {
127     outlineInfo = new PHPOutlineInfo(parent);
128     currentSegment = outlineInfo.getDeclarations();
129     final StringReader stream = new StringReader(s);
130     if (jj_input_stream == null) {
131       jj_input_stream = new SimpleCharStream(stream, 1, 1);
132     }
133     ReInit(stream);
134     astStack = new AstNode[AstStackIncrement];
135     try {
136       parse();
137     } catch (ParseException e) {
138       processParseException(e);
139     }
140     return outlineInfo;
141   }
142
143   /**
144    * This method will process the parse exception.
145    * If the error message is null, the parse exception wasn't catched and a trace is written in the log
146    * @param e the ParseException
147    */
148   private static void processParseException(final ParseException e) {
149     if (errorMessage == null) {
150       PHPeclipsePlugin.log(e);
151       errorMessage = "this exception wasn't handled by the parser please tell us how to reproduce it";
152       errorStart = jj_input_stream.getPosition();
153       errorEnd   = errorStart + 1;
154     }
155     setMarker(e);
156     errorMessage = null;
157   }
158
159   /**
160    * Create marker for the parse error
161    * @param e the ParseException
162    */
163   private static void setMarker(final ParseException e) {
164     try {
165       if (errorStart == -1) {
166         setMarker(fileToParse,
167                   errorMessage,
168                   jj_input_stream.tokenBegin,
169                   jj_input_stream.tokenBegin + e.currentToken.image.length(),
170                   errorLevel,
171                   "Line " + e.currentToken.beginLine);
172       } else {
173         setMarker(fileToParse,
174                   errorMessage,
175                   errorStart,
176                   errorEnd,
177                   errorLevel,
178                   "Line " + e.currentToken.beginLine);
179         errorStart = -1;
180         errorEnd = -1;
181       }
182     } catch (CoreException e2) {
183       PHPeclipsePlugin.log(e2);
184     }
185   }
186
187   /**
188    * Create markers according to the external parser output
189    */
190   private static void createMarkers(final String output, final IFile file) throws CoreException {
191     // delete all markers
192     file.deleteMarkers(IMarker.PROBLEM, false, 0);
193
194     int indx = 0;
195     int brIndx;
196     boolean flag = true;
197     while ((brIndx = output.indexOf("<br />", indx)) != -1) {
198       // newer php error output (tested with 4.2.3)
199       scanLine(output, file, indx, brIndx);
200       indx = brIndx + 6;
201       flag = false;
202     }
203     if (flag) {
204       while ((brIndx = output.indexOf("<br>", indx)) != -1) {
205         // older php error output (tested with 4.2.3)
206         scanLine(output, file, indx, brIndx);
207         indx = brIndx + 4;
208       }
209     }
210   }
211
212   private static void scanLine(final String output,
213                                final IFile file,
214                                final int indx,
215                                final int brIndx) throws CoreException {
216     String current;
217     StringBuffer lineNumberBuffer = new StringBuffer(10);
218     char ch;
219     current = output.substring(indx, brIndx);
220
221     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
222       int onLine = current.indexOf("on line <b>");
223       if (onLine != -1) {
224         lineNumberBuffer.delete(0, lineNumberBuffer.length());
225         for (int i = onLine; i < current.length(); i++) {
226           ch = current.charAt(i);
227           if ('0' <= ch && '9' >= ch) {
228             lineNumberBuffer.append(ch);
229           }
230         }
231
232         int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
233
234         Hashtable attributes = new Hashtable();
235
236         current = current.replaceAll("\n", "");
237         current = current.replaceAll("<b>", "");
238         current = current.replaceAll("</b>", "");
239         MarkerUtilities.setMessage(attributes, current);
240
241         if (current.indexOf(PARSE_ERROR_STRING) != -1)
242           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
243         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
244           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
245         else
246           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
247         MarkerUtilities.setLineNumber(attributes, lineNumber);
248         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
249       }
250     }
251   }
252
253   public final void parse(final String s) throws CoreException {
254     final StringReader stream = new StringReader(s);
255     if (jj_input_stream == null) {
256       jj_input_stream = new SimpleCharStream(stream, 1, 1);
257     }
258     ReInit(stream);
259     astStack = new AstNode[AstStackIncrement];
260     try {
261       parse();
262     } catch (ParseException e) {
263       processParseException(e);
264     }
265   }
266
267   /**
268    * Call the php parse command ( php -l -f &lt;filename&gt; )
269    * and create markers according to the external parser output
270    */
271   public static void phpExternalParse(final IFile file) {
272     final IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
273     final String filename = file.getLocation().toString();
274
275     final String[] arguments = { filename };
276     final MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
277     final String command = form.format(arguments);
278
279     final String parserResult = PHPStartApacheAction.getParserOutput(command, "External parser: ");
280
281     try {
282       // parse the buffer to find the errors and warnings
283       createMarkers(parserResult, file);
284     } catch (CoreException e) {
285       PHPeclipsePlugin.log(e);
286     }
287   }
288
289   private static final void parse() throws ParseException {
290           phpFile();
291   }
292 }
293
294 PARSER_END(PHPParser)
295
296 <DEFAULT> TOKEN :
297 {
298   <PHPSTARTSHORT : "<?">   : PHPPARSING
299 | <PHPSTARTLONG : "<?php"> : PHPPARSING
300 | <PHPECHOSTART : "<?=">   : PHPPARSING
301 }
302
303 <PHPPARSING> TOKEN :
304 {
305   <PHPEND :"?>"> : DEFAULT
306 }
307
308 /* Skip any character if we are not in php mode */
309 <DEFAULT> SKIP :
310 {
311  < ~[] >
312 }
313
314
315 /* WHITE SPACE */
316 <PHPPARSING> SKIP :
317 {
318   " "
319 | "\t"
320 | "\n"
321 | "\r"
322 | "\f"
323 }
324
325 /* COMMENTS */
326 <PHPPARSING> SPECIAL_TOKEN :
327 {
328   "//" : IN_SINGLE_LINE_COMMENT
329 |
330   "#"  : IN_SINGLE_LINE_COMMENT
331 |
332   <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
333 |
334   "/*" : IN_MULTI_LINE_COMMENT
335 }
336
337 <IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
338 {
339   <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : PHPPARSING
340 }
341
342 <IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
343 {
344   <SINGLE_LINE_COMMENT_PHPEND : "?>" > : DEFAULT
345 }
346
347 <IN_FORMAL_COMMENT>
348 SPECIAL_TOKEN :
349 {
350   <FORMAL_COMMENT: "*/" > : PHPPARSING
351 }
352
353 <IN_MULTI_LINE_COMMENT>
354 SPECIAL_TOKEN :
355 {
356   <MULTI_LINE_COMMENT: "*/" > : PHPPARSING
357 }
358
359 <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
360 MORE :
361 {
362   < ~[] >
363 }
364
365 /* KEYWORDS */
366 <PHPPARSING> TOKEN :
367 {
368   <CLASS    : "class">
369 | <FUNCTION : "function">
370 | <VAR      : "var">
371 | <IF       : "if">
372 | <ELSEIF   : "elseif">
373 | <ELSE     : "else">
374 | <ARRAY    : "array">
375 | <BREAK    : "break">
376 | <LIST     : "list">
377 }
378
379 /* LANGUAGE CONSTRUCT */
380 <PHPPARSING> TOKEN :
381 {
382   <PRINT              : "print">
383 | <ECHO               : "echo">
384 | <INCLUDE            : "include">
385 | <REQUIRE            : "require">
386 | <INCLUDE_ONCE       : "include_once">
387 | <REQUIRE_ONCE       : "require_once">
388 | <GLOBAL             : "global">
389 | <STATIC             : "static">
390 | <CLASSACCESS        : "->">
391 | <STATICCLASSACCESS  : "::">
392 | <ARRAYASSIGN        : "=>">
393 }
394
395 /* RESERVED WORDS AND LITERALS */
396
397 <PHPPARSING> TOKEN :
398 {
399   <CASE     : "case">
400 | <CONST    : "const">
401 | <CONTINUE : "continue">
402 | <_DEFAULT : "default">
403 | <DO       : "do">
404 | <EXTENDS  : "extends">
405 | <FOR      : "for">
406 | <GOTO     : "goto">
407 | <NEW      : "new">
408 | <NULL     : "null">
409 | <RETURN   : "return">
410 | <SUPER    : "super">
411 | <SWITCH   : "switch">
412 | <THIS     : "this">
413 | <TRUE     : "true">
414 | <FALSE    : "false">
415 | <WHILE    : "while">
416 | <ENDWHILE : "endwhile">
417 | <ENDSWITCH: "endswitch">
418 | <ENDIF    : "endif">
419 | <ENDFOR   : "endfor">
420 | <FOREACH  : "foreach">
421 | <AS       : "as" >
422 }
423
424 /* TYPES */
425 <PHPPARSING> TOKEN :
426 {
427   <STRING  : "string">
428 | <OBJECT  : "object">
429 | <BOOL    : "bool">
430 | <BOOLEAN : "boolean">
431 | <REAL    : "real">
432 | <DOUBLE  : "double">
433 | <FLOAT   : "float">
434 | <INT     : "int">
435 | <INTEGER : "integer">
436 }
437
438 <PHPPARSING> TOKEN :
439 {
440   <_ORL  : "OR">
441 | <_ANDL : "AND">
442 }
443
444 /* LITERALS */
445 <PHPPARSING> TOKEN :
446 {
447   < INTEGER_LITERAL:
448         <DECIMAL_LITERAL> (["l","L"])?
449       | <HEX_LITERAL> (["l","L"])?
450       | <OCTAL_LITERAL> (["l","L"])?
451   >
452 |
453   < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
454 |
455   < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
456 |
457   < #OCTAL_LITERAL: "0" (["0"-"7"])* >
458 |
459   < FLOATING_POINT_LITERAL:
460         (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
461       | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
462       | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
463       | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
464   >
465 |
466   < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
467 |
468   < STRING_LITERAL: (<STRING_1> | <STRING_2> | <STRING_3>)>
469 |    < STRING_1:
470       "\""
471       (
472           ~["\"","{","}"]
473         | "\\\""
474         | "\\"
475         | "{" ~["\""] "}"
476       )*
477       "\""
478     >
479 |    < STRING_2:
480       "'"
481       (
482          ~["'"]
483        | "\\'"
484       )*
485
486       "'"
487     >
488 |   < STRING_3:
489       "`"
490       (
491         ~["`"]
492       | "\\`"
493       )*
494       "`"
495     >
496 }
497
498 /* IDENTIFIERS */
499
500 <PHPPARSING> TOKEN :
501 {
502   < IDENTIFIER: (<LETTER>|<SPECIAL>) (<LETTER>|<DIGIT>|<SPECIAL>)* >
503 |
504   < #LETTER:
505       ["a"-"z"] | ["A"-"Z"]
506   >
507 |
508   < #DIGIT:
509       ["0"-"9"]
510   >
511 |
512   < #SPECIAL:
513     "_" | ["\u007f"-"\u00ff"]
514   >
515 }
516
517 /* SEPARATORS */
518
519 <PHPPARSING> TOKEN :
520 {
521   <LPAREN    : "(">
522 | <RPAREN    : ")">
523 | <LBRACE    : "{">
524 | <RBRACE    : "}">
525 | <LBRACKET  : "[">
526 | <RBRACKET  : "]">
527 | <SEMICOLON : ";">
528 | <COMMA     : ",">
529 | <DOT       : ".">
530 }
531
532
533 /* COMPARATOR */
534 <PHPPARSING> TOKEN :
535 {
536   <GT                 : ">">
537 | <LT                 : "<">
538 | <EQ                 : "==">
539 | <LE                 : "<=">
540 | <GE                 : ">=">
541 | <NE                 : "!=">
542 | <DIF                : "<>">
543 | <BANGDOUBLEEQUAL    : "!==">
544 | <TRIPLEEQUAL        : "===">
545 }
546
547 /* ASSIGNATION */
548 <PHPPARSING> TOKEN :
549 {
550   <ASSIGN             : "=">
551 | <PLUSASSIGN         : "+=">
552 | <MINUSASSIGN        : "-=">
553 | <STARASSIGN         : "*=">
554 | <SLASHASSIGN        : "/=">
555 | <ANDASSIGN          : "&=">
556 | <ORASSIGN           : "|=">
557 | <XORASSIGN          : "^=">
558 | <DOTASSIGN          : ".=">
559 | <REMASSIGN          : "%=">
560 | <TILDEEQUAL         : "~=">
561 }
562
563 /* OPERATORS */
564 <PHPPARSING> TOKEN :
565 {
566   <AT                 : "@">
567 | <DOLLAR             : "$">
568 | <BANG               : "!">
569 | <TILDE              : "~">
570 | <HOOK               : "?">
571 | <COLON              : ":">
572 | <SC_OR              : "||">
573 | <SC_AND             : "&&">
574 | <INCR               : "++">
575 | <DECR               : "--">
576 | <PLUS               : "+">
577 | <MINUS              : "-">
578 | <STAR               : "*">
579 | <SLASH              : "/">
580 | <BIT_AND            : "&">
581 | <BIT_OR             : "|">
582 | <XOR                : "^">
583 | <REM                : "%">
584 | <LSHIFT             : "<<">
585 | <RSIGNEDSHIFT       : ">>">
586 | <RUNSIGNEDSHIFT     : ">>>">
587 | <LSHIFTASSIGN       : "<<=">
588 | <RSIGNEDSHIFTASSIGN : ">>=">
589 }
590
591 <PHPPARSING> TOKEN :
592 {
593   < DOLLAR_ID: <DOLLAR> <IDENTIFIER>  >
594 }
595
596 void phpTest() :
597 {}
598 {
599   Php()
600   <EOF>
601 }
602
603 void phpFile() :
604 {}
605 {
606   try {
607     (PhpBlock())*
608     <EOF>
609   } catch (TokenMgrError e) {
610     PHPeclipsePlugin.log(e);
611     errorStart   = SimpleCharStream.getPosition();
612     errorEnd     = errorStart + 1;
613     errorMessage = e.getMessage();
614     errorLevel   = ERROR;
615     throw generateParseException();
616   }
617 }
618
619 /**
620  * A php block is a <?= expression [;]?>
621  * or <?php somephpcode ?>
622  * or <? somephpcode ?>
623  */
624 void PhpBlock() :
625 {
626   final int start = jj_input_stream.getPosition();
627 }
628 {
629   phpEchoBlock()
630 |
631   [ <PHPSTARTLONG>
632     | <PHPSTARTSHORT>
633     {try {
634       setMarker(fileToParse,
635                 "You should use '<?php' instead of '<?' it will avoid some problems with XML",
636                 start,
637                 jj_input_stream.getPosition(),
638                 INFO,
639                 "Line " + token.beginLine);
640     } catch (CoreException e) {
641       PHPeclipsePlugin.log(e);
642     }}
643   ]
644   Php()
645   try {
646     <PHPEND>
647   } catch (ParseException e) {
648     errorMessage = "'?>' expected";
649     errorLevel   = ERROR;
650     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
651     errorEnd   = jj_input_stream.getPosition() + 1;
652     throw e;
653   }
654 }
655
656 void phpEchoBlock() :
657 {}
658 {
659   <PHPECHOSTART> Expression() [ <SEMICOLON> ] <PHPEND>
660 }
661
662 void Php() :
663 {}
664 {
665   (BlockStatement())*
666 }
667
668 void ClassDeclaration() :
669 {
670   final PHPClassDeclaration classDeclaration;
671   final Token className;
672   final int pos;
673 }
674 {
675   <CLASS>
676   try {
677     {pos = jj_input_stream.getPosition();}
678     className = <IDENTIFIER>
679   } catch (ParseException e) {
680     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected";
681     errorLevel   = ERROR;
682     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
683     errorEnd     = jj_input_stream.getPosition() + 1;
684     throw e;
685   }
686   [
687     <EXTENDS>
688     try {
689       <IDENTIFIER>
690     } catch (ParseException e) {
691       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected";
692       errorLevel   = ERROR;
693       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
694       errorEnd   = jj_input_stream.getPosition() + 1;
695       throw e;
696     }
697   ]
698   {
699     if (currentSegment != null) {
700       classDeclaration = new PHPClassDeclaration(currentSegment,className.image,pos);
701       currentSegment.add(classDeclaration);
702       currentSegment = classDeclaration;
703     }
704   }
705   ClassBody()
706   {
707     if (currentSegment != null) {
708       currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
709     }
710   }
711 }
712
713 void ClassBody() :
714 {}
715 {
716   try {
717     <LBRACE>
718   } catch (ParseException e) {
719     errorMessage = "unexpected token : '"+ e.currentToken.next.image + "', '{' expected";
720     errorLevel   = ERROR;
721     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
722     errorEnd   = jj_input_stream.getPosition() + 1;
723     throw e;
724   }
725   ( ClassBodyDeclaration() )*
726   try {
727     <RBRACE>
728   } catch (ParseException e) {
729     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', 'var', 'function' or '}' expected";
730     errorLevel   = ERROR;
731     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
732     errorEnd   = jj_input_stream.getPosition() + 1;
733     throw e;
734   }
735 }
736
737 /**
738  * A class can contain only methods and fields.
739  */
740 void ClassBodyDeclaration() :
741 {}
742 {
743   MethodDeclaration()
744 | FieldDeclaration()
745 }
746
747 /**
748  * A class field declaration : it's var VariableDeclarator() (, VariableDeclarator())*;.
749  */
750 void FieldDeclaration() :
751 {
752   PHPVarDeclaration variableDeclaration;
753 }
754 {
755   <VAR> variableDeclaration = VariableDeclarator()
756   {
757     outlineInfo.addVariable(variableDeclaration.getVariable().getName());
758     if (currentSegment != null) {
759       currentSegment.add(variableDeclaration);
760     }
761   }
762   ( <COMMA>
763       variableDeclaration = VariableDeclarator()
764       {
765       if (currentSegment != null) {
766         currentSegment.add(variableDeclaration);
767       }
768       }
769   )*
770   try {
771     <SEMICOLON>
772   } catch (ParseException e) {
773     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected after variable declaration";
774     errorLevel   = ERROR;
775     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
776     errorEnd   = jj_input_stream.getPosition() + 1;
777     throw e;
778   }
779 }
780
781 PHPVarDeclaration VariableDeclarator() :
782 {
783   final String varName, varValue;
784   final int pos = jj_input_stream.getPosition();
785 }
786 {
787   varName = VariableDeclaratorId()
788   [
789     <ASSIGN>
790     try {
791       varValue = VariableInitializer()
792       {return new PHPVarDeclaration(currentSegment,varName,pos,varValue);}
793     } catch (ParseException e) {
794       errorMessage = "Literal expression expected in variable initializer";
795       errorLevel   = ERROR;
796       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
797       errorEnd   = jj_input_stream.getPosition() + 1;
798       throw e;
799     }
800   ]
801   {return new PHPVarDeclaration(currentSegment,varName,pos);}
802 }
803
804 String VariableDeclaratorId() :
805 {
806   String expr;
807   final StringBuffer buff = new StringBuffer();
808 }
809 {
810   try {
811     expr = Variable()   {buff.append(expr);}
812     ( LOOKAHEAD(2)
813       expr = VariableSuffix() {buff.append(expr);}
814     )*
815     {return buff.toString();}
816   } catch (ParseException e) {
817     errorMessage = "'$' expected for variable identifier";
818     errorLevel   = ERROR;
819     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
820     errorEnd   = jj_input_stream.getPosition() + 1;
821     throw e;
822   }
823 }
824
825 String Variable():
826 {
827   String expr = null;
828   final Token token;
829 }
830 {
831   token = <DOLLAR_ID> [<LBRACE> expr = Expression() <RBRACE>]
832   {
833     if (expr == null && !assigning) {
834       if (currentFunction != null) {
835         PHPVarDeclaration var = currentFunction.getParameter(token.image.substring(1));
836         if (var != null) {
837           var.getVariable().setUsed(true);
838         }
839       }
840       return token.image.substring(1);
841     }
842     return token + "{" + expr + "}";
843   }
844 |
845   <DOLLAR> expr = VariableName()
846   {return expr;}
847 }
848
849 String VariableName():
850 {
851 String expr = null;
852 final Token token;
853 }
854 {
855   <LBRACE> expr = Expression() <RBRACE>
856   {return "{"+expr+"}";}
857 |
858   token = <IDENTIFIER> [<LBRACE> expr = Expression() <RBRACE>]
859   {
860     if (expr == null) {
861       if (currentFunction != null) {
862         PHPVarDeclaration var = currentFunction.getParameter(token.image);
863         if (var != null) {
864           var.getVariable().setUsed(true);
865         }
866       }
867       return token.image;
868     }
869     return token + "{" + expr + "}";
870   }
871 |
872   <DOLLAR> expr = VariableName()
873   {
874     if (currentFunction != null) {
875       PHPVarDeclaration var = currentFunction.getParameter(expr);
876       if (var != null) {
877         var.getVariable().setUsed(true);
878       }
879     }
880     return "$" + expr;
881   }
882 |
883   token = <DOLLAR_ID>
884   {
885     if (currentFunction != null) {
886       PHPVarDeclaration var = currentFunction.getParameter(token.image.substring(1));
887       if (var != null) {
888         var.getVariable().setUsed(true);
889       }
890     }
891     return token.image + expr;
892   }
893 /*|      pas besoin ?
894   token = <DOLLAR_ID> [expr = VariableName()]
895   {
896   if (expr == null) {
897     return token.image;
898   }
899   return token.image + expr;
900   }*/
901 }
902
903 String VariableInitializer() :
904 {
905   final String expr;
906   final Token token;
907 }
908 {
909   expr = Literal()
910   {return expr;}
911 |
912   <MINUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
913   {return "-" + token.image;}
914 |
915   <PLUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
916   {return "+" + token.image;}
917 |
918   expr = ArrayDeclarator()
919   {return expr;}
920 |
921   token = <IDENTIFIER>
922   {return token.image;}
923 }
924
925 String ArrayVariable() :
926 {
927 String expr;
928 final StringBuffer buff = new StringBuffer();
929 }
930 {
931   expr = Expression()
932   {buff.append(expr);}
933    [<ARRAYASSIGN> expr = Expression()
934    {buff.append("=>").append(expr);}]
935   {return buff.toString();}
936 }
937
938 String ArrayInitializer() :
939 {
940 String expr;
941 final StringBuffer buff = new StringBuffer("(");
942 }
943 {
944   <LPAREN> [ expr = ArrayVariable()
945             {buff.append(expr);}
946             ( LOOKAHEAD(2) <COMMA> expr = ArrayVariable()
947             {buff.append(",").append(expr);}
948             )*
949            ]
950            [<COMMA> {buff.append(",");}]
951   <RPAREN>
952   {
953     buff.append(")");
954     return buff.toString();
955   }
956 }
957
958 /**
959  * A Method Declaration.
960  * <b>function</b> MetodDeclarator() Block()
961  */
962 void MethodDeclaration() :
963 {
964   final PHPFunctionDeclaration functionDeclaration;
965   Token functionToken;
966 }
967 {
968   functionToken = <FUNCTION>
969   try {
970     functionDeclaration = MethodDeclarator()
971     {outlineInfo.addVariable(functionDeclaration.getName());}
972   } catch (ParseException e) {
973     if (errorMessage != null) {
974       throw e;
975     }
976     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
977     errorLevel   = ERROR;
978     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
979     errorEnd   = jj_input_stream.getPosition() + 1;
980     throw e;
981   }
982   {
983     if (currentSegment != null) {
984       currentSegment.add(functionDeclaration);
985       currentSegment = functionDeclaration;
986     }
987     currentFunction = functionDeclaration;
988   }
989   Block()
990   {
991     Hashtable parameters = currentFunction.getParameters();
992     Enumeration vars = parameters.elements();
993     while (vars.hasMoreElements()) {
994       PHPVarDeclaration o = (PHPVarDeclaration) vars.nextElement();
995       if (!o.getVariable().isUsed()) {
996         try {
997           setMarker(fileToParse,
998                     "Parameter "+o.getVariable().getName()+" is never used in function",
999                     functionToken.beginLine,
1000                     WARNING,
1001                     "Line " + token.beginLine);
1002         } catch (CoreException e) {
1003           PHPeclipsePlugin.log(e);
1004         }
1005       }
1006     }
1007     currentFunction = null;
1008     if (currentSegment != null) {
1009       currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
1010     }
1011   }
1012 }
1013
1014 /**
1015  * A MethodDeclarator.
1016  * [&] IDENTIFIER(parameters ...).
1017  * @return a function description for the outline
1018  */
1019 PHPFunctionDeclaration MethodDeclarator() :
1020 {
1021   final Token identifier;
1022   final StringBuffer methodDeclaration = new StringBuffer();
1023   final Hashtable formalParameters;
1024   final int pos = jj_input_stream.getPosition();
1025 }
1026 {
1027   [ <BIT_AND> {methodDeclaration.append("&");} ]
1028   identifier = <IDENTIFIER>
1029   formalParameters = FormalParameters()
1030   {
1031     methodDeclaration.append(identifier);
1032     return new PHPFunctionDeclaration(currentSegment,methodDeclaration.toString(),pos,formalParameters);
1033   }
1034 }
1035
1036 /**
1037  * FormalParameters follows method identifier.
1038  * (FormalParameter())
1039  */
1040 Hashtable FormalParameters() :
1041 {
1042   String expr;
1043   final StringBuffer buff = new StringBuffer("(");
1044   PHPVarDeclaration var;
1045   final Hashtable parameters = new Hashtable();
1046 }
1047 {
1048   try {
1049   <LPAREN>
1050   } catch (ParseException e) {
1051     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected after function identifier";
1052     errorLevel   = ERROR;
1053     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1054     errorEnd   = jj_input_stream.getPosition() + 1;
1055     throw e;
1056   }
1057             [ var = FormalParameter()
1058               {parameters.put(var.getVariable().getName(),var);}
1059               (
1060                 <COMMA> var = FormalParameter()
1061                 {parameters.put(var.getVariable().getName(),var);}
1062               )*
1063             ]
1064   try {
1065     <RPAREN>
1066   } catch (ParseException e) {
1067     errorMessage = "')' expected";
1068     errorLevel   = ERROR;
1069     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1070     errorEnd   = jj_input_stream.getPosition() + 1;
1071     throw e;
1072   }
1073  {return parameters;}
1074 }
1075
1076 /**
1077  * A formal parameter.
1078  * $varname[=value] (,$varname[=value])
1079  */
1080 PHPVarDeclaration FormalParameter() :
1081 {
1082   final PHPVarDeclaration variableDeclaration;
1083   Token token = null;
1084 }
1085 {
1086   [token = <BIT_AND>] variableDeclaration = VariableDeclarator()
1087   {
1088     if (token != null) {
1089       variableDeclaration.getVariable().setReference(true);
1090     }
1091     return variableDeclaration;
1092   }
1093 }
1094
1095 String Type() :
1096 {}
1097 {
1098   <STRING>  {return "string";}
1099 | <BOOL>    {return "bool";}
1100 | <BOOLEAN> {return "boolean";}
1101 | <REAL>    {return "real";}
1102 | <DOUBLE>  {return "double";}
1103 | <FLOAT>   {return "float";}
1104 | <INT>     {return "int";}
1105 | <INTEGER> {return "integer";}
1106 | <OBJECT>  {return "object";}
1107 }
1108
1109 String Expression() :
1110 {
1111   final String expr;
1112   final String assignOperator;
1113   final String expr2;
1114 }
1115 {
1116   expr = PrintExpression()       {return expr;}
1117 | expr = ListExpression()        {return expr;}
1118 | LOOKAHEAD(varAssignation())
1119   expr = varAssignation()        {return expr;}
1120 | expr = ConditionalExpression() {return expr;}
1121 }
1122
1123 /**
1124  * A Variable assignation.
1125  * varName (an assign operator) any expression
1126  */
1127 String varAssignation() :
1128 {
1129   String varName,assignOperator,expr2;
1130   PHPVarDeclaration variable;
1131   final int pos = SimpleCharStream.getPosition();
1132 }
1133 {
1134   varName = VariableDeclaratorId()
1135   assignOperator = AssignmentOperator()
1136     try {
1137       expr2 = Expression()
1138     } catch (ParseException e) {
1139       if (errorMessage != null) {
1140         throw e;
1141       }
1142       errorMessage = "expression expected";
1143       errorLevel   = ERROR;
1144       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1145       errorEnd   = jj_input_stream.getPosition() + 1;
1146       throw e;
1147     }
1148     {return varName + assignOperator + expr2;}
1149 }
1150
1151 String AssignmentOperator() :
1152 {}
1153 {
1154   <ASSIGN>             {return "=";}
1155 | <STARASSIGN>         {return "*=";}
1156 | <SLASHASSIGN>        {return "/=";}
1157 | <REMASSIGN>          {return "%=";}
1158 | <PLUSASSIGN>         {return "+=";}
1159 | <MINUSASSIGN>        {return "-=";}
1160 | <LSHIFTASSIGN>       {return "<<=";}
1161 | <RSIGNEDSHIFTASSIGN> {return ">>=";}
1162 | <ANDASSIGN>          {return "&=";}
1163 | <XORASSIGN>          {return "|=";}
1164 | <ORASSIGN>           {return "|=";}
1165 | <DOTASSIGN>          {return ".=";}
1166 | <TILDEEQUAL>         {return "~=";}
1167 }
1168
1169 String ConditionalExpression() :
1170 {
1171   final String expr;
1172   String expr2 = null;
1173   String expr3 = null;
1174 }
1175 {
1176   expr = ConditionalOrExpression() [ <HOOK> expr2 = Expression() <COLON> expr3 = ConditionalExpression() ]
1177 {
1178   if (expr3 == null) {
1179     return expr;
1180   } else {
1181     return expr + "?" + expr2 + ":" + expr3;
1182   }
1183 }
1184 }
1185
1186 String ConditionalOrExpression() :
1187 {
1188   String expr;
1189   Token operator;
1190   final StringBuffer buff = new StringBuffer();
1191 }
1192 {
1193   expr = ConditionalAndExpression()
1194   {buff.append(expr);}
1195   (
1196     (operator = <SC_OR> | operator = <_ORL>) expr = ConditionalAndExpression()
1197     {
1198       buff.append(operator.image);
1199       buff.append(expr);
1200     }
1201   )*
1202   {
1203     return buff.toString();
1204   }
1205 }
1206
1207 String ConditionalAndExpression() :
1208 {
1209   String expr;
1210   Token operator;
1211   final StringBuffer buff = new StringBuffer();
1212 }
1213 {
1214   expr = ConcatExpression()
1215   {buff.append(expr);}
1216   (
1217   (operator = <SC_AND> | operator = <_ANDL>) expr = ConcatExpression()
1218     {
1219       buff.append(operator.image);
1220       buff.append(expr);
1221     }
1222   )*
1223   {return buff.toString();}
1224 }
1225
1226 String ConcatExpression() :
1227 {
1228   String expr;
1229   final StringBuffer buff = new StringBuffer();
1230 }
1231 {
1232   expr = InclusiveOrExpression()
1233   {buff.append(expr);}
1234   (
1235   <DOT> expr = InclusiveOrExpression()
1236   {buff.append(".").append(expr);}
1237   )*
1238   {return buff.toString();}
1239 }
1240
1241 String InclusiveOrExpression() :
1242 {
1243   String expr;
1244   final StringBuffer buff = new StringBuffer();
1245 }
1246 {
1247   expr = ExclusiveOrExpression()
1248   {buff.append(expr);}
1249   (
1250   <BIT_OR> expr = ExclusiveOrExpression()
1251   {buff.append("|").append(expr);}
1252   )*
1253   {return buff.toString();}
1254 }
1255
1256 String ExclusiveOrExpression() :
1257 {
1258   String expr;
1259   final StringBuffer buff = new StringBuffer();
1260 }
1261 {
1262   expr = AndExpression()
1263   {
1264     buff.append(expr);
1265   }
1266   (
1267     <XOR> expr = AndExpression()
1268   {
1269     buff.append("^");
1270     buff.append(expr);
1271   }
1272   )*
1273   {
1274     return buff.toString();
1275   }
1276 }
1277
1278 String AndExpression() :
1279 {
1280   String expr;
1281   final StringBuffer buff = new StringBuffer();
1282 }
1283 {
1284   expr = EqualityExpression()
1285   {
1286     buff.append(expr);
1287   }
1288   (
1289     <BIT_AND> expr = EqualityExpression()
1290   {
1291     buff.append("&").append(expr);
1292   }
1293   )*
1294   {return buff.toString();}
1295 }
1296
1297 String EqualityExpression() :
1298 {
1299   String expr;
1300   Token operator;
1301   final StringBuffer buff = new StringBuffer();
1302 }
1303 {
1304   expr = RelationalExpression()
1305   {buff.append(expr);}
1306   (
1307   (   operator = <EQ>
1308     | operator = <DIF>
1309     | operator = <NE>
1310     | operator = <BANGDOUBLEEQUAL>
1311     | operator = <TRIPLEEQUAL>
1312   )
1313   try {
1314     expr = RelationalExpression()
1315   } catch (ParseException e) {
1316     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected after '"+operator.image+"'";
1317     errorLevel   = ERROR;
1318     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1319     errorEnd   = jj_input_stream.getPosition() + 1;
1320     throw e;
1321   }
1322   {
1323     buff.append(operator.image);
1324     buff.append(expr);
1325   }
1326   )*
1327   {return buff.toString();}
1328 }
1329
1330 String RelationalExpression() :
1331 {
1332   String expr;
1333   Token operator;
1334   final StringBuffer buff = new StringBuffer();
1335 }
1336 {
1337   expr = ShiftExpression()
1338   {buff.append(expr);}
1339   (
1340   ( operator = <LT> | operator = <GT> | operator = <LE> | operator = <GE> ) expr = ShiftExpression()
1341   {buff.append(operator.image).append(expr);}
1342   )*
1343   {return buff.toString();}
1344 }
1345
1346 String ShiftExpression() :
1347 {
1348   String expr;
1349   Token operator;
1350   final StringBuffer buff = new StringBuffer();
1351 }
1352 {
1353   expr = AdditiveExpression()
1354   {buff.append(expr);}
1355   (
1356   (operator = <LSHIFT> | operator = <RSIGNEDSHIFT> | operator = <RUNSIGNEDSHIFT> ) expr = AdditiveExpression()
1357   {
1358     buff.append(operator.image);
1359     buff.append(expr);
1360   }
1361   )*
1362   {return buff.toString();}
1363 }
1364
1365 String AdditiveExpression() :
1366 {
1367   String expr;
1368   Token operator;
1369   final StringBuffer buff = new StringBuffer();
1370 }
1371 {
1372   expr = MultiplicativeExpression()
1373   {buff.append(expr);}
1374   (
1375    ( operator = <PLUS> | operator = <MINUS> ) expr = MultiplicativeExpression()
1376   {
1377     buff.append(operator.image);
1378     buff.append(expr);
1379   }
1380    )*
1381   {return buff.toString();}
1382 }
1383
1384 String MultiplicativeExpression() :
1385 {
1386   String expr;
1387   Token operator;
1388   final StringBuffer buff = new StringBuffer();}
1389 {
1390   try {
1391     expr = UnaryExpression()
1392   } catch (ParseException e) {
1393     errorMessage = "unexpected token '"+e.currentToken.next.image+"'";
1394     errorLevel   = ERROR;
1395     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1396     errorEnd   = jj_input_stream.getPosition() + 1;
1397     throw e;
1398   }
1399   {buff.append(expr);}
1400   (
1401     ( operator = <STAR> | operator = <SLASH> | operator = <REM> ) expr = UnaryExpression()
1402     {
1403       buff.append(operator.image);
1404       buff.append(expr);
1405     }
1406   )*
1407   {return buff.toString();}
1408 }
1409
1410 /**
1411  * An unary expression starting with @, & or nothing
1412  */
1413 String UnaryExpression() :
1414 {
1415   final String expr;
1416   final Token token;
1417   final StringBuffer buff = new StringBuffer();
1418 }
1419 {
1420   token = <BIT_AND> expr = UnaryExpressionNoPrefix()
1421   {
1422     if (token == null) {
1423       return expr;
1424     }
1425     return token.image + expr;
1426   }
1427 | (<AT> {buff.append("@");})*
1428   expr = UnaryExpressionNoPrefix()
1429   {return buff.append(expr).toString();}
1430 }
1431
1432 String UnaryExpressionNoPrefix() :
1433 {
1434   final String expr;
1435   final Token token;
1436 }
1437 {
1438   ( token = <PLUS> | token = <MINUS> ) expr = UnaryExpression()
1439   {
1440     return token.image + expr;
1441   }
1442 |
1443   expr = PreIncDecExpression()
1444   {return expr;}
1445 |
1446   expr = UnaryExpressionNotPlusMinus()
1447   {return expr;}
1448 }
1449
1450
1451 String PreIncDecExpression() :
1452 {
1453 final String expr;
1454 final Token token;
1455 }
1456 {
1457   (token = <INCR> | token = <DECR>) expr = PrimaryExpression()
1458   {return token.image + expr;}
1459 }
1460
1461 String UnaryExpressionNotPlusMinus() :
1462 {
1463   final String expr;
1464 }
1465 {
1466   <BANG> expr = UnaryExpression() {return "!" + expr;}
1467 | LOOKAHEAD( <LPAREN> (Type() | <ARRAY>) <RPAREN> )
1468   expr = CastExpression()         {return expr;}
1469 | expr = PostfixExpression()      {return expr;}
1470 | expr = Literal()                {return expr;}
1471 | <LPAREN> expr = Expression()
1472   try {
1473     <RPAREN>
1474   } catch (ParseException e) {
1475     errorMessage = "')' expected";
1476     errorLevel   = ERROR;
1477     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1478     errorEnd     = jj_input_stream.getPosition() + 1;
1479     throw e;
1480   }
1481   {return "("+expr+")";}
1482 }
1483
1484 String CastExpression() :
1485 {
1486 final String type, expr;
1487 }
1488 {
1489   <LPAREN> (type = Type() | <ARRAY> {type = "array";}) <RPAREN> expr = UnaryExpression()
1490   {return "(" + type + ")" + expr;}
1491 }
1492
1493 String PostfixExpression() :
1494 {
1495   final String expr;
1496   Token operator = null;
1497 }
1498 {
1499   expr = PrimaryExpression() [ operator = <INCR> | operator = <DECR> ]
1500   {
1501     if (operator == null) {
1502       return expr;
1503     }
1504     return expr + operator.image;
1505   }
1506 }
1507
1508 String PrimaryExpression() :
1509 {
1510   final Token identifier;
1511   String expr;
1512   final StringBuffer buff = new StringBuffer();
1513 }
1514 {
1515   LOOKAHEAD(2)
1516   identifier = <IDENTIFIER> <STATICCLASSACCESS> expr = ClassIdentifier()
1517   {buff.append(identifier.image).append("::").append(expr);}
1518   (
1519   expr = PrimarySuffix()
1520   {buff.append(expr);}
1521   )*
1522   {return buff.toString();}
1523 |
1524   expr = PrimaryPrefix()  {buff.append(expr);}
1525   ( expr = PrimarySuffix()  {buff.append(expr);} )*
1526   {return buff.toString();}
1527 |
1528   expr = ArrayDeclarator()
1529   {return "array" + expr;}
1530 }
1531
1532 String ArrayDeclarator() :
1533 {
1534   final String expr;
1535 }
1536 {
1537   <ARRAY> expr = ArrayInitializer()
1538   {return "array" + expr;}
1539 }
1540
1541 String PrimaryPrefix() :
1542 {
1543   final String expr;
1544   final Token token;
1545 }
1546 {
1547   token = <IDENTIFIER>           {return token.image;}
1548 | <NEW> expr = ClassIdentifier() {return "new " + expr;}
1549 | expr = VariableDeclaratorId()  {return expr;}
1550 }
1551
1552 String classInstantiation() :
1553 {
1554   String expr;
1555   final StringBuffer buff = new StringBuffer("new ");
1556 }
1557 {
1558   <NEW> expr = ClassIdentifier()
1559   {buff.append(expr);}
1560   [
1561     expr = PrimaryExpression()
1562     {buff.append(expr);}
1563   ]
1564   {return buff.toString();}
1565 }
1566
1567 String ClassIdentifier():
1568 {
1569   final String expr;
1570   final Token token;
1571 }
1572 {
1573   token = <IDENTIFIER>          {return token.image;}
1574 | expr = VariableDeclaratorId() {return expr;}
1575 }
1576
1577 String PrimarySuffix() :
1578 {
1579   final String expr;
1580 }
1581 {
1582   expr = Arguments()      {return expr;}
1583 | expr = VariableSuffix() {return expr;}
1584 }
1585
1586 String VariableSuffix() :
1587 {
1588   String expr = null;
1589 }
1590 {
1591   <CLASSACCESS>
1592   try {
1593     expr = VariableName()
1594   } catch (ParseException e) {
1595     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function call or field access expected";
1596     errorLevel   = ERROR;
1597     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1598     errorEnd   = jj_input_stream.getPosition() + 1;
1599     throw e;
1600   }
1601   {return "->" + expr;}
1602 |
1603   <LBRACKET> [ expr = Expression() | expr = Type() ]  //Not good
1604   try {
1605     <RBRACKET>
1606   } catch (ParseException e) {
1607     errorMessage = "']' expected";
1608     errorLevel   = ERROR;
1609     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1610     errorEnd   = jj_input_stream.getPosition() + 1;
1611     throw e;
1612   }
1613   {
1614     if(expr == null) {
1615       return "[]";
1616     }
1617     return "[" + expr + "]";
1618   }
1619 }
1620
1621 String Literal() :
1622 {
1623   final String expr;
1624   final Token token;
1625 }
1626 {
1627   token = <INTEGER_LITERAL>        {return token.image;}
1628 | token = <FLOATING_POINT_LITERAL> {return token.image;}
1629 | token = <STRING_LITERAL>         {return token.image;}
1630 | expr = BooleanLiteral()          {return expr;}
1631 | <NULL>                           {return "null";}
1632 }
1633
1634 String BooleanLiteral() :
1635 {}
1636 {
1637   <TRUE>  {return "true";}
1638 | <FALSE> {return "false";}
1639 }
1640
1641 String Arguments() :
1642 {
1643 String expr = null;
1644 }
1645 {
1646   <LPAREN> [ expr = ArgumentList() ]
1647   try {
1648     <RPAREN>
1649   } catch (ParseException e) {
1650     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list";
1651     errorLevel   = ERROR;
1652     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1653     errorEnd   = jj_input_stream.getPosition() + 1;
1654     throw e;
1655   }
1656   {
1657   if (expr == null) {
1658     return "()";
1659   }
1660   return "(" + expr + ")";
1661   }
1662 }
1663
1664 String ArgumentList() :
1665 {
1666 String expr;
1667 final StringBuffer buff = new StringBuffer();
1668 }
1669 {
1670   expr = Expression()
1671   {buff.append(expr);}
1672   ( <COMMA>
1673       try {
1674         expr = Expression()
1675       } catch (ParseException e) {
1676         errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. An expression expected after a comma in argument list";
1677         errorLevel   = ERROR;
1678         errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1679         errorEnd     = jj_input_stream.getPosition() + 1;
1680         throw e;
1681       }
1682     {buff.append(",").append(expr);}
1683    )*
1684    {return buff.toString();}
1685 }
1686
1687 /**
1688  * A Statement without break.
1689  */
1690 void StatementNoBreak() :
1691 {}
1692 {
1693   LOOKAHEAD(2)
1694   Expression()
1695   try {
1696     <SEMICOLON>
1697   } catch (ParseException e) {
1698     if (e.currentToken.next.kind != 4) {
1699       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1700       errorLevel   = ERROR;
1701       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1702       errorEnd   = jj_input_stream.getPosition() + 1;
1703       throw e;
1704     }
1705   }
1706 | LOOKAHEAD(2)
1707   LabeledStatement()
1708 | Block()
1709 | EmptyStatement()
1710 | StatementExpression()
1711   try {
1712     <SEMICOLON>
1713   } catch (ParseException e) {
1714     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1715     errorLevel   = ERROR;
1716     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1717     errorEnd     = jj_input_stream.getPosition() + 1;
1718     throw e;
1719   }
1720 | SwitchStatement()
1721 | IfStatement()
1722 | WhileStatement()
1723 | DoStatement()
1724 | ForStatement()
1725 | ForeachStatement()
1726 | ContinueStatement()
1727 | ReturnStatement()
1728 | EchoStatement()
1729 | [<AT>] IncludeStatement()
1730 | StaticStatement()
1731 | GlobalStatement()
1732 }
1733
1734 /**
1735  * A Normal statement.
1736  */
1737 void Statement() :
1738 {}
1739 {
1740   StatementNoBreak()
1741 | BreakStatement()
1742 }
1743
1744 /**
1745  * An html block inside a php syntax.
1746  */
1747 void htmlBlock() :
1748 {}
1749 {
1750   <PHPEND> (phpEchoBlock())*
1751   try {
1752     (<PHPSTARTLONG> | <PHPSTARTSHORT>)
1753   } catch (ParseException e) {
1754     errorMessage = "End of file unexpected, '<?php' expected";
1755     errorLevel   = ERROR;
1756     errorStart   = jj_input_stream.getPosition();
1757     errorEnd     = jj_input_stream.getPosition();
1758     throw e;
1759   }
1760 }
1761
1762 /**
1763  * An include statement. It's "include" an expression;
1764  */
1765 void IncludeStatement() :
1766 {
1767   final String expr;
1768   final Token token;
1769   final int pos = jj_input_stream.getPosition();
1770 }
1771 {
1772   (  token = <REQUIRE>
1773    | token = <REQUIRE_ONCE>
1774    | token = <INCLUDE>
1775    | token = <INCLUDE_ONCE> )
1776     try {
1777       expr = Expression()
1778     } catch (ParseException e) {
1779       if (errorMessage != null) {
1780         throw e;
1781       }
1782       errorMessage = "unexpected token '"+ e.currentToken.next.image+"', expression expected";
1783       errorLevel   = ERROR;
1784       errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1785       errorEnd     = jj_input_stream.getPosition() + 1;
1786       throw e;
1787     }
1788   {
1789     if (currentSegment != null) {
1790       currentSegment.add(new PHPReqIncDeclaration(currentSegment, token.image,pos,expr));
1791     }
1792   }
1793   try {
1794     <SEMICOLON>
1795   } catch (ParseException e) {
1796     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1797     errorLevel   = ERROR;
1798     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1799     errorEnd     = jj_input_stream.getPosition() + 1;
1800     throw e;
1801   }
1802 }
1803
1804 String PrintExpression() :
1805 {
1806   final String expr;
1807 }
1808 {
1809   <PRINT> expr = Expression() {return "print " + expr;}
1810 }
1811
1812 String ListExpression() :
1813 {
1814   final StringBuffer buff = new StringBuffer("list(");
1815   String expr;
1816 }
1817 {
1818   <LIST>
1819   try {
1820     <LPAREN>
1821   } catch (ParseException e) {
1822     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
1823     errorLevel   = ERROR;
1824     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1825     errorEnd     = jj_input_stream.getPosition() + 1;
1826     throw e;
1827   }
1828   [
1829     expr = VariableDeclaratorId()
1830     {buff.append(expr);}
1831   ]
1832   (
1833     try {
1834       <COMMA>
1835     } catch (ParseException e) {
1836       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
1837       errorLevel   = ERROR;
1838       errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1839       errorEnd     = jj_input_stream.getPosition() + 1;
1840       throw e;
1841     }
1842     expr = VariableDeclaratorId()
1843     {buff.append(",").append(expr);}
1844   )*
1845   {buff.append(")");}
1846   try {
1847     <RPAREN>
1848   } catch (ParseException e) {
1849     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
1850     errorLevel   = ERROR;
1851     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1852     errorEnd   = jj_input_stream.getPosition() + 1;
1853     throw e;
1854   }
1855   [ <ASSIGN> expr = Expression() {buff.append("(").append(expr);}]
1856   {return buff.toString();}
1857 }
1858
1859 /**
1860  * An echo statement.
1861  * echo anyexpression (, otherexpression)*
1862  */
1863 void EchoStatement() :
1864 {}
1865 {
1866   <ECHO> Expression() (<COMMA> Expression())*
1867   try {
1868     <SEMICOLON>
1869   } catch (ParseException e) {
1870     if (e.currentToken.next.kind != 4) {
1871       errorMessage = "';' expected after 'echo' statement";
1872       errorLevel   = ERROR;
1873       errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1874       errorEnd     = jj_input_stream.getPosition() + 1;
1875       throw e;
1876     }
1877   }
1878 }
1879
1880 void GlobalStatement() :
1881 {
1882    final int pos = jj_input_stream.getPosition();
1883    String expr;
1884 }
1885 {
1886   <GLOBAL>
1887     expr = VariableDeclaratorId()
1888     {if (currentSegment != null) {
1889       currentSegment.add(new PHPGlobalDeclaration(currentSegment, "global",pos,expr));
1890     }}
1891   (<COMMA>
1892     expr = VariableDeclaratorId()
1893     {if (currentSegment != null) {
1894       currentSegment.add(new PHPGlobalDeclaration(currentSegment, "global",pos,expr));
1895     }}
1896   )*
1897   try {
1898     <SEMICOLON>
1899   } catch (ParseException e) {
1900     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
1901     errorLevel   = ERROR;
1902     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1903     errorEnd   = jj_input_stream.getPosition() + 1;
1904     throw e;
1905   }
1906 }
1907
1908 void StaticStatement() :
1909 {}
1910 {
1911   <STATIC> VariableDeclarator() (<COMMA> VariableDeclarator())*
1912   try {
1913     <SEMICOLON>
1914   } catch (ParseException e) {
1915     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
1916     errorLevel   = ERROR;
1917     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1918     errorEnd   = jj_input_stream.getPosition() + 1;
1919     throw e;
1920   }
1921 }
1922
1923 void LabeledStatement() :
1924 {}
1925 {
1926   <IDENTIFIER> <COLON> Statement()
1927 }
1928
1929 void Block() :
1930 {}
1931 {
1932   try {
1933     <LBRACE>
1934   } catch (ParseException e) {
1935     errorMessage = "'{' expected";
1936     errorLevel   = ERROR;
1937     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1938     errorEnd   = jj_input_stream.getPosition() + 1;
1939     throw e;
1940   }
1941   ( BlockStatement() | htmlBlock())*
1942   try {
1943     <RBRACE>
1944   } catch (ParseException e) {
1945     errorMessage = "unexpected token : '"+ e.currentToken.image +"', '}' expected";
1946     errorLevel   = ERROR;
1947     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1948     errorEnd   = jj_input_stream.getPosition() + 1;
1949     throw e;
1950   }
1951 }
1952
1953 void BlockStatement() :
1954 {}
1955 {
1956   Statement()
1957 | ClassDeclaration()
1958 | MethodDeclaration()
1959 }
1960
1961 /**
1962  * A Block statement that will not contain any 'break'
1963  */
1964 void BlockStatementNoBreak() :
1965 {}
1966 {
1967   StatementNoBreak()
1968 | ClassDeclaration()
1969 | MethodDeclaration()
1970 }
1971
1972 void LocalVariableDeclaration() :
1973 {}
1974 {
1975   LocalVariableDeclarator() ( <COMMA> LocalVariableDeclarator() )*
1976 }
1977
1978 void LocalVariableDeclarator() :
1979 {}
1980 {
1981   VariableDeclaratorId() [ <ASSIGN> Expression() ]
1982 }
1983
1984 void EmptyStatement() :
1985 {}
1986 {
1987   <SEMICOLON>
1988 }
1989
1990 void StatementExpression() :
1991 {}
1992 {
1993   PreIncDecExpression()
1994 |
1995   PrimaryExpression()
1996   [ <INCR>
1997   | <DECR>
1998   | AssignmentOperator() Expression() ]
1999 }
2000
2001 void SwitchStatement() :
2002 {
2003   final int pos = jj_input_stream.getPosition();
2004 }
2005 {
2006   <SWITCH>
2007   try {
2008     <LPAREN>
2009   } catch (ParseException e) {
2010     errorMessage = "'(' expected after 'switch'";
2011     errorLevel   = ERROR;
2012     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2013     errorEnd   = jj_input_stream.getPosition() + 1;
2014     throw e;
2015   }
2016   try {
2017     Expression()
2018   } catch (ParseException e) {
2019     if (errorMessage != null) {
2020       throw e;
2021     }
2022     errorMessage = "expression expected";
2023     errorLevel   = ERROR;
2024     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2025     errorEnd   = jj_input_stream.getPosition() + 1;
2026     throw e;
2027   }
2028   try {
2029     <RPAREN>
2030   } catch (ParseException e) {
2031     errorMessage = "')' expected";
2032     errorLevel   = ERROR;
2033     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2034     errorEnd   = jj_input_stream.getPosition() + 1;
2035     throw e;
2036   }
2037   (switchStatementBrace() | switchStatementColon(pos, pos + 6))
2038 }
2039
2040 void switchStatementBrace() :
2041 {}
2042 {
2043   <LBRACE>
2044  ( switchLabel0() )*
2045   try {
2046     <RBRACE>
2047   } catch (ParseException e) {
2048     errorMessage = "'}' expected";
2049     errorLevel   = ERROR;
2050     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2051     errorEnd   = jj_input_stream.getPosition() + 1;
2052     throw e;
2053   }
2054 }
2055 /**
2056  * A Switch statement with : ... endswitch;
2057  * @param start the begin offset of the switch
2058  * @param end the end offset of the switch
2059  */
2060 void switchStatementColon(final int start, final int end) :
2061 {}
2062 {
2063   <COLON>
2064   {try {
2065   setMarker(fileToParse,
2066             "Ugly syntax detected, you should switch () {...} instead of switch (): ... enswitch;",
2067             start,
2068             end,
2069             INFO,
2070             "Line " + token.beginLine);
2071   } catch (CoreException e) {
2072     PHPeclipsePlugin.log(e);
2073   }}
2074   (switchLabel0())*
2075   try {
2076     <ENDSWITCH>
2077   } catch (ParseException e) {
2078     errorMessage = "'endswitch' expected";
2079     errorLevel   = ERROR;
2080     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2081     errorEnd   = jj_input_stream.getPosition() + 1;
2082     throw e;
2083   }
2084   try {
2085     <SEMICOLON>
2086   } catch (ParseException e) {
2087     errorMessage = "';' expected after 'endswitch' keyword";
2088     errorLevel   = ERROR;
2089     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2090     errorEnd   = jj_input_stream.getPosition() + 1;
2091     throw e;
2092   }
2093 }
2094
2095 void switchLabel0() :
2096 {
2097   Token breakToken = null;
2098   final int line;
2099 }
2100 {
2101   line = SwitchLabel()
2102   ( BlockStatementNoBreak() | htmlBlock() )*
2103   [ breakToken = BreakStatement() ]
2104   {
2105     try {
2106       if (breakToken == null) {
2107         setMarker(fileToParse,
2108                   "You should use put a 'break' at the end of your statement",
2109                   line,
2110                   INFO,
2111                   "Line " + line);
2112       }
2113     } catch (CoreException e) {
2114       PHPeclipsePlugin.log(e);
2115     }
2116   }
2117 }
2118
2119 Token BreakStatement() :
2120 {
2121   final Token token;
2122 }
2123 {
2124   token = <BREAK> [ Expression() ]
2125   try {
2126     <SEMICOLON>
2127   } catch (ParseException e) {
2128     errorMessage = "';' expected after 'break' keyword";
2129     errorLevel   = ERROR;
2130     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2131     errorEnd   = jj_input_stream.getPosition() + 1;
2132     throw e;
2133   }
2134   {return token;}
2135 }
2136
2137 int SwitchLabel() :
2138 {
2139   final Token token;
2140 }
2141 {
2142   token = <CASE>
2143   try {
2144     Expression()
2145   } catch (ParseException e) {
2146     if (errorMessage != null) throw e;
2147     errorMessage = "expression expected after 'case' keyword";
2148     errorLevel   = ERROR;
2149     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2150     errorEnd   = jj_input_stream.getPosition() + 1;
2151     throw e;
2152   }
2153   try {
2154     <COLON>
2155   } catch (ParseException e) {
2156     errorMessage = "':' expected after case expression";
2157     errorLevel   = ERROR;
2158     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2159     errorEnd   = jj_input_stream.getPosition() + 1;
2160     throw e;
2161   }
2162   {return token.beginLine;}
2163 |
2164   token = <_DEFAULT>
2165   try {
2166     <COLON>
2167   } catch (ParseException e) {
2168     errorMessage = "':' expected after 'default' keyword";
2169     errorLevel   = ERROR;
2170     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2171     errorEnd   = jj_input_stream.getPosition() + 1;
2172     throw e;
2173   }
2174   {return token.beginLine;}
2175 }
2176
2177 void IfStatement() :
2178 {
2179   final Token token;
2180   final int pos = jj_input_stream.getPosition();
2181 }
2182 {
2183   token = <IF> Condition("if") IfStatement0(pos,pos+token.image.length())
2184 }
2185
2186 void Condition(final String keyword) :
2187 {}
2188 {
2189   try {
2190     <LPAREN>
2191   } catch (ParseException e) {
2192     errorMessage = "'(' expected after " + keyword + " keyword";
2193     errorLevel   = ERROR;
2194     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length();
2195     errorEnd   = errorStart +1;
2196     processParseException(e);
2197   }
2198   Expression()
2199   try {
2200      <RPAREN>
2201   } catch (ParseException e) {
2202     errorMessage = "')' expected after " + keyword + " keyword";
2203     errorLevel   = ERROR;
2204     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2205     errorEnd   = jj_input_stream.getPosition() + 1;
2206     throw e;
2207   }
2208 }
2209
2210 void IfStatement0(final int start,final int end) :
2211 {}
2212 {
2213   <COLON> (Statement() | htmlBlock())* (ElseIfStatementColon())* [ElseStatementColon()]
2214
2215   {try {
2216   setMarker(fileToParse,
2217             "Ugly syntax detected, you should if () {...} instead of if (): ... endif;",
2218             start,
2219             end,
2220             INFO,
2221             "Line " + token.beginLine);
2222   } catch (CoreException e) {
2223     PHPeclipsePlugin.log(e);
2224   }}
2225   try {
2226     <ENDIF>
2227   } catch (ParseException e) {
2228     errorMessage = "'endif' expected";
2229     errorLevel   = ERROR;
2230     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2231     errorEnd   = jj_input_stream.getPosition() + 1;
2232     throw e;
2233   }
2234   try {
2235     <SEMICOLON>
2236   } catch (ParseException e) {
2237     errorMessage = "';' expected after 'endif' keyword";
2238     errorLevel   = ERROR;
2239     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2240     errorEnd   = jj_input_stream.getPosition() + 1;
2241     throw e;
2242   }
2243 |
2244   (Statement() |  htmlBlock())
2245   ( LOOKAHEAD(1) ElseIfStatement() )*
2246   [ LOOKAHEAD(1)
2247     <ELSE>
2248     try {
2249       Statement()
2250     } catch (ParseException e) {
2251       if (errorMessage != null) {
2252         throw e;
2253       }
2254       errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected";
2255       errorLevel   = ERROR;
2256       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2257       errorEnd   = jj_input_stream.getPosition() + 1;
2258       throw e;
2259     }
2260   ]
2261 }
2262
2263 void ElseIfStatementColon() :
2264 {}
2265 {
2266   <ELSEIF> Condition("elseif") <COLON> (Statement() | htmlBlock())*
2267 }
2268
2269 void ElseStatementColon() :
2270 {}
2271 {
2272   <ELSE> <COLON> (Statement() | htmlBlock())*
2273 }
2274
2275 void ElseIfStatement() :
2276 {}
2277 {
2278   <ELSEIF> Condition("elseif") Statement()
2279 }
2280
2281 void WhileStatement() :
2282 {
2283   final Token token;
2284   final int pos = jj_input_stream.getPosition();
2285 }
2286 {
2287   token = <WHILE> Condition("while") WhileStatement0(pos,pos + token.image.length())
2288 }
2289
2290 void WhileStatement0(final int start, final int end) :
2291 {}
2292 {
2293   <COLON> (Statement())*
2294   {try {
2295   setMarker(fileToParse,
2296             "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;",
2297             start,
2298             end,
2299             INFO,
2300             "Line " + token.beginLine);
2301   } catch (CoreException e) {
2302     PHPeclipsePlugin.log(e);
2303   }}
2304   try {
2305     <ENDWHILE>
2306   } catch (ParseException e) {
2307     errorMessage = "'endwhile' expected";
2308     errorLevel   = ERROR;
2309     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2310     errorEnd   = jj_input_stream.getPosition() + 1;
2311     throw e;
2312   }
2313   try {
2314     <SEMICOLON>
2315   } catch (ParseException e) {
2316     errorMessage = "';' expected after 'endwhile' keyword";
2317     errorLevel   = ERROR;
2318     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2319     errorEnd   = jj_input_stream.getPosition() + 1;
2320     throw e;
2321   }
2322 |
2323   Statement()
2324 }
2325
2326 void DoStatement() :
2327 {}
2328 {
2329   <DO> Statement() <WHILE> Condition("while")
2330   try {
2331     <SEMICOLON>
2332   } catch (ParseException e) {
2333     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2334     errorLevel   = ERROR;
2335     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2336     errorEnd   = jj_input_stream.getPosition() + 1;
2337     throw e;
2338   }
2339 }
2340
2341 void ForeachStatement() :
2342 {}
2343 {
2344   <FOREACH>
2345     try {
2346     <LPAREN>
2347   } catch (ParseException e) {
2348     errorMessage = "'(' expected after 'foreach' keyword";
2349     errorLevel   = ERROR;
2350     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2351     errorEnd   = jj_input_stream.getPosition() + 1;
2352     throw e;
2353   }
2354   try {
2355     Variable()
2356   } catch (ParseException e) {
2357     errorMessage = "variable expected";
2358     errorLevel   = ERROR;
2359     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2360     errorEnd   = jj_input_stream.getPosition() + 1;
2361     throw e;
2362   }
2363   ( VariableSuffix() )*
2364   try {
2365     <AS>
2366   } catch (ParseException e) {
2367     errorMessage = "'as' expected";
2368     errorLevel   = ERROR;
2369     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2370     errorEnd   = jj_input_stream.getPosition() + 1;
2371     throw e;
2372   }
2373   try {
2374     Variable()
2375   } catch (ParseException e) {
2376     errorMessage = "variable expected";
2377     errorLevel   = ERROR;
2378     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2379     errorEnd   = jj_input_stream.getPosition() + 1;
2380     throw e;
2381   }
2382   [ <ARRAYASSIGN> Expression() ]
2383   try {
2384     <RPAREN>
2385   } catch (ParseException e) {
2386     errorMessage = "')' expected after 'foreach' keyword";
2387     errorLevel   = ERROR;
2388     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2389     errorEnd   = jj_input_stream.getPosition() + 1;
2390     throw e;
2391   }
2392   try {
2393     Statement()
2394   } catch (ParseException e) {
2395     if (errorMessage != null) throw e;
2396     errorMessage = "statement expected";
2397     errorLevel   = ERROR;
2398     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2399     errorEnd   = jj_input_stream.getPosition() + 1;
2400     throw e;
2401   }
2402 }
2403
2404 void ForStatement() :
2405 {
2406 final Token token;
2407 final int pos = jj_input_stream.getPosition();
2408 }
2409 {
2410   token = <FOR>
2411   try {
2412     <LPAREN>
2413   } catch (ParseException e) {
2414     errorMessage = "'(' expected after 'for' keyword";
2415     errorLevel   = ERROR;
2416     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2417     errorEnd   = jj_input_stream.getPosition() + 1;
2418     throw e;
2419   }
2420      [ ForInit() ] <SEMICOLON> [ Expression() ] <SEMICOLON> [ StatementExpressionList() ] <RPAREN>
2421     (
2422       Statement()
2423     |
2424       <COLON> (Statement())*
2425       {
2426         try {
2427         setMarker(fileToParse,
2428                   "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;",
2429                   pos,
2430                   pos+token.image.length(),
2431                   INFO,
2432                   "Line " + token.beginLine);
2433         } catch (CoreException e) {
2434           PHPeclipsePlugin.log(e);
2435         }
2436       }
2437       try {
2438         <ENDFOR>
2439       } catch (ParseException e) {
2440         errorMessage = "'endfor' expected";
2441         errorLevel   = ERROR;
2442         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2443         errorEnd   = jj_input_stream.getPosition() + 1;
2444         throw e;
2445       }
2446       try {
2447         <SEMICOLON>
2448       } catch (ParseException e) {
2449         errorMessage = "';' expected after 'endfor' keyword";
2450         errorLevel   = ERROR;
2451         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2452         errorEnd   = jj_input_stream.getPosition() + 1;
2453         throw e;
2454       }
2455     )
2456 }
2457
2458 void ForInit() :
2459 {}
2460 {
2461   LOOKAHEAD(LocalVariableDeclaration())
2462   LocalVariableDeclaration()
2463 |
2464   StatementExpressionList()
2465 }
2466
2467 void StatementExpressionList() :
2468 {}
2469 {
2470   StatementExpression() ( <COMMA> StatementExpression() )*
2471 }
2472
2473 void ContinueStatement() :
2474 {}
2475 {
2476   <CONTINUE> [ Expression() ]
2477   try {
2478     <SEMICOLON>
2479   } catch (ParseException e) {
2480     errorMessage = "';' expected after 'continue' statement";
2481     errorLevel   = ERROR;
2482     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2483     errorEnd   = jj_input_stream.getPosition() + 1;
2484     throw e;
2485   }
2486 }
2487
2488 void ReturnStatement() :
2489 {}
2490 {
2491   <RETURN> [ Expression() ]
2492   try {
2493     <SEMICOLON>
2494   } catch (ParseException e) {
2495     errorMessage = "';' expected after 'return' statement";
2496     errorLevel   = ERROR;
2497     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2498     errorEnd   = jj_input_stream.getPosition() + 1;
2499     throw e;
2500   }
2501 }