]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexMSSQL.cxx
4a3f3bed83c4e6a71cf698416a2380536ea1f6b8
[wxWidgets.git] / src / stc / scintilla / src / LexMSSQL.cxx
1 // Scintilla source code edit control
2 /** @file LexMSSQL.cxx
3 ** Lexer for MSSQL.
4 **/
5 // By Filip Yaghob <fyaghob@gmail.com>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13
14 #include "Platform.h"
15
16 #include "PropSet.h"
17 #include "Accessor.h"
18 #include "KeyWords.h"
19 #include "Scintilla.h"
20 #include "SciLexer.h"
21
22 #ifdef SCI_NAMESPACE
23 using namespace Scintilla;
24 #endif
25
26 #define KW_MSSQL_STATEMENTS 0
27 #define KW_MSSQL_DATA_TYPES 1
28 #define KW_MSSQL_SYSTEM_TABLES 2
29 #define KW_MSSQL_GLOBAL_VARIABLES 3
30 #define KW_MSSQL_FUNCTIONS 4
31 #define KW_MSSQL_STORED_PROCEDURES 5
32 #define KW_MSSQL_OPERATORS 6
33
34 static bool isMSSQLOperator(char ch) {
35 if (isascii(ch) && isalnum(ch))
36 return false;
37 // '.' left out as it is used to make up numbers
38 if (ch == '%' || ch == '^' || ch == '&' || ch == '*' ||
39 ch == '-' || ch == '+' || ch == '=' || ch == '|' ||
40 ch == '<' || ch == '>' || ch == '/' ||
41 ch == '!' || ch == '~' || ch == '(' || ch == ')' ||
42 ch == ',')
43 return true;
44 return false;
45 }
46
47 static char classifyWordSQL(unsigned int start,
48 unsigned int end,
49 WordList *keywordlists[],
50 Accessor &styler,
51 unsigned int actualState,
52 unsigned int prevState) {
53 char s[256];
54 bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
55
56 WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS];
57 WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES];
58 WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES];
59 WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES];
60 WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS];
61 WordList &kwStoredProcedures = *keywordlists[KW_MSSQL_STORED_PROCEDURES];
62 WordList &kwOperators = *keywordlists[KW_MSSQL_OPERATORS];
63
64 for (unsigned int i = 0; i < end - start + 1 && i < 128; i++) {
65 s[i] = static_cast<char>(tolower(styler[start + i]));
66 s[i + 1] = '\0';
67 }
68 char chAttr = SCE_MSSQL_IDENTIFIER;
69
70 if (actualState == SCE_MSSQL_GLOBAL_VARIABLE) {
71
72 if (kwGlobalVariables.InList(&s[2]))
73 chAttr = SCE_MSSQL_GLOBAL_VARIABLE;
74
75 } else if (wordIsNumber) {
76 chAttr = SCE_MSSQL_NUMBER;
77
78 } else if (prevState == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
79 // Look first in datatypes
80 if (kwDataTypes.InList(s))
81 chAttr = SCE_MSSQL_DATATYPE;
82 else if (kwOperators.InList(s))
83 chAttr = SCE_MSSQL_OPERATOR;
84 else if (kwStatements.InList(s))
85 chAttr = SCE_MSSQL_STATEMENT;
86 else if (kwSystemTables.InList(s))
87 chAttr = SCE_MSSQL_SYSTABLE;
88 else if (kwFunctions.InList(s))
89 chAttr = SCE_MSSQL_FUNCTION;
90 else if (kwStoredProcedures.InList(s))
91 chAttr = SCE_MSSQL_STORED_PROCEDURE;
92
93 } else {
94 if (kwOperators.InList(s))
95 chAttr = SCE_MSSQL_OPERATOR;
96 else if (kwStatements.InList(s))
97 chAttr = SCE_MSSQL_STATEMENT;
98 else if (kwSystemTables.InList(s))
99 chAttr = SCE_MSSQL_SYSTABLE;
100 else if (kwFunctions.InList(s))
101 chAttr = SCE_MSSQL_FUNCTION;
102 else if (kwStoredProcedures.InList(s))
103 chAttr = SCE_MSSQL_STORED_PROCEDURE;
104 else if (kwDataTypes.InList(s))
105 chAttr = SCE_MSSQL_DATATYPE;
106 }
107
108 styler.ColourTo(end, chAttr);
109
110 return chAttr;
111 }
112
113 static void ColouriseMSSQLDoc(unsigned int startPos, int length,
114 int initStyle, WordList *keywordlists[], Accessor &styler) {
115
116
117 styler.StartAt(startPos);
118
119 bool fold = styler.GetPropertyInt("fold") != 0;
120 int lineCurrent = styler.GetLine(startPos);
121 int spaceFlags = 0;
122
123 int state = initStyle;
124 int prevState = initStyle;
125 char chPrev = ' ';
126 char chNext = styler[startPos];
127 styler.StartSegment(startPos);
128 unsigned int lengthDoc = startPos + length;
129 for (unsigned int i = startPos; i < lengthDoc; i++) {
130 char ch = chNext;
131 chNext = styler.SafeGetCharAt(i + 1);
132
133 if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
134 int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
135 int lev = indentCurrent;
136 if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
137 // Only non whitespace lines can be headers
138 int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
139 if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) {
140 lev |= SC_FOLDLEVELHEADERFLAG;
141 }
142 }
143 if (fold) {
144 styler.SetLevel(lineCurrent, lev);
145 }
146 }
147
148 if (styler.IsLeadByte(ch)) {
149 chNext = styler.SafeGetCharAt(i + 2);
150 chPrev = ' ';
151 i += 1;
152 continue;
153 }
154
155 // When the last char isn't part of the state (have to deal with it too)...
156 if ( (state == SCE_MSSQL_IDENTIFIER) ||
157 (state == SCE_MSSQL_STORED_PROCEDURE) ||
158 (state == SCE_MSSQL_DATATYPE) ||
159 //~ (state == SCE_MSSQL_COLUMN_NAME) ||
160 (state == SCE_MSSQL_FUNCTION) ||
161 //~ (state == SCE_MSSQL_GLOBAL_VARIABLE) ||
162 (state == SCE_MSSQL_VARIABLE)) {
163 if (!iswordchar(ch)) {
164 int stateTmp;
165
166 if ((state == SCE_MSSQL_VARIABLE) || (state == SCE_MSSQL_COLUMN_NAME)) {
167 styler.ColourTo(i - 1, state);
168 stateTmp = state;
169 } else
170 stateTmp = classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
171
172 prevState = state;
173
174 if (stateTmp == SCE_MSSQL_IDENTIFIER || stateTmp == SCE_MSSQL_VARIABLE)
175 state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
176 else
177 state = SCE_MSSQL_DEFAULT;
178 }
179 } else if (state == SCE_MSSQL_LINE_COMMENT) {
180 if (ch == '\r' || ch == '\n') {
181 styler.ColourTo(i - 1, state);
182 prevState = state;
183 state = SCE_MSSQL_DEFAULT;
184 }
185 } else if (state == SCE_MSSQL_GLOBAL_VARIABLE) {
186 if ((ch != '@') && !iswordchar(ch)) {
187 classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
188 prevState = state;
189 state = SCE_MSSQL_DEFAULT;
190 }
191 }
192
193 // If is the default or one of the above succeeded
194 if (state == SCE_MSSQL_DEFAULT || state == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
195 if (iswordstart(ch)) {
196 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
197 prevState = state;
198 state = SCE_MSSQL_IDENTIFIER;
199 } else if (ch == '/' && chNext == '*') {
200 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
201 prevState = state;
202 state = SCE_MSSQL_COMMENT;
203 } else if (ch == '-' && chNext == '-') {
204 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
205 prevState = state;
206 state = SCE_MSSQL_LINE_COMMENT;
207 } else if (ch == '\'') {
208 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
209 prevState = state;
210 state = SCE_MSSQL_STRING;
211 } else if (ch == '"') {
212 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
213 prevState = state;
214 state = SCE_MSSQL_COLUMN_NAME;
215 } else if (ch == '[') {
216 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
217 prevState = state;
218 state = SCE_MSSQL_COLUMN_NAME_2;
219 } else if (isMSSQLOperator(ch)) {
220 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
221 styler.ColourTo(i, SCE_MSSQL_OPERATOR);
222 //~ style = SCE_MSSQL_DEFAULT;
223 prevState = state;
224 state = SCE_MSSQL_DEFAULT;
225 } else if (ch == '@') {
226 styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
227 prevState = state;
228 if (chNext == '@') {
229 state = SCE_MSSQL_GLOBAL_VARIABLE;
230 // i += 2;
231 } else
232 state = SCE_MSSQL_VARIABLE;
233 }
234
235
236 // When the last char is part of the state...
237 } else if (state == SCE_MSSQL_COMMENT) {
238 if (ch == '/' && chPrev == '*') {
239 if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_MSSQL_COMMENT) &&
240 (styler.GetStartSegment() == startPos)))) {
241 styler.ColourTo(i, state);
242 //~ state = SCE_MSSQL_COMMENT;
243 prevState = state;
244 state = SCE_MSSQL_DEFAULT;
245 }
246 }
247 } else if (state == SCE_MSSQL_STRING) {
248 if (ch == '\'') {
249 if ( chNext == '\'' ) {
250 i++;
251 ch = chNext;
252 chNext = styler.SafeGetCharAt(i + 1);
253 } else {
254 styler.ColourTo(i, state);
255 prevState = state;
256 state = SCE_MSSQL_DEFAULT;
257 //i++;
258 }
259 //ch = chNext;
260 //chNext = styler.SafeGetCharAt(i + 1);
261 }
262 } else if (state == SCE_MSSQL_COLUMN_NAME) {
263 if (ch == '"') {
264 if (chNext == '"') {
265 i++;
266 ch = chNext;
267 chNext = styler.SafeGetCharAt(i + 1);
268 } else {
269 styler.ColourTo(i, state);
270 prevState = state;
271 state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
272 //i++;
273 }
274 }
275 } else if (state == SCE_MSSQL_COLUMN_NAME_2) {
276 if (ch == ']') {
277 styler.ColourTo(i, state);
278 prevState = state;
279 state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
280 //i++;
281 }
282 }
283
284 chPrev = ch;
285 }
286 styler.ColourTo(lengthDoc - 1, state);
287 }
288
289 static void FoldMSSQLDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
290 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
291 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
292 unsigned int endPos = startPos + length;
293 int visibleChars = 0;
294 int lineCurrent = styler.GetLine(startPos);
295 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
296 int levelCurrent = levelPrev;
297 char chNext = styler[startPos];
298 bool inComment = (styler.StyleAt(startPos-1) == SCE_MSSQL_COMMENT);
299 char s[10];
300 for (unsigned int i = startPos; i < endPos; i++) {
301 char ch = chNext;
302 chNext = styler.SafeGetCharAt(i + 1);
303 int style = styler.StyleAt(i);
304 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
305 // Comment folding
306 if (foldComment) {
307 if (!inComment && (style == SCE_MSSQL_COMMENT))
308 levelCurrent++;
309 else if (inComment && (style != SCE_MSSQL_COMMENT))
310 levelCurrent--;
311 inComment = (style == SCE_MSSQL_COMMENT);
312 }
313 if (style == SCE_MSSQL_STATEMENT) {
314 // Folding between begin or case and end
315 if (ch == 'b' || ch == 'B' || ch == 'c' || ch == 'C' || ch == 'e' || ch == 'E') {
316 for (unsigned int j = 0; j < 5; j++) {
317 if (!iswordchar(styler[i + j])) {
318 break;
319 }
320 s[j] = static_cast<char>(tolower(styler[i + j]));
321 s[j + 1] = '\0';
322 }
323 if ((strcmp(s, "begin") == 0) || (strcmp(s, "case") == 0)) {
324 levelCurrent++;
325 }
326 if (strcmp(s, "end") == 0) {
327 levelCurrent--;
328 }
329 }
330 }
331 if (atEOL) {
332 int lev = levelPrev;
333 if (visibleChars == 0 && foldCompact)
334 lev |= SC_FOLDLEVELWHITEFLAG;
335 if ((levelCurrent > levelPrev) && (visibleChars > 0))
336 lev |= SC_FOLDLEVELHEADERFLAG;
337 if (lev != styler.LevelAt(lineCurrent)) {
338 styler.SetLevel(lineCurrent, lev);
339 }
340 lineCurrent++;
341 levelPrev = levelCurrent;
342 visibleChars = 0;
343 }
344 if (!isspacechar(ch))
345 visibleChars++;
346 }
347 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
348 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
349 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
350 }
351
352 static const char * const sqlWordListDesc[] = {
353 "Statements",
354 "Data Types",
355 "System tables",
356 "Global variables",
357 "Functions",
358 "System Stored Procedures",
359 "Operators",
360 0,
361 };
362
363 LexerModule lmMSSQL(SCLEX_MSSQL, ColouriseMSSQLDoc, "mssql", FoldMSSQLDoc, sqlWordListDesc);