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}