001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright (c) 2009-2019 CQSE GmbH                                        |
004|                                                                          |
005+-------------------------------------------------------------------------*/
006package eu.cqse.check.framework.shallowparser.languages.go;
007
008import static eu.cqse.check.framework.scanner.ETokenType.BREAK;
009import static eu.cqse.check.framework.scanner.ETokenType.CASE;
010import static eu.cqse.check.framework.scanner.ETokenType.COLON;
011import static eu.cqse.check.framework.scanner.ETokenType.CONST;
012import static eu.cqse.check.framework.scanner.ETokenType.CONTINUE;
013import static eu.cqse.check.framework.scanner.ETokenType.DEFAULT;
014import static eu.cqse.check.framework.scanner.ETokenType.DEFER;
015import static eu.cqse.check.framework.scanner.ETokenType.ELSE;
016import static eu.cqse.check.framework.scanner.ETokenType.FALLTHROUGH;
017import static eu.cqse.check.framework.scanner.ETokenType.FOR;
018import static eu.cqse.check.framework.scanner.ETokenType.FUNC;
019import static eu.cqse.check.framework.scanner.ETokenType.GO;
020import static eu.cqse.check.framework.scanner.ETokenType.GOTO;
021import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER;
022import static eu.cqse.check.framework.scanner.ETokenType.IF;
023import static eu.cqse.check.framework.scanner.ETokenType.IMPORT;
024import static eu.cqse.check.framework.scanner.ETokenType.LBRACE;
025import static eu.cqse.check.framework.scanner.ETokenType.LPAREN;
026import static eu.cqse.check.framework.scanner.ETokenType.MULT;
027import static eu.cqse.check.framework.scanner.ETokenType.PACKAGE;
028import static eu.cqse.check.framework.scanner.ETokenType.RBRACE;
029import static eu.cqse.check.framework.scanner.ETokenType.RETURN;
030import static eu.cqse.check.framework.scanner.ETokenType.RPAREN;
031import static eu.cqse.check.framework.scanner.ETokenType.SELECT;
032import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON;
033import static eu.cqse.check.framework.scanner.ETokenType.STRING_LITERAL;
034import static eu.cqse.check.framework.scanner.ETokenType.SWITCH;
035import static eu.cqse.check.framework.scanner.ETokenType.TYPE;
036import static eu.cqse.check.framework.scanner.ETokenType.VAR;
037import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_METHOD;
038import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.TOP_LEVEL;
039
040import java.util.EnumSet;
041
042import org.conqat.lib.commons.region.Region;
043
044import eu.cqse.check.framework.scanner.ETokenType;
045import eu.cqse.check.framework.shallowparser.SubTypeNames;
046import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType;
047import eu.cqse.check.framework.shallowparser.framework.RecognizerBase;
048import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase;
049import eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates;
050
051/**
052 * Shallow parser for the Go programming language.
053 */
054public class GoShallowParser extends ShallowParserBase<EGenericParserStates> {
055
056        /** Constructor. */
057        public GoShallowParser() {
058                super(EGenericParserStates.class, EGenericParserStates.TOP_LEVEL);
059                createMetaRules();
060                createStatementRules();
061        }
062
063        /** Creates rules for meta elements. */
064        private void createMetaRules() {
065                createPackageRule();
066                createImportRule();
067                createLabelRule();
068        }
069
070        private void createPackageRule() {
071                inState(TOP_LEVEL).sequence(PACKAGE).markStart().sequence(IDENTIFIER)
072                                .createNode(EShallowEntityType.META, SubTypeNames.PACKAGE, new Region(0, -1)).endNode();
073        }
074
075        private void createImportRule() {
076                inState(TOP_LEVEL).sequence(IMPORT).markStart().sequence(STRING_LITERAL)
077                                .createNode(EShallowEntityType.META, SubTypeNames.IMPORT, new Region(0, -1)).endNode();
078                inState(TOP_LEVEL).sequence(IMPORT).markStart().skipNested(LPAREN, RPAREN)
079                                .createNode(EShallowEntityType.META, SubTypeNames.IMPORT).endNode();
080        }
081
082        private void createLabelRule() {
083                inState(IN_METHOD).sequence(IDENTIFIER, COLON).createNode(EShallowEntityType.META, SubTypeNames.LABEL, -2)
084                                .endNode();
085        }
086
087        private void createStatementRules() {
088                createDeclarationRules();
089                createIfStatementRules();
090                createSwitchStatementRules();
091                createSelectStatementRules();
092                createForStatementRules();
093                createSimpleStatementRules();
094        }
095
096        /** Creates rules for declarations. */
097        private void createDeclarationRules() {
098                createConstantDeclarationRules();
099                createTypeDeclarationRules();
100                createVariableDeclarationRules();
101                createFunctionDeclarationRules();
102                createMethodDeclarationRules();
103        }
104
105        private void createConstantDeclarationRules() {
106                RecognizerBase<EGenericParserStates> constBase = inState(IN_METHOD, TOP_LEVEL).sequenceBefore(CONST)
107                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.CONSTANT);
108                skipToEndOfStatement(constBase, true);
109        }
110
111        private void createTypeDeclarationRules() {
112                RecognizerBase<EGenericParserStates> typeBase = inState(IN_METHOD, TOP_LEVEL).sequenceBefore(TYPE)
113                                .createNode(EShallowEntityType.TYPE, SubTypeNames.DECLARATION);
114                skipToEndOfStatement(typeBase, true);
115        }
116
117        private void createVariableDeclarationRules() {
118                RecognizerBase<EGenericParserStates> typeBase = inState(IN_METHOD, TOP_LEVEL).sequenceBefore(VAR)
119                                .createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.VARIABLE, 1);
120                skipToEndOfStatement(typeBase, true);
121        }
122
123        private void createFunctionDeclarationRules() {
124                // Matches 'func MyFunction'.
125                RecognizerBase<EGenericParserStates> functionPrefix = inState(TOP_LEVEL).sequence(FUNC);
126                createGeneralFunctionRules(functionPrefix, SubTypeNames.FUNCTION);
127        }
128
129        private void createMethodDeclarationRules() {
130                // Matches 'func (...) MyMethod'.
131                RecognizerBase<EGenericParserStates> methodPrefix = inState(TOP_LEVEL).sequence(FUNC).sequence(LPAREN)
132                                .skipToWithNesting(RPAREN, LPAREN, RPAREN);
133                createGeneralFunctionRules(methodPrefix, SubTypeNames.METHOD);
134        }
135
136        private static void createGeneralFunctionRules(RecognizerBase<EGenericParserStates> base, final Object subtype) {
137                // Matches 'MyFunction(...)'.
138                RecognizerBase<EGenericParserStates> functionDef = base.markStart().sequence(IDENTIFIER).sequence(LPAREN)
139                                .skipToWithNesting(RPAREN, LPAREN, RPAREN);
140
141                // Non abstract methods continue with '{...}.
142                functionDef.skipTo(LBRACE).createNode(EShallowEntityType.METHOD, subtype, 0).parseUntil(IN_METHOD)
143                                .sequence(RBRACE).endNode();
144
145                // Abstract methods
146                functionDef.createNode(EShallowEntityType.METHOD, subtype, 0).optional(IDENTIFIER).endNode();
147                functionDef.sequence(LPAREN).skipToWithNesting(RPAREN, LPAREN, RPAREN)
148                                .createNode(EShallowEntityType.METHOD, subtype, 0).endNode();
149        }
150
151        private void createIfStatementRules() {
152                // Matches 'if ... ; i < 0 {'
153                inState(IN_METHOD).sequence(IF).markStart().skipBeforeWithNesting(LBRACE, LPAREN, RPAREN)
154                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.IF, new Region(0, -1)).sequence(LBRACE)
155
156                                .parseUntil(IN_METHOD).sequence(RBRACE).endNode();
157
158                inState(IN_METHOD).sequence(IF).parseUntil(IN_METHOD).skipTo(SEMICOLON).markStart().sequence(IDENTIFIER)
159                                .skipBefore(LBRACE).createNode(EShallowEntityType.STATEMENT, SubTypeNames.IF, new Region(0, -1))
160                                .sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode();
161
162                inState(IN_METHOD).sequence(ELSE, IF).markStart().skipBefore(LBRACE)
163                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.ELSE_IF, new Region(0, -1)).sequence(LBRACE)
164                                .parseUntil(IN_METHOD).sequence(RBRACE).endNode();
165
166                inState(IN_METHOD).sequence(ELSE, IF).parseUntil(IN_METHOD).skipTo(SEMICOLON).markStart().sequence(IDENTIFIER)
167                                .skipBefore(LBRACE).createNode(EShallowEntityType.STATEMENT, SubTypeNames.IF, new Region(0, -1))
168                                .sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode();
169
170                inState(IN_METHOD).sequence(ELSE).createNode(EShallowEntityType.STATEMENT, SubTypeNames.ELSE).sequence(LBRACE)
171
172                                .parseUntil(IN_METHOD).sequence(RBRACE).endNode();
173        }
174
175        private void createSwitchStatementRules() {
176                inState(IN_METHOD).sequence(SWITCH).createNode(EShallowEntityType.STATEMENT, SubTypeNames.SWITCH).skipTo(LBRACE)
177                                .parseUntil(IN_METHOD).sequence(RBRACE).endNode();
178
179                // Matches 'case "darwin":'
180                inState(IN_METHOD).sequence(CASE).markStart().skipBefore(COLON)
181                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.CASE).sequence(COLON).endNode();
182                // Matches 'default:'
183                inState(IN_METHOD).sequence(DEFAULT).markStart().sequence(COLON)
184                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.DEFAULT).endNode();
185        }
186
187        private void createSelectStatementRules() {
188                inState(IN_METHOD).sequence(SELECT).markStart().skipBefore(LBRACE)
189                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.SELECT).sequence(LBRACE).parseUntil(IN_METHOD)
190                                .sequence(RBRACE).endNode();
191        }
192
193        private void createForStatementRules() {
194                inState(IN_METHOD).sequence(FOR).markStart().skipBefore(LBRACE)
195                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.FOR, new Region(0, -1)).sequence(LBRACE)
196                                .parseUntil(IN_METHOD).sequence(RBRACE).endNode();
197        }
198
199        private void createSimpleStatementRules() {
200                EnumSet<ETokenType> statementStartTokens = EnumSet.of(IDENTIFIER, MULT, GO, GOTO, FALLTHROUGH, DEFER, RETURN,
201                                BREAK, CONTINUE);
202
203                RecognizerBase<EGenericParserStates> simpleStatementBase = inState(IN_METHOD, TOP_LEVEL)
204                                .sequenceBefore(statementStartTokens)
205                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, 0);
206
207                skipToEndOfStatement(simpleStatementBase, true);
208
209                // A statement may start with LPAREN.
210                RecognizerBase<EGenericParserStates> inParenthesis = inState(IN_METHOD, TOP_LEVEL).sequenceBefore(LPAREN)
211                                .skipNested(LPAREN, RPAREN)
212                                .createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, new Region(0, -1));
213                skipToEndOfStatement(inParenthesis);
214        }
215
216        /**
217         * Appends the {@link GoSkipToEndOfStatementRecognizer} to the given
218         * {@link RecognizerBase} and closes the node.
219         */
220        private static void skipToEndOfStatement(RecognizerBase<EGenericParserStates> base) {
221                skipToEndOfStatement(base, false);
222        }
223
224        /**
225         * Appends the {@link GoSkipToEndOfStatementRecognizer} to the given
226         * {@link RecognizerBase} and closes the node. Additionally set flag if at least
227         * one match should be forced.
228         */
229        private static void skipToEndOfStatement(RecognizerBase<EGenericParserStates> base, boolean forceMatch) {
230                GoSkipToEndOfStatementRecognizer recognizer = new GoSkipToEndOfStatementRecognizer();
231                recognizer.setForceMatch(forceMatch);
232                base.subRecognizer(recognizer, 0, 1).endNode();
233        }
234}