OSDN Git Service

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