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
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.
17 #include "Scintilla.h"
21 #include "LexAccessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
28 using namespace Scintilla
;
31 static inline bool IsAWordChar(const int ch
) {
32 return (ch
< 0x80) && (isalnum(ch
) || ch
== '.' || ch
== '_' || ch
== '\'');
35 static inline bool IsANumberChar(const int ch
) {
36 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_' || ch
== '\'');
39 static inline bool IsAWordStart(const int ch
) {
40 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_' || ch
== '`');
43 static void ColouriseSpecmanDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
44 Accessor
&styler
, bool caseSensitive
) {
46 WordList
&keywords
= *keywordlists
[0];
47 WordList
&keywords2
= *keywordlists
[1];
48 WordList
&keywords3
= *keywordlists
[2];
49 WordList
&keywords4
= *keywordlists
[3];
51 // Do not leak onto next line
52 if (initStyle
== SCE_SN_STRINGEOL
)
53 initStyle
= SCE_SN_CODE
;
57 StyleContext
sc(startPos
, length
, initStyle
, styler
);
59 for (; sc
.More(); sc
.Forward()) {
61 if (sc
.atLineStart
&& (sc
.state
== SCE_SN_STRING
)) {
62 // Prevent SCE_SN_STRINGEOL from leaking back to previous line
63 sc
.SetState(SCE_SN_STRING
);
66 // Handle line continuation generically.
68 if (sc
.chNext
== '\n' || sc
.chNext
== '\r') {
70 if (sc
.ch
== '\r' && sc
.chNext
== '\n') {
77 // Determine if the current state should terminate.
78 if (sc
.state
== SCE_SN_OPERATOR
) {
79 sc
.SetState(SCE_SN_CODE
);
80 } else if (sc
.state
== SCE_SN_NUMBER
) {
81 if (!IsANumberChar(sc
.ch
)) {
82 sc
.SetState(SCE_SN_CODE
);
84 } else if (sc
.state
== SCE_SN_IDENTIFIER
) {
85 if (!IsAWordChar(sc
.ch
) || (sc
.ch
== '.')) {
88 sc
.GetCurrent(s
, sizeof(s
));
90 sc
.GetCurrentLowered(s
, sizeof(s
));
92 if (keywords
.InList(s
)) {
93 sc
.ChangeState(SCE_SN_WORD
);
94 } else if (keywords2
.InList(s
)) {
95 sc
.ChangeState(SCE_SN_WORD2
);
96 } else if (keywords3
.InList(s
)) {
97 sc
.ChangeState(SCE_SN_WORD3
);
98 } else if (keywords4
.InList(s
)) {
99 sc
.ChangeState(SCE_SN_USER
);
101 sc
.SetState(SCE_SN_CODE
);
103 } else if (sc
.state
== SCE_SN_PREPROCESSOR
) {
104 if (IsASpace(sc
.ch
)) {
105 sc
.SetState(SCE_SN_CODE
);
107 } else if (sc
.state
== SCE_SN_DEFAULT
) {
108 if (sc
.Match('<', '\'')) {
110 sc
.ForwardSetState(SCE_SN_CODE
);
112 } else if (sc
.state
== SCE_SN_COMMENTLINE
|| sc
.state
== SCE_SN_COMMENTLINEBANG
) {
114 sc
.SetState(SCE_SN_CODE
);
117 } else if (sc
.state
== SCE_SN_STRING
) {
119 if (sc
.chNext
== '\"' || sc
.chNext
== '\'' || sc
.chNext
== '\\') {
122 } else if (sc
.ch
== '\"') {
123 sc
.ForwardSetState(SCE_SN_CODE
);
124 } else if (sc
.atLineEnd
) {
125 sc
.ChangeState(SCE_SN_STRINGEOL
);
126 sc
.ForwardSetState(SCE_SN_CODE
);
129 } else if (sc
.state
== SCE_SN_SIGNAL
) {
131 sc
.ChangeState(SCE_SN_STRINGEOL
);
132 sc
.ForwardSetState(SCE_SN_CODE
);
134 } else if (sc
.ch
== '\\') {
135 if (sc
.chNext
== '\"' || sc
.chNext
== '\'' || sc
.chNext
== '\\') {
138 } else if (sc
.ch
== '\'') {
139 sc
.ForwardSetState(SCE_SN_CODE
);
141 } else if (sc
.state
== SCE_SN_REGEXTAG
) {
142 if (!IsADigit(sc
.ch
)) {
143 sc
.SetState(SCE_SN_CODE
);
147 // Determine if a new state should be entered.
148 if (sc
.state
== SCE_SN_CODE
) {
149 if (sc
.ch
== '$' && IsADigit(sc
.chNext
)) {
150 sc
.SetState(SCE_SN_REGEXTAG
);
152 } else if (IsADigit(sc
.ch
)) {
153 sc
.SetState(SCE_SN_NUMBER
);
154 } else if (IsAWordStart(sc
.ch
)) {
155 sc
.SetState(SCE_SN_IDENTIFIER
);
156 } else if (sc
.Match('\'', '>')) {
157 sc
.SetState(SCE_SN_DEFAULT
);
158 sc
.Forward(); // Eat the * so it isn't used for the end of the comment
159 } else if (sc
.Match('/', '/')) {
160 if (sc
.Match("//!")) // Nice to have a different comment style
161 sc
.SetState(SCE_SN_COMMENTLINEBANG
);
163 sc
.SetState(SCE_SN_COMMENTLINE
);
164 } else if (sc
.Match('-', '-')) {
165 if (sc
.Match("--!")) // Nice to have a different comment style
166 sc
.SetState(SCE_SN_COMMENTLINEBANG
);
168 sc
.SetState(SCE_SN_COMMENTLINE
);
169 } else if (sc
.ch
== '\"') {
170 sc
.SetState(SCE_SN_STRING
);
171 } else if (sc
.ch
== '\'') {
172 sc
.SetState(SCE_SN_SIGNAL
);
173 } else if (sc
.ch
== '#' && visibleChars
== 0) {
174 // Preprocessor commands are alone on their line
175 sc
.SetState(SCE_SN_PREPROCESSOR
);
176 // Skip whitespace between # and preprocessor word
179 } while ((sc
.ch
== ' ' || sc
.ch
== '\t') && sc
.More());
181 sc
.SetState(SCE_SN_CODE
);
183 } else if (isoperator(static_cast<char>(sc
.ch
)) || sc
.ch
== '@') {
184 sc
.SetState(SCE_SN_OPERATOR
);
189 // Reset states to begining of colourise so no surprises
190 // if different sets of lines lexed.
193 if (!IsASpace(sc
.ch
)) {
200 // Store both the current line's fold level and the next lines in the
201 // level store to make it easy to pick up with each increment
202 // and to make it possible to fiddle the current level for "} else {".
203 static void FoldNoBoxSpecmanDoc(unsigned int startPos
, int length
, int,
205 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
206 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
207 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 0) != 0;
208 unsigned int endPos
= startPos
+ length
;
209 int visibleChars
= 0;
210 int lineCurrent
= styler
.GetLine(startPos
);
211 int levelCurrent
= SC_FOLDLEVELBASE
;
213 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
214 int levelMinCurrent
= levelCurrent
;
215 int levelNext
= levelCurrent
;
216 char chNext
= styler
[startPos
];
217 int styleNext
= styler
.StyleAt(startPos
);
219 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
221 chNext
= styler
.SafeGetCharAt(i
+ 1);
222 //int stylePrev = style;
224 styleNext
= styler
.StyleAt(i
+ 1);
225 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
226 if (foldComment
&& (style
== SCE_SN_COMMENTLINE
)) {
227 if (((ch
== '/') && (chNext
== '/')) ||
228 ((ch
== '-') && (chNext
== '-'))) {
229 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
230 if (chNext2
== '{') {
232 } else if (chNext2
== '}') {
237 if (style
== SCE_SN_OPERATOR
) {
239 // Measure the minimum before a '{' to allow
240 // folding on "} else {"
241 if (levelMinCurrent
> levelNext
) {
242 levelMinCurrent
= levelNext
;
245 } else if (ch
== '}') {
250 int levelUse
= levelCurrent
;
252 levelUse
= levelMinCurrent
;
254 int lev
= levelUse
| levelNext
<< 16;
255 if (visibleChars
== 0 && foldCompact
)
256 lev
|= SC_FOLDLEVELWHITEFLAG
;
257 if (levelUse
< levelNext
)
258 lev
|= SC_FOLDLEVELHEADERFLAG
;
259 if (lev
!= styler
.LevelAt(lineCurrent
)) {
260 styler
.SetLevel(lineCurrent
, lev
);
263 levelCurrent
= levelNext
;
264 levelMinCurrent
= levelCurrent
;
267 if (!isspacechar(ch
))
272 static void FoldSpecmanDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*[],
274 FoldNoBoxSpecmanDoc(startPos
, length
, initStyle
, styler
);
277 static const char * const specmanWordLists
[] = {
278 "Primary keywords and identifiers",
279 "Secondary keywords and identifiers",
280 "Sequence keywords and identifiers",
281 "User defined keywords and identifiers",
286 static void ColouriseSpecmanDocSensitive(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
288 ColouriseSpecmanDoc(startPos
, length
, initStyle
, keywordlists
, styler
, true);
292 LexerModule
lmSpecman(SCLEX_SPECMAN
, ColouriseSpecmanDocSensitive
, "specman", FoldSpecmanDoc
, specmanWordLists
);