Only replace template filename matching start of word on saving.
[geany-mirror.git] / scintilla / LexVerilog.cxx
blob3fd0fc35c6a78d45c38e0f0d5d09b10a27b1dcd6
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 // Store both the current line's fold level and the next lines in the
154 // level store to make it easy to pick up with each increment
155 // and to make it possible to fiddle the current level for "} else {".
156 static void FoldNoBoxVerilogDoc(unsigned int startPos, int length, int initStyle,
157 Accessor &styler) {
158 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
159 bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
160 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
161 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
162 // Verilog specific folding options:
163 // fold_at_module -
164 // Generally used methodology in verilog code is
165 // one module per file, so folding at module definition is useless.
166 // fold_at_brace/parenthese -
167 // Folding of long port lists can be convenient.
168 bool foldAtModule = styler.GetPropertyInt("fold.verilog.flags", 0) != 0;
169 bool foldAtBrace = 1;
170 bool foldAtParenthese = 1;
172 unsigned int endPos = startPos + length;
173 int visibleChars = 0;
174 int lineCurrent = styler.GetLine(startPos);
175 int levelCurrent = SC_FOLDLEVELBASE;
176 if (lineCurrent > 0)
177 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
178 int levelMinCurrent = levelCurrent;
179 int levelNext = levelCurrent;
180 char chNext = styler[startPos];
181 int styleNext = styler.StyleAt(startPos);
182 int style = initStyle;
183 for (unsigned int i = startPos; i < endPos; i++) {
184 char ch = chNext;
185 chNext = styler.SafeGetCharAt(i + 1);
186 int stylePrev = style;
187 style = styleNext;
188 styleNext = styler.StyleAt(i + 1);
189 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
190 if (foldComment && IsStreamCommentStyle(style)) {
191 if (!IsStreamCommentStyle(stylePrev)) {
192 levelNext++;
193 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
194 // Comments don't end at end of line and the next character may be unstyled.
195 levelNext--;
198 if (foldComment && (style == SCE_V_COMMENTLINE)) {
199 if ((ch == '/') && (chNext == '/')) {
200 char chNext2 = styler.SafeGetCharAt(i + 2);
201 if (chNext2 == '{') {
202 levelNext++;
203 } else if (chNext2 == '}') {
204 levelNext--;
208 if (foldPreprocessor && (style == SCE_V_PREPROCESSOR)) {
209 if (ch == '`') {
210 unsigned int j = i + 1;
211 while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
212 j++;
214 if (styler.Match(j, "if")) {
215 levelNext++;
216 } else if (styler.Match(j, "end")) {
217 levelNext--;
221 if (style == SCE_V_OPERATOR) {
222 if (foldAtParenthese) {
223 if (ch == '(') {
224 levelNext++;
225 } else if (ch == ')') {
226 levelNext--;
230 if (style == SCE_V_OPERATOR) {
231 if (foldAtBrace) {
232 if (ch == '{') {
233 levelNext++;
234 } else if (ch == '}') {
235 levelNext--;
239 if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) {
240 unsigned int j = i;
241 if (styler.Match(j, "case") ||
242 styler.Match(j, "casex") ||
243 styler.Match(j, "casez") ||
244 styler.Match(j, "function") ||
245 styler.Match(j, "fork") ||
246 styler.Match(j, "table") ||
247 styler.Match(j, "task") ||
248 styler.Match(j, "generate") ||
249 styler.Match(j, "specify") ||
250 styler.Match(j, "primitive") ||
251 (styler.Match(j, "module") && foldAtModule) ||
252 styler.Match(j, "begin")) {
253 levelNext++;
254 } else if (styler.Match(j, "endcase") ||
255 styler.Match(j, "endfunction") ||
256 styler.Match(j, "join") ||
257 styler.Match(j, "endtask") ||
258 styler.Match(j, "endgenerate") ||
259 styler.Match(j, "endtable") ||
260 styler.Match(j, "endspecify") ||
261 styler.Match(j, "endprimitive") ||
262 (styler.Match(j, "endmodule") && foldAtModule) ||
263 (styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j+3)))) {
264 levelNext--;
267 if (atEOL) {
268 int levelUse = levelCurrent;
269 if (foldAtElse) {
270 levelUse = levelMinCurrent;
272 int lev = levelUse | levelNext << 16;
273 if (visibleChars == 0 && foldCompact)
274 lev |= SC_FOLDLEVELWHITEFLAG;
275 if (levelUse < levelNext)
276 lev |= SC_FOLDLEVELHEADERFLAG;
277 if (lev != styler.LevelAt(lineCurrent)) {
278 styler.SetLevel(lineCurrent, lev);
280 lineCurrent++;
281 levelCurrent = levelNext;
282 levelMinCurrent = levelCurrent;
283 visibleChars = 0;
285 if (!isspacechar(ch))
286 visibleChars++;
290 static void FoldVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *[],
291 Accessor &styler) {
292 FoldNoBoxVerilogDoc(startPos, length, initStyle, styler);
295 static const char * const verilogWordLists[] = {
296 "Primary keywords and identifiers",
297 "Secondary keywords and identifiers",
298 "System Tasks",
299 "User defined tasks and identifiers",
300 "Unused",
305 LexerModule lmVerilog(SCLEX_VERILOG, ColouriseVerilogDoc, "verilog", FoldVerilogDoc, verilogWordLists);