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}