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}