001/*-------------------------------------------------------------------------+ 002| | 003| Copyright (c) 2009-2017 CQSE GmbH | 004| | 005+-------------------------------------------------------------------------*/ 006package eu.cqse.check.framework.shallowparser.languages.swift; 007 008import static eu.cqse.check.framework.scanner.ETokenType.ARROW; 009import static eu.cqse.check.framework.scanner.ETokenType.AT; 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.CASE; 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.DEFAULT; 018import static eu.cqse.check.framework.scanner.ETokenType.DEINIT; 019import static eu.cqse.check.framework.scanner.ETokenType.DOT; 020import static eu.cqse.check.framework.scanner.ETokenType.ELSE; 021import static eu.cqse.check.framework.scanner.ETokenType.ENUM; 022import static eu.cqse.check.framework.scanner.ETokenType.EOL; 023import static eu.cqse.check.framework.scanner.ETokenType.EXCLAMATION; 024import static eu.cqse.check.framework.scanner.ETokenType.EXTENSION; 025import static eu.cqse.check.framework.scanner.ETokenType.FILEPRIVATE; 026import static eu.cqse.check.framework.scanner.ETokenType.FLOATING_POINT_LITERAL; 027import static eu.cqse.check.framework.scanner.ETokenType.FOR; 028import static eu.cqse.check.framework.scanner.ETokenType.FUNC; 029import static eu.cqse.check.framework.scanner.ETokenType.GT; 030import static eu.cqse.check.framework.scanner.ETokenType.GUARD; 031import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER; 032import static eu.cqse.check.framework.scanner.ETokenType.IF; 033import static eu.cqse.check.framework.scanner.ETokenType.IMPORT; 034import static eu.cqse.check.framework.scanner.ETokenType.IN; 035import static eu.cqse.check.framework.scanner.ETokenType.INIT; 036import static eu.cqse.check.framework.scanner.ETokenType.INTEGER_LITERAL; 037import static eu.cqse.check.framework.scanner.ETokenType.INTERNAL; 038import static eu.cqse.check.framework.scanner.ETokenType.LBRACE; 039import static eu.cqse.check.framework.scanner.ETokenType.LBRACK; 040import static eu.cqse.check.framework.scanner.ETokenType.LET; 041import static eu.cqse.check.framework.scanner.ETokenType.LPAREN; 042import static eu.cqse.check.framework.scanner.ETokenType.LT; 043import static eu.cqse.check.framework.scanner.ETokenType.OPEN; 044import static eu.cqse.check.framework.scanner.ETokenType.PREPROCESSOR_DIRECTIVE; 045import static eu.cqse.check.framework.scanner.ETokenType.PRIVATE; 046import static eu.cqse.check.framework.scanner.ETokenType.PROTOCOL; 047import static eu.cqse.check.framework.scanner.ETokenType.PUBLIC; 048import static eu.cqse.check.framework.scanner.ETokenType.QUESTION; 049import static eu.cqse.check.framework.scanner.ETokenType.RBRACE; 050import static eu.cqse.check.framework.scanner.ETokenType.RBRACK; 051import static eu.cqse.check.framework.scanner.ETokenType.REPEAT; 052import static eu.cqse.check.framework.scanner.ETokenType.RETURN; 053import static eu.cqse.check.framework.scanner.ETokenType.RPAREN; 054import static eu.cqse.check.framework.scanner.ETokenType.SELF; 055import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON; 056import static eu.cqse.check.framework.scanner.ETokenType.STRING_LITERAL; 057import static eu.cqse.check.framework.scanner.ETokenType.STRUCT; 058import static eu.cqse.check.framework.scanner.ETokenType.SUPER; 059import static eu.cqse.check.framework.scanner.ETokenType.SWITCH; 060import static eu.cqse.check.framework.scanner.ETokenType.THROW; 061import static eu.cqse.check.framework.scanner.ETokenType.VAR; 062import static eu.cqse.check.framework.scanner.ETokenType.WHILE; 063import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.METHOD; 064import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.STATEMENT; 065import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.TYPE; 066import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_EXPRESSION; 067import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_METHOD; 068import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_TYPE; 069import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.TOP_LEVEL; 070 071import java.util.Arrays; 072import java.util.EnumSet; 073 074import org.conqat.lib.commons.region.Region; 075 076import eu.cqse.check.framework.scanner.ETokenType; 077import eu.cqse.check.framework.scanner.IToken; 078import eu.cqse.check.framework.shallowparser.SubTypeNames; 079import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType; 080import eu.cqse.check.framework.shallowparser.framework.RecognizerBase; 081import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase; 082import eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates; 083 084/** 085 * A shallow parser for the Swift programming language. 086 * 087 * <b>Notes:</b> Currently lambdas are only recognized in simple statements. 088 */ 089public class SwiftShallowParser extends ShallowParserBase<EGenericParserStates> { 090 091 /** PHP visibility modifiers. */ 092 private static final EnumSet<ETokenType> VISIBILITY_MODIFIERS = EnumSet.of(OPEN, PUBLIC, INTERNAL, PRIVATE, 093 FILEPRIVATE); 094 095 /** All token types that may stand at the beginning of new statement. */ 096 private static final EnumSet<ETokenType> STATEMENT_START_TOKENS = EnumSet.of(IDENTIFIER, RETURN, BREAK, CONTINUE, 097 THROW, SUPER, SELF, LPAREN, INTEGER_LITERAL, BOOLEAN_LITERAL, STRING_LITERAL, FLOATING_POINT_LITERAL); 098 099 /** All tokens that are valid statement separators. */ 100 private static final EnumSet<ETokenType> STATEMENT_SEPARATORS = EnumSet.of(EOL, SEMICOLON, RBRACE); 101 102 /** Token types with are allowed for type definitions. */ 103 private static final EnumSet<ETokenType> VALID_TYPE_TOKEN_TYPES = EnumSet.of(IDENTIFIER, QUESTION, DOT, LPAREN, 104 RPAREN, ARROW, COMMA, LT, GT, LBRACK, RBRACK, EXCLAMATION, EOL); 105 106 /** Constructor. */ 107 public SwiftShallowParser() { 108 super(EGenericParserStates.class, TOP_LEVEL); 109 110 createMetaRules(); 111 createTypeRules(); 112 createMethodRules(); 113 createStatementRules(); 114 createSubExpressionRules(); 115 116 // remove any isolated EOLs 117 inAnyState().sequence(EOL); 118 } 119 120 /** Creates rules for meta elements. */ 121 private void createMetaRules() { 122 inState(TOP_LEVEL).sequence(IMPORT).markStart().skipBefore(EOL) 123 .createNode(EShallowEntityType.META, SubTypeNames.IMPORT, new Region(0, -1)).endNode(); 124 inAnyState().sequence(AT, IDENTIFIER).skipNested(LPAREN, RPAREN) 125 .createNode(EShallowEntityType.META, SubTypeNames.ANNOTATION, 1).endNode(); 126 127 inAnyState().sequence(PREPROCESSOR_DIRECTIVE).skipTo(EOL) 128 .createNode(EShallowEntityType.META, SubTypeNames.PREPROCESSOR_DIRECTIVE).endNode(); 129 } 130 131 /** Creates sub expression rules. */ 132 private void createSubExpressionRules() { 133 finishLambdaRule( 134 inState(IN_EXPRESSION) 135 .sequence(LBRACE).skipBeforeWithNesting(EnumSet.of(IN, RBRACE), 136 Arrays.asList(LPAREN, LBRACK, LBRACE), Arrays.asList(RPAREN, RBRACK, RBRACE)) 137 .sequence(IN)); 138 finishLambdaRule(inState(IN_EXPRESSION).sequence(LBRACE)); 139 } 140 141 /** Finishes the given lambda rule. */ 142 private static void finishLambdaRule(RecognizerBase<EGenericParserStates> lambdaRule) { 143 lambdaRule.createNode(EShallowEntityType.METHOD, SubTypeNames.LAMBDA).parseUntil(IN_METHOD).sequence(RBRACE) 144 .endNode(); 145 } 146 147 /** Creates the statement rules. */ 148 private void createStatementRules() { 149 createLoopRules(); 150 createConditionalRules(); 151 createSimpleStatementRule(); 152 createSwitchStatementRule(); 153 createLocalVariableRule(VAR); 154 createLocalVariableRule(LET); 155 } 156 157 /** Creates a rule for a local variable declaration */ 158 private void createLocalVariableRule(ETokenType keyword) { 159 inState(TOP_LEVEL, IN_METHOD).sequence(keyword) 160 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.LOCAL_VARIABLE, 1) 161 .skipToWithNesting(EOL, Arrays.asList(LPAREN, LBRACE, LBRACK), Arrays.asList(RPAREN, RBRACE, RBRACK), 162 createSubExpressionRecognizer()) 163 .endNode(); 164 } 165 166 /** Creates a rule for a switch/case statement. */ 167 private void createSwitchStatementRule() { 168 inState(TOP_LEVEL, IN_METHOD).sequence(SWITCH).createNode(EShallowEntityType.STATEMENT, SubTypeNames.SWITCH) 169 .skipNested(LPAREN, RPAREN, createSubExpressionRecognizer()).skipTo(LBRACE).parseUntil(IN_METHOD) 170 .sequence(RBRACE).endNode(); 171 inState(IN_METHOD).sequence(CASE).createNode(EShallowEntityType.META, SubTypeNames.CASE) 172 .skipToWithNesting(COLON, LBRACK, RBRACK).endNode(); 173 inState(IN_METHOD).sequence(DEFAULT).createNode(EShallowEntityType.META, SubTypeNames.DEFAULT).skipTo(COLON) 174 .endNode(); 175 } 176 177 /** Creates a simple statement rule. */ 178 private void createSimpleStatementRule() { 179 inState(TOP_LEVEL, IN_METHOD).sequence(SEMICOLON) 180 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.EMPTY_STATEMENT).endNode(); 181 182 RecognizerBase<EGenericParserStates> statementRule = inState(TOP_LEVEL, IN_METHOD); 183 finishSimpleStatementRule(statementRule.sequenceBefore(LPAREN)); 184 finishSimpleStatementRule(statementRule.sequence(STATEMENT_START_TOKENS)); 185 186 } 187 188 /** Finishes a simple statement rule. */ 189 private void finishSimpleStatementRule(RecognizerBase<EGenericParserStates> statementRule) { 190 statementRule.createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, 0) 191 .skipBeforeWithNesting(STATEMENT_SEPARATORS, Arrays.asList(LPAREN, LBRACE, LBRACK), 192 Arrays.asList(RPAREN, RBRACE, RBRACK), createSubExpressionRecognizer()) 193 .optional(EnumSet.of(SEMICOLON, EOL)).endNode(); 194 } 195 196 /** Creates rules for conditional statements. */ 197 private void createConditionalRules() { 198 createConditionalRule(SubTypeNames.IF_LET, IF, LET); 199 createConditionalRule(SubTypeNames.IF_VAR, IF, VAR); 200 createConditionalRule(SubTypeNames.IF, IF); 201 createConditionalRule(SubTypeNames.ELSE_IF, ELSE, IF); 202 createConditionalRule(SubTypeNames.ELSE, ELSE); 203 createConditionalRule(SubTypeNames.GUARD, GUARD); 204 } 205 206 /** Creates a rule for a conditional. */ 207 private void createConditionalRule(String subtype, Object... matchTerms) { 208 endWithPossibleContinuation( 209 inState(TOP_LEVEL, IN_METHOD).sequence(matchTerms).skipToWithNesting(LBRACE, LPAREN, RPAREN) 210 .createNode(STATEMENT, subtype).parseUntil(IN_METHOD).sequence(RBRACE), 211 EnumSet.of(ELSE)); 212 } 213 214 /** Creates rules for loops */ 215 private void createLoopRules() { 216 // repeat while 217 inState(TOP_LEVEL, IN_METHOD).sequence(REPEAT) 218 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.REPEAT_WHILE) 219 .skipToWithNesting(LBRACE, LPAREN, RPAREN).parseUntil(IN_METHOD).sequence(RBRACE, WHILE).skipTo(EOL) 220 .endNode(); 221 222 createWhileRule(SubTypeNames.WHILE_LET, WHILE, LET); 223 createWhileRule(0, EnumSet.of(FOR, WHILE, REPEAT)); 224 } 225 226 /** Creates a while rule */ 227 private void createWhileRule(Object subtype, Object... matchTerms) { 228 inState(TOP_LEVEL, IN_METHOD).sequence(matchTerms).createNode(EShallowEntityType.STATEMENT, subtype) 229 .skipToWithNesting(LBRACE, LPAREN, RPAREN).parseUntil(IN_METHOD).sequence(RBRACE).endNode(); 230 } 231 232 /** Creates rules for types */ 233 public void createTypeRules() { 234 createTypeRule(CLASS, SubTypeNames.CLASS); 235 createTypeRule(PROTOCOL, SubTypeNames.PROTOCOL); 236 createTypeRule(STRUCT, SubTypeNames.STRUCT); 237 createTypeRule(ENUM, SubTypeNames.ENUM); 238 createTypeRule(EXTENSION, SubTypeNames.EXTENSION); 239 240 createPropertyRule(VAR, SubTypeNames.ATTRIBUTE); 241 createPropertyRule(LET, SubTypeNames.ATTRIBUTE); 242 createPropertyRule(CASE, SubTypeNames.ENUM_LITERAL); 243 } 244 245 /** Creates a property rule */ 246 private void createPropertyRule(ETokenType propertyKeyword, String subtype) { 247 inState(IN_TYPE).optional(VISIBILITY_MODIFIERS).markStart().sequence(propertyKeyword, IDENTIFIER) 248 .createNode(EShallowEntityType.ATTRIBUTE, subtype, 1).skipToWithNesting(EOL, LBRACE, RBRACE).endNode(); 249 } 250 251 /** Creates a type rule for the given keyword */ 252 private void createTypeRule(ETokenType typeTokenType, String subTypeName) { 253 inState(TOP_LEVEL).optional(VISIBILITY_MODIFIERS).sequence(typeTokenType, IDENTIFIER) 254 .createNode(TYPE, subTypeName, -1).skipTo(LBRACE).parseUntil(IN_TYPE).sequence(RBRACE).endNode(); 255 } 256 257 /** Creates the method rules */ 258 private void createMethodRules() { 259 finishMethodRule(inState(TOP_LEVEL, IN_TYPE).optional(VISIBILITY_MODIFIERS).sequence(FUNC, IDENTIFIER), 260 SubTypeNames.METHOD); 261 262 createConstructorDestructorRule(INIT, SubTypeNames.CONSTRUCTOR); 263 createConstructorDestructorRule(DEINIT, SubTypeNames.DESTRUCTOR); 264 265 } 266 267 /** Creates a constructor/destructor rule. */ 268 private void createConstructorDestructorRule(ETokenType keywordToken, String subtype) { 269 finishMethodRule(inState(IN_TYPE).optional(VISIBILITY_MODIFIERS).sequence(keywordToken), subtype); 270 } 271 272 /** Finishes the given method rule for the specified subtype */ 273 private void finishMethodRule(RecognizerBase<EGenericParserStates> rule, String subtype) { 274 RecognizerBase<EGenericParserStates> methodHeaderRule = rule.createNode(METHOD, subtype, -1) 275 .skipNested(LPAREN, RPAREN).optionalSubRecognizer(createReturnTypeRecognizer()); 276 methodHeaderRule.repeated(EOL).sequence(LBRACE).parseUntil(IN_METHOD).sequence(RBRACE).endNode(); 277 methodHeaderRule.endNode(); 278 } 279 280 /** Matches a return type definition like -> SomeType? */ 281 private RecognizerBase<EGenericParserStates> createReturnTypeRecognizer() { 282 return createRecognizer(start -> start.repeated(EOL).sequence(ARROW).repeated(VALID_TYPE_TOKEN_TYPES)); 283 } 284 285 /** Creates a recognizer that matches lambdas within expressions. */ 286 private RecognizerBase<EGenericParserStates> createSubExpressionRecognizer() { 287 return createRecognizer(start -> start.sequenceBefore(LBRACE).parseOnce(EGenericParserStates.IN_EXPRESSION)); 288 } 289 290 /** {@inheritDoc} */ 291 @Override 292 protected boolean isFilteredToken(IToken token, IToken previousToken) { 293 return super.isFilteredToken(token, previousToken) 294 || (previousToken != null && previousToken.getType() == EOL && token.getType() == EOL); 295 } 296 297}