001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package eu.cqse.check.framework.shallowparser.languages.delphi;
018
019import static eu.cqse.check.framework.scanner.ETokenType.ABSTRACT;
020import static eu.cqse.check.framework.scanner.ETokenType.ARRAY;
021import static eu.cqse.check.framework.scanner.ETokenType.AT;
022import static eu.cqse.check.framework.scanner.ETokenType.BEGIN;
023import static eu.cqse.check.framework.scanner.ETokenType.BOOLEAN_LITERAL;
024import static eu.cqse.check.framework.scanner.ETokenType.BREAK;
025import static eu.cqse.check.framework.scanner.ETokenType.CASE;
026import static eu.cqse.check.framework.scanner.ETokenType.CDECL;
027import static eu.cqse.check.framework.scanner.ETokenType.CLASS;
028import static eu.cqse.check.framework.scanner.ETokenType.COLON;
029import static eu.cqse.check.framework.scanner.ETokenType.COMMA;
030import static eu.cqse.check.framework.scanner.ETokenType.CONST;
031import static eu.cqse.check.framework.scanner.ETokenType.CONSTRUCTOR;
032import static eu.cqse.check.framework.scanner.ETokenType.CONTINUE;
033import static eu.cqse.check.framework.scanner.ETokenType.DESTRUCTOR;
034import static eu.cqse.check.framework.scanner.ETokenType.DISPINTERFACE;
035import static eu.cqse.check.framework.scanner.ETokenType.DO;
036import static eu.cqse.check.framework.scanner.ETokenType.DOT;
037import static eu.cqse.check.framework.scanner.ETokenType.DOUBLE_DOT;
038import static eu.cqse.check.framework.scanner.ETokenType.DYNAMIC;
039import static eu.cqse.check.framework.scanner.ETokenType.ELSE;
040import static eu.cqse.check.framework.scanner.ETokenType.END;
041import static eu.cqse.check.framework.scanner.ETokenType.EQ;
042import static eu.cqse.check.framework.scanner.ETokenType.EXCEPT;
043import static eu.cqse.check.framework.scanner.ETokenType.EXIT;
044import static eu.cqse.check.framework.scanner.ETokenType.EXTERNAL;
045import static eu.cqse.check.framework.scanner.ETokenType.FILE;
046import static eu.cqse.check.framework.scanner.ETokenType.FINALIZATION;
047import static eu.cqse.check.framework.scanner.ETokenType.FINALLY;
048import static eu.cqse.check.framework.scanner.ETokenType.FLOATING_POINT_LITERAL;
049import static eu.cqse.check.framework.scanner.ETokenType.FOR;
050import static eu.cqse.check.framework.scanner.ETokenType.FORWARD;
051import static eu.cqse.check.framework.scanner.ETokenType.FUNCTION;
052import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER;
053import static eu.cqse.check.framework.scanner.ETokenType.IF;
054import static eu.cqse.check.framework.scanner.ETokenType.IMPLEMENTATION;
055import static eu.cqse.check.framework.scanner.ETokenType.INDEX;
056import static eu.cqse.check.framework.scanner.ETokenType.INHERITED;
057import static eu.cqse.check.framework.scanner.ETokenType.INITIALIZATION;
058import static eu.cqse.check.framework.scanner.ETokenType.INTEGER_LITERAL;
059import static eu.cqse.check.framework.scanner.ETokenType.INTERFACE;
060import static eu.cqse.check.framework.scanner.ETokenType.LBRACK;
061import static eu.cqse.check.framework.scanner.ETokenType.LPAREN;
062import static eu.cqse.check.framework.scanner.ETokenType.OF;
063import static eu.cqse.check.framework.scanner.ETokenType.ON;
064import static eu.cqse.check.framework.scanner.ETokenType.OPERATOR;
065import static eu.cqse.check.framework.scanner.ETokenType.OVERLOAD;
066import static eu.cqse.check.framework.scanner.ETokenType.OVERRIDE;
067import static eu.cqse.check.framework.scanner.ETokenType.PACKED;
068import static eu.cqse.check.framework.scanner.ETokenType.PASCAL;
069import static eu.cqse.check.framework.scanner.ETokenType.PRIVATE;
070import static eu.cqse.check.framework.scanner.ETokenType.PROCEDURE;
071import static eu.cqse.check.framework.scanner.ETokenType.PROGRAM;
072import static eu.cqse.check.framework.scanner.ETokenType.PROPERTY;
073import static eu.cqse.check.framework.scanner.ETokenType.PROTECTED;
074import static eu.cqse.check.framework.scanner.ETokenType.PUBLIC;
075import static eu.cqse.check.framework.scanner.ETokenType.PUBLISHED;
076import static eu.cqse.check.framework.scanner.ETokenType.RAISE;
077import static eu.cqse.check.framework.scanner.ETokenType.RBRACK;
078import static eu.cqse.check.framework.scanner.ETokenType.RECORD;
079import static eu.cqse.check.framework.scanner.ETokenType.REFERENCE;
080import static eu.cqse.check.framework.scanner.ETokenType.REGISTER;
081import static eu.cqse.check.framework.scanner.ETokenType.REPEAT;
082import static eu.cqse.check.framework.scanner.ETokenType.RPAREN;
083import static eu.cqse.check.framework.scanner.ETokenType.SAFECALL;
084import static eu.cqse.check.framework.scanner.ETokenType.SELF;
085import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON;
086import static eu.cqse.check.framework.scanner.ETokenType.SET;
087import static eu.cqse.check.framework.scanner.ETokenType.STATIC;
088import static eu.cqse.check.framework.scanner.ETokenType.STDCALL;
089import static eu.cqse.check.framework.scanner.ETokenType.STRICT;
090import static eu.cqse.check.framework.scanner.ETokenType.STRING_LITERAL;
091import static eu.cqse.check.framework.scanner.ETokenType.THEN;
092import static eu.cqse.check.framework.scanner.ETokenType.TO;
093import static eu.cqse.check.framework.scanner.ETokenType.TRY;
094import static eu.cqse.check.framework.scanner.ETokenType.TYPE;
095import static eu.cqse.check.framework.scanner.ETokenType.UNIT;
096import static eu.cqse.check.framework.scanner.ETokenType.UNTIL;
097import static eu.cqse.check.framework.scanner.ETokenType.USES;
098import static eu.cqse.check.framework.scanner.ETokenType.VAR;
099import static eu.cqse.check.framework.scanner.ETokenType.VARARGS;
100import static eu.cqse.check.framework.scanner.ETokenType.VIRTUAL;
101import static eu.cqse.check.framework.scanner.ETokenType.WHILE;
102import static eu.cqse.check.framework.scanner.ETokenType.WITH;
103import static eu.cqse.check.framework.scanner.ETokenType.WRITE;
104import static eu.cqse.check.framework.scanner.ETokenType.XOR;
105import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_CASE;
106import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_CONST;
107import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_ENUM;
108import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_IMPLEMENTATION;
109import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_INTERFACE;
110import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_METHOD;
111import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_TYPE;
112import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_TYPE_CASE;
113import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_TYPE_CASE_LABEL;
114import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_TYPE_DECL;
115import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.IN_VAR;
116import static eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates.TOP_LEVEL;
117
118import java.util.EnumSet;
119
120import org.conqat.lib.commons.region.Region;
121
122import eu.cqse.check.framework.scanner.ETokenType;
123import eu.cqse.check.framework.shallowparser.SubTypeNames;
124import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType;
125import eu.cqse.check.framework.shallowparser.framework.RecognizerBase;
126import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase;
127import eu.cqse.check.framework.shallowparser.languages.delphi.DelphiShallowParser.EDelphiParserStates;
128
129/**
130 * A shallow parser for Delphi.
131 * 
132 * This parser currently recognizes types (classes, records, enumerations,
133 * ranges, sets), procedures, functions and global directives like
134 * initialization and finalization sections. Within methods, control structures
135 * and simple statements can be parsed. The parser does not parse into the
136 * statements. Nested methods are supported.
137 */
138public class DelphiShallowParser extends ShallowParserBase<EDelphiParserStates> {
139
140        /** All possible states of the DelphiShallowParser. */
141        public static enum EDelphiParserStates {
142
143                /** Top-level state. */
144                TOP_LEVEL,
145
146                /** Inside a interface state. */
147                IN_INTERFACE,
148
149                /**
150                 * Inside a implementation section (and initialization and
151                 * finalization).
152                 */
153                IN_IMPLEMENTATION,
154
155                /** Inside a type-section. */
156                IN_TYPE,
157
158                /** Inside a type declaration, for example a class or a record. */
159                IN_TYPE_DECL,
160
161                /** Inside a case statement within a type declaration. */
162                IN_TYPE_CASE,
163
164                /** Inside the label of a case statement within a type declaration. */
165                IN_TYPE_CASE_LABEL,
166
167                /** Inside an enum declaration. */
168                IN_ENUM,
169
170                /** Inside a variable-section. */
171                IN_VAR,
172
173                /** Inside a const-section. */
174                IN_CONST,
175
176                /** Inside a case-of statement. */
177                IN_CASE,
178
179                /** Inside a method's head/variable declarations. */
180                IN_METHOD_HEAD,
181
182                /** Inside a method's implementation. */
183                IN_METHOD
184        }
185
186        /** A set of all token types, that indicate a new top-level section. */
187        private static final EnumSet<ETokenType> TOP_LEVEL_KEYWORDS = EnumSet.of(IMPLEMENTATION, INTERFACE, BEGIN,
188                        FINALIZATION, INITIALIZATION);
189
190        /** States that are either implementation or interface. */
191        private static final EDelphiParserStates[] SECTION_STATES = { IN_INTERFACE, IN_IMPLEMENTATION };
192
193        /**
194         * A set of all token types that either indicate a new top-level section, or
195         * a new declaration within an implementation or interface section.
196         */
197        private static final EnumSet<ETokenType> TOP_LEVEL_OR_SECTION_KEYWORDS = EnumSet.of(PROGRAM, UNIT, INTERFACE,
198                        IMPLEMENTATION, TYPE, VAR, CONST, PROCEDURE, FUNCTION, BEGIN, END, INITIALIZATION, FINALIZATION);
199
200        /**
201         * A set of all token types that mark the beginning of a
202         * method/function/procedure declaration.
203         */
204        private static final EnumSet<ETokenType> METHOD_KEYWORDS = EnumSet.of(FUNCTION, PROCEDURE, CONSTRUCTOR, DESTRUCTOR,
205                        OPERATOR);
206
207        /**
208         * A set of all token types that mark the beginning of a simple statement.
209         */
210        private static final EnumSet<ETokenType> SIMPLE_STATEMENT_TOKENS = EnumSet.of(IDENTIFIER, INHERITED, INDEX, RAISE,
211                        EXIT, CONTINUE, BREAK, AT, WRITE, LPAREN, SELF);
212
213        /**
214         * A set of all token types that can be used as modifiers for
215         * methods/functions/procedures.
216         */
217        private static final EnumSet<ETokenType> METHOD_MODIFIERS = EnumSet.of(ABSTRACT, CDECL, DYNAMIC, FORWARD, OVERLOAD,
218                        OVERRIDE, PASCAL, REGISTER, SAFECALL, STATIC, STDCALL, VARARGS, VIRTUAL);
219
220        /** A set of all token types that can be used as access modifiers. */
221        private static final EnumSet<ETokenType> ACCESS_MODIFIERS = EnumSet.of(PUBLIC, PROTECTED, PRIVATE, PUBLISHED);
222
223        /** A set of all token types that can be used as case literals. */
224        private static final EnumSet<ETokenType> CASE_LITERALS = EnumSet.of(IDENTIFIER, INTEGER_LITERAL,
225                        FLOATING_POINT_LITERAL, BOOLEAN_LITERAL, STRING_LITERAL);
226
227        /**
228         * A set of all tokens that indicate a new member within or the end of a
229         * type declaration.
230         */
231        private static final EnumSet<ETokenType> TYPE_MEMBER_TOKENS;
232
233        /** A set of all token types that mark the end of a method's head. */
234        private static final EnumSet<ETokenType> METHOD_SECTION_TOKENS;
235
236        static {
237                TYPE_MEMBER_TOKENS = EnumSet.of(STRICT, CASE, CLASS, PROPERTY, IDENTIFIER, END);
238                TYPE_MEMBER_TOKENS.addAll(ACCESS_MODIFIERS);
239                TYPE_MEMBER_TOKENS.addAll(METHOD_KEYWORDS);
240
241                METHOD_SECTION_TOKENS = EnumSet.of(BEGIN, VAR, CONST, TYPE);
242                METHOD_SECTION_TOKENS.addAll(METHOD_KEYWORDS);
243        }
244
245        /** Constructor. */
246        public DelphiShallowParser() {
247                super(EDelphiParserStates.class, TOP_LEVEL);
248                createTopLevelRules();
249                createTypeRules();
250                createEnumRules();
251                createTypeDeclRules();
252                createMethodSectionRules();
253                createVarRules();
254                createConstRules();
255                createMethodRules();
256                createClassAttributeRules();
257        }
258
259        /** Create rules for all top-level structures. */
260        private void createTopLevelRules() {
261                // program or unit declaration
262                inState(TOP_LEVEL).sequence(EnumSet.of(PROGRAM, UNIT)).skipTo(SEMICOLON)
263                                .createNode(EShallowEntityType.META, 0, 1).endNode();
264
265                // uses declaration
266                inAnyState().sequence(USES).skipTo(SEMICOLON).createNode(EShallowEntityType.META, 0).endNode();
267
268                // interface section
269                inState(TOP_LEVEL).sequence(INTERFACE).createNode(EShallowEntityType.META, 0).parseUntilOrEof(IN_INTERFACE)
270                                .sequenceBefore(TOP_LEVEL_KEYWORDS).endNode();
271
272                // implementation section
273                inState(TOP_LEVEL).sequence(IMPLEMENTATION).createNode(EShallowEntityType.META, 0)
274                                .parseUntilOrEof(IN_IMPLEMENTATION).sequenceBefore(TOP_LEVEL_KEYWORDS).endNode();
275
276                // list of type declarations
277                inState(IN_INTERFACE).sequence(TYPE).parseUntilOrEof(IN_TYPE).sequenceBefore(TOP_LEVEL_OR_SECTION_KEYWORDS);
278
279                // variable declaration
280                inState(SECTION_STATES).sequence(VAR).parseUntilOrEof(IN_VAR).sequenceBefore(TOP_LEVEL_OR_SECTION_KEYWORDS);
281
282                // const declaration
283                inState(SECTION_STATES).sequence(CONST).parseUntilOrEof(IN_CONST).sequenceBefore(TOP_LEVEL_OR_SECTION_KEYWORDS);
284
285                // declaration of methods
286                inState(IN_INTERFACE).sequence(METHOD_KEYWORDS, IDENTIFIER).repeated(DOT, IDENTIFIER)
287                                .createNode(EShallowEntityType.METHOD, 0, new Region(1, -1)).skipNested(LPAREN, RPAREN)
288                                .skipTo(SEMICOLON).endNode();
289
290                // method implementation (nested functions are
291                // processed in IN_METHOD state)
292                RecognizerBase<EDelphiParserStates> methodRecognizer = inState(IN_IMPLEMENTATION, IN_METHOD)
293                                .sequence(METHOD_KEYWORDS, IDENTIFIER).repeated(DOT, IDENTIFIER)
294                                .createNode(EShallowEntityType.METHOD, 0, new Region(1, -1)).skipNested(LPAREN, RPAREN)
295                                .skipTo(SEMICOLON).parseUntilOrEof(IN_METHOD);
296                methodRecognizer.sequence(END).optional(SEMICOLON).endNode();
297
298                // global begin
299                inState(TOP_LEVEL, IN_IMPLEMENTATION).sequence(BEGIN)
300                                .createNode(EShallowEntityType.METHOD, SubTypeNames.GLOBAL_BEGIN).parseUntil(IN_METHOD).sequence(END)
301                                .optional(SEMICOLON).endNode();
302
303                // initialization/finalization
304                inState(TOP_LEVEL).sequence(EnumSet.of(INITIALIZATION, FINALIZATION)).createNode(EShallowEntityType.METHOD, 0)
305                                .parseUntil(IN_METHOD).sequenceBefore(TOP_LEVEL_OR_SECTION_KEYWORDS).endNode();
306        }
307
308        /**
309         * Create rules for parsing types like classes, records, enumerations,
310         * function pointers, ranges, sets and meta-classes.
311         */
312        private void createTypeRules() {
313                RecognizerBase<EDelphiParserStates> typeAlternative = inState(IN_TYPE).sequence(IDENTIFIER).skipTo(EQ);
314
315                // existing type alias
316                typeAlternative.optional(TYPE).sequence(IDENTIFIER, SEMICOLON)
317                                .createNode(EShallowEntityType.TYPE, SubTypeNames.ALIAS, 0).endNode();
318
319                // type pointer
320                typeAlternative.sequence(XOR, IDENTIFIER, SEMICOLON)
321                                .createNode(EShallowEntityType.TYPE, SubTypeNames.TYPE_POINTER, 0).endNode();
322
323                // array or file of existing types
324                typeAlternative.sequence(EnumSet.of(ARRAY, FILE)).skipToWithNesting(SEMICOLON, LPAREN, RPAREN)
325                                .createNode(EShallowEntityType.TYPE, 2, 0).endNode();
326
327                // function pointer declaration
328                typeAlternative.sequence(EnumSet.of(PROCEDURE, FUNCTION))
329                                .createNode(EShallowEntityType.TYPE, SubTypeNames.FUNCTION_POINTER, 0).skipNested(LPAREN, RPAREN)
330                                .skipTo(SEMICOLON).endNode();
331
332                // anonymous method declaration
333                typeAlternative.sequence(REFERENCE, TO, EnumSet.of(PROCEDURE, FUNCTION))
334                                .createNode(EShallowEntityType.TYPE, SubTypeNames.ANONYMOUS_METHOD, 0).skipNested(LPAREN, RPAREN)
335                                .skipTo(SEMICOLON).endNode();
336
337                // enum declaration
338                typeAlternative.sequence(LPAREN).createNode(EShallowEntityType.TYPE, SubTypeNames.ENUM, 0).parseUntil(IN_ENUM)
339                                .sequence(RPAREN, SEMICOLON).endNode();
340
341                // range declaration
342                EnumSet<ETokenType> rangeTypes = EnumSet.of(INTEGER_LITERAL, STRING_LITERAL);
343                typeAlternative.sequence(rangeTypes, DOUBLE_DOT, rangeTypes, SEMICOLON)
344                                .createNode(EShallowEntityType.TYPE, SubTypeNames.RANGE, 0).endNode();
345
346                // set declaration
347                typeAlternative.sequence(SET, OF).createNode(EShallowEntityType.TYPE, SubTypeNames.SET, 0).skipTo(SEMICOLON)
348                                .endNode();
349
350                // meta-class type
351                typeAlternative.sequence(CLASS, OF, CLASS, TYPE, SEMICOLON)
352                                .createNode(EShallowEntityType.TYPE, SubTypeNames.META_CLASS, 0).endNode();
353
354                // class/record/interface/dispinterface declaration with possible
355                // inheritance
356                RecognizerBase<EDelphiParserStates> declAlternative = typeAlternative.optional(PACKED)
357                                .sequence(EnumSet.of(CLASS, INTERFACE, RECORD, DISPINTERFACE))
358                                .createNode(EShallowEntityType.TYPE, -1, 0).skipNested(LPAREN, RPAREN);
359                // helper declaration
360                endTypeDeclaration(declAlternative.sequence(IDENTIFIER).skipNested(LPAREN, RPAREN).sequence(FOR, IDENTIFIER));
361                endTypeDeclaration(declAlternative);
362        }
363
364        /**
365         * End a type declaration recognizer. Either a semicolon or a type body is
366         * expected.
367         */
368        private static void endTypeDeclaration(RecognizerBase<EDelphiParserStates> recognizer) {
369                recognizer.sequence(SEMICOLON).endNode();
370                recognizer.parseUntil(IN_TYPE_DECL).sequence(END).optional(SEMICOLON).endNode();
371        }
372
373        /** Create rules for parsing enumerations. */
374        private void createEnumRules() {
375                // beginning enum-literal
376                inState(IN_ENUM).sequence(IDENTIFIER).optional(EQ, INTEGER_LITERAL)
377                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ENUM_LITERAL, 0).endNode();
378
379                // enum-literal separated with comma
380                inState(IN_ENUM).sequence(COMMA, IDENTIFIER).optional(EQ, INTEGER_LITERAL)
381                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ENUM_LITERAL, 1).endNode();
382        }
383
384        /** Create rules for parsing classes and records. */
385        private void createTypeDeclRules() {
386                // access modifiers
387                inState(IN_TYPE_DECL).optional(STRICT).sequence(ACCESS_MODIFIERS)
388                                .createNode(EShallowEntityType.META, new Region(0, -1)).endNode();
389
390                // function/procedure declaration
391                RecognizerBase<EDelphiParserStates> methodBase = inState(IN_TYPE_DECL).optional(CLASS)
392                                .sequence(METHOD_KEYWORDS, IDENTIFIER).createNode(EShallowEntityType.METHOD, -2, -1)
393                                .skipNested(LPAREN, RPAREN).skipTo(SEMICOLON);
394                appendMethodModifierRules(methodBase);
395
396                // property declaration
397                inState(IN_TYPE_DECL).sequence(PROPERTY).skipTo(SEMICOLON)
398                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.PROPERTY, 1).endNode();
399
400                // attribute declaration
401                inState(IN_TYPE_DECL).sequence(IDENTIFIER).skipTo(SEMICOLON)
402                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ATTRIBUTE, 0).endNode();
403
404                // case statement
405                inState(IN_TYPE_DECL).sequence(CASE).skipTo(OF).createNode(EShallowEntityType.META, SubTypeNames.CASE)
406                                .parseUntil(IN_TYPE_CASE).sequenceBefore(TYPE_MEMBER_TOKENS).endNode();
407
408                createTypeCaseRules();
409        }
410
411        /** Create rules for parsing case statements within type declarations. */
412        private void createTypeCaseRules() {
413                inState(IN_TYPE_CASE).sequence(CASE_LITERALS).skipTo(COLON).sequence(LPAREN)
414                                .createNode(EShallowEntityType.META, SubTypeNames.CASE_LABEL, 0).parseUntil(IN_TYPE_CASE_LABEL)
415                                .sequence(RPAREN, SEMICOLON).endNode();
416
417                inState(IN_TYPE_CASE_LABEL).optional(SEMICOLON).markStart().sequence(IDENTIFIER, COLON)
418                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ATTRIBUTE, 0)
419                                .skipBefore(EnumSet.of(SEMICOLON, RPAREN)).endNode();
420        }
421
422        /**
423         * Create rules for parsing sections within a method. Possible sections are
424         * variable, constant, type declarations or the method's body.
425         */
426        private void createMethodSectionRules() {
427                // variable declaration within method
428                inState(IN_METHOD).sequence(VAR).parseUntil(IN_VAR).sequenceBefore(METHOD_SECTION_TOKENS);
429
430                // const declaration within method
431                inState(IN_METHOD).sequence(CONST).parseUntil(IN_CONST).sequenceBefore(METHOD_SECTION_TOKENS);
432
433                // type declaration within method
434                inState(IN_METHOD).sequence(TYPE).parseUntil(EDelphiParserStates.IN_TYPE).sequenceBefore(METHOD_SECTION_TOKENS);
435
436                // begin of method body
437                inState(IN_METHOD).sequence(BEGIN).parseUntil(IN_METHOD).sequenceBefore(END).optional(SEMICOLON);
438        }
439
440        /** Create rules for parsing variable declarations within a var-section. */
441        private void createVarRules() {
442                // variable declaration
443                inState(IN_VAR).sequence(IDENTIFIER, COLON).skipTo(SEMICOLON)
444                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.LOCAL_VARIABLE, 0).endNode();
445        }
446
447        /** Create rules for parsing const declarations within a const-section. */
448        private void createConstRules() {
449                // const declaration
450                inState(IN_CONST).sequence(IDENTIFIER).optional(COLON).skipTo(EQ).skipTo(SEMICOLON)
451                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.CONSTANT, 0).endNode();
452        }
453
454        /** Create rules for parsing the body of a method/procedure/function. */
455        private void createMethodRules() {
456                // anonymous block
457                inState(IN_METHOD).sequence(BEGIN).createNode(EShallowEntityType.STATEMENT, SubTypeNames.ANONYMOUS_BLOCK)
458                                .parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON).endNode();
459
460                createIfElseRules();
461                createTryExceptFinallyRules();
462                createLoopRules();
463                createCaseRules();
464                createWithRules();
465                createSimpleStatementRules();
466        }
467
468        /**
469         * Append rules for parsing method/function/procedure modifiers to the given
470         * recognizer.
471         */
472        private static void appendMethodModifierRules(RecognizerBase<EDelphiParserStates> recognizer) {
473                RecognizerBase<EDelphiParserStates> modifierAlternative = recognizer.repeated(METHOD_MODIFIERS, SEMICOLON);
474                // parse external directive
475                modifierAlternative.sequence(EXTERNAL).skipTo(SEMICOLON).endNode();
476                // the last modifier was the end
477                modifierAlternative.endNode();
478        }
479
480        /** Create rules for parsing if/else structures. */
481        private void createIfElseRules() {
482                RecognizerBase<EDelphiParserStates> ifAlternative = inState(IN_METHOD).sequence(IF)
483                                .createNode(EShallowEntityType.STATEMENT, 0).skipTo(THEN);
484                endWithPossibleContinuation(
485                                ifAlternative.sequence(BEGIN).parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON),
486                                EnumSet.of(ELSE));
487                endWithPossibleContinuation(ifAlternative.parseOnce(IN_METHOD), EnumSet.of(ELSE));
488
489                RecognizerBase<EDelphiParserStates> elseIfAlternative = inState(IN_METHOD).sequence(ELSE, IF)
490                                .createNode(EShallowEntityType.STATEMENT, new int[] { 0, 1 }).skipTo(THEN);
491                endWithPossibleContinuation(
492                                elseIfAlternative.sequence(BEGIN).parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON),
493                                EnumSet.of(ELSE));
494                endWithPossibleContinuation(elseIfAlternative.parseOnce(IN_METHOD), EnumSet.of(ELSE));
495
496                RecognizerBase<EDelphiParserStates> elseAlternative = inState(IN_METHOD).sequence(ELSE)
497                                .createNode(EShallowEntityType.STATEMENT, 0);
498                elseAlternative.sequence(BEGIN).parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON).endNode();
499                elseAlternative.parseOnce(IN_METHOD).endNode();
500        }
501
502        /** Create rules for parsing try, except and finally structures. */
503        private void createTryExceptFinallyRules() {
504                RecognizerBase<EDelphiParserStates> tryAlternative = inState(IN_METHOD).sequence(TRY)
505                                .createNode(EShallowEntityType.STATEMENT, 0).parseUntil(IN_METHOD);
506                endWithContinuationOrEnd(tryAlternative, EnumSet.of(EXCEPT, FINALLY));
507
508                RecognizerBase<EDelphiParserStates> exceptAlternative = inState(IN_METHOD).sequence(EXCEPT)
509                                .createNode(EShallowEntityType.STATEMENT, 0).parseUntil(IN_METHOD);
510                endWithContinuationOrEnd(exceptAlternative, EnumSet.of(EXCEPT, FINALLY));
511
512                inState(IN_METHOD).sequence(FINALLY).createNode(EShallowEntityType.STATEMENT, 0).parseUntil(IN_METHOD)
513                                .sequence(END).optional(SEMICOLON).endNode();
514
515                // on clause
516                RecognizerBase<EDelphiParserStates> onAlternative = inState(IN_METHOD)
517                                .sequence(ON, IDENTIFIER, COLON, IDENTIFIER, DO).createNode(EShallowEntityType.META, 0, 1);
518                endWithPossibleContinuation(
519                                onAlternative.sequence(BEGIN).parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON),
520                                EnumSet.of(ON, ELSE));
521                endWithPossibleContinuation(onAlternative.parseOnce(IN_METHOD), EnumSet.of(ON, ELSE));
522        }
523
524        /**
525         * End the given recognizer's current node with continuation, if one of the
526         * given continuation tokens is recognized and sequence before it. Otherwise
527         * expect an end and a semicolon token and end the current node.
528         */
529        private static void endWithContinuationOrEnd(RecognizerBase<EDelphiParserStates> recognizer,
530                        EnumSet<ETokenType> continuationTokens) {
531                recognizer.sequenceBefore(continuationTokens).endNodeWithContinuation();
532                recognizer.sequence(END).optional(SEMICOLON).endNode();
533        }
534
535        /** Create rules for parsing loops. */
536        private void createLoopRules() {
537                // repeat until loop
538                inState(IN_METHOD).sequence(REPEAT).createNode(EShallowEntityType.STATEMENT, 0).parseUntil(IN_METHOD)
539                                .sequence(UNTIL).skipTo(SEMICOLON).endNode();
540
541                // while/for loop
542                RecognizerBase<EDelphiParserStates> whileForAlternative = inState(IN_METHOD).sequence(EnumSet.of(WHILE, FOR))
543                                .createNode(EShallowEntityType.STATEMENT, 0).skipTo(DO);
544                whileForAlternative.sequence(BEGIN).parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON).endNode();
545                whileForAlternative.parseOnce(IN_METHOD).endNode();
546        }
547
548        /** Create rules for parsing case structures. */
549        private void createCaseRules() {
550                inState(IN_METHOD).sequence(CASE).skipTo(OF).createNode(EShallowEntityType.STATEMENT, 0).parseUntil(IN_CASE)
551                                .sequence(END).optional(SEMICOLON).endNode();
552
553                appendCaseLabelBody(inState(IN_CASE).sequence(CASE_LITERALS).skipTo(COLON).createNode(EShallowEntityType.META,
554                                SubTypeNames.CASE, 0));
555
556                RecognizerBase<EDelphiParserStates> elseRecognizer = inState(IN_CASE).sequence(ELSE)
557                                .createNode(EShallowEntityType.META, 0);
558                elseRecognizer.parseUntil(IN_METHOD).sequenceBefore(END).endNode();
559        }
560
561        /**
562         * Appends rules for parsing the body of a case label to the given
563         * recognizer.
564         */
565        private static void appendCaseLabelBody(RecognizerBase<EDelphiParserStates> recognizer) {
566                endCaseLabelRecognizer(recognizer.sequence(BEGIN).parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON));
567                endCaseLabelRecognizer(recognizer.parseOnce(IN_METHOD));
568
569        }
570
571        /**
572         * Ends a case-label recognizer, which must sequence before another
573         * case-label, else or end.
574         */
575        private static void endCaseLabelRecognizer(RecognizerBase<EDelphiParserStates> recognizer) {
576                recognizer.sequenceBefore(EnumSet.of(IDENTIFIER, INTEGER_LITERAL, FLOATING_POINT_LITERAL, STRING_LITERAL,
577                                BOOLEAN_LITERAL, ELSE, END)).endNode();
578        }
579
580        /** Create rules for parsing with statements. */
581        private void createWithRules() {
582                RecognizerBase<EDelphiParserStates> withRecognizer = inState(IN_METHOD).sequence(WITH).skipTo(DO)
583                                .createNode(EShallowEntityType.STATEMENT, 0);
584                withRecognizer.sequence(BEGIN).parseUntil(IN_METHOD).sequence(END).optional(SEMICOLON).endNode();
585                withRecognizer.parseOnce(IN_METHOD).endNode();
586        }
587
588        /** Create rules for parsing simple statements within methods. */
589        private void createSimpleStatementRules() {
590                // simple statement
591                inState(IN_METHOD).sequence(SIMPLE_STATEMENT_TOKENS).skipBefore(EnumSet.of(SEMICOLON, UNTIL, ELSE, END))
592                                .optional(SEMICOLON).createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, 0)
593                                .endNode();
594
595                // empty statement
596                inState(IN_METHOD).sequence(SEMICOLON).createNode(EShallowEntityType.STATEMENT, SubTypeNames.EMPTY_STATEMENT)
597                                .endNode();
598
599        }
600
601        /** Create rules for parsing attributes at any place. */
602        private void createClassAttributeRules() {
603                inAnyState().sequence(LBRACK).skipToWithNesting(RBRACK, LBRACK, RBRACK)
604                                .createNode(EShallowEntityType.META, SubTypeNames.ATTRIBUTE, 1).endNode();
605        }
606}