1 // Scintilla source code edit control
2 /** @file LexProgress.cxx
3 ** Lexer for Progress 4GL.
4 ** Based on LexCPP.cxx of Neil Hodgson <neilh@scintilla.org>
6 // Copyright 2006-2007 by Yuval Papish <Yuval@YuvCom.com>
7 // The License.txt file describes the conditions under which this software may be distributed.
10 WebSpeed support in html lexer
11 Support "end triggers" expression of the triggers phrase
12 change lmPS to lmProgress
13 Support more than 6 comments levels
25 #include "StyleContext.h"
27 #include "Scintilla.h"
31 using namespace Scintilla
;
34 static inline bool IsAWordChar(int ch
) {
35 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_');
38 static inline bool IsAWordStart(int ch
) {
39 return (ch
< 0x80) && (isalpha(ch
) || ch
== '_');
42 enum SentenceStart
{ SetSentenceStart
= 0xf, ResetSentenceStart
= 0x10}; // true -> bit = 0
44 static void Colourise4glDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
47 WordList
&keywords1
= *keywordlists
[0];
48 WordList
&keywords2
= *keywordlists
[1];
49 WordList
&keywords3
= *keywordlists
[2];
50 //WordList &keywords4 = *keywordlists[3];
51 //WordList &keywords5 = *keywordlists[4];
56 StyleContext
sc(startPos
, length
, initStyle
, styler
);
58 for (; sc
.More(); sc
.Forward()) {
61 // Reset states to begining of colourise so no surprises
62 // if different sets of lines lexed.
66 // Handle line continuation generically.
68 if (sc
.chNext
> ' ') {
69 // skip special char after ~
74 // Skip whitespace between ~ and EOL
75 while (sc
.More() && (sc
.chNext
== ' ' || sc
.chNext
== '\t') ) {
78 if (sc
.chNext
== '\n' || sc
.chNext
== '\r') {
80 if (sc
.ch
== '\r' && sc
.chNext
== '\n') {
88 // Determine if a new state should be terminated.
89 mask
= sc
.state
& 0x10;
90 switch (sc
.state
& 0xf) {
91 case SCE_4GL_OPERATOR
:
92 sc
.SetState(SCE_4GL_DEFAULT
| mask
);
95 if (!(IsADigit(sc
.ch
))) {
96 sc
.SetState(SCE_4GL_DEFAULT
| mask
);
99 case SCE_4GL_IDENTIFIER
:
100 if (!IsAWordChar(sc
.ch
) && sc
.ch
!= '-') {
102 sc
.GetCurrentLowered(s
, sizeof(s
));
103 if (((sc
.state
& 0x10) == 0) && keywords2
.InList(s
) || keywords3
.InList(s
)) {
104 sc
.ChangeState(SCE_4GL_BLOCK
| ResetSentenceStart
);
106 else if (keywords1
.InList(s
)) {
107 if ((s
[0] == 'e' && s
[1] =='n' && s
[2] == 'd' && !isalnum(s
[3]) && s
[3] != '-') ||
108 (s
[0] == 'f' && s
[1] =='o' && s
[2] == 'r' && s
[3] == 'w' && s
[4] =='a' && s
[5] == 'r' && s
[6] == 'd'&& !isalnum(s
[7]))) {
109 sc
.ChangeState(SCE_4GL_END
| ResetSentenceStart
);
111 else if ((s
[0] == 'e' && s
[1] =='l' && s
[2] == 's' && s
[3] == 'e') ||
112 (s
[0] == 't' && s
[1] =='h' && s
[2] == 'e' && s
[3] == 'n')) {
113 sc
.ChangeState(SCE_4GL_WORD
& SetSentenceStart
);
116 sc
.ChangeState(SCE_4GL_WORD
| ResetSentenceStart
);
119 sc
.SetState(SCE_4GL_DEFAULT
| (sc
.state
& 0x10));
122 case SCE_4GL_PREPROCESSOR
:
123 if (sc
.atLineStart
) {
124 sc
.SetState(SCE_4GL_DEFAULT
& SetSentenceStart
);
125 } else if (sc
.ch
== '*' && sc
.chNext
== '/') {
126 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
131 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
134 case SCE_4GL_CHARACTER
:
136 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
140 if ((sc
.state
& 0xf) >= SCE_4GL_COMMENT1
) {
141 if (sc
.ch
== '*' && sc
.chNext
== '/') {
143 if ((sc
.state
& 0xf) == SCE_4GL_COMMENT1
) {
144 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
147 sc
.SetState((sc
.state
& 0x1f) - 1);
148 } else if (sc
.ch
== '/' && sc
.chNext
== '*') {
150 sc
.SetState((sc
.state
& 0x1f) + 1);
155 // Determine if a new state should be entered.
156 mask
= sc
.state
& 0x10;
157 if ((sc
.state
& 0xf) == SCE_4GL_DEFAULT
) {
158 if (IsADigit(sc
.ch
) || (sc
.ch
== '.' && IsADigit(sc
.chNext
))) {
159 sc
.SetState(SCE_4GL_NUMBER
| ResetSentenceStart
);
160 } else if (IsAWordStart(sc
.ch
) || (sc
.ch
== '@')) {
161 sc
.SetState(SCE_4GL_IDENTIFIER
| mask
);
162 } else if (sc
.ch
== '/' && sc
.chNext
== '*') {
163 sc
.SetState(SCE_4GL_COMMENT1
| mask
);
165 } else if (sc
.ch
== '\"') {
166 sc
.SetState(SCE_4GL_STRING
| ResetSentenceStart
);
167 } else if (sc
.ch
== '\'') {
168 sc
.SetState(SCE_4GL_CHARACTER
| ResetSentenceStart
);
169 } else if (sc
.ch
== '&' && visibleChars
== 0 && ((sc
.state
& 0x10) == 0)) {
170 sc
.SetState(SCE_4GL_PREPROCESSOR
| ResetSentenceStart
);
171 // Skip whitespace between & and preprocessor word
174 } while ((sc
.ch
== ' ' || sc
.ch
== '\t') && sc
.More());
175 // Handle syntactical line termination
176 } else if ((sc
.ch
== '.' || sc
.ch
== ':' || sc
.ch
== '}') && (sc
.chNext
== ' ' || sc
.chNext
== '\t' || sc
.chNext
== '\n' || sc
.chNext
== '\r')) {
177 sc
.SetState(sc
.state
& SetSentenceStart
);
178 } else if (isoperator(static_cast<char>(sc
.ch
))) {
180 sc
.SetState(SCE_4GL_OPERATOR
& SetSentenceStart
);
182 sc
.SetState(SCE_4GL_OPERATOR
| ResetSentenceStart
);
186 if (!IsASpace(sc
.ch
)) {
193 static bool IsStreamCommentStyle(int style
) {
194 return (style
& 0xf) >= SCE_4GL_COMMENT1
;
197 // Store both the current line's fold level and the next lines in the
198 // level store to make it easy to pick up with each increment
199 // and to make it possible to fiddle the current level for "} else {".
200 static void FoldNoBox4glDoc(unsigned int startPos
, int length
, int initStyle
,
202 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
203 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
204 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 0) != 0;
205 unsigned int endPos
= startPos
+ length
;
206 int visibleChars
= 0;
207 int lineCurrent
= styler
.GetLine(startPos
);
208 int levelCurrent
= SC_FOLDLEVELBASE
;
210 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
211 int levelMinCurrent
= levelCurrent
;
212 int levelNext
= levelCurrent
;
213 char chNext
= static_cast<char>(tolower(styler
[startPos
]));
214 int styleNext
= styler
.StyleAt(startPos
);
215 int style
= initStyle
;
216 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
218 chNext
= static_cast<char>(tolower(styler
.SafeGetCharAt(i
+ 1)));
219 int stylePrev
= style
;
221 styleNext
= styler
.StyleAt(i
+ 1);
222 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
223 if (foldComment
&& IsStreamCommentStyle(style
)) {
224 if (!IsStreamCommentStyle(stylePrev
)) {
226 } else if (!IsStreamCommentStyle(styleNext
)) { // && !atEOL) {
227 // Comments don't end at end of line and the next character may be unstyled.
231 else if ((style
& 0xf) == SCE_4GL_BLOCK
&& !isalnum(chNext
)) {
234 else if ((style
& 0xf) == SCE_4GL_END
&& (ch
== 'e' || ch
== 'f')) {
238 int levelUse
= levelCurrent
;
240 levelUse
= levelMinCurrent
;
242 int lev
= levelUse
| levelNext
<< 16;
243 if (visibleChars
== 0 && foldCompact
)
244 lev
|= SC_FOLDLEVELWHITEFLAG
;
245 if (levelUse
< levelNext
)
246 lev
|= SC_FOLDLEVELHEADERFLAG
;
247 if (lev
!= styler
.LevelAt(lineCurrent
)) {
248 styler
.SetLevel(lineCurrent
, lev
);
251 levelCurrent
= levelNext
;
252 levelMinCurrent
= levelCurrent
;
255 if (!isspacechar(ch
))
260 static void Fold4glDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*[],
262 FoldNoBox4glDoc(startPos
, length
, initStyle
, styler
);
265 static const char * const FglWordLists
[] = {
266 "Primary keywords and identifiers",
267 "Secondary keywords and identifiers",
268 "Documentation comment keywords",
270 "Global classes and typedefs",
274 LexerModule
lmProgress(SCLEX_PS
, Colourise4glDoc
, "progress", Fold4glDoc
, FglWordLists
);