1 // Scintilla source code edit control
2 /** @file LexSpecman.cxx
3  ** Lexer for Specman E language.
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 using namespace Scintilla;
28 
IsAWordChar(const int ch)29 static inline bool IsAWordChar(const int ch) {
30 	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
31 }
32 
IsANumberChar(const int ch)33 static inline bool IsANumberChar(const int ch) {
34 	return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '\'');
35 }
36 
IsAWordStart(const int ch)37 static inline bool IsAWordStart(const int ch) {
38 	return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '`');
39 }
40 
ColouriseSpecmanDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler,bool caseSensitive)41 static void ColouriseSpecmanDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
42                             Accessor &styler, bool caseSensitive) {
43 
44 	WordList &keywords = *keywordlists[0];
45 	WordList &keywords2 = *keywordlists[1];
46 	WordList &keywords3 = *keywordlists[2];
47 	WordList &keywords4 = *keywordlists[3];
48 
49 	// Do not leak onto next line
50 	if (initStyle == SCE_SN_STRINGEOL)
51 		initStyle = SCE_SN_CODE;
52 
53 	int visibleChars = 0;
54 
55 	StyleContext sc(startPos, length, initStyle, styler);
56 
57 	for (; sc.More(); sc.Forward()) {
58 
59 		if (sc.atLineStart && (sc.state == SCE_SN_STRING)) {
60 			// Prevent SCE_SN_STRINGEOL from leaking back to previous line
61 			sc.SetState(SCE_SN_STRING);
62 		}
63 
64 		// Handle line continuation generically.
65 		if (sc.ch == '\\') {
66 			if (sc.chNext == '\n' || sc.chNext == '\r') {
67 				sc.Forward();
68 				if (sc.ch == '\r' && sc.chNext == '\n') {
69 					sc.Forward();
70 				}
71 				continue;
72 			}
73 		}
74 
75 		// Determine if the current state should terminate.
76 		if (sc.state == SCE_SN_OPERATOR) {
77 			sc.SetState(SCE_SN_CODE);
78 		} else if (sc.state == SCE_SN_NUMBER) {
79 			if (!IsANumberChar(sc.ch)) {
80 				sc.SetState(SCE_SN_CODE);
81 			}
82 		} else if (sc.state == SCE_SN_IDENTIFIER) {
83 			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
84 				char s[100];
85 				if (caseSensitive) {
86 					sc.GetCurrent(s, sizeof(s));
87 				} else {
88 					sc.GetCurrentLowered(s, sizeof(s));
89 				}
90 				if (keywords.InList(s)) {
91 					sc.ChangeState(SCE_SN_WORD);
92 				} else if (keywords2.InList(s)) {
93 					sc.ChangeState(SCE_SN_WORD2);
94 				} else if (keywords3.InList(s)) {
95                                         sc.ChangeState(SCE_SN_WORD3);
96 				} else if (keywords4.InList(s)) {
97 					sc.ChangeState(SCE_SN_USER);
98 				}
99 				sc.SetState(SCE_SN_CODE);
100 			}
101 		} else if (sc.state == SCE_SN_PREPROCESSOR) {
102                         if (IsASpace(sc.ch)) {
103                                 sc.SetState(SCE_SN_CODE);
104                         }
105 		} else if (sc.state == SCE_SN_DEFAULT) {
106 			if (sc.Match('<', '\'')) {
107 				sc.Forward();
108 				sc.ForwardSetState(SCE_SN_CODE);
109 			}
110 		} else if (sc.state == SCE_SN_COMMENTLINE || sc.state == SCE_SN_COMMENTLINEBANG) {
111 			if (sc.atLineEnd) {
112 				sc.SetState(SCE_SN_CODE);
113 				visibleChars = 0;
114 			}
115 		} else if (sc.state == SCE_SN_STRING) {
116 			if (sc.ch == '\\') {
117 				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
118 					sc.Forward();
119 				}
120 			} else if (sc.ch == '\"') {
121 				sc.ForwardSetState(SCE_SN_CODE);
122 			} else if (sc.atLineEnd) {
123 				sc.ChangeState(SCE_SN_STRINGEOL);
124 				sc.ForwardSetState(SCE_SN_CODE);
125 				visibleChars = 0;
126 			}
127 		} else if (sc.state == SCE_SN_SIGNAL) {
128 			if (sc.atLineEnd) {
129 				sc.ChangeState(SCE_SN_STRINGEOL);
130 				sc.ForwardSetState(SCE_SN_CODE);
131 				visibleChars = 0;
132 			} else if (sc.ch == '\\') {
133 				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
134 					sc.Forward();
135 				}
136 			} else if (sc.ch == '\'') {
137 				sc.ForwardSetState(SCE_SN_CODE);
138 			}
139 		} else if (sc.state == SCE_SN_REGEXTAG) {
140 			if (!IsADigit(sc.ch)) {
141 				sc.SetState(SCE_SN_CODE);
142 			}
143 		}
144 
145 		// Determine if a new state should be entered.
146 		if (sc.state == SCE_SN_CODE) {
147 			if (sc.ch == '$' && IsADigit(sc.chNext)) {
148 				sc.SetState(SCE_SN_REGEXTAG);
149                                 sc.Forward();
150 			} else if (IsADigit(sc.ch)) {
151                                 sc.SetState(SCE_SN_NUMBER);
152 			} else if (IsAWordStart(sc.ch)) {
153 				sc.SetState(SCE_SN_IDENTIFIER);
154 			} else if (sc.Match('\'', '>')) {
155                                 sc.SetState(SCE_SN_DEFAULT);
156 				sc.Forward();	// Eat the * so it isn't used for the end of the comment
157 			} else if (sc.Match('/', '/')) {
158 				if (sc.Match("//!"))	// Nice to have a different comment style
159 					sc.SetState(SCE_SN_COMMENTLINEBANG);
160 				else
161 					sc.SetState(SCE_SN_COMMENTLINE);
162 			} else if (sc.Match('-', '-')) {
163 				if (sc.Match("--!"))	// Nice to have a different comment style
164 					sc.SetState(SCE_SN_COMMENTLINEBANG);
165 				else
166 					sc.SetState(SCE_SN_COMMENTLINE);
167 			} else if (sc.ch == '\"') {
168 				sc.SetState(SCE_SN_STRING);
169 			} else if (sc.ch == '\'') {
170 				sc.SetState(SCE_SN_SIGNAL);
171 			} else if (sc.ch == '#' && visibleChars == 0) {
172 				// Preprocessor commands are alone on their line
173 				sc.SetState(SCE_SN_PREPROCESSOR);
174 				// Skip whitespace between # and preprocessor word
175 				do {
176 					sc.Forward();
177 				} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
178 				if (sc.atLineEnd) {
179 					sc.SetState(SCE_SN_CODE);
180 				}
181 			} else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@') {
182 				sc.SetState(SCE_SN_OPERATOR);
183 			}
184 		}
185 
186 		if (sc.atLineEnd) {
187 			// Reset states to begining of colourise so no surprises
188 			// if different sets of lines lexed.
189 			visibleChars = 0;
190 		}
191 		if (!IsASpace(sc.ch)) {
192 			visibleChars++;
193 		}
194 	}
195 	sc.Complete();
196 }
197 
198 // Store both the current line's fold level and the next lines in the
199 // level store to make it easy to pick up with each increment
200 // and to make it possible to fiddle the current level for "} else {".
FoldNoBoxSpecmanDoc(Sci_PositionU startPos,Sci_Position length,int,Accessor & styler)201 static void FoldNoBoxSpecmanDoc(Sci_PositionU startPos, Sci_Position length, int,
202                             Accessor &styler) {
203 	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
204 	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
205 	bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
206 	Sci_PositionU endPos = startPos + length;
207 	int visibleChars = 0;
208 	Sci_Position lineCurrent = styler.GetLine(startPos);
209 	int levelCurrent = SC_FOLDLEVELBASE;
210 	if (lineCurrent > 0)
211 		levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
212 	int levelMinCurrent = levelCurrent;
213 	int levelNext = levelCurrent;
214 	char chNext = styler[startPos];
215 	int styleNext = styler.StyleAt(startPos);
216 	int style;
217 	for (Sci_PositionU i = startPos; i < endPos; i++) {
218 		char ch = chNext;
219 		chNext = styler.SafeGetCharAt(i + 1);
220 		//int stylePrev = style;
221 		style = styleNext;
222 		styleNext = styler.StyleAt(i + 1);
223 		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
224 		if (foldComment && (style == SCE_SN_COMMENTLINE)) {
225 			if (((ch == '/') && (chNext == '/')) ||
226                             ((ch == '-') && (chNext == '-'))) {
227 				char chNext2 = styler.SafeGetCharAt(i + 2);
228 				if (chNext2 == '{') {
229 					levelNext++;
230 				} else if (chNext2 == '}') {
231 					levelNext--;
232 				}
233 			}
234 		}
235 		if (style == SCE_SN_OPERATOR) {
236 			if (ch == '{') {
237 				// Measure the minimum before a '{' to allow
238 				// folding on "} else {"
239 				if (levelMinCurrent > levelNext) {
240 					levelMinCurrent = levelNext;
241 				}
242 				levelNext++;
243 			} else if (ch == '}') {
244 				levelNext--;
245 			}
246 		}
247 		if (atEOL) {
248 			int levelUse = levelCurrent;
249 			if (foldAtElse) {
250 				levelUse = levelMinCurrent;
251 			}
252 			int lev = levelUse | levelNext << 16;
253 			if (visibleChars == 0 && foldCompact)
254 				lev |= SC_FOLDLEVELWHITEFLAG;
255 			if (levelUse < levelNext)
256 				lev |= SC_FOLDLEVELHEADERFLAG;
257 			if (lev != styler.LevelAt(lineCurrent)) {
258 				styler.SetLevel(lineCurrent, lev);
259 			}
260 			lineCurrent++;
261 			levelCurrent = levelNext;
262 			levelMinCurrent = levelCurrent;
263 			visibleChars = 0;
264 		}
265 		if (!isspacechar(ch))
266 			visibleChars++;
267 	}
268 }
269 
FoldSpecmanDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)270 static void FoldSpecmanDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[],
271                        Accessor &styler) {
272 	FoldNoBoxSpecmanDoc(startPos, length, initStyle, styler);
273 }
274 
275 static const char * const specmanWordLists[] = {
276             "Primary keywords and identifiers",
277             "Secondary keywords and identifiers",
278             "Sequence keywords and identifiers",
279             "User defined keywords and identifiers",
280             "Unused",
281             0,
282         };
283 
ColouriseSpecmanDocSensitive(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)284 static void ColouriseSpecmanDocSensitive(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
285                                      Accessor &styler) {
286 	ColouriseSpecmanDoc(startPos, length, initStyle, keywordlists, styler, true);
287 }
288 
289 
290 LexerModule lmSpecman(SCLEX_SPECMAN, ColouriseSpecmanDocSensitive, "specman", FoldSpecmanDoc, specmanWordLists);
291