package net.sourceforge.phpdt.sql.editors; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.rules.EndOfLineRule; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IPredicateRule; import org.eclipse.jface.text.rules.IRule; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.IWhitespaceDetector; import org.eclipse.jface.text.rules.MultiLineRule; import org.eclipse.jface.text.rules.RuleBasedPartitionScanner; import org.eclipse.jface.text.rules.SingleLineRule; import org.eclipse.jface.text.rules.Token; import org.eclipse.jface.text.rules.WhitespaceRule; public class SQLPartitionScanner extends RuleBasedPartitionScanner { public final static String SQL_COMMENT = "__sql_comment"; public final static String SQL_IDENTIFIER = "__sql_word"; public final static String SQL_STRING = "__sql_string"; public final static String SQL_KEYWORD = "__sql_keyword"; public final static String SQL_SYMBOL = "__sql_symbol"; public final static String SQL_SEPARATOR = "__sql_separator"; public final static String SQL_NUMERIC = "__sql_numeric"; private final static String[] KEYWORDS = { "ALTER", "AND", "BY", "COLUMN", "CREATE", "DELETE", "DROP", "FROM", "GROUP", "INSERT", "INTO", "NOT", "NULL", "OR", "ORDER", "SELECT", "SEQUENCE", "SET", "TABLE", "UNION", "UNIQUE", "UPDATE", "USING", "VALUES", "VIEW", "WHEN", "WHERE" }; public SQLPartitionScanner() { List rules = new ArrayList(); IToken comment = new Token(SQL_COMMENT); IToken string = new Token(SQL_STRING); IToken identifier = new Token(SQL_IDENTIFIER); IToken keyword = new Token(SQL_KEYWORD); IToken separator = new Token(SQL_SEPARATOR); IToken symbol = new Token(SQL_SYMBOL); IToken whitespace = new Token(IDocument.DEFAULT_CONTENT_TYPE); IToken numeric = new Token(SQL_NUMERIC); rules.add(new PredicateRuleAdapter(new WhitespaceRule(new WhitespaceDetector()), whitespace)); rules.add(new MultiLineRule("/*", "*/", comment)); rules.add(new EndOfLineRule("--", comment)); rules.add(new SingleLineRule("'", "'", string)); rules.add(new PredicateRuleAdapter(new SQLNumberRule(numeric), numeric)); SQLWordRule wordRule = new SQLWordRule(identifier); for (int i = 0; i < KEYWORDS.length; i++) { wordRule.addKeyword(KEYWORDS[i], keyword); } rules.add(new PredicateRuleAdapter(wordRule, keyword)); rules.add(new PredicateRuleAdapter(wordRule, identifier)); rules.add(new PredicateRuleAdapter(new SQLSeparatorRule(separator), separator)); rules.add(new PredicateRuleAdapter(new SymbolRule(symbol), symbol)); IPredicateRule[] result= new IPredicateRule[rules.size()]; rules.toArray(result); setPredicateRules(result); } } class PredicateRuleAdapter implements IPredicateRule { IRule rule; IToken token; public PredicateRuleAdapter(IRule rule, IToken token) { this.rule = rule; this.token = token; } public IToken evaluate(ICharacterScanner scanner, boolean resume) { return rule.evaluate(scanner); } public IToken getSuccessToken() { return token; } public IToken evaluate(ICharacterScanner scanner) { return rule.evaluate(scanner); } } class SQLSeparatorRule implements IRule { IToken token; public SQLSeparatorRule(IToken token) { this.token = token; } public IToken evaluate(ICharacterScanner scanner) { char c = (char) scanner.read(); if (c == ';') { return token; } scanner.unread(); return Token.UNDEFINED; } } class SymbolRule implements IRule { IToken token; public SymbolRule(IToken token) { this.token = token; } public IToken evaluate(ICharacterScanner scanner) { int val = scanner.read(); if (val != scanner.EOF) { char c = (char) val; if (!Character.isWhitespace(c) && !Character.isLetterOrDigit(c) && c != '_') { return token; } } scanner.unread(); return Token.UNDEFINED; } } class WhitespaceDetector implements IWhitespaceDetector { public boolean isWhitespace(char c) { return Character.isWhitespace(c); } } class SQLNumberRule implements IRule { private IToken token; public SQLNumberRule(IToken token) { this.token = token; } public IToken evaluate(ICharacterScanner scanner) { char c = (char) scanner.read(); if (Character.isDigit(c)) { // postive numbers and zero do { c= (char) scanner.read(); } while (Character.isDigit(c) || c == '.'); scanner.unread(); return token; } else if (c == '-') { // negative numbers c = (char) scanner.read(); if (Character.isDigit(c)) { do { c= (char) scanner.read(); } while (Character.isDigit(c) || c == '.'); scanner.unread(); return token; } else { scanner.unread(); scanner.unread(); return Token.UNDEFINED; } } else { scanner.unread(); return Token.UNDEFINED; } } } class SQLWordRule implements IRule { private IToken token; private HashMap keywords = new HashMap(); public SQLWordRule(IToken token) { this.token = token; } public void addKeyword(String word, IToken token) { keywords.put(word.toUpperCase(), token); } public IToken evaluate(ICharacterScanner scanner) { char c = (char) scanner.read(); if (Character.isLetter(c) || c == '_') { StringBuffer value = new StringBuffer(); do { value.append(c); c= (char) scanner.read(); } while (Character.isLetterOrDigit(c) || c == '_'); scanner.unread(); IToken retVal = (IToken) keywords.get(value.toString().toUpperCase()); if (retVal != null) { return retVal; } else { return token; } } else { scanner.unread(); return Token.UNDEFINED; } } }