]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/src/LexBasic.cxx
Interface fixes for Phoenix
[wxWidgets.git] / src / stc / scintilla / src / LexBasic.cxx
CommitLineData
1e9bafca
RD
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.
7
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.
11//
12// Mail me (elias <at> users <dot> sf <dot> net) for any bugs.
13
14// Folding only works for simple things like functions or types.
15
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.
18
19#include <stdlib.h>
20#include <string.h>
21#include <stdio.h>
22#include <ctype.h>
23#include <stdarg.h>
24
25#include "Platform.h"
26
27#include "PropSet.h"
28#include "Accessor.h"
29#include "StyleContext.h"
30#include "KeyWords.h"
31#include "Scintilla.h"
32#include "SciLexer.h"
33
7e0c58e9
RD
34#ifdef SCI_NAMESPACE
35using namespace Scintilla;
36#endif
37
1e9bafca
RD
38/* Bits:
39 * 1 - whitespace
40 * 2 - operator
41 * 4 - identifier
42 * 8 - decimal digit
43 * 16 - hex digit
44 * 32 - bin digit
45 */
46static int character_classification[128] =
47{
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
56};
57
58static bool IsSpace(int c) {
59 return c < 128 && (character_classification[c] & 1);
60}
61
62static bool IsOperator(int c) {
63 return c < 128 && (character_classification[c] & 2);
64}
65
66static bool IsIdentifier(int c) {
67 return c < 128 && (character_classification[c] & 4);
68}
69
70static bool IsDigit(int c) {
71 return c < 128 && (character_classification[c] & 8);
72}
73
74static bool IsHexDigit(int c) {
75 return c < 128 && (character_classification[c] & 16);
76}
77
78static bool IsBinDigit(int c) {
79 return c < 128 && (character_classification[c] & 32);
80}
81
82static int LowerCase(int c)
83{
84 if (c >= 'A' && c <= 'Z')
85 return 'a' + c - 'A';
86 return c;
87}
88
89static 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);
93
94 StyleContext sc(startPos, length, initStyle, styler);
95
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,
111 };
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]);
116 }
117 }
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);
125 }
126 }
127 }
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);
149 }
150 if (sc.atLineEnd) {
151 sc.ChangeState(SCE_B_ERROR);
152 sc.SetState(SCE_B_DEFAULT);
153 }
b8193d80 154 } else if (sc.state == SCE_B_COMMENT || sc.state == SCE_B_PREPROCESSOR) {
1e9bafca
RD
155 if (sc.atLineEnd) {
156 sc.SetState(SCE_B_DEFAULT);
157 }
158 }
159
160 if (sc.atLineStart)
161 isfirst = true;
162
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)) {
b8193d80
RD
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);
1e9bafca
RD
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);
193 }
194 }
195
196 if (!IsSpace(sc.ch))
197 isfirst = false;
198
199 if (!sc.More())
200 break;
201 }
202 sc.Complete();
203}
204
205static int CheckBlitzFoldPoint(char const *token, int &level) {
206 if (!strcmp(token, "function") ||
207 !strcmp(token, "type")) {
208 level |= SC_FOLDLEVELHEADERFLAG;
209 return 1;
210 }
211 if (!strcmp(token, "end function") ||
212 !strcmp(token, "end type")) {
213 return -1;
214 }
215 return 0;
216}
217
218static 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;
225 }
226 if (!strcmp(token, "endprocedure") ||
227 !strcmp(token, "endenumeration") ||
228 !strcmp(token, "endinterface") ||
229 !strcmp(token, "endstructure")) {
230 return -1;
231 }
232 return 0;
233}
234
235static 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;
241 }
242 if (!strcmp(token, "end function") ||
243 !strcmp(token, "end sub") ||
244 !strcmp(token, "end type")) {
245 return -1;
246 }
247 return 0;
248}
249
250static 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++;
277 }
278 else // done with this line
279 done = 1;
280 }
281 } else if (wordlen < 255) {
282 wordlen++;
283 }
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;
291 }
292 }
293 }
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;
307 }
308 }
309}
310
311static void ColouriseBlitzBasicDoc(unsigned int startPos, int length, int initStyle,
312 WordList *keywordlists[], Accessor &styler) {
313 ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');
314}
315
316static void ColourisePureBasicDoc(unsigned int startPos, int length, int initStyle,
317 WordList *keywordlists[], Accessor &styler) {
318 ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');
319}
320
321static void ColouriseFreeBasicDoc(unsigned int startPos, int length, int initStyle,
322 WordList *keywordlists[], Accessor &styler) {
323 ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, '\'');
324}
325
326static void FoldBlitzBasicDoc(unsigned int startPos, int length, int,
327 WordList *[], Accessor &styler) {
328 FoldBasicDoc(startPos, length, styler, CheckBlitzFoldPoint);
329}
330
331static void FoldPureBasicDoc(unsigned int startPos, int length, int,
332 WordList *[], Accessor &styler) {
333 FoldBasicDoc(startPos, length, styler, CheckPureFoldPoint);
334}
335
336static void FoldFreeBasicDoc(unsigned int startPos, int length, int,
337 WordList *[], Accessor &styler) {
338 FoldBasicDoc(startPos, length, styler, CheckFreeFoldPoint);
339}
340
341static const char * const blitzbasicWordListDesc[] = {
342 "BlitzBasic Keywords",
343 "user1",
344 "user2",
345 "user3",
346 0
347};
348
349static const char * const purebasicWordListDesc[] = {
350 "PureBasic Keywords",
351 "PureBasic PreProcessor Keywords",
352 "user defined 1",
353 "user defined 2",
354 0
355};
356
357static const char * const freebasicWordListDesc[] = {
358 "FreeBasic Keywords",
359 "FreeBasic PreProcessor Keywords",
360 "user defined 1",
361 "user defined 2",
362 0
363};
364
365LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, ColouriseBlitzBasicDoc, "blitzbasic",
366 FoldBlitzBasicDoc, blitzbasicWordListDesc);
367
368LexerModule lmPureBasic(SCLEX_PUREBASIC, ColourisePureBasicDoc, "purebasic",
369 FoldPureBasicDoc, purebasicWordListDesc);
370
371LexerModule lmFreeBasic(SCLEX_FREEBASIC, ColouriseFreeBasicDoc, "freebasic",
372 FoldFreeBasicDoc, freebasicWordListDesc);
373