1
// Scintilla source code edit control
5
// Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
6
// The License.txt file describes the conditions under which this software may be distributed.
18
#include "StyleContext.h"
24
using namespace Scintilla;
31
static void ColouriseDocument(
32
unsigned int startPos,
35
WordList *keywordlists[],
38
static const char * const adaWordListDesc[] = {
43
LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);
49
// Functions that have apostropheStartsAttribute as a parameter set it according to whether
50
// an apostrophe encountered after processing the current token will start an attribute or
51
// a character literal.
52
static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
53
static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
54
static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
55
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
56
static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
57
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
58
static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
59
static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
60
static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
62
static inline bool IsDelimiterCharacter(int ch);
63
static inline bool IsNumberStartCharacter(int ch);
64
static inline bool IsNumberCharacter(int ch);
65
static inline bool IsSeparatorOrDelimiterCharacter(int ch);
66
static bool IsValidIdentifier(const std::string& identifier);
67
static bool IsValidNumber(const std::string& number);
68
static inline bool IsWordStartCharacter(int ch);
69
static inline bool IsWordCharacter(int ch);
71
static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
72
apostropheStartsAttribute = true;
74
sc.SetState(SCE_ADA_CHARACTER);
76
// Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
77
// is handled correctly)
81
ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
84
static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
85
while (!sc.atLineEnd && !sc.Match(chEnd)) {
90
sc.ForwardSetState(SCE_ADA_DEFAULT);
92
sc.ChangeState(stateEOL);
96
static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
97
// Apostrophe meaning is not changed, but the parameter is present for uniformity
99
sc.SetState(SCE_ADA_COMMENTLINE);
101
while (!sc.atLineEnd) {
106
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
107
apostropheStartsAttribute = sc.Match (')');
108
sc.SetState(SCE_ADA_DELIMITER);
109
sc.ForwardSetState(SCE_ADA_DEFAULT);
112
static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
113
apostropheStartsAttribute = false;
115
sc.SetState(SCE_ADA_LABEL);
121
std::string identifier;
123
while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
124
identifier += static_cast<char>(tolower(sc.ch));
129
if (sc.Match('>', '>')) {
133
sc.ChangeState(SCE_ADA_ILLEGAL);
136
// If the name is an invalid identifier or a keyword, then make it invalid label
137
if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
138
sc.ChangeState(SCE_ADA_ILLEGAL);
141
sc.SetState(SCE_ADA_DEFAULT);
145
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
146
apostropheStartsAttribute = true;
149
sc.SetState(SCE_ADA_NUMBER);
151
// Get all characters up to a delimiter or a separator, including points, but excluding
152
// double points (ranges).
153
while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
154
number += static_cast<char>(sc.ch);
158
// Special case: exponent with sign
159
if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
160
(sc.ch == '+' || sc.ch == '-')) {
161
number += static_cast<char>(sc.ch);
164
while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
165
number += static_cast<char>(sc.ch);
170
if (!IsValidNumber(number)) {
171
sc.ChangeState(SCE_ADA_ILLEGAL);
174
sc.SetState(SCE_ADA_DEFAULT);
177
static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
178
apostropheStartsAttribute = true;
180
sc.SetState(SCE_ADA_STRING);
183
ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
186
static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
187
// Apostrophe meaning is not changed, but the parameter is present for uniformity
188
sc.SetState(SCE_ADA_DEFAULT);
189
sc.ForwardSetState(SCE_ADA_DEFAULT);
192
static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
193
apostropheStartsAttribute = true;
194
sc.SetState(SCE_ADA_IDENTIFIER);
198
while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
199
word += static_cast<char>(tolower(sc.ch));
203
if (!IsValidIdentifier(word)) {
204
sc.ChangeState(SCE_ADA_ILLEGAL);
206
} else if (keywords.InList(word.c_str())) {
207
sc.ChangeState(SCE_ADA_WORD);
210
apostropheStartsAttribute = false;
214
sc.SetState(SCE_ADA_DEFAULT);
221
static void ColouriseDocument(
222
unsigned int startPos,
225
WordList *keywordlists[],
227
WordList &keywords = *keywordlists[0];
229
StyleContext sc(startPos, length, initStyle, styler);
231
int lineCurrent = styler.GetLine(startPos);
232
bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;
236
// Go to the next line
240
// Remember the line state for future incremental lexing
241
styler.SetLineState(lineCurrent, apostropheStartsAttribute);
243
// Don't continue any styles on the next line
244
sc.SetState(SCE_ADA_DEFAULT);
248
if (sc.Match('-', '-')) {
249
ColouriseComment(sc, apostropheStartsAttribute);
252
} else if (sc.Match('"')) {
253
ColouriseString(sc, apostropheStartsAttribute);
256
} else if (sc.Match('\'') && !apostropheStartsAttribute) {
257
ColouriseCharacter(sc, apostropheStartsAttribute);
260
} else if (sc.Match('<', '<')) {
261
ColouriseLabel(sc, keywords, apostropheStartsAttribute);
264
} else if (IsASpace(sc.ch)) {
265
ColouriseWhiteSpace(sc, apostropheStartsAttribute);
268
} else if (IsDelimiterCharacter(sc.ch)) {
269
ColouriseDelimiter(sc, apostropheStartsAttribute);
272
} else if (IsADigit(sc.ch) || sc.ch == '#') {
273
ColouriseNumber(sc, apostropheStartsAttribute);
275
// Keywords or identifiers
277
ColouriseWord(sc, keywords, apostropheStartsAttribute);
284
static inline bool IsDelimiterCharacter(int ch) {
308
static inline bool IsNumberCharacter(int ch) {
309
return IsNumberStartCharacter(ch) ||
313
(ch >= 'a' && ch <= 'f') ||
314
(ch >= 'A' && ch <= 'F');
317
static inline bool IsNumberStartCharacter(int ch) {
321
static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
322
return IsASpace(ch) || IsDelimiterCharacter(ch);
325
static bool IsValidIdentifier(const std::string& identifier) {
326
// First character can't be '_', so initialize the flag to true
327
bool lastWasUnderscore = true;
329
size_t length = identifier.length();
331
// Zero-length identifiers are not valid (these can occur inside labels)
336
// Check for valid character at the start
337
if (!IsWordStartCharacter(identifier[0])) {
341
// Check for only valid characters and no double underscores
342
for (size_t i = 0; i < length; i++) {
343
if (!IsWordCharacter(identifier[i]) ||
344
(identifier[i] == '_' && lastWasUnderscore)) {
347
lastWasUnderscore = identifier[i] == '_';
350
// Check for underscore at the end
351
if (lastWasUnderscore == true) {
359
static bool IsValidNumber(const std::string& number) {
360
size_t hashPos = number.find("#");
361
bool seenDot = false;
364
size_t length = number.length();
367
return false; // Just in case
370
if (hashPos == std::string::npos) {
371
bool canBeSpecial = false;
373
for (; i < length; i++) {
374
if (number[i] == '_') {
378
canBeSpecial = false;
379
} else if (number[i] == '.') {
380
if (!canBeSpecial || seenDot) {
383
canBeSpecial = false;
385
} else if (IsADigit(number[i])) {
396
bool canBeSpecial = false;
400
for (; i < length; i++) {
405
canBeSpecial = false;
406
} else if (IsADigit(ch)) {
407
base = base * 10 + (ch - '0');
411
} else if (ch == '#' && canBeSpecial) {
423
i++; // Skip over '#'
426
canBeSpecial = false;
428
for (; i < length; i++) {
429
int ch = tolower(number[i]);
435
canBeSpecial = false;
437
} else if (ch == '.') {
438
if (!canBeSpecial || seenDot) {
441
canBeSpecial = false;
444
} else if (IsADigit(ch)) {
445
if (ch - '0' >= base) {
450
} else if (ch >= 'a' && ch <= 'f') {
451
if (ch - 'a' + 10 >= base) {
456
} else if (ch == '#' && canBeSpecial) {
471
// Exponent (optional)
473
if (number[i] != 'e' && number[i] != 'E')
476
i++; // Move past 'E'
482
if (number[i] == '+')
484
else if (number[i] == '-') {
488
return false; // Integer literals should not have negative exponents
496
bool canBeSpecial = false;
498
for (; i < length; i++) {
499
if (number[i] == '_') {
503
canBeSpecial = false;
504
} else if (IsADigit(number[i])) {
515
// if i == length, number was parsed successfully.
519
static inline bool IsWordCharacter(int ch) {
520
return IsWordStartCharacter(ch) || IsADigit(ch);
523
static inline bool IsWordStartCharacter(int ch) {
524
return (isascii(ch) && isalpha(ch)) || ch == '_';