Improved support for comment folding
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.quantum.sql / src / com / quantum / editors / SQLPartitionScanner.java
1 package com.quantum.editors;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6
7 import org.eclipse.jface.text.IDocument;
8 import org.eclipse.jface.text.rules.EndOfLineRule;
9 import org.eclipse.jface.text.rules.ICharacterScanner;
10 import org.eclipse.jface.text.rules.IPredicateRule;
11 import org.eclipse.jface.text.rules.IRule;
12 import org.eclipse.jface.text.rules.IToken;
13 import org.eclipse.jface.text.rules.IWhitespaceDetector;
14 import org.eclipse.jface.text.rules.MultiLineRule;
15 import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
16 import org.eclipse.jface.text.rules.SingleLineRule;
17 import org.eclipse.jface.text.rules.Token;
18 import org.eclipse.jface.text.rules.WhitespaceRule;
19
20 public class SQLPartitionScanner extends RuleBasedPartitionScanner {
21         public final static String SQL_COMMENT = "__sql_comment"; //$NON-NLS-1$
22         public final static String SQL_IDENTIFIER = "__sql_word"; //$NON-NLS-1$
23         public final static String SQL_STRING = "__sql_string"; //$NON-NLS-1$
24         public final static String SQL_KEYWORD = "__sql_keyword"; //$NON-NLS-1$
25         public final static String SQL_SYMBOL = "__sql_symbol"; //$NON-NLS-1$
26         public final static String SQL_SEPARATOR = "__sql_separator"; //$NON-NLS-1$
27         public final static String SQL_NUMERIC = "__sql_numeric"; //$NON-NLS-1$
28         
29         private final static String[] KEYWORDS = {
30                 "ALTER", //$NON-NLS-1$
31                 "AND", //$NON-NLS-1$
32                 "BY", //$NON-NLS-1$
33                 "COLUMN", //$NON-NLS-1$
34                 "CREATE", //$NON-NLS-1$
35                 "DELETE", //$NON-NLS-1$
36                 "DROP", //$NON-NLS-1$
37                 "FROM", //$NON-NLS-1$
38                 "GROUP",  //$NON-NLS-1$
39                 "INSERT", //$NON-NLS-1$
40                 "INTO", //$NON-NLS-1$
41                 "NOT", //$NON-NLS-1$
42                 "NULL", //$NON-NLS-1$
43                 "OR", //$NON-NLS-1$
44                 "ORDER", //$NON-NLS-1$
45                 "SELECT", //$NON-NLS-1$
46                 "SEQUENCE", //$NON-NLS-1$
47                 "SET",  //$NON-NLS-1$
48                 "TABLE", //$NON-NLS-1$
49                 "UNION", //$NON-NLS-1$
50                 "UNIQUE", //$NON-NLS-1$
51                 "UPDATE", //$NON-NLS-1$
52                 "USING", //$NON-NLS-1$
53                 "VALUES", //$NON-NLS-1$
54                 "VIEW", //$NON-NLS-1$
55                 "WHEN", //$NON-NLS-1$
56                 "WHERE" //$NON-NLS-1$
57         };
58
59         public SQLPartitionScanner() {
60
61                 List rules = new ArrayList();
62
63                 IToken comment = new Token(SQL_COMMENT);
64                 IToken string = new Token(SQL_STRING);
65                 IToken identifier = new Token(SQL_IDENTIFIER);
66                 IToken keyword = new Token(SQL_KEYWORD);
67                 IToken separator = new Token(SQL_SEPARATOR);
68                 IToken symbol = new Token(SQL_SYMBOL);
69                 IToken whitespace = new Token(IDocument.DEFAULT_CONTENT_TYPE);
70                 IToken numeric = new Token(SQL_NUMERIC);
71                 
72                 rules.add(new PredicateRuleAdapter(new WhitespaceRule(new WhitespaceDetector()), whitespace));
73                 rules.add(new MultiLineRule("/*", "*/", comment)); //$NON-NLS-1$ //$NON-NLS-2$
74                 rules.add(new EndOfLineRule("--", comment)); //$NON-NLS-1$
75                 rules.add(new SingleLineRule("'", "'", string)); //$NON-NLS-1$ //$NON-NLS-2$
76                 rules.add(new PredicateRuleAdapter(new SQLNumberRule(numeric), numeric));
77                 SQLWordRule wordRule = new SQLWordRule(identifier);
78                 for (int i = 0; i < KEYWORDS.length; i++) {
79                         wordRule.addKeyword(KEYWORDS[i], keyword);
80                 }
81                 rules.add(new PredicateRuleAdapter(wordRule, keyword));
82                 rules.add(new PredicateRuleAdapter(wordRule, identifier));
83                 rules.add(new PredicateRuleAdapter(new SQLSeparatorRule(separator), separator));
84                 rules.add(new PredicateRuleAdapter(new SymbolRule(symbol), symbol));
85                 
86                 IPredicateRule[] result= new IPredicateRule[rules.size()];
87                 rules.toArray(result);
88                 setPredicateRules(result);
89         }
90 }
91
92 class PredicateRuleAdapter implements IPredicateRule {
93         IRule rule;
94         IToken token;
95         public PredicateRuleAdapter(IRule rule, IToken token) {
96                 this.rule = rule;
97                 this.token = token;
98         }
99         
100         public IToken evaluate(ICharacterScanner scanner, boolean resume) {
101                 return rule.evaluate(scanner);
102         }
103
104         public IToken getSuccessToken() {
105                 return token;
106         }
107
108         public IToken evaluate(ICharacterScanner scanner) {
109                 return rule.evaluate(scanner);
110         }
111
112 }
113
114 class SQLSeparatorRule implements IRule {
115         IToken token;
116         public SQLSeparatorRule(IToken token) {
117                 this.token = token;
118         }
119         public IToken evaluate(ICharacterScanner scanner) {
120                 char c = (char) scanner.read();
121                 if (c == ';') {
122                         return token;
123                 }
124                 scanner.unread();
125                 return Token.UNDEFINED;
126         }
127
128 }
129
130 class SymbolRule implements IRule {
131         IToken token;
132         public SymbolRule(IToken token) {
133                 this.token = token;
134         }
135         public IToken evaluate(ICharacterScanner scanner) {
136                 int val = scanner.read();
137                 if (val != ICharacterScanner.EOF) {
138                         char c = (char) val;
139                         if (!Character.isWhitespace(c) && !Character.isLetterOrDigit(c) && c != '_') {
140                                 return token;
141                         }
142                 }
143                 scanner.unread();
144                 return Token.UNDEFINED;
145         }
146
147 }
148
149 class WhitespaceDetector implements IWhitespaceDetector {
150
151         public boolean isWhitespace(char c) {
152                 return Character.isWhitespace(c);
153         }
154 }
155
156 class SQLNumberRule implements IRule {
157         private IToken token;
158         
159         public SQLNumberRule(IToken token) {
160                 this.token = token;
161         }
162
163         public IToken evaluate(ICharacterScanner scanner) {
164                 char c = (char) scanner.read();
165                 if (Character.isDigit(c)) {
166                         // postive numbers and zero
167                         do {
168                                 c= (char) scanner.read();
169                         } while (Character.isDigit(c) || c == '.');
170                         scanner.unread();
171                         return token;
172                 } else if (c == '-') {
173                         // negative numbers
174                         c = (char) scanner.read();
175                         if (Character.isDigit(c)) {
176                                 do {
177                                         c= (char) scanner.read();
178                                 } while (Character.isDigit(c) || c == '.');
179                                 scanner.unread();
180                                 return token;
181                         } else {
182                                 scanner.unread();
183                                 scanner.unread();
184                                 return Token.UNDEFINED;
185                         }
186                 } else {
187                         scanner.unread();
188                         return Token.UNDEFINED;
189                 }
190         }
191 }
192
193 class SQLWordRule implements IRule {
194         private IToken token;
195         private HashMap keywords = new HashMap();
196         
197         public SQLWordRule(IToken token) {
198                 this.token = token;
199         }
200
201         public void addKeyword(String word, IToken token) {
202                 keywords.put(word.toUpperCase(), token);
203         }
204
205         public IToken evaluate(ICharacterScanner scanner) {
206                 char c = (char) scanner.read();
207                 if (Character.isLetter(c) || c == '_') {
208                         StringBuffer value = new StringBuffer();
209                         do {
210                                 value.append(c);
211                                 c= (char) scanner.read();
212                         } while (Character.isLetterOrDigit(c) || c == '_');
213                         scanner.unread();
214                         IToken retVal = (IToken) keywords.get(value.toString().toUpperCase());
215                         if (retVal != null) {
216                                 return retVal;
217                         } else {
218                                 return token;
219                         }
220                 } else {
221                         scanner.unread();
222                         return Token.UNDEFINED;
223                 }
224         }
225 }