Set release date.
[geany-mirror.git] / scintilla / LexVerilog.cxx
blob8b531bb7e3688ec8fc8c6c80293a16115bf67a10
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.
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
15 #include "Platform.h"
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "StyleContext.h"
20 #include "KeyWords.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
24 #ifdef SCI_NAMESPACE
25 using namespace Scintilla;
26 #endif
28 static inline bool IsAWordChar(const int ch) {
29 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
32 static inline bool IsAWordStart(const int ch) {
33 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '$');
36 static void ColouriseVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
37 Accessor &styler) {
39 WordList &keywords = *keywordlists[0];
40 WordList &keywords2 = *keywordlists[1];
41 WordList &keywords3 = *keywordlists[2];
42 WordList &keywords4 = *keywordlists[3];
44 // Do not leak onto next line
45 if (initStyle == SCE_V_STRINGEOL)
46 initStyle = SCE_V_DEFAULT;
48 StyleContext sc(startPos, length, initStyle, styler);
50 for (; sc.More(); sc.Forward()) {
52 if (sc.atLineStart && (sc.state == SCE_V_STRING)) {
53 // Prevent SCE_V_STRINGEOL from leaking back to previous line
54 sc.SetState(SCE_V_STRING);
57 // Handle line continuation generically.
58 if (sc.ch == '\\') {
59 if (sc.chNext == '\n' || sc.chNext == '\r') {
60 sc.Forward();
61 if (sc.ch == '\r' && sc.chNext == '\n') {
62 sc.Forward();
64 continue;
68 // Determine if the current state should terminate.
69 if (sc.state == SCE_V_OPERATOR) {
70 sc.SetState(SCE_V_DEFAULT);
71 } else if (sc.state == SCE_V_NUMBER) {
72 if (!IsAWordChar(sc.ch)) {
73 sc.SetState(SCE_V_DEFAULT);
75 } else if (sc.state == SCE_V_IDENTIFIER) {
76 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
77 char s[100];
78 sc.GetCurrent(s, sizeof(s));
79 if (keywords.InList(s)) {
80 sc.ChangeState(SCE_V_WORD);
81 } else if (keywords2.InList(s)) {
82 sc.ChangeState(SCE_V_WORD2);
83 } else if (keywords3.InList(s)) {
84 sc.ChangeState(SCE_V_WORD3);
85 } else if (keywords4.InList(s)) {
86 sc.ChangeState(SCE_V_USER);
88 sc.SetState(SCE_V_DEFAULT);
90 } else if (sc.state == SCE_V_PREPROCESSOR) {
91 if (!IsAWordChar(sc.ch)) {
92 sc.SetState(SCE_V_DEFAULT);
94 } else if (sc.state == SCE_V_COMMENT) {
95 if (sc.Match('*', '/')) {
96 sc.Forward();
97 sc.ForwardSetState(SCE_V_DEFAULT);
99 } else if (sc.state == SCE_V_COMMENTLINE || sc.state == SCE_V_COMMENTLINEBANG) {
100 if (sc.atLineStart) {
101 sc.SetState(SCE_V_DEFAULT);
103 } else if (sc.state == SCE_V_STRING) {
104 if (sc.ch == '\\') {
105 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
106 sc.Forward();
108 } else if (sc.ch == '\"') {
109 sc.ForwardSetState(SCE_V_DEFAULT);
110 } else if (sc.atLineEnd) {
111 sc.ChangeState(SCE_V_STRINGEOL);
112 sc.ForwardSetState(SCE_V_DEFAULT);
116 // Determine if a new state should be entered.
117 if (sc.state == SCE_V_DEFAULT) {
118 if (IsADigit(sc.ch) || (sc.ch == '\'') || (sc.ch == '.' && IsADigit(sc.chNext))) {
119 sc.SetState(SCE_V_NUMBER);
120 } else if (IsAWordStart(sc.ch)) {
121 sc.SetState(SCE_V_IDENTIFIER);
122 } else if (sc.Match('/', '*')) {
123 sc.SetState(SCE_V_COMMENT);
124 sc.Forward(); // Eat the * so it isn't used for the end of the comment
125 } else if (sc.Match('/', '/')) {
126 if (sc.Match("//!")) // Nice to have a different comment style
127 sc.SetState(SCE_V_COMMENTLINEBANG);
128 else
129 sc.SetState(SCE_V_COMMENTLINE);
130 } else if (sc.ch == '\"') {
131 sc.SetState(SCE_V_STRING);
132 } else if (sc.ch == '`') {
133 sc.SetState(SCE_V_PREPROCESSOR);
134 // Skip whitespace between ` and preprocessor word
135 do {
136 sc.Forward();
137 } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
138 if (sc.atLineEnd) {
139 sc.SetState(SCE_V_DEFAULT);
141 } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '#') {
142 sc.SetState(SCE_V_OPERATOR);
146 sc.Complete();
149 static bool IsStreamCommentStyle(int style) {
150 return style == SCE_V_COMMENT;
153 static bool IsCommentLine(int line, Accessor &styler) {
154 int pos = styler.LineStart(line);
155 int eolPos = styler.LineStart(line + 1) - 1;
156 for (int i = pos; i < eolPos; i++) {
157 char ch = styler[i];
158 char chNext = styler.SafeGetCharAt(i + 1);
159 int style = styler.StyleAt(i);
160 if (ch == '/' && chNext == '/' &&
161 (style == SCE_V_COMMENTLINE || style == SCE_V_COMMENTLINEBANG)) {
162 return true;
163 } else if (!IsASpaceOrTab(ch)) {
164 return false;
167 return false;
169 // Store both the current line's fold level and the next lines in the
170 // level store to make it easy to pick up with each increment
171 // and to make it possible to fiddle the current level for "} else {".
172 static void FoldNoBoxVerilogDoc(unsigned int startPos, int length, int initStyle,
173 Accessor &styler) {
174 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
175 bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
176 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
177 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
178 // Verilog specific folding options:
179 // fold_at_module -
180 // Generally used methodology in verilog code is
181 // one module per file, so folding at module definition is useless.
182 // fold_at_brace/parenthese -
183 // Folding of long port lists can be convenient.
184 bool foldAtModule = styler.GetPropertyInt("fold.verilog.flags", 0) != 0;
185 bool foldAtBrace = 1;
186 bool foldAtParenthese = 1;
188 unsigned int endPos = startPos + length;
189 int visibleChars = 0;
190 int lineCurrent = styler.GetLine(startPos);
191 int levelCurrent = SC_FOLDLEVELBASE;
192 if (lineCurrent > 0)
193 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
194 int levelMinCurrent = levelCurrent;
195 int levelNext = levelCurrent;
196 char chNext = styler[startPos];
197 int styleNext = styler.StyleAt(startPos);
198 int style = initStyle;
199 for (unsigned int i = startPos; i < endPos; i++) {
200 char ch = chNext;
201 chNext = styler.SafeGetCharAt(i + 1);
202 int stylePrev = style;
203 style = styleNext;
204 styleNext = styler.StyleAt(i + 1);
205 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
206 if (foldComment && IsStreamCommentStyle(style)) {
207 if (!IsStreamCommentStyle(stylePrev)) {
208 levelNext++;
209 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
210 // Comments don't end at end of line and the next character may be unstyled.
211 levelNext--;
214 if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
216 if (!IsCommentLine(lineCurrent - 1, styler)
217 && IsCommentLine(lineCurrent + 1, styler))
218 levelNext++;
219 else if (IsCommentLine(lineCurrent - 1, styler)
220 && !IsCommentLine(lineCurrent+1, styler))
221 levelNext--;
223 if (foldComment && (style == SCE_V_COMMENTLINE)) {
224 if ((ch == '/') && (chNext == '/')) {
225 char chNext2 = styler.SafeGetCharAt(i + 2);
226 if (chNext2 == '{') {
227 levelNext++;
228 } else if (chNext2 == '}') {
229 levelNext--;
233 if (foldPreprocessor && (style == SCE_V_PREPROCESSOR)) {
234 if (ch == '`') {
235 unsigned int j = i + 1;
236 while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
237 j++;
239 if (styler.Match(j, "if")) {
240 levelNext++;
241 } else if (styler.Match(j, "end")) {
242 levelNext--;
246 if (style == SCE_V_OPERATOR) {
247 if (foldAtParenthese) {
248 if (ch == '(') {
249 levelNext++;
250 } else if (ch == ')') {
251 levelNext--;
255 if (style == SCE_V_OPERATOR) {
256 if (foldAtBrace) {
257 if (ch == '{') {
258 levelNext++;
259 } else if (ch == '}') {
260 levelNext--;
264 if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) {
265 unsigned int j = i;
266 if (styler.Match(j, "case") ||
267 styler.Match(j, "casex") ||
268 styler.Match(j, "casez") ||
269 styler.Match(j, "function") ||
270 styler.Match(j, "fork") ||
271 styler.Match(j, "table") ||
272 styler.Match(j, "task") ||
273 styler.Match(j, "generate") ||
274 styler.Match(j, "specify") ||
275 styler.Match(j, "primitive") ||
276 (styler.Match(j, "module") && foldAtModule) ||
277 styler.Match(j, "begin")) {
278 levelNext++;
279 } else if (styler.Match(j, "endcase") ||
280 styler.Match(j, "endfunction") ||
281 styler.Match(j, "join") ||
282 styler.Match(j, "endtask") ||
283 styler.Match(j, "endgenerate") ||
284 styler.Match(j, "endtable") ||
285 styler.Match(j, "endspecify") ||
286 styler.Match(j, "endprimitive") ||
287 (styler.Match(j, "endmodule") && foldAtModule) ||
288 (styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j+3)))) {
289 levelNext--;
292 if (atEOL) {
293 int levelUse = levelCurrent;
294 if (foldAtElse) {
295 levelUse = levelMinCurrent;
297 int lev = levelUse | levelNext << 16;
298 if (visibleChars == 0 && foldCompact)
299 lev |= SC_FOLDLEVELWHITEFLAG;
300 if (levelUse < levelNext)
301 lev |= SC_FOLDLEVELHEADERFLAG;
302 if (lev != styler.LevelAt(lineCurrent)) {
303 styler.SetLevel(lineCurrent, lev);
305 lineCurrent++;
306 levelCurrent = levelNext;
307 levelMinCurrent = levelCurrent;
308 visibleChars = 0;
310 if (!isspacechar(ch))
311 visibleChars++;
315 static void FoldVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *[],
316 Accessor &styler) {
317 FoldNoBoxVerilogDoc(startPos, length, initStyle, styler);
320 static const char * const verilogWordLists[] = {
321 "Primary keywords and identifiers",
322 "Secondary keywords and identifiers",
323 "System Tasks",
324 "User defined tasks and identifiers",
325 "Unused",
330 LexerModule lmVerilog(SCLEX_VERILOG, ColouriseVerilogDoc, "verilog", FoldVerilogDoc, verilogWordLists);