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 
== '_';