]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexTAL.cxx
Allow unsetting wxMenuItem as start of radio group too.
[wxWidgets.git] / src / stc / scintilla / lexers / LexTAL.cxx
1 // Scintilla source code edit control
2 /** @file LexTAL.cxx
3 ** Lexer for TAL
4 ** Based on LexPascal.cxx
5 ** Written by Laurent le Tynevez
6 ** Updated by Simon Steele <s.steele@pnotepad.org> September 2002
7 ** Updated by Mathias Rauen <scite@madshi.net> May 2003 (Delphi adjustments)
8 ** Updated by Rod Falck, Aug 2006 Converted to TAL
9 **/
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdarg.h>
15 #include <assert.h>
16 #include <ctype.h>
17
18 #include "ILexer.h"
19 #include "Scintilla.h"
20 #include "SciLexer.h"
21
22 #include "WordList.h"
23 #include "LexAccessor.h"
24 #include "Accessor.h"
25 #include "StyleContext.h"
26 #include "CharacterSet.h"
27 #include "LexerModule.h"
28
29 #ifdef SCI_NAMESPACE
30 using namespace Scintilla;
31 #endif
32
33 inline bool isTALoperator(char ch)
34 {
35 return ch == '\'' || ch == '@' || ch == '#' || isoperator(ch);
36 }
37
38 inline bool isTALwordchar(char ch)
39 {
40 return ch == '$' || ch == '^' || iswordchar(ch);
41 }
42
43 inline bool isTALwordstart(char ch)
44 {
45 return ch == '$' || ch == '^' || iswordstart(ch);
46 }
47
48 static void getRange(unsigned int start,
49 unsigned int end,
50 Accessor &styler,
51 char *s,
52 unsigned int len) {
53 unsigned int i = 0;
54 while ((i < end - start + 1) && (i < len-1)) {
55 s[i] = static_cast<char>(tolower(styler[start + i]));
56 i++;
57 }
58 s[i] = '\0';
59 }
60
61 static bool IsStreamCommentStyle(int style) {
62 return style == SCE_C_COMMENT ||
63 style == SCE_C_COMMENTDOC ||
64 style == SCE_C_COMMENTDOCKEYWORD ||
65 style == SCE_C_COMMENTDOCKEYWORDERROR;
66 }
67
68 static void ColourTo(Accessor &styler, unsigned int end, unsigned int attr, bool bInAsm) {
69 if ((bInAsm) && (attr == SCE_C_OPERATOR || attr == SCE_C_NUMBER || attr == SCE_C_DEFAULT || attr == SCE_C_WORD || attr == SCE_C_IDENTIFIER)) {
70 styler.ColourTo(end, SCE_C_REGEX);
71 } else
72 styler.ColourTo(end, attr);
73 }
74
75 // returns 1 if the item starts a class definition, and -1 if the word is "end", and 2 if the word is "asm"
76 static int classifyWordTAL(unsigned int start, unsigned int end, /*WordList &keywords*/WordList *keywordlists[], Accessor &styler, bool bInAsm) {
77 int ret = 0;
78
79 WordList& keywords = *keywordlists[0];
80 WordList& builtins = *keywordlists[1];
81 WordList& nonreserved_keywords = *keywordlists[2];
82
83 char s[100];
84 getRange(start, end, styler, s, sizeof(s));
85
86 char chAttr = SCE_C_IDENTIFIER;
87 if (isdigit(s[0]) || (s[0] == '.')) {
88 chAttr = SCE_C_NUMBER;
89 }
90 else {
91 if (keywords.InList(s)) {
92 chAttr = SCE_C_WORD;
93
94 if (strcmp(s, "asm") == 0) {
95 ret = 2;
96 }
97 else if (strcmp(s, "end") == 0) {
98 ret = -1;
99 }
100 }
101 else if (s[0] == '$' || builtins.InList(s)) {
102 chAttr = SCE_C_WORD2;
103 }
104 else if (nonreserved_keywords.InList(s)) {
105 chAttr = SCE_C_UUID;
106 }
107 }
108 ColourTo(styler, end, chAttr, (bInAsm && ret != -1));
109 return ret;
110 }
111
112 static int classifyFoldPointTAL(const char* s) {
113 int lev = 0;
114 if (!(isdigit(s[0]) || (s[0] == '.'))) {
115 if (strcmp(s, "begin") == 0 ||
116 strcmp(s, "block") == 0) {
117 lev=1;
118 } else if (strcmp(s, "end") == 0) {
119 lev=-1;
120 }
121 }
122 return lev;
123 }
124
125 static void ColouriseTALDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
126 Accessor &styler) {
127
128 styler.StartAt(startPos);
129
130 int state = initStyle;
131 if (state == SCE_C_CHARACTER) // Does not leak onto next line
132 state = SCE_C_DEFAULT;
133 char chPrev = ' ';
134 char chNext = styler[startPos];
135 unsigned int lengthDoc = startPos + length;
136
137 bool bInClassDefinition;
138
139 int currentLine = styler.GetLine(startPos);
140 if (currentLine > 0) {
141 styler.SetLineState(currentLine, styler.GetLineState(currentLine-1));
142 bInClassDefinition = (styler.GetLineState(currentLine) == 1);
143 } else {
144 styler.SetLineState(currentLine, 0);
145 bInClassDefinition = false;
146 }
147
148 bool bInAsm = (state == SCE_C_REGEX);
149 if (bInAsm)
150 state = SCE_C_DEFAULT;
151
152 styler.StartSegment(startPos);
153 int visibleChars = 0;
154 for (unsigned int i = startPos; i < lengthDoc; i++) {
155 char ch = chNext;
156
157 chNext = styler.SafeGetCharAt(i + 1);
158
159 if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
160 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
161 // Avoid triggering two times on Dos/Win
162 // End of line
163 if (state == SCE_C_CHARACTER) {
164 ColourTo(styler, i, state, bInAsm);
165 state = SCE_C_DEFAULT;
166 }
167 visibleChars = 0;
168 currentLine++;
169 styler.SetLineState(currentLine, (bInClassDefinition ? 1 : 0));
170 }
171
172 if (styler.IsLeadByte(ch)) {
173 chNext = styler.SafeGetCharAt(i + 2);
174 chPrev = ' ';
175 i += 1;
176 continue;
177 }
178
179 if (state == SCE_C_DEFAULT) {
180 if (isTALwordstart(ch)) {
181 ColourTo(styler, i-1, state, bInAsm);
182 state = SCE_C_IDENTIFIER;
183 } else if (ch == '!' && chNext != '*') {
184 ColourTo(styler, i-1, state, bInAsm);
185 state = SCE_C_COMMENT;
186 } else if (ch == '!' && chNext == '*') {
187 ColourTo(styler, i-1, state, bInAsm);
188 state = SCE_C_COMMENTDOC;
189 } else if (ch == '-' && chNext == '-') {
190 ColourTo(styler, i-1, state, bInAsm);
191 state = SCE_C_COMMENTLINE;
192 } else if (ch == '"') {
193 ColourTo(styler, i-1, state, bInAsm);
194 state = SCE_C_STRING;
195 } else if (ch == '?' && visibleChars == 0) {
196 ColourTo(styler, i-1, state, bInAsm);
197 state = SCE_C_PREPROCESSOR;
198 } else if (isTALoperator(ch)) {
199 ColourTo(styler, i-1, state, bInAsm);
200 ColourTo(styler, i, SCE_C_OPERATOR, bInAsm);
201 }
202 } else if (state == SCE_C_IDENTIFIER) {
203 if (!isTALwordchar(ch)) {
204 int lStateChange = classifyWordTAL(styler.GetStartSegment(), i - 1, keywordlists, styler, bInAsm);
205
206 if(lStateChange == 1) {
207 styler.SetLineState(currentLine, 1);
208 bInClassDefinition = true;
209 } else if(lStateChange == 2) {
210 bInAsm = true;
211 } else if(lStateChange == -1) {
212 styler.SetLineState(currentLine, 0);
213 bInClassDefinition = false;
214 bInAsm = false;
215 }
216
217 state = SCE_C_DEFAULT;
218 chNext = styler.SafeGetCharAt(i + 1);
219 if (ch == '!' && chNext != '*') {
220 state = SCE_C_COMMENT;
221 } else if (ch == '!' && chNext == '*') {
222 ColourTo(styler, i-1, state, bInAsm);
223 state = SCE_C_COMMENTDOC;
224 } else if (ch == '-' && chNext == '-') {
225 state = SCE_C_COMMENTLINE;
226 } else if (ch == '"') {
227 state = SCE_C_STRING;
228 } else if (isTALoperator(ch)) {
229 ColourTo(styler, i, SCE_C_OPERATOR, bInAsm);
230 }
231 }
232 } else {
233 if (state == SCE_C_PREPROCESSOR) {
234 if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) {
235 ColourTo(styler, i-1, state, bInAsm);
236 state = SCE_C_DEFAULT;
237 }
238 } else if (state == SCE_C_COMMENT) {
239 if (ch == '!' || (ch == '\r' || ch == '\n') ) {
240 ColourTo(styler, i, state, bInAsm);
241 state = SCE_C_DEFAULT;
242 }
243 } else if (state == SCE_C_COMMENTDOC) {
244 if (ch == '!' || (ch == '\r' || ch == '\n')) {
245 if (((i > styler.GetStartSegment() + 2) || (
246 (initStyle == SCE_C_COMMENTDOC) &&
247 (styler.GetStartSegment() == static_cast<unsigned int>(startPos))))) {
248 ColourTo(styler, i, state, bInAsm);
249 state = SCE_C_DEFAULT;
250 }
251 }
252 } else if (state == SCE_C_COMMENTLINE) {
253 if (ch == '\r' || ch == '\n') {
254 ColourTo(styler, i-1, state, bInAsm);
255 state = SCE_C_DEFAULT;
256 }
257 } else if (state == SCE_C_STRING) {
258 if (ch == '"') {
259 ColourTo(styler, i, state, bInAsm);
260 state = SCE_C_DEFAULT;
261 }
262 }
263 }
264 if (!isspacechar(ch))
265 visibleChars++;
266 chPrev = ch;
267 }
268 ColourTo(styler, lengthDoc - 1, state, bInAsm);
269 }
270
271 static void FoldTALDoc(unsigned int startPos, int length, int initStyle, WordList *[],
272 Accessor &styler) {
273 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
274 bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
275 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
276 unsigned int endPos = startPos + length;
277 int visibleChars = 0;
278 int lineCurrent = styler.GetLine(startPos);
279 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
280 int levelCurrent = levelPrev;
281 char chNext = styler[startPos];
282 int styleNext = styler.StyleAt(startPos);
283 int style = initStyle;
284 bool was_end = false;
285 bool section = false;
286
287 int lastStart = 0;
288
289 for (unsigned int i = startPos; i < endPos; i++) {
290 char ch = chNext;
291 chNext = styler.SafeGetCharAt(i + 1);
292 int stylePrev = style;
293 style = styleNext;
294 styleNext = styler.StyleAt(i + 1);
295 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
296
297 if (stylePrev == SCE_C_DEFAULT && (style == SCE_C_WORD || style == SCE_C_UUID || style == SCE_C_PREPROCESSOR))
298 {
299 // Store last word start point.
300 lastStart = i;
301 }
302
303 if (stylePrev == SCE_C_WORD || style == SCE_C_UUID || stylePrev == SCE_C_PREPROCESSOR) {
304 if(isTALwordchar(ch) && !isTALwordchar(chNext)) {
305 char s[100];
306 getRange(lastStart, i, styler, s, sizeof(s));
307 if (stylePrev == SCE_C_PREPROCESSOR && strcmp(s, "?section") == 0)
308 {
309 section = true;
310 levelCurrent = 1;
311 levelPrev = 0;
312 }
313 else if (stylePrev == SCE_C_WORD || stylePrev == SCE_C_UUID)
314 {
315 if (strcmp(s, "block") == 0)
316 {
317 // block keyword is ignored immediately after end keyword
318 if (!was_end)
319 levelCurrent++;
320 }
321 else
322 levelCurrent += classifyFoldPointTAL(s);
323 if (strcmp(s, "end") == 0)
324 {
325 was_end = true;
326 }
327 else
328 {
329 was_end = false;
330 }
331 }
332 }
333 }
334
335 if (foldComment && (style == SCE_C_COMMENTLINE)) {
336 if ((ch == '/') && (chNext == '/')) {
337 char chNext2 = styler.SafeGetCharAt(i + 2);
338 if (chNext2 == '{') {
339 levelCurrent++;
340 } else if (chNext2 == '}') {
341 levelCurrent--;
342 }
343 }
344 }
345
346 if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
347 if (ch == '{' && chNext == '$') {
348 unsigned int j=i+2; // skip {$
349 while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
350 j++;
351 }
352 if (styler.Match(j, "region") || styler.Match(j, "if")) {
353 levelCurrent++;
354 } else if (styler.Match(j, "end")) {
355 levelCurrent--;
356 }
357 }
358 }
359
360 if (foldComment && IsStreamCommentStyle(style)) {
361 if (!IsStreamCommentStyle(stylePrev)) {
362 levelCurrent++;
363 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
364 // Comments don't end at end of line and the next character may be unstyled.
365 levelCurrent--;
366 }
367 }
368
369 if (atEOL) {
370 int lev = levelPrev | SC_FOLDLEVELBASE;
371 if (visibleChars == 0 && foldCompact)
372 lev |= SC_FOLDLEVELWHITEFLAG;
373 if ((levelCurrent > levelPrev || section) && (visibleChars > 0))
374 lev |= SC_FOLDLEVELHEADERFLAG;
375 if (lev != styler.LevelAt(lineCurrent)) {
376 styler.SetLevel(lineCurrent, lev);
377 }
378 lineCurrent++;
379 levelPrev = levelCurrent;
380 visibleChars = 0;
381 section = false;
382 }
383
384 if (!isspacechar(ch))
385 visibleChars++;
386 }
387
388 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
389 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
390 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
391 }
392
393 static const char * const TALWordListDesc[] = {
394 "Keywords",
395 "Builtins",
396 0
397 };
398
399 LexerModule lmTAL(SCLEX_TAL, ColouriseTALDoc, "TAL", FoldTALDoc, TALWordListDesc);