/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.hibernate.eclipse.hqleditor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.rules.EndOfLineRule;
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.RuleBasedScanner;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.eclipse.jface.text.rules.WordRule;
import org.eclipse.swt.SWT;
import org.hibernate.eclipse.hqleditor.preferences.HQLPreferenceConstants;
public class HQLCodeScanner extends RuleBasedScanner {
/** Defines the HQL keywords. Based on hql.g antlr grammer in 2005 ;) */
private static String[] hqlKeywords = {
"between", //$NON-NLS-1$
"class", //$NON-NLS-1$
"delete", //$NON-NLS-1$
"desc", //$NON-NLS-1$
"distinct", //$NON-NLS-1$
"elements", //$NON-NLS-1$
"escape", //$NON-NLS-1$
"exists", //$NON-NLS-1$
"false", //$NON-NLS-1$
"fetch", //$NON-NLS-1$
"from", //$NON-NLS-1$
"full", //$NON-NLS-1$
"group", //$NON-NLS-1$
"having", //$NON-NLS-1$
"in", //$NON-NLS-1$
"indices", //$NON-NLS-1$
"inner", //$NON-NLS-1$
"insert", //$NON-NLS-1$
"into", //$NON-NLS-1$
"is", //$NON-NLS-1$
"join", //$NON-NLS-1$
"left", //$NON-NLS-1$
"like", //$NON-NLS-1$
"new", //$NON-NLS-1$
"not", //$NON-NLS-1$
"null", //$NON-NLS-1$
"or", //$NON-NLS-1$
"order", //$NON-NLS-1$
"outer", //$NON-NLS-1$
"properties", //$NON-NLS-1$
"right", //$NON-NLS-1$
"select", //$NON-NLS-1$
"set", //$NON-NLS-1$
"some", //$NON-NLS-1$
"true", //$NON-NLS-1$
"union", //$NON-NLS-1$
"update", //$NON-NLS-1$
"versioned", //$NON-NLS-1$
"where", //$NON-NLS-1$
"and", //$NON-NLS-1$
"or", //$NON-NLS-1$
// -- SQL tokens --
// These aren't part of HQL, but usefull when you have SQL in the editor
"case", //$NON-NLS-1$
"end", //$NON-NLS-1$
"else", //$NON-NLS-1$
"then", //$NON-NLS-1$
"when", //$NON-NLS-1$
"on", //$NON-NLS-1$
"with", //$NON-NLS-1$
// -- EJBQL tokens --
"both", //$NON-NLS-1$
"empty", //$NON-NLS-1$
"leading", //$NON-NLS-1$
"member", //$NON-NLS-1$
"object", //$NON-NLS-1$
"of", //$NON-NLS-1$
"trailing", //$NON-NLS-1$
};
/** built-in function names. Various normal builtin functions in SQL/HQL. Maybe sShould try and do this dynamically based on dialect */
private static String[] builtInFunctions = {
// standard sql92 functions
"substring", //$NON-NLS-1$
"locate", //$NON-NLS-1$
"trim", //$NON-NLS-1$
"length", //$NON-NLS-1$
"bit_length", //$NON-NLS-1$
"coalesce", //$NON-NLS-1$
"nullif", //$NON-NLS-1$
"abs", //$NON-NLS-1$
"mod", //$NON-NLS-1$
"sqrt", //$NON-NLS-1$
"upper", //$NON-NLS-1$
"lower", //$NON-NLS-1$
"cast", //$NON-NLS-1$
"extract", //$NON-NLS-1$
// time functions mapped to ansi extract
"second", //$NON-NLS-1$
"minute", //$NON-NLS-1$
"hour", //$NON-NLS-1$
"day", //$NON-NLS-1$
"month", //$NON-NLS-1$
"year", //$NON-NLS-1$
"str", //$NON-NLS-1$
// misc functions - based on oracle dialect
"sign", //$NON-NLS-1$
"acos", //$NON-NLS-1$
"asin", //$NON-NLS-1$
"atan", //$NON-NLS-1$
"cos", //$NON-NLS-1$
"cosh", //$NON-NLS-1$
"exp", //$NON-NLS-1$
"ln", //$NON-NLS-1$
"sin", //$NON-NLS-1$
"sinh", //$NON-NLS-1$
"stddev", //$NON-NLS-1$
"sqrt", //$NON-NLS-1$
"tan", //$NON-NLS-1$
"tanh", //$NON-NLS-1$
"variance", //$NON-NLS-1$
"round", //$NON-NLS-1$
"trunc", //$NON-NLS-1$
"ceil", //$NON-NLS-1$
"floor", //$NON-NLS-1$
"chr", //$NON-NLS-1$
"initcap", //$NON-NLS-1$
"lower", //$NON-NLS-1$
"ltrim", //$NON-NLS-1$
"rtrim", //$NON-NLS-1$
"soundex", //$NON-NLS-1$
"upper", //$NON-NLS-1$
"ascii", //$NON-NLS-1$
"length", //$NON-NLS-1$
"to_char", //$NON-NLS-1$
"to_date", //$NON-NLS-1$
"current_date", //$NON-NLS-1$
"current_time", //$NON-NLS-1$
"current_timestamp", //$NON-NLS-1$
"lastday", //$NON-NLS-1$
"sysday", //$NON-NLS-1$
"systimestamp", //$NON-NLS-1$
"uid", //$NON-NLS-1$
"user", //$NON-NLS-1$
"rowid", //$NON-NLS-1$
"rownum", //$NON-NLS-1$
"concat", //$NON-NLS-1$
"instr", //$NON-NLS-1$
"instrb", //$NON-NLS-1$
"lpad", //$NON-NLS-1$
"replace", //$NON-NLS-1$
"rpad", //$NON-NLS-1$
"substr", //$NON-NLS-1$
"substrb", //$NON-NLS-1$
"translate", //$NON-NLS-1$
"substring", //$NON-NLS-1$
"locate", //$NON-NLS-1$
"bit_length", //$NON-NLS-1$
"coalesce", //$NON-NLS-1$
"atan2", //$NON-NLS-1$
"log", //$NON-NLS-1$
"mod", //$NON-NLS-1$
"nvl", //$NON-NLS-1$
"nvl2", //$NON-NLS-1$
"power", //$NON-NLS-1$
"add_months", //$NON-NLS-1$
"months_between", //$NON-NLS-1$
"next_day", //$NON-NLS-1$
};
static {
// for performance in search.
Arrays.sort(builtInFunctions);
Arrays.sort(hqlKeywords);
}
static public class HQLWhiteSpaceDetector implements IWhitespaceDetector {
public boolean isWhitespace( char c ) {
return Character.isWhitespace( c );
}
}
public HQLCodeScanner( HQLColors colorProvider ) {
final IToken commentToken = new Token( new TextAttribute( colorProvider.getColor( HQLPreferenceConstants.HQL_COMMENT_COLOR )));
final IToken stringToken = new Token( new TextAttribute( colorProvider.getColor( HQLPreferenceConstants.HQL_QUOTED_LITERAL_COLOR )));
final IToken keywordToken = new Token( new TextAttribute( colorProvider.getColor( HQLPreferenceConstants.HQL_KEYWORD_COLOR ), null, SWT.BOLD)) {
public Object getData() {
// TODO Auto-generated method stub
return super.getData();
}
};
final IToken functionToken = new Token( new TextAttribute( colorProvider.getColor( HQLPreferenceConstants.HQL_KEYWORD_COLOR )));
final IToken otherToken = new Token( new TextAttribute( colorProvider.getColor( HQLPreferenceConstants.HQL_DEFAULT_COLOR )));
setDefaultReturnToken( otherToken );
List<IRule> rules = new ArrayList<IRule>();
rules.add( new EndOfLineRule( "--", commentToken )); //$NON-NLS-1$
rules.add( new SingleLineRule( "'", "'", stringToken, '\\' )); //$NON-NLS-1$ //$NON-NLS-2$
rules.add( new WhitespaceRule( new HQLWhiteSpaceDetector() ));
//rules.add( new HQLLexerRule( hqlToken )); // TODO: need to categorize tokens into types.
WordRule wordRule = new WordRule( new HQLWordDetector(), otherToken );
addWordRules( keywordToken, wordRule, getHQLKeywords() );
addWordRules( functionToken, wordRule, getHQLFunctionNames() );
rules.add( wordRule );
setRules( rules.toArray( new IRule[ rules.size() ] ) );
}
private void addWordRules(final IToken token, WordRule wordRule, String[] reservedWords) {
for (int i = 0; i < reservedWords.length; i++) {
wordRule.addWord( reservedWords[i], token );
wordRule.addWord( reservedWords[i].toUpperCase(), token );
}
}
public static String[] getHQLKeywords() {
return hqlKeywords;
}
public static String[] getHQLFunctionNames() {
return builtInFunctions;
}
} // end class