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