001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright (c) 2009-2017 CQSE GmbH                                        |
004|                                                                          |
005+-------------------------------------------------------------------------*/
006package eu.cqse.check.framework.shallowparser.languages.kotlin;
007
008import static eu.cqse.check.framework.scanner.ETokenType.ABSTRACT;
009import static eu.cqse.check.framework.scanner.ETokenType.ACTUAL;
010import static eu.cqse.check.framework.scanner.ETokenType.ANNOTATION;
011import static eu.cqse.check.framework.scanner.ETokenType.ARROW;
012import static eu.cqse.check.framework.scanner.ETokenType.AT;
013import static eu.cqse.check.framework.scanner.ETokenType.BOOLEAN_LITERAL;
014import static eu.cqse.check.framework.scanner.ETokenType.BREAK;
015import static eu.cqse.check.framework.scanner.ETokenType.BY;
016import static eu.cqse.check.framework.scanner.ETokenType.CATCH;
017import static eu.cqse.check.framework.scanner.ETokenType.CLASS;
018import static eu.cqse.check.framework.scanner.ETokenType.COLON;
019import static eu.cqse.check.framework.scanner.ETokenType.COMMA;
020import static eu.cqse.check.framework.scanner.ETokenType.COMPANION;
021import static eu.cqse.check.framework.scanner.ETokenType.CONST;
022import static eu.cqse.check.framework.scanner.ETokenType.CONSTRUCTOR;
023import static eu.cqse.check.framework.scanner.ETokenType.CONTINUE;
024import static eu.cqse.check.framework.scanner.ETokenType.CROSSINLINE;
025import static eu.cqse.check.framework.scanner.ETokenType.DATA;
026import static eu.cqse.check.framework.scanner.ETokenType.DELEGATE;
027import static eu.cqse.check.framework.scanner.ETokenType.DO;
028import static eu.cqse.check.framework.scanner.ETokenType.DOT;
029import static eu.cqse.check.framework.scanner.ETokenType.DYNAMIC;
030import static eu.cqse.check.framework.scanner.ETokenType.ELSE;
031import static eu.cqse.check.framework.scanner.ETokenType.ENUM;
032import static eu.cqse.check.framework.scanner.ETokenType.EOL;
033import static eu.cqse.check.framework.scanner.ETokenType.EQ;
034import static eu.cqse.check.framework.scanner.ETokenType.EXPECT;
035import static eu.cqse.check.framework.scanner.ETokenType.EXTERNAL;
036import static eu.cqse.check.framework.scanner.ETokenType.FIELD;
037import static eu.cqse.check.framework.scanner.ETokenType.FILE;
038import static eu.cqse.check.framework.scanner.ETokenType.FINAL;
039import static eu.cqse.check.framework.scanner.ETokenType.FINALLY;
040import static eu.cqse.check.framework.scanner.ETokenType.FLOATING_POINT_LITERAL;
041import static eu.cqse.check.framework.scanner.ETokenType.FOR;
042import static eu.cqse.check.framework.scanner.ETokenType.FUN;
043import static eu.cqse.check.framework.scanner.ETokenType.GET;
044import static eu.cqse.check.framework.scanner.ETokenType.GT;
045import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER;
046import static eu.cqse.check.framework.scanner.ETokenType.IF;
047import static eu.cqse.check.framework.scanner.ETokenType.IMPORT;
048import static eu.cqse.check.framework.scanner.ETokenType.IN;
049import static eu.cqse.check.framework.scanner.ETokenType.INFIX;
050import static eu.cqse.check.framework.scanner.ETokenType.INIT;
051import static eu.cqse.check.framework.scanner.ETokenType.INLINE;
052import static eu.cqse.check.framework.scanner.ETokenType.INNER;
053import static eu.cqse.check.framework.scanner.ETokenType.INTEGER_LITERAL;
054import static eu.cqse.check.framework.scanner.ETokenType.INTERFACE;
055import static eu.cqse.check.framework.scanner.ETokenType.INTERNAL;
056import static eu.cqse.check.framework.scanner.ETokenType.IT;
057import static eu.cqse.check.framework.scanner.ETokenType.LATEINIT;
058import static eu.cqse.check.framework.scanner.ETokenType.LBRACE;
059import static eu.cqse.check.framework.scanner.ETokenType.LBRACK;
060import static eu.cqse.check.framework.scanner.ETokenType.LPAREN;
061import static eu.cqse.check.framework.scanner.ETokenType.LT;
062import static eu.cqse.check.framework.scanner.ETokenType.MINUS;
063import static eu.cqse.check.framework.scanner.ETokenType.NOINLINE;
064import static eu.cqse.check.framework.scanner.ETokenType.NULL_LITERAL;
065import static eu.cqse.check.framework.scanner.ETokenType.OBJECT;
066import static eu.cqse.check.framework.scanner.ETokenType.OPEN;
067import static eu.cqse.check.framework.scanner.ETokenType.OPERATOR;
068import static eu.cqse.check.framework.scanner.ETokenType.OUT;
069import static eu.cqse.check.framework.scanner.ETokenType.OVERRIDE;
070import static eu.cqse.check.framework.scanner.ETokenType.PACKAGE;
071import static eu.cqse.check.framework.scanner.ETokenType.PARAM;
072import static eu.cqse.check.framework.scanner.ETokenType.PRIVATE;
073import static eu.cqse.check.framework.scanner.ETokenType.PROPERTY;
074import static eu.cqse.check.framework.scanner.ETokenType.PROTECTED;
075import static eu.cqse.check.framework.scanner.ETokenType.PUBLIC;
076import static eu.cqse.check.framework.scanner.ETokenType.QUESTION;
077import static eu.cqse.check.framework.scanner.ETokenType.RBRACE;
078import static eu.cqse.check.framework.scanner.ETokenType.RBRACK;
079import static eu.cqse.check.framework.scanner.ETokenType.RECEIVER;
080import static eu.cqse.check.framework.scanner.ETokenType.REIFIED;
081import static eu.cqse.check.framework.scanner.ETokenType.RETURN;
082import static eu.cqse.check.framework.scanner.ETokenType.RPAREN;
083import static eu.cqse.check.framework.scanner.ETokenType.SEALED;
084import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON;
085import static eu.cqse.check.framework.scanner.ETokenType.SET;
086import static eu.cqse.check.framework.scanner.ETokenType.SETPARAM;
087import static eu.cqse.check.framework.scanner.ETokenType.STRING_LITERAL;
088import static eu.cqse.check.framework.scanner.ETokenType.SUPER;
089import static eu.cqse.check.framework.scanner.ETokenType.SUSPEND;
090import static eu.cqse.check.framework.scanner.ETokenType.TAILREC;
091import static eu.cqse.check.framework.scanner.ETokenType.THIS;
092import static eu.cqse.check.framework.scanner.ETokenType.THROW;
093import static eu.cqse.check.framework.scanner.ETokenType.VAL;
094import static eu.cqse.check.framework.scanner.ETokenType.VAR;
095import static eu.cqse.check.framework.scanner.ETokenType.VARARG;
096import static eu.cqse.check.framework.scanner.ETokenType.WHEN;
097import static eu.cqse.check.framework.scanner.ETokenType.WHERE;
098import static eu.cqse.check.framework.scanner.ETokenType.WHILE;
099import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.METHOD;
100import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.STATEMENT;
101import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.TYPE;
102import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.IN_ENUM;
103import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.IN_LAMBDA;
104import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.IN_METHOD;
105import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.IN_PROPERTY;
106import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.IN_STATEMENT;
107import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.IN_TYPE;
108import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.IN_WHEN;
109import static eu.cqse.check.framework.shallowparser.languages.kotlin.EKotlinParserStates.TOP_LEVEL;
110import static org.conqat.lib.commons.enums.EnumUtils.mergeSets;
111
112import java.util.Arrays;
113import java.util.EnumSet;
114import java.util.List;
115
116import org.conqat.lib.commons.region.Region;
117
118import eu.cqse.check.framework.scanner.ETokenType;
119import eu.cqse.check.framework.shallowparser.SubTypeNames;
120import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType;
121import eu.cqse.check.framework.shallowparser.framework.RecognizerBase;
122import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase;
123
124/**
125 * A shallow parser for the Kotlin programming language.
126 */
127public class KotlinShallowParser extends ShallowParserBase<EKotlinParserStates> {
128
129        /** Kotlin visibility modifiers. */
130        private static final EnumSet<ETokenType> MODIFIERS = EnumSet.of(ABSTRACT, FINAL, OPEN, ANNOTATION, SEALED, DATA,
131                        OVERRIDE, FINAL, LATEINIT, PRIVATE, PROTECTED, PUBLIC, INTERNAL, IN, OUT, NOINLINE, INNER, EXPECT, ACTUAL,
132                        CROSSINLINE, VARARG, REIFIED, TAILREC, OPERATOR, INFIX, INLINE, EXTERNAL, CONST, SUSPEND, COMPANION);
133
134        /**
135         * Soft keywords, which can also be used as identifiers, and identifiers itself.
136         */
137        private static final EnumSet<ETokenType> KEYWORD_OR_IDENTIFIER = mergeSets(MODIFIERS, IDENTIFIER, VARARG, FIELD, IT,
138                        BY, CATCH, CONSTRUCTOR, DELEGATE, DYNAMIC, ENUM, FIELD, FILE, FINALLY, GET, IMPORT, INIT, PARAM, PROPERTY,
139                        RECEIVER, SET, SETPARAM, WHERE);
140
141        /** All token types that may stand at the beginning of new statement. */
142        private static final EnumSet<ETokenType> STATEMENT_START_TOKENS = mergeSets(KEYWORD_OR_IDENTIFIER, RETURN, BREAK,
143                        CONTINUE, THROW, SUPER, LPAREN, INTEGER_LITERAL, BOOLEAN_LITERAL, STRING_LITERAL, NULL_LITERAL,
144                        FLOATING_POINT_LITERAL, IT, FIELD, MINUS, THIS);
145
146        /** Token types, which are allowed inside a generic <...> expression. */
147        /* package */ static final EnumSet<ETokenType> VALID_INSIDE_GENERIC_TOKEN_TYPES = EnumSet.of(IDENTIFIER, QUESTION,
148                        DOT, LPAREN, RPAREN, ARROW, COMMA);
149
150        /** Token types with are allowed for type definitions. */
151        private static final EnumSet<ETokenType> VALID_TYPE_TOKEN_TYPES = mergeSets(VALID_INSIDE_GENERIC_TOKEN_TYPES, LT,
152                        GT);
153
154        /** List of opening brackets. */
155        private static final List<ETokenType> OPENING_BRACKETS = Arrays.asList(LPAREN, LBRACK, LBRACE);
156
157        /** List of closing brackets. */
158        private static final List<ETokenType> CLOSING_BRACKETS = Arrays.asList(RPAREN, RBRACK, RBRACE);
159
160        /** Constructor. */
161        public KotlinShallowParser() {
162                super(EKotlinParserStates.class, TOP_LEVEL);
163                createMetaRules();
164                createTypeRules();
165                createMethodRules();
166                createStatementRules();
167                createSubExpressionRules();
168
169                // remove any isolated EOLs
170                inAnyState().sequence(EOL);
171        }
172
173        /** Creates rules for meta elements. */
174        private void createMetaRules() {
175                inState(TOP_LEVEL).sequence(IMPORT).markStart().skipBefore(EOL)
176                                .createNode(EShallowEntityType.META, SubTypeNames.IMPORT, new Region(0, -1)).endNode();
177                inState(TOP_LEVEL).sequence(PACKAGE).markStart().skipBefore(EOL)
178                                .createNode(EShallowEntityType.META, SubTypeNames.PACKAGE, new Region(0, -1)).endNode();
179                inAnyState().sequence(AT, KEYWORD_OR_IDENTIFIER).repeated(DOT, KEYWORD_OR_IDENTIFIER).skipNested(LPAREN, RPAREN)
180                                .createNode(EShallowEntityType.META, SubTypeNames.ANNOTATION, 1).endNode();
181        }
182
183        /** Creates the statement rules. */
184        private void createStatementRules() {
185                createLoopRules();
186                createConditionalRules();
187                createSimpleStatementRule();
188                createWhenStatementRule();
189                createLocalVariableRule(VAR);
190                createLocalVariableRule(VAL);
191                createLocalVariableRule(CONST);
192        }
193
194        /** Creates rules for loops */
195        private void createLoopRules() {
196                endWithBlock(inState(TOP_LEVEL, IN_METHOD).sequence(WHILE)
197                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.WHILE).sequence(LPAREN)
198                                .skipToWithNesting(RPAREN, LPAREN, RPAREN));
199                endWithBlock(
200                                inState(TOP_LEVEL, IN_METHOD).sequence(FOR).createNode(EShallowEntityType.STATEMENT, SubTypeNames.FOR)
201                                                .sequence(LPAREN).skipToWithNesting(RPAREN, LPAREN, RPAREN));
202                RecognizerBase<EKotlinParserStates> doWhileRule = inState(TOP_LEVEL, IN_METHOD).sequence(DO)
203                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.DO_WHILE);
204                doWhileRule.sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE, WHILE).skipTo(EOL).endNode();
205                doWhileRule.repeated(EOL).parseOnce(IN_METHOD).sequence(WHILE).skipTo(EOL).endNode();
206        }
207
208        /** Creates rules for conditional statements. */
209        private void createConditionalRules() {
210                createConditionalRule(SubTypeNames.IF, IF);
211                createConditionalRule(SubTypeNames.ELSE_IF, ELSE, IF);
212                createElseConditionalRule();
213        }
214
215        /** Creates a rule for a conditional. */
216        private void createConditionalRule(String subtype, Object... matchTerms) {
217                endWithBlockAndContinuation(inState(TOP_LEVEL, IN_METHOD, IN_STATEMENT).sequence(matchTerms).sequence(LPAREN)
218                                .skipToWithNesting(RPAREN, LPAREN, RPAREN).createNode(STATEMENT, subtype), EnumSet.of(ELSE));
219        }
220
221        /** Creates a rule for a conditional. */
222        private void createElseConditionalRule() {
223                endWithBlock(
224                                inState(TOP_LEVEL, IN_METHOD, IN_STATEMENT).sequence(ELSE).createNode(STATEMENT, SubTypeNames.ELSE));
225        }
226
227        /** Creates a simple statement rule. */
228        private void createSimpleStatementRule() {
229                inState(TOP_LEVEL, IN_METHOD).sequence(SEMICOLON)
230                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.EMPTY_STATEMENT).endNode();
231
232                finishStatementRule(inState(TOP_LEVEL, IN_METHOD).sequenceBefore(STATEMENT_START_TOKENS)
233                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, 0));
234        }
235
236        /** Creates a rule for a when statement (similar to switch/case in Java). */
237        private void createWhenStatementRule() {
238                inState(TOP_LEVEL, IN_METHOD, IN_STATEMENT).sequence(WHEN)
239                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.WHEN)
240                                .skipNested(LPAREN, RPAREN, createSubExpressionRecognizer()).skipTo(LBRACE).parseUntil(IN_WHEN)
241                                .sequence(RBRACE).endNode();
242        }
243
244        /** Creates a rule for a local variable declaration */
245        private void createLocalVariableRule(ETokenType keyword) {
246                RecognizerBase<EKotlinParserStates> localVariableRule = inState(TOP_LEVEL, IN_METHOD).optional(MODIFIERS)
247                                .sequence(keyword).createNode(EShallowEntityType.STATEMENT, SubTypeNames.LOCAL_VARIABLE, 1);
248
249                // Variable with optional type and initialization
250                finishStatementRule(localVariableRule.sequence(KEYWORD_OR_IDENTIFIER)
251                                .optionalSubRecognizer(createReturnTypeRecognizer()).sequence(EQ));
252
253                // Destructuring variable declaration
254                finishStatementRule(localVariableRule.skipNested(LPAREN, RPAREN)
255                                .optionalSubRecognizer(createReturnTypeRecognizer()).sequence(EQ));
256
257                // Variable definition without initialization
258                localVariableRule.sequence(KEYWORD_OR_IDENTIFIER).optionalSubRecognizer(createReturnTypeRecognizer()).endNode();
259        }
260
261        /** Finishes a statement rule. */
262        private void finishStatementRule(RecognizerBase<EKotlinParserStates> statementRule) {
263                completeStatementRule(statementRule).endNode();
264        }
265
266        /**
267         * Completes the given rule to match everything that belongs to the current
268         * statement. The statement may also be distributed over multiple lines.
269         */
270        private RecognizerBase<EKotlinParserStates> completeStatementRule(
271                        RecognizerBase<EKotlinParserStates> statementRule) {
272                return statementRule.subRecognizer(
273                                new KotlinStatementSubRecognizer(createSubExpressionRecognizer(), OPENING_BRACKETS, CLOSING_BRACKETS));
274        }
275
276        /**
277         * Creates a rule to finish a node with either a simple statement or a block of
278         * statements.
279         */
280        private void endWithBlock(RecognizerBase<EKotlinParserStates> recognizer) {
281                endWithBlockAndContinuation(recognizer, null);
282        }
283
284        /**
285         * Creates a rule to finish a node with either a simple statement or a block of
286         * statements and a continuation.
287         */
288        private void endWithBlockAndContinuation(RecognizerBase<EKotlinParserStates> recognizer,
289                        EnumSet<ETokenType> continuationTokens) {
290                endWithPossibleContinuation(recognizer.sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE),
291                                continuationTokens);
292                endWithPossibleContinuation(recognizer.repeated(EOL).parseOnce(IN_METHOD), continuationTokens);
293        }
294
295        /** Creates rules for types */
296        public void createTypeRules() {
297                createEnumTypeRule();
298                createTypeRule(CLASS, SubTypeNames.CLASS);
299                createTypeRule(INTERFACE, SubTypeNames.INTERFACE);
300                createTypeRule(OBJECT, SubTypeNames.OBJECT);
301
302                createPropertyRule(VAR, SubTypeNames.PROPERTY);
303                createPropertyRule(VAL, SubTypeNames.PROPERTY);
304
305                createPropertyGetterRule(GET);
306                createPropertyGetterRule(SET);
307        }
308
309        /** Creates a type rule for the given keyword */
310        private void createEnumTypeRule() {
311                RecognizerBase<EKotlinParserStates> typeNode = inState(TOP_LEVEL, IN_TYPE).optional(MODIFIERS)
312                                .sequence(ENUM, CLASS, KEYWORD_OR_IDENTIFIER).createNode(TYPE, SubTypeNames.ENUM_CLASS, -1)
313                                .optionalSubRecognizer(createPrimaryConstructorRecognizer()).skipNested(LPAREN, RPAREN);
314                RecognizerBase<EKotlinParserStates> inEnumRule = typeNode.skipTo(LBRACE).parseUntil(IN_ENUM);
315                inEnumRule.sequence(SEMICOLON).parseUntil(IN_TYPE).sequence(RBRACE).endNode();
316                inEnumRule.sequence(RBRACE).endNode();
317                typeNode.endNode();
318
319                // Enum literal with or without anonymous class
320                RecognizerBase<EKotlinParserStates> enumLiteral = inState(IN_ENUM).sequence(KEYWORD_OR_IDENTIFIER)
321                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ENUM_LITERAL, -1).skipNested(LPAREN, RPAREN);
322                enumLiteral.sequence(LBRACE).parseUntil(IN_TYPE).sequence(RBRACE).endNode();
323                enumLiteral.endNode();
324                inState(IN_ENUM).sequence(COMMA);
325        }
326
327        /** Creates a type rule for the given keyword */
328        private void createTypeRule(ETokenType typeTokenType, String subTypeName) {
329                RecognizerBase<EKotlinParserStates> typeNode = inState(TOP_LEVEL, IN_TYPE).optional(MODIFIERS)
330                                .sequence(typeTokenType).markStart().sequence(KEYWORD_OR_IDENTIFIER).skipNested(LT, GT)
331                                .createNode(TYPE, subTypeName, 0).optionalSubRecognizer(createPrimaryConstructorRecognizer())
332                                .skipNested(LPAREN, RPAREN);
333                typeNode.skipTo(LBRACE).parseUntil(IN_TYPE).sequence(RBRACE).endNode();
334                typeNode.endNode();
335        }
336
337        /** Creates a property rule */
338        private void createPropertyRule(ETokenType propertyKeyword, String subtype) {
339                RecognizerBase<EKotlinParserStates> typeFollowRecognizer = createRecognizer(
340                                start -> start.sequence(IDENTIFIER).skipNested(LT, GT).sequence(DOT));
341                RecognizerBase<EKotlinParserStates> attributeRule = inState(TOP_LEVEL, IN_TYPE).optional(MODIFIERS)
342                                .sequence(propertyKeyword).skipNested(LT, GT).markStart().repeatedSubRecognizer(typeFollowRecognizer)
343                                .sequence(KEYWORD_OR_IDENTIFIER).createNode(EShallowEntityType.ATTRIBUTE, subtype, new Region(0, -1))
344                                .optionalSubRecognizer(createReturnTypeRecognizer());
345
346                endWithPossibleGetterOrSetter(completeStatementRule(attributeRule.sequence(EQ)));
347                endWithPossibleGetterOrSetter(attributeRule);
348        }
349
350        /**
351         * Creates rules to allow getters and setters as follow-up to the given rule.
352         */
353        private void endWithPossibleGetterOrSetter(RecognizerBase<EKotlinParserStates> attributeRule) {
354                attributeRule.preCondition(createPreGetterAndSetterPrecondition()).skipAny(EnumSet.of(EOL))
355                                .parseOnce(IN_PROPERTY).skipAny(EnumSet.of(EOL)).parseOnce(IN_PROPERTY).endNode();
356                attributeRule.skipAny(EnumSet.of(EOL)).parseOnce(IN_PROPERTY).endNode();
357                attributeRule.endNode();
358        }
359
360        /**
361         * Creates a recognizer, which is used to differentiate between the case that a
362         * property is followed by none, one or two GET/SET definitions. This
363         * recognizers matches if we have GET and SET.
364         */
365        private RecognizerBase<EKotlinParserStates> createPreGetterAndSetterPrecondition() {
366                return createRecognizer(start -> {
367                        // Matches the beginning of a get/set definition
368                        RecognizerBase<EKotlinParserStates> firstGetterSetter = start.skipAny(EnumSet.of(EOL)).optional(MODIFIERS)
369                                        .sequence(EnumSet.of(GET, SET));
370
371                        // Directly followed by a second get/set
372                        firstGetterSetter.skipAny(EnumSet.of(EOL)).optional(MODIFIERS).sequence(EnumSet.of(GET, SET));
373
374                        // Matches the parenthesis after the get/set
375                        RecognizerBase<EKotlinParserStates> getterSetterWithBodyRule = firstGetterSetter.sequenceBefore(LPAREN)
376                                        .skipNested(LPAREN, RPAREN);
377
378                        // Followed by EQ and an expression and the beginning of a second get/set
379                        completeStatementRule(getterSetterWithBodyRule.sequence(EQ)).skipAny(EnumSet.of(EOL)).optional(MODIFIERS)
380                                        .sequence(EnumSet.of(GET, SET));
381
382                        // Followed by curly braces and the beginning of a second get/set
383                        getterSetterWithBodyRule.sequenceBefore(LBRACE).skipNested(LBRACE, RBRACE).skipAny(EnumSet.of(EOL))
384                                        .optional(MODIFIERS).sequence(EnumSet.of(GET, SET));
385                });
386        }
387
388        /** Create a rule to match custom property getters and setters. */
389        private void createPropertyGetterRule(ETokenType tokenType) {
390                RecognizerBase<EKotlinParserStates> plainGetterSetterRule = inState(IN_PROPERTY).optional(MODIFIERS).markStart()
391                                .sequence(tokenType).createNode(METHOD, SubTypeNames.METHOD, 0);
392
393                RecognizerBase<EKotlinParserStates> methodRule = plainGetterSetterRule.sequenceBefore(LPAREN).skipNested(LPAREN,
394                                RPAREN);
395                methodRule.sequence(EQ).repeated(EOL).parseOnce(IN_METHOD).endNode();
396                methodRule.sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode();
397
398                plainGetterSetterRule.endNode();
399        }
400
401        /** Recognizes a primary constructor */
402        private RecognizerBase<EKotlinParserStates> createPrimaryConstructorRecognizer() {
403                return createRecognizer(start -> start.optional(MODIFIERS).markStart().optional(CONSTRUCTOR).sequence(LPAREN)
404                                .skipTo(RPAREN).optionalSubRecognizer(createReturnTypeRecognizer()));
405        }
406
407        /** Creates the method rules */
408        private void createMethodRules() {
409                finishMethodRule(inState(TOP_LEVEL, IN_TYPE, IN_METHOD).optional(MODIFIERS).sequence(FUN).skipNested(LT, GT)
410                                .markStart().skipBefore(LPAREN), SubTypeNames.METHOD);
411
412                // Create constructor rules
413                inState(IN_TYPE).optional(MODIFIERS).markStart().sequence(INIT).createNode(METHOD, SubTypeNames.CONSTRUCTOR, 0)
414                                .sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode();
415                finishMethodRule(inState(IN_TYPE).optional(MODIFIERS).markStart().sequence(CONSTRUCTOR),
416                                SubTypeNames.CONSTRUCTOR);
417        }
418
419        /** Finishes the given method rule for the specified subtype */
420        private void finishMethodRule(RecognizerBase<EKotlinParserStates> rule, String subtype) {
421                RecognizerBase<EKotlinParserStates> methodRule = rule.createNode(METHOD, subtype, new Region(0, -1))
422                                .skipNested(LPAREN, RPAREN).optionalSubRecognizer(createReturnTypeRecognizer());
423                methodRule.sequence(EQ).repeated(EOL).parseOnce(IN_METHOD).endNode();
424                methodRule.sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode();
425                methodRule.endNode();
426        }
427
428        /**
429         * Matches a return type definition like : SomeType or : super(...) on
430         * constructors
431         */
432        private RecognizerBase<EKotlinParserStates> createReturnTypeRecognizer() {
433                RecognizerBase<EKotlinParserStates> subExpressionRule = createRecognizer(
434                                start -> start.sequence(COLON).sequence(EnumSet.of(SUPER, THIS)).skipNested(LPAREN, RPAREN));
435                // Super constructor call
436                // Type definition
437                subExpressionRule.sequence(COLON).repeated(VALID_TYPE_TOKEN_TYPES);
438                return subExpressionRule;
439        }
440
441        /** Creates a recognizer that matches lambdas within expressions. */
442        private RecognizerBase<EKotlinParserStates> createSubExpressionRecognizer() {
443                RecognizerBase<EKotlinParserStates> subExpressionRule = createRecognizer(
444                                start -> start.sequenceBefore(LBRACE).parseOnce(IN_LAMBDA));
445                subExpressionRule.sequenceBefore(IF).parseOnce(IN_STATEMENT);
446                subExpressionRule.sequenceBefore(WHEN).parseOnce(IN_STATEMENT);
447                return subExpressionRule;
448        }
449
450        /**
451         * Creates sub expression rules.
452         * 
453         * IN_LAMBDA indicates we are at the beginning of a lambda {
454         * 
455         * IN_WHEN indicates we are inside a WHEN statement and expect to find "case"
456         * statements there (there is no keyword in Kotlin for that).
457         */
458        private void createSubExpressionRules() {
459                finishLambdaRule(inState(IN_LAMBDA).sequence(LBRACE)
460                                .skipBeforeWithNesting(EnumSet.of(ARROW, RBRACE), OPENING_BRACKETS, CLOSING_BRACKETS).sequence(ARROW));
461                finishLambdaRule(inState(IN_LAMBDA).sequence(LBRACE));
462
463                inState(IN_WHEN).sequence(EOL);
464                endWithBlock(inState(IN_WHEN).sequence(ELSE, ARROW).createNode(EShallowEntityType.META, SubTypeNames.ELSE));
465                endWithBlock(inState(IN_WHEN).skipToWithNesting(ARROW, OPENING_BRACKETS, CLOSING_BRACKETS)
466                                .createNode(EShallowEntityType.META, SubTypeNames.CASE, 0));
467        }
468
469        /** Finishes the given lambda rule. */
470        private static void finishLambdaRule(RecognizerBase<EKotlinParserStates> lambdaRule) {
471                lambdaRule.createNode(EShallowEntityType.METHOD, SubTypeNames.LAMBDA).parseUntil(IN_METHOD).sequence(RBRACE)
472                                .endNode();
473        }
474}