Add an UI to enable/disable specific overlay handlers.
[TortoiseGit.git] / ext / scintilla / src / LexBasic.cxx
blob9a52186b946535b8bf4d99f843411b2b7f0366f9
1 // Scintilla source code edit control
2 /** @file LexBasic.cxx
3 ** Lexer for BlitzBasic and PureBasic.
4 **/
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 // This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics
9 // and derivatives. Once they diverge enough, might want to split it into multiple
10 // lexers for more code clearity.
12 // Mail me (elias <at> users <dot> sf <dot> net) for any bugs.
14 // Folding only works for simple things like functions or types.
16 // You may want to have a look at my ctags lexer as well, if you additionally to coloring
17 // and folding need to extract things like label tags in your editor.
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <stdarg.h>
25 #include "Platform.h"
27 #include "PropSet.h"
28 #include "Accessor.h"
29 #include "StyleContext.h"
30 #include "KeyWords.h"
31 #include "Scintilla.h"
32 #include "SciLexer.h"
34 #ifdef SCI_NAMESPACE
35 using namespace Scintilla;
36 #endif
38 /* Bits:
39 * 1 - whitespace
40 * 2 - operator
41 * 4 - identifier
42 * 8 - decimal digit
43 * 16 - hex digit
44 * 32 - bin digit
46 static int character_classification[128] =
48 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2,
51 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
52 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
53 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
54 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
55 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
58 static bool IsSpace(int c) {
59 return c < 128 && (character_classification[c] & 1);
62 static bool IsOperator(int c) {
63 return c < 128 && (character_classification[c] & 2);
66 static bool IsIdentifier(int c) {
67 return c < 128 && (character_classification[c] & 4);
70 static bool IsDigit(int c) {
71 return c < 128 && (character_classification[c] & 8);
74 static bool IsHexDigit(int c) {
75 return c < 128 && (character_classification[c] & 16);
78 static bool IsBinDigit(int c) {
79 return c < 128 && (character_classification[c] & 32);
82 static int LowerCase(int c)
84 if (c >= 'A' && c <= 'Z')
85 return 'a' + c - 'A';
86 return c;
89 static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle,
90 WordList *keywordlists[], Accessor &styler, char comment_char) {
91 bool wasfirst = true, isfirst = true; // true if first token in a line
92 styler.StartAt(startPos);
94 StyleContext sc(startPos, length, initStyle, styler);
96 // Can't use sc.More() here else we miss the last character
97 for (; ; sc.Forward()) {
98 if (sc.state == SCE_B_IDENTIFIER) {
99 if (!IsIdentifier(sc.ch)) {
100 // Labels
101 if (wasfirst && sc.Match(':')) {
102 sc.ChangeState(SCE_B_LABEL);
103 sc.ForwardSetState(SCE_B_DEFAULT);
104 } else {
105 char s[100];
106 int kstates[4] = {
107 SCE_B_KEYWORD,
108 SCE_B_KEYWORD2,
109 SCE_B_KEYWORD3,
110 SCE_B_KEYWORD4,
112 sc.GetCurrentLowered(s, sizeof(s));
113 for (int i = 0; i < 4; i++) {
114 if (keywordlists[i]->InList(s)) {
115 sc.ChangeState(kstates[i]);
118 // Types, must set them as operator else they will be
119 // matched as number/constant
120 if (sc.Match('.') || sc.Match('$') || sc.Match('%') ||
121 sc.Match('#')) {
122 sc.SetState(SCE_B_OPERATOR);
123 } else {
124 sc.SetState(SCE_B_DEFAULT);
128 } else if (sc.state == SCE_B_OPERATOR) {
129 if (!IsOperator(sc.ch) || sc.Match('#'))
130 sc.SetState(SCE_B_DEFAULT);
131 } else if (sc.state == SCE_B_LABEL) {
132 if (!IsIdentifier(sc.ch))
133 sc.SetState(SCE_B_DEFAULT);
134 } else if (sc.state == SCE_B_CONSTANT) {
135 if (!IsIdentifier(sc.ch))
136 sc.SetState(SCE_B_DEFAULT);
137 } else if (sc.state == SCE_B_NUMBER) {
138 if (!IsDigit(sc.ch))
139 sc.SetState(SCE_B_DEFAULT);
140 } else if (sc.state == SCE_B_HEXNUMBER) {
141 if (!IsHexDigit(sc.ch))
142 sc.SetState(SCE_B_DEFAULT);
143 } else if (sc.state == SCE_B_BINNUMBER) {
144 if (!IsBinDigit(sc.ch))
145 sc.SetState(SCE_B_DEFAULT);
146 } else if (sc.state == SCE_B_STRING) {
147 if (sc.ch == '"') {
148 sc.ForwardSetState(SCE_B_DEFAULT);
150 if (sc.atLineEnd) {
151 sc.ChangeState(SCE_B_ERROR);
152 sc.SetState(SCE_B_DEFAULT);
154 } else if (sc.state == SCE_B_COMMENT || sc.state == SCE_B_PREPROCESSOR) {
155 if (sc.atLineEnd) {
156 sc.SetState(SCE_B_DEFAULT);
160 if (sc.atLineStart)
161 isfirst = true;
163 if (sc.state == SCE_B_DEFAULT || sc.state == SCE_B_ERROR) {
164 if (isfirst && sc.Match('.')) {
165 sc.SetState(SCE_B_LABEL);
166 } else if (isfirst && sc.Match('#')) {
167 wasfirst = isfirst;
168 sc.SetState(SCE_B_IDENTIFIER);
169 } else if (sc.Match(comment_char)) {
170 // Hack to make deprecated QBASIC '$Include show
171 // up in freebasic with SCE_B_PREPROCESSOR.
172 if (comment_char == '\'' && sc.Match(comment_char, '$'))
173 sc.SetState(SCE_B_PREPROCESSOR);
174 else
175 sc.SetState(SCE_B_COMMENT);
176 } else if (sc.Match('"')) {
177 sc.SetState(SCE_B_STRING);
178 } else if (IsDigit(sc.ch)) {
179 sc.SetState(SCE_B_NUMBER);
180 } else if (sc.Match('$')) {
181 sc.SetState(SCE_B_HEXNUMBER);
182 } else if (sc.Match('%')) {
183 sc.SetState(SCE_B_BINNUMBER);
184 } else if (sc.Match('#')) {
185 sc.SetState(SCE_B_CONSTANT);
186 } else if (IsOperator(sc.ch)) {
187 sc.SetState(SCE_B_OPERATOR);
188 } else if (IsIdentifier(sc.ch)) {
189 wasfirst = isfirst;
190 sc.SetState(SCE_B_IDENTIFIER);
191 } else if (!IsSpace(sc.ch)) {
192 sc.SetState(SCE_B_ERROR);
196 if (!IsSpace(sc.ch))
197 isfirst = false;
199 if (!sc.More())
200 break;
202 sc.Complete();
205 static int CheckBlitzFoldPoint(char const *token, int &level) {
206 if (!strcmp(token, "function") ||
207 !strcmp(token, "type")) {
208 level |= SC_FOLDLEVELHEADERFLAG;
209 return 1;
211 if (!strcmp(token, "end function") ||
212 !strcmp(token, "end type")) {
213 return -1;
215 return 0;
218 static int CheckPureFoldPoint(char const *token, int &level) {
219 if (!strcmp(token, "procedure") ||
220 !strcmp(token, "enumeration") ||
221 !strcmp(token, "interface") ||
222 !strcmp(token, "structure")) {
223 level |= SC_FOLDLEVELHEADERFLAG;
224 return 1;
226 if (!strcmp(token, "endprocedure") ||
227 !strcmp(token, "endenumeration") ||
228 !strcmp(token, "endinterface") ||
229 !strcmp(token, "endstructure")) {
230 return -1;
232 return 0;
235 static int CheckFreeFoldPoint(char const *token, int &level) {
236 if (!strcmp(token, "function") ||
237 !strcmp(token, "sub") ||
238 !strcmp(token, "type")) {
239 level |= SC_FOLDLEVELHEADERFLAG;
240 return 1;
242 if (!strcmp(token, "end function") ||
243 !strcmp(token, "end sub") ||
244 !strcmp(token, "end type")) {
245 return -1;
247 return 0;
250 static void FoldBasicDoc(unsigned int startPos, int length,
251 Accessor &styler, int (*CheckFoldPoint)(char const *, int &)) {
252 int line = styler.GetLine(startPos);
253 int level = styler.LevelAt(line);
254 int go = 0, done = 0;
255 int endPos = startPos + length;
256 char word[256];
257 int wordlen = 0;
258 int i;
259 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
260 // Scan for tokens at the start of the line (they may include
261 // whitespace, for tokens like "End Function"
262 for (i = startPos; i < endPos; i++) {
263 int c = styler.SafeGetCharAt(i);
264 if (!done && !go) {
265 if (wordlen) { // are we scanning a token already?
266 word[wordlen] = static_cast<char>(LowerCase(c));
267 if (!IsIdentifier(c)) { // done with token
268 word[wordlen] = '\0';
269 go = CheckFoldPoint(word, level);
270 if (!go) {
271 // Treat any whitespace as single blank, for
272 // things like "End Function".
273 if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) {
274 word[wordlen] = ' ';
275 if (wordlen < 255)
276 wordlen++;
278 else // done with this line
279 done = 1;
281 } else if (wordlen < 255) {
282 wordlen++;
284 } else { // start scanning at first non-whitespace character
285 if (!IsSpace(c)) {
286 if (IsIdentifier(c)) {
287 word[0] = static_cast<char>(LowerCase(c));
288 wordlen = 1;
289 } else // done with this line
290 done = 1;
294 if (c == '\n') { // line end
295 if (!done && wordlen == 0 && foldCompact) // line was only space
296 level |= SC_FOLDLEVELWHITEFLAG;
297 if (level != styler.LevelAt(line))
298 styler.SetLevel(line, level);
299 level += go;
300 line++;
301 // reset state
302 wordlen = 0;
303 level &= ~SC_FOLDLEVELHEADERFLAG;
304 level &= ~SC_FOLDLEVELWHITEFLAG;
305 go = 0;
306 done = 0;
311 static void ColouriseBlitzBasicDoc(unsigned int startPos, int length, int initStyle,
312 WordList *keywordlists[], Accessor &styler) {
313 ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');
316 static void ColourisePureBasicDoc(unsigned int startPos, int length, int initStyle,
317 WordList *keywordlists[], Accessor &styler) {
318 ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');
321 static void ColouriseFreeBasicDoc(unsigned int startPos, int length, int initStyle,
322 WordList *keywordlists[], Accessor &styler) {
323 ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, '\'');
326 static void FoldBlitzBasicDoc(unsigned int startPos, int length, int,
327 WordList *[], Accessor &styler) {
328 FoldBasicDoc(startPos, length, styler, CheckBlitzFoldPoint);
331 static void FoldPureBasicDoc(unsigned int startPos, int length, int,
332 WordList *[], Accessor &styler) {
333 FoldBasicDoc(startPos, length, styler, CheckPureFoldPoint);
336 static void FoldFreeBasicDoc(unsigned int startPos, int length, int,
337 WordList *[], Accessor &styler) {
338 FoldBasicDoc(startPos, length, styler, CheckFreeFoldPoint);
341 static const char * const blitzbasicWordListDesc[] = {
342 "BlitzBasic Keywords",
343 "user1",
344 "user2",
345 "user3",
349 static const char * const purebasicWordListDesc[] = {
350 "PureBasic Keywords",
351 "PureBasic PreProcessor Keywords",
352 "user defined 1",
353 "user defined 2",
357 static const char * const freebasicWordListDesc[] = {
358 "FreeBasic Keywords",
359 "FreeBasic PreProcessor Keywords",
360 "user defined 1",
361 "user defined 2",
365 LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, ColouriseBlitzBasicDoc, "blitzbasic",
366 FoldBlitzBasicDoc, blitzbasicWordListDesc);
368 LexerModule lmPureBasic(SCLEX_PUREBASIC, ColourisePureBasicDoc, "purebasic",
369 FoldPureBasicDoc, purebasicWordListDesc);
371 LexerModule lmFreeBasic(SCLEX_FREEBASIC, ColouriseFreeBasicDoc, "freebasic",
372 FoldFreeBasicDoc, freebasicWordListDesc);