OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexVB.cxx
1 // Scintilla source code edit control\r
2 /** @file LexVB.cxx\r
3  ** Lexer for Visual Basic and VBScript.\r
4  **/\r
5 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>\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 "StyleContext.h"\r
19 #include "KeyWords.h"\r
20 #include "Scintilla.h"\r
21 #include "SciLexer.h"\r
22 \r
23 #ifdef SCI_NAMESPACE\r
24 using namespace Scintilla;\r
25 #endif\r
26 \r
27 // Internal state, highlighted as number\r
28 #define SCE_B_FILENUMBER SCE_B_DEFAULT+100\r
29 \r
30 \r
31 static bool IsVBComment(Accessor &styler, int pos, int len) {\r
32         return len > 0 && styler[pos] == '\'';\r
33 }\r
34 \r
35 static inline bool IsTypeCharacter(int ch) {\r
36         return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$';\r
37 }\r
38 \r
39 // Extended to accept accented characters\r
40 static inline bool IsAWordChar(int ch) {\r
41         return ch >= 0x80 ||\r
42                (isalnum(ch) || ch == '.' || ch == '_');\r
43 }\r
44 \r
45 static inline bool IsAWordStart(int ch) {\r
46         return ch >= 0x80 ||\r
47                (isalpha(ch) || ch == '_');\r
48 }\r
49 \r
50 static inline bool IsANumberChar(int ch) {\r
51         // Not exactly following number definition (several dots are seen as OK, etc.)\r
52         // but probably enough in most cases.\r
53         return (ch < 0x80) &&\r
54                 (isdigit(ch) || toupper(ch) == 'E' ||\r
55              ch == '.' || ch == '-' || ch == '+');\r
56 }\r
57 \r
58 static void ColouriseVBDoc(unsigned int startPos, int length, int initStyle,\r
59                            WordList *keywordlists[], Accessor &styler, bool vbScriptSyntax) {\r
60 \r
61         WordList &keywords = *keywordlists[0];\r
62         WordList &keywords2 = *keywordlists[1];\r
63         WordList &keywords3 = *keywordlists[2];\r
64         WordList &keywords4 = *keywordlists[3];\r
65 \r
66         styler.StartAt(startPos);\r
67 \r
68         int visibleChars = 0;\r
69         int fileNbDigits = 0;\r
70 \r
71         // Do not leak onto next line\r
72         if (initStyle == SCE_B_STRINGEOL || initStyle == SCE_B_COMMENT || initStyle == SCE_B_PREPROCESSOR) {\r
73                 initStyle = SCE_B_DEFAULT;\r
74         }\r
75 \r
76         StyleContext sc(startPos, length, initStyle, styler);\r
77 \r
78         for (; sc.More(); sc.Forward()) {\r
79 \r
80                 if (sc.state == SCE_B_OPERATOR) {\r
81                         sc.SetState(SCE_B_DEFAULT);\r
82                 } else if (sc.state == SCE_B_IDENTIFIER) {\r
83                         if (!IsAWordChar(sc.ch)) {\r
84                                 // In Basic (except VBScript), a variable name or a function name\r
85                                 // can end with a special character indicating the type of the value\r
86                                 // held or returned.\r
87                                 bool skipType = false;\r
88                                 if (!vbScriptSyntax && IsTypeCharacter(sc.ch)) {\r
89                                         sc.Forward();   // Skip it\r
90                                         skipType = true;\r
91                                 }\r
92                                 if (sc.ch == ']') {\r
93                                         sc.Forward();\r
94                                 }\r
95                                 char s[100];\r
96                                 sc.GetCurrentLowered(s, sizeof(s));\r
97                                 if (skipType) {\r
98                                         s[strlen(s) - 1] = '\0';\r
99                                 }\r
100                                 if (strcmp(s, "rem") == 0) {\r
101                                         sc.ChangeState(SCE_B_COMMENT);\r
102                                 } else {\r
103                                         if (keywords.InList(s)) {\r
104                                                 sc.ChangeState(SCE_B_KEYWORD);\r
105                                         } else if (keywords2.InList(s)) {\r
106                                                 sc.ChangeState(SCE_B_KEYWORD2);\r
107                                         } else if (keywords3.InList(s)) {\r
108                                                 sc.ChangeState(SCE_B_KEYWORD3);\r
109                                         } else if (keywords4.InList(s)) {\r
110                                                 sc.ChangeState(SCE_B_KEYWORD4);\r
111                                         }       // Else, it is really an identifier...\r
112                                         sc.SetState(SCE_B_DEFAULT);\r
113                                 }\r
114                         }\r
115                 } else if (sc.state == SCE_B_NUMBER) {\r
116                         // We stop the number definition on non-numerical non-dot non-eE non-sign char\r
117                         // Also accepts A-F for hex. numbers\r
118                         if (!IsANumberChar(sc.ch) && !(tolower(sc.ch) >= 'a' && tolower(sc.ch) <= 'f')) {\r
119                                 sc.SetState(SCE_B_DEFAULT);\r
120                         }\r
121                 } else if (sc.state == SCE_B_STRING) {\r
122                         // VB doubles quotes to preserve them, so just end this string\r
123                         // state now as a following quote will start again\r
124                         if (sc.ch == '\"') {\r
125                                 if (sc.chNext == '\"') {\r
126                                         sc.Forward();\r
127                                 } else {\r
128                                         if (tolower(sc.chNext) == 'c') {\r
129                                                 sc.Forward();\r
130                                         }\r
131                                         sc.ForwardSetState(SCE_B_DEFAULT);\r
132                                 }\r
133                         } else if (sc.atLineEnd) {\r
134                                 visibleChars = 0;\r
135                                 sc.ChangeState(SCE_B_STRINGEOL);\r
136                                 sc.ForwardSetState(SCE_B_DEFAULT);\r
137                         }\r
138                 } else if (sc.state == SCE_B_COMMENT) {\r
139                         if (sc.atLineEnd) {\r
140                                 visibleChars = 0;\r
141                                 sc.ForwardSetState(SCE_B_DEFAULT);\r
142                         }\r
143                 } else if (sc.state == SCE_B_PREPROCESSOR) {\r
144                         if (sc.atLineEnd) {\r
145                                 visibleChars = 0;\r
146                                 sc.ForwardSetState(SCE_B_DEFAULT);\r
147                         }\r
148                 } else if (sc.state == SCE_B_FILENUMBER) {\r
149                         if (IsADigit(sc.ch)) {\r
150                                 fileNbDigits++;\r
151                                 if (fileNbDigits > 3) {\r
152                                         sc.ChangeState(SCE_B_DATE);\r
153                                 }\r
154                         } else if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ',') {\r
155                                 // Regular uses: Close #1; Put #1, ...; Get #1, ... etc.\r
156                                 // Too bad if date is format #27, Oct, 2003# or something like that...\r
157                                 // Use regular number state\r
158                                 sc.ChangeState(SCE_B_NUMBER);\r
159                                 sc.SetState(SCE_B_DEFAULT);\r
160                         } else if (sc.ch == '#') {\r
161                                 sc.ChangeState(SCE_B_DATE);\r
162                                 sc.ForwardSetState(SCE_B_DEFAULT);\r
163                         } else {\r
164                                 sc.ChangeState(SCE_B_DATE);\r
165                         }\r
166                         if (sc.state != SCE_B_FILENUMBER) {\r
167                                 fileNbDigits = 0;\r
168                         }\r
169                 } else if (sc.state == SCE_B_DATE) {\r
170                         if (sc.atLineEnd) {\r
171                                 visibleChars = 0;\r
172                                 sc.ChangeState(SCE_B_STRINGEOL);\r
173                                 sc.ForwardSetState(SCE_B_DEFAULT);\r
174                         } else if (sc.ch == '#') {\r
175                                 sc.ForwardSetState(SCE_B_DEFAULT);\r
176                         }\r
177                 }\r
178 \r
179                 if (sc.state == SCE_B_DEFAULT) {\r
180                         if (sc.ch == '\'') {\r
181                                 sc.SetState(SCE_B_COMMENT);\r
182                         } else if (sc.ch == '\"') {\r
183                                 sc.SetState(SCE_B_STRING);\r
184                         } else if (sc.ch == '#' && visibleChars == 0) {\r
185                                 // Preprocessor commands are alone on their line\r
186                                 sc.SetState(SCE_B_PREPROCESSOR);\r
187                         } else if (sc.ch == '#') {\r
188                                 // It can be a date literal, ending with #, or a file number, from 1 to 511\r
189                                 // The date literal depends on the locale, so anything can go between #'s.\r
190                                 // Can be #January 1, 1993# or #1 Jan 93# or #05/11/2003#, etc.\r
191                                 // So we set the FILENUMBER state, and switch to DATE if it isn't a file number\r
192                                 sc.SetState(SCE_B_FILENUMBER);\r
193                         } else if (sc.ch == '&' && tolower(sc.chNext) == 'h') {\r
194                                 // Hexadecimal number\r
195                                 sc.SetState(SCE_B_NUMBER);\r
196                                 sc.Forward();\r
197                         } else if (sc.ch == '&' && tolower(sc.chNext) == 'o') {\r
198                                 // Octal number\r
199                                 sc.SetState(SCE_B_NUMBER);\r
200                                 sc.Forward();\r
201                         } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {\r
202                                 sc.SetState(SCE_B_NUMBER);\r
203                         } else if (IsAWordStart(sc.ch) || (sc.ch == '[')) {\r
204                                 sc.SetState(SCE_B_IDENTIFIER);\r
205                         } else if (isoperator(static_cast<char>(sc.ch)) || (sc.ch == '\\')) {   // Integer division\r
206                                 sc.SetState(SCE_B_OPERATOR);\r
207                         }\r
208                 }\r
209 \r
210                 if (sc.atLineEnd) {\r
211                         visibleChars = 0;\r
212                 }\r
213                 if (!IsASpace(sc.ch)) {\r
214                         visibleChars++;\r
215                 }\r
216         }\r
217         sc.Complete();\r
218 }\r
219 \r
220 static void FoldVBDoc(unsigned int startPos, int length, int,\r
221                                                    WordList *[], Accessor &styler) {\r
222         int endPos = startPos + length;\r
223 \r
224         // Backtrack to previous line in case need to fix its fold status\r
225         int lineCurrent = styler.GetLine(startPos);\r
226         if (startPos > 0) {\r
227                 if (lineCurrent > 0) {\r
228                         lineCurrent--;\r
229                         startPos = styler.LineStart(lineCurrent);\r
230                 }\r
231         }\r
232         int spaceFlags = 0;\r
233         int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsVBComment);\r
234         char chNext = styler[startPos];\r
235         for (int i = startPos; i < endPos; i++) {\r
236                 char ch = chNext;\r
237                 chNext = styler.SafeGetCharAt(i + 1);\r
238 \r
239                 if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {\r
240                         int lev = indentCurrent;\r
241                         int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsVBComment);\r
242                         if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {\r
243                                 // Only non whitespace lines can be headers\r
244                                 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {\r
245                                         lev |= SC_FOLDLEVELHEADERFLAG;\r
246                                 } else if (indentNext & SC_FOLDLEVELWHITEFLAG) {\r
247                                         // Line after is blank so check the next - maybe should continue further?\r
248                                         int spaceFlags2 = 0;\r
249                                         int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsVBComment);\r
250                                         if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {\r
251                                                 lev |= SC_FOLDLEVELHEADERFLAG;\r
252                                         }\r
253                                 }\r
254                         }\r
255                         indentCurrent = indentNext;\r
256                         styler.SetLevel(lineCurrent, lev);\r
257                         lineCurrent++;\r
258                 }\r
259         }\r
260 }\r
261 \r
262 static void ColouriseVBNetDoc(unsigned int startPos, int length, int initStyle,\r
263                            WordList *keywordlists[], Accessor &styler) {\r
264         ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, false);\r
265 }\r
266 \r
267 static void ColouriseVBScriptDoc(unsigned int startPos, int length, int initStyle,\r
268                            WordList *keywordlists[], Accessor &styler) {\r
269         ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, true);\r
270 }\r
271 \r
272 static const char * const vbWordListDesc[] = {\r
273         "Keywords",\r
274         "user1",\r
275         "user2",\r
276         "user3",\r
277         0\r
278 };\r
279 \r
280 LexerModule lmVB(SCLEX_VB, ColouriseVBNetDoc, "vb", FoldVBDoc, vbWordListDesc);\r
281 LexerModule lmVBScript(SCLEX_VBSCRIPT, ColouriseVBScriptDoc, "vbscript", FoldVBDoc, vbWordListDesc);\r
282 \r