001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 the ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package eu.cqse.check.framework.shallowparser.languages.tsql; 018 019//TODO (DP): Leaving this here, as it comes in handy when working on the parser. Will remove it later. 020//import static eu.cqse.check.framework.scanner.ETokenType.*; 021//import static eu.cqse.check.framework.shallowparser.languages.tsql.TsqlShallowParser.ETsqlParserStates.*; 022//import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.*; 023//import static eu.cqse.check.framework.scanner.ETokenType.ETokenClass.*; 024import static eu.cqse.check.framework.scanner.ETokenType.ALL; 025import static eu.cqse.check.framework.scanner.ETokenType.BEGIN; 026import static eu.cqse.check.framework.scanner.ETokenType.BY; 027import static eu.cqse.check.framework.scanner.ETokenType.CREATE; 028import static eu.cqse.check.framework.scanner.ETokenType.DISTINCT; 029import static eu.cqse.check.framework.scanner.ETokenType.ELSE; 030import static eu.cqse.check.framework.scanner.ETokenType.END; 031import static eu.cqse.check.framework.scanner.ETokenType.EOF; 032import static eu.cqse.check.framework.scanner.ETokenType.EOL; 033import static eu.cqse.check.framework.scanner.ETokenType.EXCEPT; 034import static eu.cqse.check.framework.scanner.ETokenType.FOR; 035import static eu.cqse.check.framework.scanner.ETokenType.FROM; 036import static eu.cqse.check.framework.scanner.ETokenType.FUNCTION; 037import static eu.cqse.check.framework.scanner.ETokenType.GROUP; 038import static eu.cqse.check.framework.scanner.ETokenType.HAVING; 039import static eu.cqse.check.framework.scanner.ETokenType.IF; 040import static eu.cqse.check.framework.scanner.ETokenType.INTERSECT; 041import static eu.cqse.check.framework.scanner.ETokenType.INTO; 042import static eu.cqse.check.framework.scanner.ETokenType.LPAREN; 043import static eu.cqse.check.framework.scanner.ETokenType.OPTION; 044import static eu.cqse.check.framework.scanner.ETokenType.ORDER; 045import static eu.cqse.check.framework.scanner.ETokenType.PERCENT; 046import static eu.cqse.check.framework.scanner.ETokenType.RETURN; 047import static eu.cqse.check.framework.scanner.ETokenType.RETURNS; 048import static eu.cqse.check.framework.scanner.ETokenType.RPAREN; 049import static eu.cqse.check.framework.scanner.ETokenType.SELECT; 050import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON; 051import static eu.cqse.check.framework.scanner.ETokenType.TABLE; 052import static eu.cqse.check.framework.scanner.ETokenType.TOP; 053import static eu.cqse.check.framework.scanner.ETokenType.UNION; 054import static eu.cqse.check.framework.scanner.ETokenType.WHERE; 055import static eu.cqse.check.framework.scanner.ETokenType.WHILE; 056import static eu.cqse.check.framework.scanner.ETokenType.WITH; 057import static eu.cqse.check.framework.scanner.ETokenType.ETokenClass.KEYWORD; 058import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.META; 059import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.STATEMENT; 060import static eu.cqse.check.framework.shallowparser.languages.tsql.TsqlShallowParser.ETsqlParserStates.IN_BLOCK; 061import static eu.cqse.check.framework.shallowparser.languages.tsql.TsqlShallowParser.ETsqlParserStates.IN_METHOD; 062import static eu.cqse.check.framework.shallowparser.languages.tsql.TsqlShallowParser.ETsqlParserStates.TOP_LEVEL; 063 064import java.util.EnumSet; 065 066import org.conqat.lib.commons.region.Region; 067 068import eu.cqse.check.framework.scanner.ETokenType; 069import eu.cqse.check.framework.scanner.IToken; 070import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType; 071import eu.cqse.check.framework.shallowparser.framework.RecognizerBase; 072import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase; 073 074/** 075 */ 076public class TsqlShallowParser extends ShallowParserBase<TsqlShallowParser.ETsqlParserStates> { 077 078 /** The states used in this parser. */ 079 public static enum ETsqlParserStates { 080 TOP_LEVEL, IN_METHOD, IN_BLOCK 081 } 082 083 private static final EnumSet<ETokenType> SELECT_STATEMENT_KEYWORDS = EnumSet.of(SELECT, WITH, ORDER, FOR, OPTION, 084 UNION, ALL, EXCEPT, INTERSECT, DISTINCT, TOP, PERCENT, INTO, FROM, WHERE, GROUP, BY, HAVING); 085 086 private static final EnumSet<ETokenType> NO_SELECT_STATEMENT_KEYWORDS = EnumSet.copyOf(ETokenType.KEYWORDS); 087 088 { 089 NO_SELECT_STATEMENT_KEYWORDS.removeAll(SELECT_STATEMENT_KEYWORDS); 090 } 091 092 /** Constructor. */ 093 public TsqlShallowParser() { 094 super(ETsqlParserStates.class, ETsqlParserStates.TOP_LEVEL); 095 096 createMethodRules(); 097 createStatementRules(); 098 } 099 100 /** Creates parser rules for statements. */ 101 private void createStatementRules() { 102 103 createBlockStatementRule(IF); 104 createBlockStatementRule(ELSE); 105 createBlockStatementRule(WHILE); 106 107 inAnyState().sequence(BEGIN).createNode(STATEMENT, 0, new Region(1, -1)).parseUntil(IN_BLOCK).sequence(END) 108 .endNode(); 109 110 inAnyState().sequence(SELECT).createNode(STATEMENT, 0).skipBefore(NO_SELECT_STATEMENT_KEYWORDS).endNode(); 111 112 inAnyState().markStart().sequence(KEYWORD).skipBefore(KEYWORD).createNode(STATEMENT, 0).endNode(); 113 114 // TODO (DP): EOF is not recognized, so that the node is always 115 // incomplete. Should be STATEMENT, not META 116 inAnyState().sequence(KEYWORD).createNode(META, 0).skipBefore(EOF).endNode(); 117 118 } 119 120 private void createBlockStatementRule(ETokenType blockStatementType) { 121 inAnyState().sequence(blockStatementType).skipNested(LPAREN, RPAREN).skipBefore(KEYWORD).sequence(BEGIN) 122 .createNode(STATEMENT, 0).parseUntil(IN_BLOCK).sequence(END).endNode(); 123 } 124 125 /** Creates parser rules for functions and procedures. */ 126 private void createMethodRules() { 127 // TODO (DP): We might need to create an Identifier set, which copes 128 // with [FUNCTION] or [My cool table name] 129 130 RecognizerBase<ETsqlParserStates> methodStart = inState(TOP_LEVEL).sequence(CREATE).markStart() 131 .sequence(FUNCTION).createNode(EShallowEntityType.METHOD, 0).skipTo(RETURNS); 132 133 // T-SQL Scalar Function Syntax 134 methodStart.skipTo(BEGIN).parseUntil(IN_METHOD).sequence(END).endNode(); 135 136 // T-SQL Inline Table-Valued Function Syntax 137 methodStart.sequence(TABLE).skipTo(RETURN).parseUntil(IN_METHOD).sequence(END).endNode(); 138 } 139 140 /** {@inheritDoc} */ 141 @Override 142 protected boolean isFilteredToken(IToken token, IToken previousToken) { 143 return super.isFilteredToken(token, previousToken) || token.getType() == EOL || token.getType() == SEMICOLON; 144 } 145 146}