]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/lexers/LexAda.cxx
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / stc / scintilla / lexers / LexAda.cxx
CommitLineData
9e730a78
RD
1// Scintilla source code edit control
2/** @file LexAda.cxx
3 ** Lexer for Ada 95
4 **/
5// Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
65ec6247
RD
6// The License.txt file describes the conditions under which this software may be distributed.
7
9e730a78 8#include <stdlib.h>
9e730a78
RD
9#include <string.h>
10#include <stdio.h>
1dcf666d
RD
11#include <stdarg.h>
12#include <assert.h>
13#include <ctype.h>
65ec6247 14
9e96e16f
RD
15#include <string>
16
1dcf666d
RD
17#include "ILexer.h"
18#include "Scintilla.h"
19#include "SciLexer.h"
65ec6247 20
1dcf666d
RD
21#include "WordList.h"
22#include "LexAccessor.h"
65ec6247 23#include "Accessor.h"
9e730a78 24#include "StyleContext.h"
1dcf666d
RD
25#include "CharacterSet.h"
26#include "LexerModule.h"
9e730a78 27
7e0c58e9
RD
28#ifdef SCI_NAMESPACE
29using namespace Scintilla;
30#endif
31
9e730a78
RD
32/*
33 * Interface
34 */
35
36static void ColouriseDocument(
37 unsigned int startPos,
38 int length,
39 int initStyle,
40 WordList *keywordlists[],
41 Accessor &styler);
42
43static const char * const adaWordListDesc[] = {
44 "Keywords",
45 0
46};
47
48LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);
49
50/*
51 * Implementation
52 */
53
54// Functions that have apostropheStartsAttribute as a parameter set it according to whether
55// an apostrophe encountered after processing the current token will start an attribute or
56// a character literal.
57static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
58static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
59static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
60static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
61static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
62static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
63static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
64static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
65static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
66
67static inline bool IsDelimiterCharacter(int ch);
68static inline bool IsNumberStartCharacter(int ch);
69static inline bool IsNumberCharacter(int ch);
70static inline bool IsSeparatorOrDelimiterCharacter(int ch);
9e96e16f
RD
71static bool IsValidIdentifier(const std::string& identifier);
72static bool IsValidNumber(const std::string& number);
9e730a78
RD
73static inline bool IsWordStartCharacter(int ch);
74static inline bool IsWordCharacter(int ch);
65ec6247 75
9e730a78
RD
76static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
77 apostropheStartsAttribute = true;
65ec6247 78
9e730a78 79 sc.SetState(SCE_ADA_CHARACTER);
65ec6247 80
9e730a78
RD
81 // Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
82 // is handled correctly)
83 sc.Forward();
84 sc.Forward();
85
86 ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
87}
88
89static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
90 while (!sc.atLineEnd && !sc.Match(chEnd)) {
91 sc.Forward();
65ec6247 92 }
65ec6247 93
9e730a78
RD
94 if (!sc.atLineEnd) {
95 sc.ForwardSetState(SCE_ADA_DEFAULT);
96 } else {
97 sc.ChangeState(stateEOL);
65ec6247 98 }
65ec6247
RD
99}
100
9e730a78
RD
101static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
102 // Apostrophe meaning is not changed, but the parameter is present for uniformity
65ec6247 103
9e730a78
RD
104 sc.SetState(SCE_ADA_COMMENTLINE);
105
106 while (!sc.atLineEnd) {
107 sc.Forward();
108 }
109}
110
111static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
112 apostropheStartsAttribute = sc.Match (')');
113 sc.SetState(SCE_ADA_DELIMITER);
114 sc.ForwardSetState(SCE_ADA_DEFAULT);
115}
116
117static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
118 apostropheStartsAttribute = false;
119
120 sc.SetState(SCE_ADA_LABEL);
121
122 // Skip "<<"
123 sc.Forward();
124 sc.Forward();
125
9e96e16f 126 std::string identifier;
9e730a78
RD
127
128 while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
129 identifier += static_cast<char>(tolower(sc.ch));
130 sc.Forward();
131 }
132
133 // Skip ">>"
134 if (sc.Match('>', '>')) {
135 sc.Forward();
136 sc.Forward();
137 } else {
138 sc.ChangeState(SCE_ADA_ILLEGAL);
139 }
140
141 // If the name is an invalid identifier or a keyword, then make it invalid label
142 if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
143 sc.ChangeState(SCE_ADA_ILLEGAL);
144 }
145
146 sc.SetState(SCE_ADA_DEFAULT);
147
148}
149
150static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
151 apostropheStartsAttribute = true;
152
9e96e16f 153 std::string number;
9e730a78
RD
154 sc.SetState(SCE_ADA_NUMBER);
155
156 // Get all characters up to a delimiter or a separator, including points, but excluding
157 // double points (ranges).
158 while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
159 number += static_cast<char>(sc.ch);
160 sc.Forward();
161 }
162
163 // Special case: exponent with sign
164 if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
165 (sc.ch == '+' || sc.ch == '-')) {
166 number += static_cast<char>(sc.ch);
167 sc.Forward ();
168
169 while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
170 number += static_cast<char>(sc.ch);
171 sc.Forward();
172 }
173 }
174
175 if (!IsValidNumber(number)) {
176 sc.ChangeState(SCE_ADA_ILLEGAL);
177 }
178
179 sc.SetState(SCE_ADA_DEFAULT);
180}
181
182static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
183 apostropheStartsAttribute = true;
184
185 sc.SetState(SCE_ADA_STRING);
186 sc.Forward();
187
188 ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
189}
190
191static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
192 // Apostrophe meaning is not changed, but the parameter is present for uniformity
193 sc.SetState(SCE_ADA_DEFAULT);
194 sc.ForwardSetState(SCE_ADA_DEFAULT);
195}
196
197static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
198 apostropheStartsAttribute = true;
199 sc.SetState(SCE_ADA_IDENTIFIER);
200
9e96e16f 201 std::string word;
9e730a78
RD
202
203 while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
204 word += static_cast<char>(tolower(sc.ch));
205 sc.Forward();
206 }
207
208 if (!IsValidIdentifier(word)) {
209 sc.ChangeState(SCE_ADA_ILLEGAL);
210
211 } else if (keywords.InList(word.c_str())) {
212 sc.ChangeState(SCE_ADA_WORD);
213
214 if (word != "all") {
215 apostropheStartsAttribute = false;
216 }
217 }
218
219 sc.SetState(SCE_ADA_DEFAULT);
220}
221
222//
223// ColouriseDocument
224//
225
226static void ColouriseDocument(
227 unsigned int startPos,
228 int length,
229 int initStyle,
230 WordList *keywordlists[],
231 Accessor &styler) {
65ec6247 232 WordList &keywords = *keywordlists[0];
9e730a78
RD
233
234 StyleContext sc(startPos, length, initStyle, styler);
235
236 int lineCurrent = styler.GetLine(startPos);
237 bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;
238
239 while (sc.More()) {
240 if (sc.atLineEnd) {
241 // Go to the next line
242 sc.Forward();
243 lineCurrent++;
244
245 // Remember the line state for future incremental lexing
246 styler.SetLineState(lineCurrent, apostropheStartsAttribute);
247
248 // Don't continue any styles on the next line
249 sc.SetState(SCE_ADA_DEFAULT);
65ec6247 250 }
65ec6247 251
9e730a78
RD
252 // Comments
253 if (sc.Match('-', '-')) {
254 ColouriseComment(sc, apostropheStartsAttribute);
255
256 // Strings
257 } else if (sc.Match('"')) {
258 ColouriseString(sc, apostropheStartsAttribute);
259
260 // Characters
261 } else if (sc.Match('\'') && !apostropheStartsAttribute) {
262 ColouriseCharacter(sc, apostropheStartsAttribute);
263
264 // Labels
265 } else if (sc.Match('<', '<')) {
266 ColouriseLabel(sc, keywords, apostropheStartsAttribute);
267
268 // Whitespace
a33203cb 269 } else if (IsASpace(sc.ch)) {
9e730a78
RD
270 ColouriseWhiteSpace(sc, apostropheStartsAttribute);
271
272 // Delimiters
273 } else if (IsDelimiterCharacter(sc.ch)) {
274 ColouriseDelimiter(sc, apostropheStartsAttribute);
275
276 // Numbers
a33203cb 277 } else if (IsADigit(sc.ch) || sc.ch == '#') {
9e730a78
RD
278 ColouriseNumber(sc, apostropheStartsAttribute);
279
280 // Keywords or identifiers
281 } else {
282 ColouriseWord(sc, keywords, apostropheStartsAttribute);
283 }
284 }
285
286 sc.Complete();
287}
288
289static inline bool IsDelimiterCharacter(int ch) {
290 switch (ch) {
291 case '&':
292 case '\'':
293 case '(':
294 case ')':
295 case '*':
296 case '+':
297 case ',':
298 case '-':
299 case '.':
300 case '/':
301 case ':':
302 case ';':
303 case '<':
304 case '=':
305 case '>':
306 case '|':
307 return true;
308 default:
309 return false;
310 }
311}
312
313static inline bool IsNumberCharacter(int ch) {
314 return IsNumberStartCharacter(ch) ||
315 ch == '_' ||
316 ch == '.' ||
317 ch == '#' ||
318 (ch >= 'a' && ch <= 'f') ||
319 (ch >= 'A' && ch <= 'F');
320}
321
322static inline bool IsNumberStartCharacter(int ch) {
a33203cb 323 return IsADigit(ch);
9e730a78
RD
324}
325
326static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
a33203cb 327 return IsASpace(ch) || IsDelimiterCharacter(ch);
9e730a78
RD
328}
329
9e96e16f 330static bool IsValidIdentifier(const std::string& identifier) {
9e730a78
RD
331 // First character can't be '_', so initialize the flag to true
332 bool lastWasUnderscore = true;
333
88a8b04e 334 size_t length = identifier.length();
9e730a78
RD
335
336 // Zero-length identifiers are not valid (these can occur inside labels)
337 if (length == 0) {
338 return false;
339 }
340
341 // Check for valid character at the start
342 if (!IsWordStartCharacter(identifier[0])) {
343 return false;
344 }
345
346 // Check for only valid characters and no double underscores
88a8b04e 347 for (size_t i = 0; i < length; i++) {
9e730a78
RD
348 if (!IsWordCharacter(identifier[i]) ||
349 (identifier[i] == '_' && lastWasUnderscore)) {
350 return false;
65ec6247 351 }
9e730a78
RD
352 lastWasUnderscore = identifier[i] == '_';
353 }
354
355 // Check for underscore at the end
356 if (lastWasUnderscore == true) {
357 return false;
358 }
65ec6247 359
9e730a78
RD
360 // All checks passed
361 return true;
362}
363
9e96e16f
RD
364static bool IsValidNumber(const std::string& number) {
365 size_t hashPos = number.find("#");
9e730a78
RD
366 bool seenDot = false;
367
88a8b04e
RD
368 size_t i = 0;
369 size_t length = number.length();
9e730a78
RD
370
371 if (length == 0)
372 return false; // Just in case
373
374 // Decimal number
9e96e16f 375 if (hashPos == std::string::npos) {
9e730a78
RD
376 bool canBeSpecial = false;
377
378 for (; i < length; i++) {
379 if (number[i] == '_') {
380 if (!canBeSpecial) {
381 return false;
382 }
383 canBeSpecial = false;
384 } else if (number[i] == '.') {
385 if (!canBeSpecial || seenDot) {
386 return false;
387 }
388 canBeSpecial = false;
389 seenDot = true;
a33203cb 390 } else if (IsADigit(number[i])) {
9e730a78
RD
391 canBeSpecial = true;
392 } else {
393 break;
65ec6247 394 }
9e730a78
RD
395 }
396
397 if (!canBeSpecial)
398 return false;
399 } else {
400 // Based number
401 bool canBeSpecial = false;
402 int base = 0;
403
404 // Parse base
405 for (; i < length; i++) {
406 int ch = number[i];
407 if (ch == '_') {
408 if (!canBeSpecial)
409 return false;
410 canBeSpecial = false;
a33203cb 411 } else if (IsADigit(ch)) {
9e730a78
RD
412 base = base * 10 + (ch - '0');
413 if (base > 16)
414 return false;
415 canBeSpecial = true;
416 } else if (ch == '#' && canBeSpecial) {
417 break;
418 } else {
419 return false;
65ec6247 420 }
9e730a78
RD
421 }
422
423 if (base < 2)
424 return false;
425 if (i == length)
426 return false;
427
428 i++; // Skip over '#'
429
430 // Parse number
431 canBeSpecial = false;
432
433 for (; i < length; i++) {
434 int ch = tolower(number[i]);
435
436 if (ch == '_') {
437 if (!canBeSpecial) {
438 return false;
439 }
440 canBeSpecial = false;
441
442 } else if (ch == '.') {
443 if (!canBeSpecial || seenDot) {
444 return false;
445 }
446 canBeSpecial = false;
447 seenDot = true;
448
a33203cb 449 } else if (IsADigit(ch)) {
9e730a78
RD
450 if (ch - '0' >= base) {
451 return false;
452 }
453 canBeSpecial = true;
454
455 } else if (ch >= 'a' && ch <= 'f') {
456 if (ch - 'a' + 10 >= base) {
457 return false;
65ec6247 458 }
9e730a78
RD
459 canBeSpecial = true;
460
461 } else if (ch == '#' && canBeSpecial) {
462 break;
463
464 } else {
465 return false;
65ec6247 466 }
9e730a78
RD
467 }
468
469 if (i == length) {
470 return false;
471 }
472
473 i++;
474 }
475
476 // Exponent (optional)
477 if (i < length) {
478 if (number[i] != 'e' && number[i] != 'E')
479 return false;
480
481 i++; // Move past 'E'
482
483 if (i == length) {
484 return false;
485 }
486
487 if (number[i] == '+')
488 i++;
489 else if (number[i] == '-') {
490 if (seenDot) {
491 i++;
492 } else {
493 return false; // Integer literals should not have negative exponents
65ec6247 494 }
9e730a78
RD
495 }
496
497 if (i == length) {
498 return false;
499 }
500
501 bool canBeSpecial = false;
502
503 for (; i < length; i++) {
504 if (number[i] == '_') {
505 if (!canBeSpecial) {
506 return false;
507 }
508 canBeSpecial = false;
a33203cb 509 } else if (IsADigit(number[i])) {
9e730a78
RD
510 canBeSpecial = true;
511 } else {
512 return false;
65ec6247
RD
513 }
514 }
515
9e730a78
RD
516 if (!canBeSpecial)
517 return false;
65ec6247 518 }
65ec6247 519
9e730a78
RD
520 // if i == length, number was parsed successfully.
521 return i == length;
522}
523
524static inline bool IsWordCharacter(int ch) {
a33203cb 525 return IsWordStartCharacter(ch) || IsADigit(ch);
65ec6247
RD
526}
527
9e730a78 528static inline bool IsWordStartCharacter(int ch) {
a33203cb 529 return (isascii(ch) && isalpha(ch)) || ch == '_';
9e730a78 530}