Update Scintilla to version 3.5.2
[TortoiseGit.git] / ext / scintilla / lexers / LexVHDL.cxx
blob2752d2c550baf0e5fe2f89720a437fd8aff7af84
1 // Scintilla source code edit control
2 /** @file LexVHDL.cxx
3 ** Lexer for VHDL
4 ** Written by Phil Reid,
5 ** Based on:
6 ** - The Verilog Lexer by Avi Yegudin
7 ** - The Fortran Lexer by Chuan-jian Shen
8 ** - The C++ lexer by Neil Hodgson
9 **/
10 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
11 // The License.txt file describes the conditions under which this software may be distributed.
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <assert.h>
18 #include <ctype.h>
20 #include "ILexer.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
24 #include "WordList.h"
25 #include "LexAccessor.h"
26 #include "Accessor.h"
27 #include "StyleContext.h"
28 #include "CharacterSet.h"
29 #include "LexerModule.h"
31 #ifdef SCI_NAMESPACE
32 using namespace Scintilla;
33 #endif
35 static void ColouriseVHDLDoc(
36 unsigned int startPos,
37 int length,
38 int initStyle,
39 WordList *keywordlists[],
40 Accessor &styler);
43 /***************************************/
44 static inline bool IsAWordChar(const int ch) {
45 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' );
48 /***************************************/
49 static inline bool IsAWordStart(const int ch) {
50 return (ch < 0x80) && (isalnum(ch) || ch == '_');
53 /***************************************/
54 static inline bool IsABlank(unsigned int ch) {
55 return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ;
58 /***************************************/
59 static void ColouriseVHDLDoc(
60 unsigned int startPos,
61 int length,
62 int initStyle,
63 WordList *keywordlists[],
64 Accessor &styler)
66 WordList &Keywords = *keywordlists[0];
67 WordList &Operators = *keywordlists[1];
68 WordList &Attributes = *keywordlists[2];
69 WordList &Functions = *keywordlists[3];
70 WordList &Packages = *keywordlists[4];
71 WordList &Types = *keywordlists[5];
72 WordList &User = *keywordlists[6];
74 StyleContext sc(startPos, length, initStyle, styler);
76 for (; sc.More(); sc.Forward())
79 // Determine if the current state should terminate.
80 if (sc.state == SCE_VHDL_OPERATOR) {
81 sc.SetState(SCE_VHDL_DEFAULT);
82 } else if (sc.state == SCE_VHDL_NUMBER) {
83 if (!IsAWordChar(sc.ch) && (sc.ch != '#')) {
84 sc.SetState(SCE_VHDL_DEFAULT);
86 } else if (sc.state == SCE_VHDL_IDENTIFIER) {
87 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
88 char s[100];
89 sc.GetCurrentLowered(s, sizeof(s));
90 if (Keywords.InList(s)) {
91 sc.ChangeState(SCE_VHDL_KEYWORD);
92 } else if (Operators.InList(s)) {
93 sc.ChangeState(SCE_VHDL_STDOPERATOR);
94 } else if (Attributes.InList(s)) {
95 sc.ChangeState(SCE_VHDL_ATTRIBUTE);
96 } else if (Functions.InList(s)) {
97 sc.ChangeState(SCE_VHDL_STDFUNCTION);
98 } else if (Packages.InList(s)) {
99 sc.ChangeState(SCE_VHDL_STDPACKAGE);
100 } else if (Types.InList(s)) {
101 sc.ChangeState(SCE_VHDL_STDTYPE);
102 } else if (User.InList(s)) {
103 sc.ChangeState(SCE_VHDL_USERWORD);
105 sc.SetState(SCE_VHDL_DEFAULT);
107 } else if (sc.state == SCE_VHDL_COMMENT || sc.state == SCE_VHDL_COMMENTLINEBANG) {
108 if (sc.atLineEnd) {
109 sc.SetState(SCE_VHDL_DEFAULT);
111 } else if (sc.state == SCE_VHDL_STRING) {
112 if (sc.ch == '\\') {
113 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
114 sc.Forward();
116 } else if (sc.ch == '\"') {
117 sc.ForwardSetState(SCE_VHDL_DEFAULT);
118 } else if (sc.atLineEnd) {
119 sc.ChangeState(SCE_VHDL_STRINGEOL);
120 sc.ForwardSetState(SCE_VHDL_DEFAULT);
122 } else if (sc.state == SCE_VHDL_BLOCK_COMMENT){
123 if(sc.ch == '*' && sc.chNext == '/'){
124 sc.Forward();
125 sc.ForwardSetState(SCE_VHDL_DEFAULT);
129 // Determine if a new state should be entered.
130 if (sc.state == SCE_VHDL_DEFAULT) {
131 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
132 sc.SetState(SCE_VHDL_NUMBER);
133 } else if (IsAWordStart(sc.ch)) {
134 sc.SetState(SCE_VHDL_IDENTIFIER);
135 } else if (sc.Match('-', '-')) {
136 if (sc.Match("--!")) // Nice to have a different comment style
137 sc.SetState(SCE_VHDL_COMMENTLINEBANG);
138 else
139 sc.SetState(SCE_VHDL_COMMENT);
140 } else if (sc.Match('/', '*')){
141 sc.SetState(SCE_VHDL_BLOCK_COMMENT);
142 } else if (sc.ch == '\"') {
143 sc.SetState(SCE_VHDL_STRING);
144 } else if (isoperator(static_cast<char>(sc.ch))) {
145 sc.SetState(SCE_VHDL_OPERATOR);
149 sc.Complete();
151 //=============================================================================
152 static bool IsCommentLine(int line, Accessor &styler) {
153 int pos = styler.LineStart(line);
154 int eol_pos = styler.LineStart(line + 1) - 1;
155 for (int i = pos; i < eol_pos; i++) {
156 char ch = styler[i];
157 char chNext = styler[i+1];
158 if ((ch == '-') && (chNext == '-'))
159 return true;
160 else if (ch != ' ' && ch != '\t')
161 return false;
163 return false;
165 static bool IsCommentBlockStart(int line, Accessor &styler)
167 int pos = styler.LineStart(line);
168 int eol_pos = styler.LineStart(line + 1) - 1;
169 for (int i = pos; i < eol_pos; i++) {
170 char ch = styler[i];
171 char chNext = styler[i+1];
172 char style = styler.StyleAt(i);
173 if ((style == SCE_VHDL_BLOCK_COMMENT) && (ch == '/') && (chNext == '*'))
174 return true;
176 return false;
179 static bool IsCommentBlockEnd(int line, Accessor &styler)
181 int pos = styler.LineStart(line);
182 int eol_pos = styler.LineStart(line + 1) - 1;
184 for (int i = pos; i < eol_pos; i++) {
185 char ch = styler[i];
186 char chNext = styler[i+1];
187 char style = styler.StyleAt(i);
188 if ((style == SCE_VHDL_BLOCK_COMMENT) && (ch == '*') && (chNext == '/'))
189 return true;
191 return false;
194 static bool IsCommentStyle(char style)
196 return style == SCE_VHDL_BLOCK_COMMENT || style == SCE_VHDL_COMMENT || style == SCE_VHDL_COMMENTLINEBANG;
199 //=============================================================================
200 // Folding the code
201 static void FoldNoBoxVHDLDoc(
202 unsigned int startPos,
203 int length,
204 int,
205 Accessor &styler)
207 // Decided it would be smarter to have the lexer have all keywords included. Therefore I
208 // don't check if the style for the keywords that I use to adjust the levels.
209 char words[] =
210 "architecture begin block case component else elsif end entity generate loop package process record then "
211 "procedure function when";
212 WordList keywords;
213 keywords.Set(words);
215 bool foldComment = styler.GetPropertyInt("fold.comment", 1) != 0;
216 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
217 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 1) != 0;
218 bool foldAtBegin = styler.GetPropertyInt("fold.at.Begin", 1) != 0;
219 bool foldAtParenthese = styler.GetPropertyInt("fold.at.Parenthese", 1) != 0;
220 //bool foldAtWhen = styler.GetPropertyInt("fold.at.When", 1) != 0; //< fold at when in case statements
222 int visibleChars = 0;
223 unsigned int endPos = startPos + length;
225 int lineCurrent = styler.GetLine(startPos);
226 int levelCurrent = SC_FOLDLEVELBASE;
227 if(lineCurrent > 0)
228 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
229 //int levelMinCurrent = levelCurrent;
230 int levelMinCurrentElse = levelCurrent; //< Used for folding at 'else'
231 int levelMinCurrentBegin = levelCurrent; //< Used for folding at 'begin'
232 int levelNext = levelCurrent;
234 /***************************************/
235 int lastStart = 0;
236 char prevWord[32] = "";
238 /***************************************/
239 // Find prev word
240 // The logic for going up or down a level depends on a the previous keyword
241 // This code could be cleaned up.
242 int end = 0;
243 unsigned int j;
244 for(j = startPos; j>0; j--)
246 char ch = styler.SafeGetCharAt(j);
247 char chPrev = styler.SafeGetCharAt(j-1);
248 int style = styler.StyleAt(j);
249 int stylePrev = styler.StyleAt(j-1);
250 if ((!IsCommentStyle(style)) && (stylePrev != SCE_VHDL_STRING))
252 if(IsAWordChar(chPrev) && !IsAWordChar(ch))
254 end = j-1;
257 if ((!IsCommentStyle(style)) && (style != SCE_VHDL_STRING))
259 if(!IsAWordChar(chPrev) && IsAWordStart(ch) && (end != 0))
261 char s[32];
262 unsigned int k;
263 for(k=0; (k<31 ) && (k<end-j+1 ); k++) {
264 s[k] = static_cast<char>(tolower(styler[j+k]));
266 s[k] = '\0';
268 if(keywords.InList(s)) {
269 strcpy(prevWord, s);
270 break;
275 for(j=j+static_cast<unsigned int>(strlen(prevWord)); j<endPos; j++)
277 char ch = styler.SafeGetCharAt(j);
278 int style = styler.StyleAt(j);
279 if ((!IsCommentStyle(style)) && (style != SCE_VHDL_STRING))
281 if((ch == ';') && (strcmp(prevWord, "end") == 0))
283 strcpy(prevWord, ";");
288 char chNext = styler[startPos];
289 char chPrev = '\0';
290 char chNextNonBlank;
291 int styleNext = styler.StyleAt(startPos);
292 //Platform::DebugPrintf("Line[%04d] Prev[%20s] ************************* Level[%x]\n", lineCurrent+1, prevWord, levelCurrent);
294 /***************************************/
295 for (unsigned int i = startPos; i < endPos; i++)
297 char ch = chNext;
298 chNext = styler.SafeGetCharAt(i + 1);
299 chPrev = styler.SafeGetCharAt(i - 1);
300 chNextNonBlank = chNext;
301 unsigned int j = i+1;
302 while(IsABlank(chNextNonBlank) && j<endPos)
304 j ++ ;
305 chNextNonBlank = styler.SafeGetCharAt(j);
307 int style = styleNext;
308 styleNext = styler.StyleAt(i + 1);
309 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
311 if (foldComment && atEOL)
313 if(IsCommentLine(lineCurrent, styler))
315 if(!IsCommentLine(lineCurrent-1, styler) && IsCommentLine(lineCurrent+1, styler))
317 levelNext++;
319 else if(IsCommentLine(lineCurrent-1, styler) && !IsCommentLine(lineCurrent+1, styler))
321 levelNext--;
324 else
326 if (IsCommentBlockStart(lineCurrent, styler) && !IsCommentBlockEnd(lineCurrent, styler))
328 levelNext++;
330 else if (IsCommentBlockEnd(lineCurrent, styler) && !IsCommentBlockStart(lineCurrent, styler))
332 levelNext--;
337 if ((style == SCE_VHDL_OPERATOR) && foldAtParenthese)
339 if(ch == '(') {
340 levelNext++;
341 } else if (ch == ')') {
342 levelNext--;
346 if ((!IsCommentStyle(style)) && (style != SCE_VHDL_STRING))
348 if((ch == ';') && (strcmp(prevWord, "end") == 0))
350 strcpy(prevWord, ";");
353 if(!IsAWordChar(chPrev) && IsAWordStart(ch))
355 lastStart = i;
358 if(IsAWordChar(ch) && !IsAWordChar(chNext)) {
359 char s[32];
360 unsigned int k;
361 for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
362 s[k] = static_cast<char>(tolower(styler[lastStart+k]));
364 s[k] = '\0';
366 if(keywords.InList(s))
368 if (
369 strcmp(s, "architecture") == 0 ||
370 strcmp(s, "case") == 0 ||
371 strcmp(s, "generate") == 0 ||
372 strcmp(s, "block") == 0 ||
373 strcmp(s, "loop") == 0 ||
374 strcmp(s, "package") ==0 ||
375 strcmp(s, "process") == 0 ||
376 strcmp(s, "record") == 0 ||
377 strcmp(s, "then") == 0)
379 if (strcmp(prevWord, "end") != 0)
381 if (levelMinCurrentElse > levelNext) {
382 levelMinCurrentElse = levelNext;
384 levelNext++;
386 } else if (
387 strcmp(s, "component") == 0 ||
388 strcmp(s, "entity") == 0 ||
389 strcmp(s, "configuration") == 0 )
391 if (strcmp(prevWord, "end") != 0)
392 { // check for instantiated unit by backward searching for the colon.
393 unsigned pos = lastStart-1;
394 char chAtPos, styleAtPos;
395 do{// skip white spaces
396 styleAtPos = styler.StyleAt(pos);
397 chAtPos = styler.SafeGetCharAt(pos--);
398 }while(pos>0 &&
399 (chAtPos == ' ' || chAtPos == '\t' ||
400 chAtPos == '\n' || chAtPos == '\r' ||
401 IsCommentStyle(styleAtPos)));
403 // check for a colon (':') before the instantiated units "entity", "component" or "configuration". Don't fold thereafter.
404 if (chAtPos != ':')
406 if (levelMinCurrentElse > levelNext) {
407 levelMinCurrentElse = levelNext;
409 levelNext++;
412 } else if (
413 strcmp(s, "procedure") == 0 ||
414 strcmp(s, "function") == 0)
416 if (strcmp(prevWord, "end") != 0) // check for "end procedure" etc.
417 { // This code checks to see if the procedure / function is a definition within a "package"
418 // rather than the actual code in the body.
419 int BracketLevel = 0;
420 for(int pos=i+1; pos<styler.Length(); pos++)
422 int styleAtPos = styler.StyleAt(pos);
423 char chAtPos = styler.SafeGetCharAt(pos);
424 if(chAtPos == '(') BracketLevel++;
425 if(chAtPos == ')') BracketLevel--;
427 (BracketLevel == 0) &&
428 (!IsCommentStyle(styleAtPos)) &&
429 (styleAtPos != SCE_VHDL_STRING) &&
430 !iswordchar(styler.SafeGetCharAt(pos-1)) &&
431 styler.Match(pos, "is") &&
432 !iswordchar(styler.SafeGetCharAt(pos+2)))
434 if (levelMinCurrentElse > levelNext) {
435 levelMinCurrentElse = levelNext;
437 levelNext++;
438 break;
440 if((BracketLevel == 0) && (chAtPos == ';'))
442 break;
447 } else if (strcmp(s, "end") == 0) {
448 levelNext--;
449 } else if(strcmp(s, "elsif") == 0) { // elsif is followed by then so folding occurs correctly
450 levelNext--;
451 } else if (strcmp(s, "else") == 0) {
452 if(strcmp(prevWord, "when") != 0) // ignore a <= x when y else z;
454 levelMinCurrentElse = levelNext - 1; // VHDL else is all on its own so just dec. the min level
456 } else if(
457 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "architecture") == 0)) ||
458 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "function") == 0)) ||
459 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "procedure") == 0)))
461 levelMinCurrentBegin = levelNext - 1;
463 //Platform::DebugPrintf("Line[%04d] Prev[%20s] Cur[%20s] Level[%x]\n", lineCurrent+1, prevWord, s, levelCurrent);
464 strcpy(prevWord, s);
468 if (atEOL) {
469 int levelUse = levelCurrent;
471 if (foldAtElse && (levelMinCurrentElse < levelUse)) {
472 levelUse = levelMinCurrentElse;
474 if (foldAtBegin && (levelMinCurrentBegin < levelUse)) {
475 levelUse = levelMinCurrentBegin;
477 int lev = levelUse | levelNext << 16;
478 if (visibleChars == 0 && foldCompact)
479 lev |= SC_FOLDLEVELWHITEFLAG;
481 if (levelUse < levelNext)
482 lev |= SC_FOLDLEVELHEADERFLAG;
483 if (lev != styler.LevelAt(lineCurrent)) {
484 styler.SetLevel(lineCurrent, lev);
486 //Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
487 lineCurrent++;
488 levelCurrent = levelNext;
489 //levelMinCurrent = levelCurrent;
490 levelMinCurrentElse = levelCurrent;
491 levelMinCurrentBegin = levelCurrent;
492 visibleChars = 0;
494 /***************************************/
495 if (!isspacechar(ch)) visibleChars++;
498 /***************************************/
499 // Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
502 //=============================================================================
503 static void FoldVHDLDoc(unsigned int startPos, int length, int initStyle, WordList *[],
504 Accessor &styler) {
505 FoldNoBoxVHDLDoc(startPos, length, initStyle, styler);
508 //=============================================================================
509 static const char * const VHDLWordLists[] = {
510 "Keywords",
511 "Operators",
512 "Attributes",
513 "Standard Functions",
514 "Standard Packages",
515 "Standard Types",
516 "User Words",
521 LexerModule lmVHDL(SCLEX_VHDL, ColouriseVHDLDoc, "vhdl", FoldVHDLDoc, VHDLWordLists);
524 // Keyword:
525 // access after alias all architecture array assert attribute begin block body buffer bus case component
526 // configuration constant disconnect downto else elsif end entity exit file for function generate generic
527 // group guarded if impure in inertial inout is label library linkage literal loop map new next null of
528 // on open others out package port postponed procedure process pure range record register reject report
529 // return select severity shared signal subtype then to transport type unaffected units until use variable
530 // wait when while with
532 // Operators:
533 // abs and mod nand nor not or rem rol ror sla sll sra srl xnor xor
535 // Attributes:
536 // left right low high ascending image value pos val succ pred leftof rightof base range reverse_range
537 // length delayed stable quiet transaction event active last_event last_active last_value driving
538 // driving_value simple_name path_name instance_name
540 // Std Functions:
541 // now readline read writeline write endfile resolved to_bit to_bitvector to_stdulogic to_stdlogicvector
542 // to_stdulogicvector to_x01 to_x01z to_UX01 rising_edge falling_edge is_x shift_left shift_right rotate_left
543 // rotate_right resize to_integer to_unsigned to_signed std_match to_01
545 // Std Packages:
546 // std ieee work standard textio std_logic_1164 std_logic_arith std_logic_misc std_logic_signed
547 // std_logic_textio std_logic_unsigned numeric_bit numeric_std math_complex math_real vital_primitives
548 // vital_timing
550 // Std Types:
551 // boolean bit character severity_level integer real time delay_length natural positive string bit_vector
552 // file_open_kind file_open_status line text side width std_ulogic std_ulogic_vector std_logic
553 // std_logic_vector X01 X01Z UX01 UX01Z unsigned signed