001/*-------------------------------------------------------------------------+ 002| | 003| Copyright (c) 2009-2018 CQSE GmbH | 004| | 005+-------------------------------------------------------------------------*/ 006package eu.cqse.check.framework.shallowparser.languages.objectivec; 007 008import static eu.cqse.check.framework.scanner.ETokenType.AUTORELEASEPOOL; 009import static eu.cqse.check.framework.scanner.ETokenType.BOOL; 010import static eu.cqse.check.framework.scanner.ETokenType.BOOLEAN_LITERAL; 011import static eu.cqse.check.framework.scanner.ETokenType.BREAK; 012import static eu.cqse.check.framework.scanner.ETokenType.CHAR; 013import static eu.cqse.check.framework.scanner.ETokenType.CLASS; 014import static eu.cqse.check.framework.scanner.ETokenType.COLON; 015import static eu.cqse.check.framework.scanner.ETokenType.COMMA; 016import static eu.cqse.check.framework.scanner.ETokenType.CONTINUE; 017import static eu.cqse.check.framework.scanner.ETokenType.DOUBLE; 018import static eu.cqse.check.framework.scanner.ETokenType.ELSE; 019import static eu.cqse.check.framework.scanner.ETokenType.ENUM; 020import static eu.cqse.check.framework.scanner.ETokenType.EQ; 021import static eu.cqse.check.framework.scanner.ETokenType.FINALLY; 022import static eu.cqse.check.framework.scanner.ETokenType.FLOAT; 023import static eu.cqse.check.framework.scanner.ETokenType.FLOATING_POINT_LITERAL; 024import static eu.cqse.check.framework.scanner.ETokenType.FOR; 025import static eu.cqse.check.framework.scanner.ETokenType.GOTO; 026import static eu.cqse.check.framework.scanner.ETokenType.ID; 027import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER; 028import static eu.cqse.check.framework.scanner.ETokenType.IMPLEMENTATION; 029import static eu.cqse.check.framework.scanner.ETokenType.IMPORT; 030import static eu.cqse.check.framework.scanner.ETokenType.INT; 031import static eu.cqse.check.framework.scanner.ETokenType.INTEGER_LITERAL; 032import static eu.cqse.check.framework.scanner.ETokenType.INTERFACE; 033import static eu.cqse.check.framework.scanner.ETokenType.LBRACE; 034import static eu.cqse.check.framework.scanner.ETokenType.LBRACK; 035import static eu.cqse.check.framework.scanner.ETokenType.LONG; 036import static eu.cqse.check.framework.scanner.ETokenType.LPAREN; 037import static eu.cqse.check.framework.scanner.ETokenType.MINUS; 038import static eu.cqse.check.framework.scanner.ETokenType.MULT; 039import static eu.cqse.check.framework.scanner.ETokenType.PLUS; 040import static eu.cqse.check.framework.scanner.ETokenType.PREPROCESSOR_DIRECTIVE; 041import static eu.cqse.check.framework.scanner.ETokenType.PREPROCESSOR_INCLUDE; 042import static eu.cqse.check.framework.scanner.ETokenType.RBRACE; 043import static eu.cqse.check.framework.scanner.ETokenType.RETURN; 044import static eu.cqse.check.framework.scanner.ETokenType.RPAREN; 045import static eu.cqse.check.framework.scanner.ETokenType.SELF; 046import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON; 047import static eu.cqse.check.framework.scanner.ETokenType.SHORT; 048import static eu.cqse.check.framework.scanner.ETokenType.SIGNED; 049import static eu.cqse.check.framework.scanner.ETokenType.STATIC; 050import static eu.cqse.check.framework.scanner.ETokenType.STRING_LITERAL; 051import static eu.cqse.check.framework.scanner.ETokenType.STRUCT; 052import static eu.cqse.check.framework.scanner.ETokenType.SUPER; 053import static eu.cqse.check.framework.scanner.ETokenType.SWITCH; 054import static eu.cqse.check.framework.scanner.ETokenType.SYNCHRONIZED; 055import static eu.cqse.check.framework.scanner.ETokenType.THROW; 056import static eu.cqse.check.framework.scanner.ETokenType.UNION; 057import static eu.cqse.check.framework.scanner.ETokenType.UNSIGNED; 058import static eu.cqse.check.framework.scanner.ETokenType.VOID; 059import static eu.cqse.check.framework.scanner.ETokenType.WHILE; 060import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.ATTRIBUTE; 061import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.METHOD; 062import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_EXPRESSION; 063import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_METHOD; 064import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_TYPE; 065import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.TOP_LEVEL; 066 067import java.util.EnumSet; 068 069import org.conqat.lib.commons.region.Region; 070 071import eu.cqse.check.framework.scanner.ELanguage; 072import eu.cqse.check.framework.scanner.ETokenType; 073import eu.cqse.check.framework.shallowparser.SubTypeNames; 074import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType; 075import eu.cqse.check.framework.shallowparser.framework.RecognizerBase; 076import eu.cqse.check.framework.shallowparser.languages.base.CStyleShallowParserBase; 077import eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates; 078 079/** 080 * Shallow parser for {@link ELanguage#OBJECTIVE_C}. 081 */ 082public class ObjectiveCShallowParser extends CStyleShallowParserBase { 083 084 /** All token types that may stand at the beginning of new statement. */ 085 private static final EnumSet<ETokenType> STATEMENT_START_TOKENS = EnumSet.of(IDENTIFIER, RETURN, BREAK, CONTINUE, 086 THROW, SUPER, SELF, LPAREN, INTEGER_LITERAL, BOOLEAN_LITERAL, STRING_LITERAL, FLOATING_POINT_LITERAL, CLASS, 087 AUTORELEASEPOOL, LBRACK, MULT, GOTO); 088 089 @Override 090 protected void createClassElementsRules() { 091 createMethodRules(); 092 typePattern(inState(IN_TYPE).sequence(ETokenType.PROPERTY)).sequence(IDENTIFIER) 093 .createNode(ATTRIBUTE, SubTypeNames.PROPERTY, -1).skipTo(SEMICOLON).endNode(); 094 typePatternInState(TOP_LEVEL).sequence(IDENTIFIER).createNode(ATTRIBUTE, SubTypeNames.GLOBAL_VARIABLE, -1) 095 .skipTo(SEMICOLON).endNode(); 096 typePatternInState(IN_TYPE).sequence(IDENTIFIER).createNode(ATTRIBUTE, SubTypeNames.ATTRIBUTE, -1) 097 .skipTo(SEMICOLON).endNode(); 098 } 099 100 @Override 101 protected void createTypeRules() { 102 createTypedefRules(); 103 createEnumRules(); 104 105 inState(TOP_LEVEL).markStart().sequence(EnumSet.of(IMPLEMENTATION, INTERFACE), IDENTIFIER) 106 .createNode(EShallowEntityType.TYPE, 0, 1).optional(COLON, IDENTIFIER).parseUntil(IN_TYPE) 107 .sequence(ETokenType.END).endNode(); 108 109 // anonymous types 110 inAnyState().sequence(getTypeKeywords(), LBRACE).createNode(EShallowEntityType.TYPE, 0, "<anonymous>") 111 .parseUntil(IN_TYPE).sequence(RBRACE).optional(SEMICOLON).endNode(); 112 } 113 114 /** Creates rules for parsing enums and enum classes. */ 115 private void createEnumRules() { 116 // enum (both anonymous and named) 117 finishEnumDeclaration(inAnyState().sequence(ENUM), SubTypeNames.ENUM, 1); 118 finishEnumDeclaration(inAnyState().sequence(ENUM, CLASS), SubTypeNames.ENUM_CLASS, 2); 119 120 RecognizerBase<EGenericParserStates> enumLiteralAlternative = inState(IN_TYPE).sequence(IDENTIFIER); 121 finishEnumLiteral(enumLiteralAlternative.sequenceBefore(EnumSet.of(COMMA, RBRACE))); 122 finishEnumLiteral(enumLiteralAlternative.sequence(EQ).skipBefore(EnumSet.of(COMMA, RBRACE))); 123 } 124 125 /** Finishes the rule for enum or enum class declarations. */ 126 private static void finishEnumDeclaration(RecognizerBase<EGenericParserStates> enumAlternative, String subType, 127 Object name) { 128 enumAlternative.sequence(LBRACE).createNode(EShallowEntityType.TYPE, subType).parseUntil(IN_TYPE) 129 .sequence(RBRACE).optional(SEMICOLON).endNode(); 130 enumAlternative.sequence(IDENTIFIER).sequenceBefore(EnumSet.of(LBRACE, COLON)).skipTo(LBRACE) 131 .createNode(EShallowEntityType.TYPE, subType, name).parseUntil(IN_TYPE).sequence(RBRACE) 132 .optional(SEMICOLON).endNode(); 133 } 134 135 /** Finishes the rule for a enum literal. */ 136 private static void finishEnumLiteral(RecognizerBase<EGenericParserStates> enumLiteralAlternative) { 137 enumLiteralAlternative.createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ENUM_LITERAL, 0).endNode(); 138 } 139 140 @Override 141 protected void createMetaRules() { 142 inAnyState().sequence(EnumSet.of(PREPROCESSOR_DIRECTIVE, PREPROCESSOR_INCLUDE)) 143 .createNode(EShallowEntityType.META, 0).endNode(); 144 inAnyState().sequence(IMPORT).skipTo(SEMICOLON) 145 .createNode(EShallowEntityType.META, SubTypeNames.IMPORT, new Region(1, -2)).endNode(); 146 } 147 148 /** Recognizes methods. */ 149 private void createMethodRules() { 150 RecognizerBase<EGenericParserStates> topLevelMethod = typePatternInState(TOP_LEVEL).markStart() 151 .sequence(IDENTIFIER, LPAREN).skipTo(RPAREN); 152 topLevelMethod.sequence(LBRACE).createNode(METHOD, SubTypeNames.METHOD_IMPLEMENTATION, 0).parseUntil(IN_METHOD) 153 .sequence(RBRACE).endNode(); 154 155 RecognizerBase<EGenericParserStates> classMethod = inState(IN_TYPE).sequence(EnumSet.of(MINUS, PLUS), LPAREN) 156 .skipTo(RPAREN).markStart().sequence(IDENTIFIER).skipBeforeWithNesting(LBRACE, LPAREN, RPAREN) 157 .sequence(LBRACE); 158 classMethod.createNode(EShallowEntityType.METHOD, SubTypeNames.METHOD_IMPLEMENTATION, 0).parseUntil(IN_METHOD) 159 .sequence(RBRACE).endNode(); 160 161 inState(IN_TYPE).sequence(EnumSet.of(MINUS, PLUS), LPAREN).skipTo(RPAREN).markStart() 162 .sequence(IDENTIFIER, SEMICOLON).createNode(METHOD, SubTypeNames.METHOD_DECLARATION, 0).endNode(); 163 inState(IN_TYPE).sequence(EnumSet.of(MINUS, PLUS), LPAREN).skipTo(RPAREN).markStart() 164 .sequence(IDENTIFIER, COLON).skipBefore(SEMICOLON).sequence(SEMICOLON) 165 .createNode(METHOD, SubTypeNames.METHOD_DECLARATION, 0).endNode(); 166 167 } 168 169 /** {@inheritDoc} */ 170 @Override 171 protected void createSubExpressionRules() { 172 inState(IN_EXPRESSION).createNode(EShallowEntityType.METHOD, SubTypeNames.LAMBDA).parseUntil(IN_METHOD) 173 .sequence(RBRACE).endNode(); 174 } 175 176 /** {@inheritDoc} */ 177 @Override 178 protected EnumSet<ETokenType> getTypeKeywords() { 179 return EnumSet.of(CLASS, STRUCT, UNION, ENUM); 180 } 181 182 /** {@inheritDoc} */ 183 @Override 184 protected EnumSet<ETokenType> getSimpleBlockKeywordsWithParentheses() { 185 return EnumSet.of(WHILE, FOR, SWITCH, AUTORELEASEPOOL, SYNCHRONIZED); 186 } 187 188 /** {@inheritDoc} */ 189 @Override 190 protected EnumSet<ETokenType> getSimpleBlockKeywordsWithoutParentheses() { 191 return EnumSet.of(ELSE, FINALLY); 192 } 193 194 /** {@inheritDoc} */ 195 @Override 196 protected EnumSet<ETokenType> getStatementStartTokens() { 197 return STATEMENT_START_TOKENS; 198 } 199 200 /** {@inheritDoc} */ 201 @Override 202 protected RecognizerBase<EGenericParserStates> typePattern(RecognizerBase<EGenericParserStates> currentState) { 203 EnumSet<ETokenType> modifierKeywords = EnumSet.of(STATIC, LONG, SHORT, UNSIGNED, SIGNED); 204 EnumSet<ETokenType> typeNames = EnumSet.of(IDENTIFIER, VOID, INT, FLOAT, DOUBLE, CHAR, BOOL, ID); 205 return currentState.repeated(modifierKeywords).sequence(typeNames).optional(MULT); 206 } 207 208 /** {@inheritDoc} */ 209 @Override 210 protected RecognizerBase<EGenericParserStates> getSubExpressionRecognizer() { 211 return new ObjectiveCLambdaRecognizer(); 212 } 213 214}