]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexVerilog.cxx
Allow unsetting wxMenuItem as start of radio group too.
[wxWidgets.git] / src / stc / scintilla / lexers / LexVerilog.cxx
1 // Scintilla source code edit control
2 /** @file LexVerilog.cxx
3 ** Lexer for Verilog.
4 ** Written by Avi Yegudin, based on C++ lexer by Neil Hodgson
5 **/
6 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
30
31 static inline bool IsAWordChar(const int ch) {
32 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\''|| ch == '$');
33 }
34
35 static inline bool IsAWordStart(const int ch) {
36 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '$');
37 }
38
39 static void ColouriseVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
40 Accessor &styler) {
41
42 WordList &keywords = *keywordlists[0];
43 WordList &keywords2 = *keywordlists[1];
44 WordList &keywords3 = *keywordlists[2];
45 WordList &keywords4 = *keywordlists[3];
46
47 // Do not leak onto next line
48 if (initStyle == SCE_V_STRINGEOL)
49 initStyle = SCE_V_DEFAULT;
50
51 StyleContext sc(startPos, length, initStyle, styler);
52
53 for (; sc.More(); sc.Forward()) {
54
55 if (sc.atLineStart && (sc.state == SCE_V_STRING)) {
56 // Prevent SCE_V_STRINGEOL from leaking back to previous line
57 sc.SetState(SCE_V_STRING);
58 }
59
60 // Handle line continuation generically.
61 if (sc.ch == '\\') {
62 if (sc.chNext == '\n' || sc.chNext == '\r') {
63 sc.Forward();
64 if (sc.ch == '\r' && sc.chNext == '\n') {
65 sc.Forward();
66 }
67 continue;
68 }
69 }
70
71 // Determine if the current state should terminate.
72 if (sc.state == SCE_V_OPERATOR) {
73 sc.SetState(SCE_V_DEFAULT);
74 } else if (sc.state == SCE_V_NUMBER) {
75 if (!IsAWordChar(sc.ch)) {
76 sc.SetState(SCE_V_DEFAULT);
77 }
78 } else if (sc.state == SCE_V_IDENTIFIER) {
79 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
80 char s[100];
81 sc.GetCurrent(s, sizeof(s));
82 if (keywords.InList(s)) {
83 sc.ChangeState(SCE_V_WORD);
84 } else if (keywords2.InList(s)) {
85 sc.ChangeState(SCE_V_WORD2);
86 } else if (keywords3.InList(s)) {
87 sc.ChangeState(SCE_V_WORD3);
88 } else if (keywords4.InList(s)) {
89 sc.ChangeState(SCE_V_USER);
90 }
91 sc.SetState(SCE_V_DEFAULT);
92 }
93 } else if (sc.state == SCE_V_PREPROCESSOR) {
94 if (!IsAWordChar(sc.ch)) {
95 sc.SetState(SCE_V_DEFAULT);
96 }
97 } else if (sc.state == SCE_V_COMMENT) {
98 if (sc.Match('*', '/')) {
99 sc.Forward();
100 sc.ForwardSetState(SCE_V_DEFAULT);
101 }
102 } else if (sc.state == SCE_V_COMMENTLINE || sc.state == SCE_V_COMMENTLINEBANG) {
103 if (sc.atLineStart) {
104 sc.SetState(SCE_V_DEFAULT);
105 }
106 } else if (sc.state == SCE_V_STRING) {
107 if (sc.ch == '\\') {
108 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
109 sc.Forward();
110 }
111 } else if (sc.ch == '\"') {
112 sc.ForwardSetState(SCE_V_DEFAULT);
113 } else if (sc.atLineEnd) {
114 sc.ChangeState(SCE_V_STRINGEOL);
115 sc.ForwardSetState(SCE_V_DEFAULT);
116 }
117 }
118
119 // Determine if a new state should be entered.
120 if (sc.state == SCE_V_DEFAULT) {
121 if (IsADigit(sc.ch) || (sc.ch == '\'') || (sc.ch == '.' && IsADigit(sc.chNext))) {
122 sc.SetState(SCE_V_NUMBER);
123 } else if (IsAWordStart(sc.ch)) {
124 sc.SetState(SCE_V_IDENTIFIER);
125 } else if (sc.Match('/', '*')) {
126 sc.SetState(SCE_V_COMMENT);
127 sc.Forward(); // Eat the * so it isn't used for the end of the comment
128 } else if (sc.Match('/', '/')) {
129 if (sc.Match("//!")) // Nice to have a different comment style
130 sc.SetState(SCE_V_COMMENTLINEBANG);
131 else
132 sc.SetState(SCE_V_COMMENTLINE);
133 } else if (sc.ch == '\"') {
134 sc.SetState(SCE_V_STRING);
135 } else if (sc.ch == '`') {
136 sc.SetState(SCE_V_PREPROCESSOR);
137 // Skip whitespace between ` and preprocessor word
138 do {
139 sc.Forward();
140 } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
141 if (sc.atLineEnd) {
142 sc.SetState(SCE_V_DEFAULT);
143 }
144 } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '#') {
145 sc.SetState(SCE_V_OPERATOR);
146 }
147 }
148 }
149 sc.Complete();
150 }
151
152 static bool IsStreamCommentStyle(int style) {
153 return style == SCE_V_COMMENT;
154 }
155
156 static bool IsCommentLine(int line, Accessor &styler) {
157 int pos = styler.LineStart(line);
158 int eolPos = styler.LineStart(line + 1) - 1;
159 for (int i = pos; i < eolPos; i++) {
160 char ch = styler[i];
161 char chNext = styler.SafeGetCharAt(i + 1);
162 int style = styler.StyleAt(i);
163 if (ch == '/' && chNext == '/' &&
164 (style == SCE_V_COMMENTLINE || style == SCE_V_COMMENTLINEBANG)) {
165 return true;
166 } else if (!IsASpaceOrTab(ch)) {
167 return false;
168 }
169 }
170 return false;
171 }
172 // Store both the current line's fold level and the next lines in the
173 // level store to make it easy to pick up with each increment
174 // and to make it possible to fiddle the current level for "} else {".
175 static void FoldNoBoxVerilogDoc(unsigned int startPos, int length, int initStyle,
176 Accessor &styler) {
177 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
178 bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
179 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
180 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
181 // Verilog specific folding options:
182 // fold_at_module -
183 // Generally used methodology in verilog code is
184 // one module per file, so folding at module definition is useless.
185 // fold_at_brace/parenthese -
186 // Folding of long port lists can be convenient.
187 bool foldAtModule = styler.GetPropertyInt("fold.verilog.flags", 0) != 0;
188 bool foldAtBrace = 1;
189 bool foldAtParenthese = 1;
190
191 unsigned int endPos = startPos + length;
192 int visibleChars = 0;
193 int lineCurrent = styler.GetLine(startPos);
194 int levelCurrent = SC_FOLDLEVELBASE;
195 if (lineCurrent > 0)
196 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
197 int levelMinCurrent = levelCurrent;
198 int levelNext = levelCurrent;
199 char chNext = styler[startPos];
200 int styleNext = styler.StyleAt(startPos);
201 int style = initStyle;
202 for (unsigned int i = startPos; i < endPos; i++) {
203 char ch = chNext;
204 chNext = styler.SafeGetCharAt(i + 1);
205 int stylePrev = style;
206 style = styleNext;
207 styleNext = styler.StyleAt(i + 1);
208 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
209 if (foldComment && IsStreamCommentStyle(style)) {
210 if (!IsStreamCommentStyle(stylePrev)) {
211 levelNext++;
212 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
213 // Comments don't end at end of line and the next character may be unstyled.
214 levelNext--;
215 }
216 }
217 if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
218 {
219 if (!IsCommentLine(lineCurrent - 1, styler)
220 && IsCommentLine(lineCurrent + 1, styler))
221 levelNext++;
222 else if (IsCommentLine(lineCurrent - 1, styler)
223 && !IsCommentLine(lineCurrent+1, styler))
224 levelNext--;
225 }
226 if (foldComment && (style == SCE_V_COMMENTLINE)) {
227 if ((ch == '/') && (chNext == '/')) {
228 char chNext2 = styler.SafeGetCharAt(i + 2);
229 if (chNext2 == '{') {
230 levelNext++;
231 } else if (chNext2 == '}') {
232 levelNext--;
233 }
234 }
235 }
236 if (foldPreprocessor && (style == SCE_V_PREPROCESSOR)) {
237 if (ch == '`') {
238 unsigned int j = i + 1;
239 while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
240 j++;
241 }
242 if (styler.Match(j, "if")) {
243 levelNext++;
244 } else if (styler.Match(j, "end")) {
245 levelNext--;
246 }
247 }
248 }
249 if (style == SCE_V_OPERATOR) {
250 if (foldAtParenthese) {
251 if (ch == '(') {
252 levelNext++;
253 } else if (ch == ')') {
254 levelNext--;
255 }
256 }
257 }
258 if (style == SCE_V_OPERATOR) {
259 if (foldAtBrace) {
260 if (ch == '{') {
261 levelNext++;
262 } else if (ch == '}') {
263 levelNext--;
264 }
265 }
266 }
267 if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) {
268 unsigned int j = i;
269 if (styler.Match(j, "case") ||
270 styler.Match(j, "casex") ||
271 styler.Match(j, "casez") ||
272 styler.Match(j, "class") ||
273 styler.Match(j, "function") ||
274 styler.Match(j, "generate") ||
275 styler.Match(j, "covergroup") ||
276 styler.Match(j, "package") ||
277 styler.Match(j, "primitive") ||
278 styler.Match(j, "program") ||
279 styler.Match(j, "sequence") ||
280 styler.Match(j, "specify") ||
281 styler.Match(j, "table") ||
282 styler.Match(j, "task") ||
283 styler.Match(j, "fork") ||
284 (styler.Match(j, "module") && foldAtModule) ||
285 styler.Match(j, "begin")) {
286 levelNext++;
287 } else if (styler.Match(j, "endcase") ||
288 styler.Match(j, "endclass") ||
289 styler.Match(j, "endfunction") ||
290 styler.Match(j, "endgenerate") ||
291 styler.Match(j, "endgroup") ||
292 styler.Match(j, "endpackage") ||
293 styler.Match(j, "endprimitive") ||
294 styler.Match(j, "endprogram") ||
295 styler.Match(j, "endsequence") ||
296 styler.Match(j, "endspecify") ||
297 styler.Match(j, "endtable") ||
298 styler.Match(j, "endtask") ||
299 styler.Match(j, "join") ||
300 styler.Match(j, "join_any") ||
301 styler.Match(j, "join_none") ||
302 (styler.Match(j, "endmodule") && foldAtModule) ||
303 (styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j+3)))) {
304 levelNext--;
305 }
306 }
307 if (atEOL) {
308 int levelUse = levelCurrent;
309 if (foldAtElse) {
310 levelUse = levelMinCurrent;
311 }
312 int lev = levelUse | levelNext << 16;
313 if (visibleChars == 0 && foldCompact)
314 lev |= SC_FOLDLEVELWHITEFLAG;
315 if (levelUse < levelNext)
316 lev |= SC_FOLDLEVELHEADERFLAG;
317 if (lev != styler.LevelAt(lineCurrent)) {
318 styler.SetLevel(lineCurrent, lev);
319 }
320 lineCurrent++;
321 levelCurrent = levelNext;
322 levelMinCurrent = levelCurrent;
323 visibleChars = 0;
324 }
325 if (!isspacechar(ch))
326 visibleChars++;
327 }
328 }
329
330 static void FoldVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *[],
331 Accessor &styler) {
332 FoldNoBoxVerilogDoc(startPos, length, initStyle, styler);
333 }
334
335 static const char * const verilogWordLists[] = {
336 "Primary keywords and identifiers",
337 "Secondary keywords and identifiers",
338 "System Tasks",
339 "User defined tasks and identifiers",
340 "Unused",
341 0,
342 };
343
344
345 LexerModule lmVerilog(SCLEX_VERILOG, ColouriseVerilogDoc, "verilog", FoldVerilogDoc, verilogWordLists);