*** empty log message ***
[anjuta-git-plugin.git] / scintilla / LexVerilog.cxx
blob43ef7eb37dbdb2d144ea22eee46eb4737d1bb902
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 static inline bool IsAWordChar(const int ch) {
25 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
28 static inline bool IsAWordStart(const int ch) {
29 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '$');
32 static void ColouriseVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
33 Accessor &styler) {
35 WordList &keywords = *keywordlists[0];
36 WordList &keywords2 = *keywordlists[1];
37 WordList &keywords3 = *keywordlists[2];
38 WordList &keywords4 = *keywordlists[3];
40 // Do not leak onto next line
41 if (initStyle == SCE_V_STRINGEOL)
42 initStyle = SCE_V_DEFAULT;
44 StyleContext sc(startPos, length, initStyle, styler);
46 for (; sc.More(); sc.Forward()) {
48 if (sc.atLineStart && (sc.state == SCE_V_STRING)) {
49 // Prevent SCE_V_STRINGEOL from leaking back to previous line
50 sc.SetState(SCE_V_STRING);
53 // Handle line continuation generically.
54 if (sc.ch == '\\') {
55 if (sc.chNext == '\n' || sc.chNext == '\r') {
56 sc.Forward();
57 if (sc.ch == '\r' && sc.chNext == '\n') {
58 sc.Forward();
60 continue;
64 // Determine if the current state should terminate.
65 if (sc.state == SCE_V_OPERATOR) {
66 sc.SetState(SCE_V_DEFAULT);
67 } else if (sc.state == SCE_V_NUMBER) {
68 if (!IsAWordChar(sc.ch)) {
69 sc.SetState(SCE_V_DEFAULT);
71 } else if (sc.state == SCE_V_IDENTIFIER) {
72 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
73 char s[100];
74 sc.GetCurrent(s, sizeof(s));
75 if (keywords.InList(s)) {
76 sc.ChangeState(SCE_V_WORD);
77 } else if (keywords2.InList(s)) {
78 sc.ChangeState(SCE_V_WORD2);
79 } else if (keywords3.InList(s)) {
80 sc.ChangeState(SCE_V_WORD3);
81 } else if (keywords4.InList(s)) {
82 sc.ChangeState(SCE_V_USER);
84 sc.SetState(SCE_V_DEFAULT);
86 } else if (sc.state == SCE_V_PREPROCESSOR) {
87 if (!IsAWordChar(sc.ch)) {
88 sc.SetState(SCE_V_DEFAULT);
90 } else if (sc.state == SCE_V_COMMENT) {
91 if (sc.Match('*', '/')) {
92 sc.Forward();
93 sc.ForwardSetState(SCE_V_DEFAULT);
95 } else if (sc.state == SCE_V_COMMENTLINE || sc.state == SCE_V_COMMENTLINEBANG) {
96 if (sc.atLineEnd) {
97 sc.SetState(SCE_V_DEFAULT);
99 } else if (sc.state == SCE_V_STRING) {
100 if (sc.ch == '\\') {
101 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
102 sc.Forward();
104 } else if (sc.ch == '\"') {
105 sc.ForwardSetState(SCE_V_DEFAULT);
106 } else if (sc.atLineEnd) {
107 sc.ChangeState(SCE_V_STRINGEOL);
108 sc.ForwardSetState(SCE_V_DEFAULT);
112 // Determine if a new state should be entered.
113 if (sc.state == SCE_V_DEFAULT) {
114 if (IsADigit(sc.ch) || (sc.ch == '\'') || (sc.ch == '.' && IsADigit(sc.chNext))) {
115 sc.SetState(SCE_V_NUMBER);
116 } else if (IsAWordStart(sc.ch)) {
117 sc.SetState(SCE_V_IDENTIFIER);
118 } else if (sc.Match('/', '*')) {
119 sc.SetState(SCE_V_COMMENT);
120 sc.Forward(); // Eat the * so it isn't used for the end of the comment
121 } else if (sc.Match('/', '/')) {
122 if (sc.Match("//!")) // Nice to have a different comment style
123 sc.SetState(SCE_V_COMMENTLINEBANG);
124 else
125 sc.SetState(SCE_V_COMMENTLINE);
126 } else if (sc.ch == '\"') {
127 sc.SetState(SCE_V_STRING);
128 } else if (sc.ch == '`') {
129 sc.SetState(SCE_V_PREPROCESSOR);
130 // Skip whitespace between ` and preprocessor word
131 do {
132 sc.Forward();
133 } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
134 if (sc.atLineEnd) {
135 sc.SetState(SCE_V_DEFAULT);
137 } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '#') {
138 sc.SetState(SCE_V_OPERATOR);
142 sc.Complete();
145 static bool IsStreamCommentStyle(int style) {
146 return style == SCE_V_COMMENT;
149 // Store both the current line's fold level and the next lines in the
150 // level store to make it easy to pick up with each increment
151 // and to make it possible to fiddle the current level for "} else {".
152 static void FoldNoBoxVerilogDoc(unsigned int startPos, int length, int initStyle,
153 Accessor &styler) {
154 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
155 bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
156 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
157 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
158 // Verilog specific folding options:
159 // fold_at_module -
160 // Generally used methodology in verilog code is
161 // one module per file, so folding at module definition is useless.
162 // fold_at_brace/parenthese -
163 // Folding of long port lists can be convenient.
164 bool foldAtModule = styler.GetPropertyInt("fold.verilog.flags", 0) != 0;
165 bool foldAtBrace = 1;
166 bool foldAtParenthese = 1;
168 unsigned int endPos = startPos + length;
169 int visibleChars = 0;
170 int lineCurrent = styler.GetLine(startPos);
171 int levelCurrent = SC_FOLDLEVELBASE;
172 if (lineCurrent > 0)
173 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
174 int levelMinCurrent = levelCurrent;
175 int levelNext = levelCurrent;
176 char chNext = styler[startPos];
177 int styleNext = styler.StyleAt(startPos);
178 int style = initStyle;
179 for (unsigned int i = startPos; i < endPos; i++) {
180 char ch = chNext;
181 chNext = styler.SafeGetCharAt(i + 1);
182 int stylePrev = style;
183 style = styleNext;
184 styleNext = styler.StyleAt(i + 1);
185 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
186 if (foldComment && IsStreamCommentStyle(style)) {
187 if (!IsStreamCommentStyle(stylePrev)) {
188 levelNext++;
189 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
190 // Comments don't end at end of line and the next character may be unstyled.
191 levelNext--;
194 if (foldComment && (style == SCE_V_COMMENTLINE)) {
195 if ((ch == '/') && (chNext == '/')) {
196 char chNext2 = styler.SafeGetCharAt(i + 2);
197 if (chNext2 == '{') {
198 levelNext++;
199 } else if (chNext2 == '}') {
200 levelNext--;
204 if (foldPreprocessor && (style == SCE_V_PREPROCESSOR)) {
205 if (ch == '`') {
206 unsigned int j = i + 1;
207 while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
208 j++;
210 if (styler.Match(j, "if")) {
211 levelNext++;
212 } else if (styler.Match(j, "end")) {
213 levelNext--;
217 if (style == SCE_V_OPERATOR) {
218 if (foldAtParenthese) {
219 if (ch == '(') {
220 levelNext++;
221 } else if (ch == ')') {
222 levelNext--;
226 if (style == SCE_V_OPERATOR) {
227 if (foldAtBrace) {
228 if (ch == '{') {
229 levelNext++;
230 } else if (ch == '}') {
231 levelNext--;
235 if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) {
236 unsigned int j = i;
237 if (styler.Match(j, "case") ||
238 styler.Match(j, "casex") ||
239 styler.Match(j, "casez") ||
240 styler.Match(j, "function") ||
241 styler.Match(j, "fork") ||
242 styler.Match(j, "table") ||
243 styler.Match(j, "task") ||
244 styler.Match(j, "specify") ||
245 styler.Match(j, "primitive") ||
246 styler.Match(j, "module") && foldAtModule ||
247 styler.Match(j, "begin")) {
248 levelNext++;
249 } else if (styler.Match(j, "endcase") ||
250 styler.Match(j, "endfunction") ||
251 styler.Match(j, "join") ||
252 styler.Match(j, "endtask") ||
253 styler.Match(j, "endtable") ||
254 styler.Match(j, "endspecify") ||
255 styler.Match(j, "endprimitive") ||
256 styler.Match(j, "endmodule") && foldAtModule ||
257 styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j+3))) {
258 levelNext--;
261 if (atEOL) {
262 int levelUse = levelCurrent;
263 if (foldAtElse) {
264 levelUse = levelMinCurrent;
266 int lev = levelUse | levelNext << 16;
267 if (visibleChars == 0 && foldCompact)
268 lev |= SC_FOLDLEVELWHITEFLAG;
269 if (levelUse < levelNext)
270 lev |= SC_FOLDLEVELHEADERFLAG;
271 if (lev != styler.LevelAt(lineCurrent)) {
272 styler.SetLevel(lineCurrent, lev);
274 lineCurrent++;
275 levelCurrent = levelNext;
276 levelMinCurrent = levelCurrent;
277 visibleChars = 0;
279 if (!isspacechar(ch))
280 visibleChars++;
284 static void FoldVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *[],
285 Accessor &styler) {
286 FoldNoBoxVerilogDoc(startPos, length, initStyle, styler);
289 static const char * const verilogWordLists[] = {
290 "Primary keywords and identifiers",
291 "Secondary keywords and identifiers",
292 "System Tasks",
293 "User defined tasks and identifiers",
294 "Unused",
299 LexerModule lmVerilog(SCLEX_VERILOG, ColouriseVerilogDoc, "verilog", FoldVerilogDoc, verilogWordLists);