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.xtend; 018 019import static eu.cqse.check.framework.scanner.ETokenType.ABSTRACT; 020import static eu.cqse.check.framework.scanner.ETokenType.ANNOTATION; 021import static eu.cqse.check.framework.scanner.ETokenType.AT_OPERATOR; 022import static eu.cqse.check.framework.scanner.ETokenType.BOOLEAN; 023import static eu.cqse.check.framework.scanner.ETokenType.BYTE; 024import static eu.cqse.check.framework.scanner.ETokenType.CASE; 025import static eu.cqse.check.framework.scanner.ETokenType.CATCH; 026import static eu.cqse.check.framework.scanner.ETokenType.CHAR; 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.CREATE; 031import static eu.cqse.check.framework.scanner.ETokenType.DEF; 032import static eu.cqse.check.framework.scanner.ETokenType.DEFAULT; 033import static eu.cqse.check.framework.scanner.ETokenType.DISPATCH; 034import static eu.cqse.check.framework.scanner.ETokenType.DO; 035import static eu.cqse.check.framework.scanner.ETokenType.DOT; 036import static eu.cqse.check.framework.scanner.ETokenType.DOUBLE; 037import static eu.cqse.check.framework.scanner.ETokenType.DOUBLE_ARROW; 038import static eu.cqse.check.framework.scanner.ETokenType.ELSE; 039import static eu.cqse.check.framework.scanner.ETokenType.ENUM; 040import static eu.cqse.check.framework.scanner.ETokenType.EXTENSION; 041import static eu.cqse.check.framework.scanner.ETokenType.FINAL; 042import static eu.cqse.check.framework.scanner.ETokenType.FINALLY; 043import static eu.cqse.check.framework.scanner.ETokenType.FLOAT; 044import static eu.cqse.check.framework.scanner.ETokenType.FOR; 045import static eu.cqse.check.framework.scanner.ETokenType.GT; 046import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER; 047import static eu.cqse.check.framework.scanner.ETokenType.IF; 048import static eu.cqse.check.framework.scanner.ETokenType.IMPORT; 049import static eu.cqse.check.framework.scanner.ETokenType.INT; 050import static eu.cqse.check.framework.scanner.ETokenType.INTERFACE; 051import static eu.cqse.check.framework.scanner.ETokenType.LBRACE; 052import static eu.cqse.check.framework.scanner.ETokenType.LBRACK; 053import static eu.cqse.check.framework.scanner.ETokenType.LONG; 054import static eu.cqse.check.framework.scanner.ETokenType.LPAREN; 055import static eu.cqse.check.framework.scanner.ETokenType.LT; 056import static eu.cqse.check.framework.scanner.ETokenType.MULT; 057import static eu.cqse.check.framework.scanner.ETokenType.NATIVE; 058import static eu.cqse.check.framework.scanner.ETokenType.NEW; 059import static eu.cqse.check.framework.scanner.ETokenType.OR; 060import static eu.cqse.check.framework.scanner.ETokenType.OVERRIDE; 061import static eu.cqse.check.framework.scanner.ETokenType.PACKAGE; 062import static eu.cqse.check.framework.scanner.ETokenType.PRIVATE; 063import static eu.cqse.check.framework.scanner.ETokenType.PROTECTED; 064import static eu.cqse.check.framework.scanner.ETokenType.PUBLIC; 065import static eu.cqse.check.framework.scanner.ETokenType.RBRACE; 066import static eu.cqse.check.framework.scanner.ETokenType.RBRACK; 067import static eu.cqse.check.framework.scanner.ETokenType.RPAREN; 068import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON; 069import static eu.cqse.check.framework.scanner.ETokenType.SHORT; 070import static eu.cqse.check.framework.scanner.ETokenType.STATIC; 071import static eu.cqse.check.framework.scanner.ETokenType.STRICTFP; 072import static eu.cqse.check.framework.scanner.ETokenType.SWITCH; 073import static eu.cqse.check.framework.scanner.ETokenType.SYNCHRONIZED; 074import static eu.cqse.check.framework.scanner.ETokenType.TEMPLATE_LITERAL; 075import static eu.cqse.check.framework.scanner.ETokenType.THROWS; 076import static eu.cqse.check.framework.scanner.ETokenType.TRANSIENT; 077import static eu.cqse.check.framework.scanner.ETokenType.TRY; 078import static eu.cqse.check.framework.scanner.ETokenType.VAL; 079import static eu.cqse.check.framework.scanner.ETokenType.VAR; 080import static eu.cqse.check.framework.scanner.ETokenType.VOID; 081import static eu.cqse.check.framework.scanner.ETokenType.VOLATILE; 082import static eu.cqse.check.framework.scanner.ETokenType.WHILE; 083import static eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState.IN_ENUM; 084import static eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState.IN_LAMBDA; 085import static eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState.IN_METHOD; 086import static eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState.IN_METHOD_WITH_TEMPLATE; 087import static eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState.IN_SINGLE_STATEMENT; 088import static eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState.IN_TOP_LEVEL; 089import static eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState.IN_TYPE; 090 091import java.util.EnumSet; 092 093import org.conqat.lib.commons.region.Region; 094 095import eu.cqse.check.framework.scanner.ETokenType; 096import eu.cqse.check.framework.scanner.ETokenType.ETokenClass; 097import eu.cqse.check.framework.scanner.IToken; 098import eu.cqse.check.framework.shallowparser.SubTypeNames; 099import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType; 100import eu.cqse.check.framework.shallowparser.framework.RecognizerBase; 101import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase; 102import eu.cqse.check.framework.shallowparser.languages.xtend.XtendShallowParser.EXtendShallowParserState; 103 104/** 105 * Shallow parser for Xtend. 106 * <p> 107 * Same features as the Java shallow parser: 108 * <ul> 109 * <li>The parser recognizes types (classes, enums, interfaces, annotations), 110 * methods and attributes, and individual statements.</li> 111 * <li>It recognizes the nesting of statements (e.g. in loops), but does not 112 * parse into the statements. For example, it recognizes an if-statement and 113 * provides the list of sub-statements, but does not provide direct access to 114 * the if-condition.</li> 115 * <li>Import and package statements are parsed as meta information.</li> 116 * <li>Annotations are recognized as meta information, but only annotations at 117 * types and methods. Annotations at parameters are not parsed, as the parser 118 * does not parse into the parameter list of methods.</li> 119 * <li>The parser does not recognize anonymous classes. These are treated as a 120 * single long statement or attribute. Inner classes, however, are parsed 121 * correctly.</li> 122 * <li>The parser recognizes try, switch and if assignments to fields.</li> 123 * <li>The parser can deal with multiple classes in a single file.</li> 124 * </ul> 125 */ 126public class XtendShallowParser extends ShallowParserBase<EXtendShallowParserState> { 127 128 /** The states of the xtend parser */ 129 public static enum EXtendShallowParserState { 130 /** Top level state (e.g. at the beginning of the file). */ 131 IN_TOP_LEVEL, 132 133 /** State inside a type (class, interface or annotation) definition. */ 134 IN_TYPE, 135 136 /** State inside a method definition. */ 137 IN_METHOD, 138 139 /** State inside a method definition with template literal. */ 140 IN_METHOD_WITH_TEMPLATE, 141 142 /** State inside a region, that accepts only a single statement. */ 143 IN_SINGLE_STATEMENT, 144 145 /** State inside an enum body. */ 146 IN_ENUM, 147 148 /** 149 * State to match a lambda expression, the content of the lambda 150 * expression however is treated as IN_METHOD 151 */ 152 IN_LAMBDA 153 } 154 155 /** All modifiers that may be part of a type definition. */ 156 private static final EnumSet<ETokenType> TYPE_MODIFIERS = EnumSet.of(PUBLIC, PRIVATE, PROTECTED, PACKAGE, STRICTFP, 157 ABSTRACT, STATIC); 158 159 /** All possible types of a field. */ 160 private static final EnumSet<ETokenType> FIELD_TYPES = EnumSet.of(BOOLEAN, BYTE, CHAR, DOUBLE, FLOAT, INT, LONG, 161 SHORT, VOID); 162 163 /** All possible modifiers of a field. */ 164 private static final EnumSet<ETokenType> FIELD_MODIFIERS = EnumSet.of(PUBLIC, PRIVATE, PROTECTED, PACKAGE, STATIC, 165 FINAL, EXTENSION, VOLATILE, TRANSIENT); 166 167 /** All possible modifiers of a method. */ 168 private static final EnumSet<ETokenType> METHOD_MODIFIERS = EnumSet.of(PUBLIC, PRIVATE, PROTECTED, PACKAGE, STATIC, 169 ABSTRACT, DISPATCH, FINAL, STRICTFP, NATIVE, SYNCHRONIZED); 170 171 /** Constructor */ 172 public XtendShallowParser() { 173 super(EXtendShallowParserState.class, IN_TOP_LEVEL); 174 createMetaRules(); 175 createTypeDefRules(); 176 177 createEnumBodyRule(); 178 179 createMethodDefRule(); 180 createConstructorDefRule(); 181 182 createLoopRules(); 183 createSwitchCaseRules(); 184 createContinuationRules(); 185 186 createAnonymousBlock(); 187 createFieldRules(); 188 createSingleStatementRule(); 189 190 createLambdaExpressionRule(); 191 192 createEmptyStatementRule(); 193 } 194 195 /** Creates the meta rules, such as package, annotation and import. */ 196 private void createMetaRules() { 197 createImportRule(); 198 createPackageRule(); 199 createAnnotationRule(); 200 } 201 202 /** Creates the rule for imports. */ 203 private void createImportRule() { 204 inState(IN_TOP_LEVEL).sequence(IMPORT).optional(STATIC).optional(EXTENSION).markStart().sequence(IDENTIFIER) 205 .repeated(DOT, EnumSet.of(IDENTIFIER, MULT)) 206 .createNode(EShallowEntityType.META, SubTypeNames.IMPORT, new Region(0, -1)).optional(SEMICOLON) 207 .endNode(); 208 } 209 210 /** Creates the rule for package declarations. */ 211 private void createPackageRule() { 212 inState(IN_TOP_LEVEL).sequence(PACKAGE).sequence(IDENTIFIER).repeated(DOT, IDENTIFIER) 213 .createNode(EShallowEntityType.META, 0, new Region(1, -1)).optional(SEMICOLON).endNode(); 214 } 215 216 /** Creates the rule for annotations. */ 217 private void createAnnotationRule() { 218 inState(IN_TOP_LEVEL, IN_TYPE, IN_METHOD).sequence(AT_OPERATOR, IDENTIFIER) 219 .createNode(EShallowEntityType.META, SubTypeNames.ANNOTATION, -1).skipNested(LPAREN, RPAREN).endNode(); 220 } 221 222 /** Creates all rules that recognize type definitions. */ 223 private void createTypeDefRules() { 224 createTypeDefRule(ENUM, SubTypeNames.ENUM, IN_ENUM, IN_TOP_LEVEL, IN_TYPE); 225 createTypeDefRule(INTERFACE, SubTypeNames.INTERFACE, IN_TYPE, IN_TOP_LEVEL, IN_TYPE); 226 createTypeDefRule(ANNOTATION, SubTypeNames.ANNOTATION, IN_TYPE, IN_TOP_LEVEL, IN_TYPE); 227 createTypeDefRule(CLASS, SubTypeNames.CLASS, IN_TYPE, IN_TOP_LEVEL, IN_TYPE, IN_METHOD); 228 } 229 230 /** Creates a rule that matches a specific type definition. */ 231 private void createTypeDefRule(ETokenType type, String subtypeName, EXtendShallowParserState substate, 232 EXtendShallowParserState... states) { 233 inState(states).repeated(TYPE_MODIFIERS).sequence(type).sequence(IDENTIFIER) 234 .createNode(EShallowEntityType.TYPE, subtypeName, -1).skipTo(LBRACE).parseUntil(substate) 235 .sequence(RBRACE).endNode(); 236 } 237 238 /** Recognizes an enumeration inside of an enum body. */ 239 private void createEnumBodyRule() { 240 inState(IN_ENUM).sequence(IDENTIFIER).sequenceBefore(COMMA) 241 .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ENUM_LITERAL, 0).endNode(); 242 243 inState(IN_ENUM).sequence(IDENTIFIER).sequenceBefore(RBRACE) 244 .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ENUM_LITERAL, 0).endNode(); 245 } 246 247 /** Creates rule that recognizes method definitions. */ 248 private void createMethodDefRule() { 249 RecognizerBase<EXtendShallowParserState> baseRecognizer = inState(IN_TYPE).repeated(METHOD_MODIFIERS) 250 .sequence(EnumSet.of(DEF, OVERRIDE)).repeated(METHOD_MODIFIERS).optional(FIELD_TYPES) 251 .repeated(METHOD_MODIFIERS); 252 253 RecognizerBase<EXtendShallowParserState> baseWithSimpleCreate = baseRecognizer.optional(IDENTIFIER) 254 .sequence(CREATE).skipTo(NEW).sequence(IDENTIFIER).skipNested(LPAREN, RPAREN); 255 256 appendMethodNode(baseWithSimpleCreate); 257 appendMethodNode(baseRecognizer); 258 259 inState(IN_METHOD_WITH_TEMPLATE).sequence(TEMPLATE_LITERAL) 260 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, -1).endNode(); 261 } 262 263 /** Appends the node for a method. */ 264 private static void appendMethodNode(RecognizerBase<EXtendShallowParserState> baseRecognizer) { 265 RecognizerBase<EXtendShallowParserState> newBaseRecognizer = baseRecognizer.skipBefore(LPAREN) 266 .createNode(EShallowEntityType.METHOD, SubTypeNames.METHOD, -1).skipNested(LPAREN, RPAREN); 267 268 // Method header only with a "throws" clause (in interface declaration) 269 RecognizerBase<EXtendShallowParserState> withThrowsException = newBaseRecognizer.sequence(THROWS) 270 .subRecognizer(new XtendSkipToEndOfStatementRecognizer(), 0, 1); 271 272 appendRecognizeMethodBody(newBaseRecognizer); 273 appendRecognizeMethodBody(withThrowsException); 274 275 withThrowsException.endNode(); // abstract method def 276 newBaseRecognizer.endNode(); // abstract method def 277 } 278 279 /** 280 * Appends the rule to recognize the method body, which is either a 281 * statement block or a template. 282 */ 283 private static void appendRecognizeMethodBody(RecognizerBase<EXtendShallowParserState> baseRecognizer) { 284 baseRecognizer.sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode(); 285 baseRecognizer.sequenceBefore(TEMPLATE_LITERAL).parseOnce(IN_METHOD_WITH_TEMPLATE).endNode(); 286 } 287 288 /** Creates rule for constructors. */ 289 private void createConstructorDefRule() { 290 inState(IN_TYPE).sequence(NEW).createNode(EShallowEntityType.METHOD, SubTypeNames.CONSTRUCTOR).skipTo(LBRACE) 291 .parseUntil(IN_METHOD).sequence(RBRACE).endNode(); 292 } 293 294 /** Creates all rules that correspond to loops. */ 295 private void createLoopRules() { 296 createForRule(); 297 createDoWhileRule(); 298 createWhileRule(); 299 } 300 301 /** Creates rule for for statements. */ 302 private void createForRule() { 303 RecognizerBase<EXtendShallowParserState> baseRecognizer = inState(IN_METHOD).sequence(FOR) 304 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.FOR).skipNested(LPAREN, RPAREN); 305 306 appendEndNodeWithBlockOrSingleStatement(baseRecognizer); 307 } 308 309 /** Creates rule for do while statements. */ 310 private void createDoWhileRule() { 311 RecognizerBase<EXtendShallowParserState> baseRecognizer = inState(IN_METHOD).sequence(DO) 312 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.DO); 313 314 appendWhileRuleInDoWhile(baseRecognizer.sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE)); 315 appendWhileRuleInDoWhile(baseRecognizer.parseOnce(IN_SINGLE_STATEMENT)); 316 } 317 318 /** Appends the while statement to the rule after the do block. */ 319 private static void appendWhileRuleInDoWhile(RecognizerBase<EXtendShallowParserState> baseRecognizer) { 320 baseRecognizer.sequence(WHILE).skipNested(LPAREN, RPAREN).endNode(); 321 } 322 323 /** Creates rule for while statement. */ 324 private void createWhileRule() { 325 RecognizerBase<EXtendShallowParserState> baseRecognizer = inState(IN_METHOD).sequence(WHILE) 326 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.WHILE).skipNested(LPAREN, RPAREN); 327 appendEndNodeWithBlockOrSingleStatement(baseRecognizer); 328 } 329 330 /** Creates rule that matches switch case statements. */ 331 private void createSwitchCaseRules() { 332 inState(IN_METHOD).sequence(SWITCH).createNode(EShallowEntityType.STATEMENT, SubTypeNames.SWITCH).skipTo(LBRACE) 333 .parseUntil(IN_METHOD).sequence(RBRACE).endNode(); 334 createCaseRules(); 335 } 336 337 /** Creates rules that apply within a switch block. */ 338 private void createCaseRules() { 339 inState(IN_METHOD).sequence(DEFAULT).sequence(COLON).createNode(EShallowEntityType.META, SubTypeNames.DEFAULT) 340 .endNode(); 341 342 // type guard (with optional case) 343 inState(IN_METHOD).repeated(IDENTIFIER, DOT).sequence(IDENTIFIER).skipNested(LT, GT) 344 .sequenceBefore(EnumSet.of(COMMA, COLON, CASE)).skipTo(EnumSet.of(COMMA, COLON)) 345 .createNode(EShallowEntityType.META, SubTypeNames.CASE).endNode(); 346 347 // case only 348 inState(IN_METHOD).sequence(CASE) 349 .skipToWithNesting(EnumSet.of(COMMA, COLON), ETokenType.LPAREN, ETokenType.RPAREN) 350 .createNode(EShallowEntityType.META, SubTypeNames.CASE).endNode(); 351 } 352 353 /** 354 * Creates rule for statements with continuation like if-else statements and 355 * try-catch-finally. 356 */ 357 private void createContinuationRules() { 358 createRuleWithContinuation(IF, ELSE, ELSE, IF); 359 createRuleWithContinuation(TRY, FINALLY, CATCH); 360 } 361 362 /** 363 * Create one rule for a statement with continuation. 364 */ 365 private void createRuleWithContinuation(ETokenType first, ETokenType last, ETokenType... middle) { 366 RecognizerBase<EXtendShallowParserState> baseMid = inState(IN_METHOD).sequence((Object[]) middle) 367 .createNode(EShallowEntityType.STATEMENT, new Region(0, -1)).skipNested(LPAREN, RPAREN); 368 appendSingleStatementAndBlockForContinuationNode(baseMid, last, middle); 369 370 RecognizerBase<EXtendShallowParserState> baseFirst = inState(IN_METHOD).sequence(EnumSet.of(first, last)) 371 .createNode(EShallowEntityType.STATEMENT, new Region(0, -1)).skipNested(LPAREN, RPAREN); 372 appendSingleStatementAndBlockForContinuationNode(baseFirst, last, middle); 373 374 } 375 376 /** 377 * Appends single statement and blocks of statements rule to continuation 378 * constructs. 379 */ 380 private static void appendSingleStatementAndBlockForContinuationNode( 381 RecognizerBase<EXtendShallowParserState> baseRecognizer, ETokenType last, ETokenType... middle) { 382 RecognizerBase<EXtendShallowParserState> baseBlock = baseRecognizer.sequence(LBRACE).parseUntil(IN_METHOD) 383 .sequence(RBRACE); 384 RecognizerBase<EXtendShallowParserState> baseSingleStatement = baseRecognizer.parseOnce(IN_SINGLE_STATEMENT); 385 appendEndOfNodeInContinuationConstructs(baseBlock, last, middle); 386 appendEndOfNodeInContinuationConstructs(baseSingleStatement, last, middle); 387 } 388 389 /** Appends the rules for the end of a node in continuation constructs. */ 390 private static void appendEndOfNodeInContinuationConstructs(RecognizerBase<EXtendShallowParserState> baseRecognizer, 391 ETokenType last, ETokenType... middle) { 392 baseRecognizer.sequenceBefore(last).endNodeWithContinuation(); 393 baseRecognizer.sequenceBefore((Object[]) middle).endNodeWithContinuation(); 394 baseRecognizer.optional(ETokenType.SEMICOLON).endNode(); 395 } 396 397 /** Rule for anonymous blocks. */ 398 private void createAnonymousBlock() { 399 inAnyState().sequence(LBRACE).createNode(EShallowEntityType.STATEMENT, SubTypeNames.ANONYMOUS_BLOCK) 400 .parseUntil(IN_METHOD).sequence(RBRACE).endNode(); 401 } 402 403 /** Creates all rules that correspond to field definitions. */ 404 private void createFieldRules() { 405 createFieldRule(EShallowEntityType.ATTRIBUTE, SubTypeNames.ATTRIBUTE, IN_TYPE); 406 createFieldRule(EShallowEntityType.STATEMENT, SubTypeNames.LOCAL_VARIABLE, IN_METHOD); 407 408 // Addition to attribute, as local variables cannot be defined via 409 // "IDENTIFIER IDENTIFIER" 410 RecognizerBase<EXtendShallowParserState> baseWithIdentifier = inState(IN_TYPE).repeated(FIELD_MODIFIERS) 411 .sequence(IDENTIFIER).skipNested(LT, GT).repeated(LBRACK, RBRACK).sequence(IDENTIFIER); 412 413 appendFieldNodeAndSkipToEnd(baseWithIdentifier, EShallowEntityType.ATTRIBUTE, SubTypeNames.ATTRIBUTE); 414 } 415 416 /** Create rule for attributes. */ 417 private void createFieldRule(EShallowEntityType type, String subtype, EXtendShallowParserState... states) { 418 419 // To declare an attribute or a variable it must include either 420 // val, var or an actual type 421 RecognizerBase<EXtendShallowParserState> baseWithValOrVar = inState(states).repeated(FIELD_MODIFIERS) 422 .sequence(EnumSet.of(VAL, VAR)).repeated(FIELD_MODIFIERS).optional(FIELD_TYPES).repeated(LBRACK, RBRACK) 423 .sequence(IDENTIFIER).skipNested(LT, GT).repeated(LBRACK, RBRACK).optional(IDENTIFIER); 424 425 RecognizerBase<EXtendShallowParserState> baseWithFieldType = inState(states).repeated(FIELD_MODIFIERS) 426 .sequence(FIELD_TYPES).repeated(LBRACK, RBRACK).sequence(IDENTIFIER); 427 428 // Additional rule because constructs like this are valid: 429 // var (String)=>String stringToStringFunction = [ toUpperCase ] 430 RecognizerBase<EXtendShallowParserState> baseWithLambda = inState(states).repeated(FIELD_MODIFIERS) 431 .sequence(EnumSet.of(VAL, VAR)).skipNested(LPAREN, RPAREN).sequence(DOUBLE_ARROW) 432 .sequence(EnumSet.of(IDENTIFIER, DOUBLE, FLOAT, BYTE, SHORT, LONG, CHAR, INT, BOOLEAN)) 433 .sequence(IDENTIFIER); 434 435 appendFieldNodeAndSkipToEnd(baseWithValOrVar, type, subtype); 436 appendFieldNodeAndSkipToEnd(baseWithFieldType, type, subtype); 437 appendFieldNodeAndSkipToEnd(baseWithLambda, type, subtype); 438 } 439 440 /** 441 * Creates a node of a given type and subtype and skips to the end of the 442 * statement, the name of the node is defined by the previous token. 443 */ 444 private static void appendFieldNodeAndSkipToEnd(RecognizerBase<EXtendShallowParserState> baseRecognizer, 445 EShallowEntityType type, String subtype) { 446 RecognizerBase<EXtendShallowParserState> alternative = baseRecognizer.createNode(type, subtype, -1); 447 alternative.sequence(ETokenType.EQ).subRecognizer(new XtendSkipToEndOfStatementRecognizer(), 0, 1).endNode(); 448 alternative.optional(ETokenType.SEMICOLON).endNode(); 449 } 450 451 /** 452 * Factory method for a recognizer that matches a single statement. Should 453 * match nearly everything, that is left. 454 */ 455 private void createSingleStatementRule() { 456 RecognizerBase<EXtendShallowParserState> baseClasses = inState(IN_METHOD, IN_SINGLE_STATEMENT).sequence( 457 EnumSet.of(ETokenClass.KEYWORD, ETokenClass.IDENTIFIER, ETokenClass.LITERAL, ETokenClass.OPERATOR)); 458 459 // this is especially needed, because a statement can start with 460 // LPAREN. 461 RecognizerBase<EXtendShallowParserState> baseLparen = inState(IN_METHOD, IN_SINGLE_STATEMENT) 462 .sequenceBefore(LPAREN); 463 464 appendSingleStatementNode(baseClasses); 465 appendSingleStatementNode(baseLparen); 466 } 467 468 /** Appends the node creation for a simple statement. */ 469 private static void appendSingleStatementNode(RecognizerBase<EXtendShallowParserState> baseRecognizer) { 470 baseRecognizer.createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, 0) 471 .subRecognizer(new XtendSkipToEndOfStatementRecognizer(), 0, 1).endNode(); 472 } 473 474 /** Rule to recognize lambda expressions */ 475 private void createLambdaExpressionRule() { 476 RecognizerBase<EXtendShallowParserState> alternative = inState(IN_LAMBDA).sequence(LBRACK) 477 .createNode(EShallowEntityType.METHOD, SubTypeNames.LAMBDA_EXPRESSION); 478 alternative.skipBeforeWithNesting(EnumSet.of(RBRACK, OR), LBRACK, RBRACK).sequence(OR).parseUntil(IN_METHOD) 479 .sequence(RBRACK).endNode(); 480 481 alternative.parseUntil(IN_METHOD).sequence(RBRACK).endNode(); 482 } 483 484 /** Matches for single semicolons and adds an empty statement for them. */ 485 private void createEmptyStatementRule() { 486 inAnyState().sequence(SEMICOLON).createNode(EShallowEntityType.STATEMENT, SubTypeNames.EMPTY_STATEMENT, 0) 487 .endNode(); 488 } 489 490 /** 491 * Ends a rule with either multiple statements in a block or a single 492 * statement. 493 */ 494 private static void appendEndNodeWithBlockOrSingleStatement( 495 RecognizerBase<EXtendShallowParserState> baseRecognizer) { 496 baseRecognizer.sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode(); 497 baseRecognizer.parseOnce(IN_SINGLE_STATEMENT).endNode(); 498 } 499 500 /** {@inheritDoc} */ 501 @Override 502 protected boolean isFilteredToken(IToken token, IToken previousToken) { 503 return super.isFilteredToken(token, previousToken) || token.getType() == ETokenType.EOL; 504 } 505}