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}