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
21 #include "Scintilla.h"
25 #include "LexAccessor.h"
27 #include "StyleContext.h"
28 #include "CharacterSet.h"
29 #include "LexerModule.h"
32 using namespace Scintilla
;
35 static inline bool IsAWordChar(int ch
) {
36 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_');
39 static inline bool IsAWordStart(int ch
) {
40 return (ch
< 0x80) && (isalpha(ch
) || ch
== '_');
43 enum SentenceStart
{ SetSentenceStart
= 0xf, ResetSentenceStart
= 0x10}; // true -> bit = 0
45 static void Colourise4glDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*keywordlists
[],
48 WordList
&keywords1
= *keywordlists
[0]; // regular keywords
49 WordList
&keywords2
= *keywordlists
[1]; // block opening keywords, only when SentenceStart
50 WordList
&keywords3
= *keywordlists
[2]; // block opening keywords
51 //WordList &keywords4 = *keywordlists[3]; // preprocessor keywords. Not implemented
53 Sci_Position currentLine
= styler
.GetLine(startPos
);
54 // Initialize the block comment /* */ nesting level, if we are inside such a comment.
55 int blockCommentLevel
= 0;
56 if (initStyle
== SCE_4GL_COMMENT1
||
57 initStyle
== SCE_4GL_COMMENT1_
) {
58 blockCommentLevel
= styler
.GetLineState(currentLine
- 1);
61 // Do not leak single-line comments onto next line
62 if (initStyle
== SCE_4GL_COMMENT2
||
63 initStyle
== SCE_4GL_COMMENT2_
) {
64 initStyle
= SCE_4GL_DEFAULT
;
70 StyleContext
sc(startPos
, length
, initStyle
, styler
);
72 for (; sc
.More(); sc
.Forward()) {
75 // Reset states to begining of colourise so no surprises
76 // if different sets of lines lexed.
81 // Update the line state, so it can be seen by next line
82 currentLine
= styler
.GetLine(sc
.currentPos
);
83 if (sc
.state
== SCE_4GL_COMMENT1
||
84 sc
.state
== SCE_4GL_COMMENT1_
) {
85 // Inside a block comment, we set the line state
86 styler
.SetLineState(currentLine
, blockCommentLevel
);
88 // Reset the line state
89 styler
.SetLineState(currentLine
, 0);
93 // Handle line continuation generically.
94 if ((sc
.state
& 0xf) < SCE_4GL_COMMENT1
) {
96 if (sc
.chNext
> ' ') {
97 // skip special char after ~
102 // Skip whitespace between ~ and EOL
103 while (sc
.More() && (sc
.chNext
== ' ' || sc
.chNext
== '\t') ) {
106 if (sc
.chNext
== '\n' || sc
.chNext
== '\r') {
108 if (sc
.ch
== '\r' && sc
.chNext
== '\n') {
117 // Determine if a new state should be terminated.
118 mask
= sc
.state
& 0x10;
119 switch (sc
.state
& 0xf) {
120 case SCE_4GL_OPERATOR
:
121 sc
.SetState(SCE_4GL_DEFAULT
| mask
);
124 // Hex numbers (0xnnnn) are supported so accept any
125 // alphanumeric character if it follows a leading digit.
126 if (!(IsAlphaNumeric(sc
.ch
))) {
127 sc
.SetState(SCE_4GL_DEFAULT
| mask
);
130 case SCE_4GL_IDENTIFIER
:
131 if (!IsAWordChar(sc
.ch
) && sc
.ch
!= '-') {
133 sc
.GetCurrentLowered(s
, sizeof(s
));
134 if ((((sc
.state
& 0x10) == 0) && keywords2
.InListAbbreviated(s
, '(')) || keywords3
.InListAbbreviated(s
, '(')) {
135 sc
.ChangeState(SCE_4GL_BLOCK
| ResetSentenceStart
);
137 else if (keywords1
.InListAbbreviated(s
, '(')) {
138 if ((s
[0] == 'e' && s
[1] =='n' && s
[2] == 'd' && !isalnum(s
[3]) && s
[3] != '-') ||
139 (s
[0] == 'f' && s
[1] =='o' && s
[2] == 'r' && s
[3] == 'w' && s
[4] =='a' && s
[5] == 'r' && s
[6] == 'd'&& !isalnum(s
[7]))) {
140 sc
.ChangeState(SCE_4GL_END
| ResetSentenceStart
);
142 else if ((s
[0] == 'e' && s
[1] =='l' && s
[2] == 's' && s
[3] == 'e') ||
143 (s
[0] == 't' && s
[1] =='h' && s
[2] == 'e' && s
[3] == 'n')) {
144 sc
.ChangeState(SCE_4GL_WORD
& SetSentenceStart
);
147 sc
.ChangeState(SCE_4GL_WORD
| ResetSentenceStart
);
150 sc
.SetState(SCE_4GL_DEFAULT
| (sc
.state
& 0x10));
153 case SCE_4GL_PREPROCESSOR
:
154 if (sc
.atLineStart
) {
155 sc
.SetState(SCE_4GL_DEFAULT
& SetSentenceStart
);
157 /* code removed to allow comments inside preprocessor
158 else if (sc.ch == '*' && sc.chNext == '/') {
159 sc.ForwardSetState(SCE_4GL_DEFAULT | sentenceStartState); } */
163 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
166 case SCE_4GL_CHARACTER
:
168 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
171 case SCE_4GL_COMMENT1
:
172 if (sc
.Match('/', '*')) {
175 } else if (sc
.Match('*', '/') && blockCommentLevel
> 0) {
178 if (blockCommentLevel
== 0) {
179 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
183 case SCE_4GL_COMMENT2
:
185 sc
.ForwardSetState(SCE_4GL_DEFAULT
| mask
);
190 // Determine if a new state should be entered.
191 mask
= sc
.state
& 0x10;
192 if ((sc
.state
& 0xf) == SCE_4GL_DEFAULT
) {
193 if (IsADigit(sc
.ch
) || (sc
.ch
== '.' && IsADigit(sc
.chNext
))) {
194 sc
.SetState(SCE_4GL_NUMBER
| ResetSentenceStart
);
195 } else if (IsAWordStart(sc
.ch
) || (sc
.ch
== '@')) {
196 sc
.SetState(SCE_4GL_IDENTIFIER
| mask
);
197 } else if (sc
.Match('/', '*')) {
198 blockCommentLevel
= 1;
199 sc
.SetState(SCE_4GL_COMMENT1
| mask
);
201 } else if (sc
.Match('/', '/') &&
202 (sc
.atLineStart
|| sc
.chPrev
== ' ' || sc
.chPrev
== '\t')) {
203 sc
.SetState(SCE_4GL_COMMENT2
| mask
);
204 } else if (sc
.ch
== '\"') {
205 sc
.SetState(SCE_4GL_STRING
| ResetSentenceStart
);
206 } else if (sc
.ch
== '\'') {
207 sc
.SetState(SCE_4GL_CHARACTER
| ResetSentenceStart
);
208 } else if (sc
.ch
== '&' && visibleChars
== 0 && ((sc
.state
& 0x10) == 0)) {
209 sc
.SetState(SCE_4GL_PREPROCESSOR
| ResetSentenceStart
);
210 // Skip whitespace between & and preprocessor word
213 } while ((sc
.ch
== ' ' || sc
.ch
== '\t') && sc
.More());
214 // Handle syntactical line termination
215 } else if ((sc
.ch
== '.' || sc
.ch
== ':' || sc
.ch
== '}') && (sc
.chNext
== ' ' || sc
.chNext
== '\t' || sc
.chNext
== '\n' || sc
.chNext
== '\r')) {
216 sc
.SetState(sc
.state
& SetSentenceStart
);
217 } else if (isoperator(static_cast<char>(sc
.ch
))) {
218 /* This code allows highlight of handles. Alas, it would cause the phrase "last-event:function"
219 to be recognized as a BlockBegin */
222 sc
.SetState(SCE_4GL_OPERATOR
& SetSentenceStart
);
224 sc
.SetState(SCE_4GL_OPERATOR
| ResetSentenceStart
);
228 if (!IsASpace(sc
.ch
)) {
235 static bool IsStreamCommentStyle(int style
) {
236 return (style
& 0xf) == SCE_4GL_COMMENT1
;
239 // Store both the current line's fold level and the next lines in the
240 // level store to make it easy to pick up with each increment
241 // and to make it possible to fiddle the current level for "} else {".
242 static void FoldNoBox4glDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
,
244 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
245 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
246 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 0) != 0;
247 Sci_PositionU endPos
= startPos
+ length
;
248 int visibleChars
= 0;
249 Sci_Position lineCurrent
= styler
.GetLine(startPos
);
250 int levelCurrent
= SC_FOLDLEVELBASE
;
252 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
253 int levelMinCurrent
= levelCurrent
;
254 int levelNext
= levelCurrent
;
255 char chNext
= static_cast<char>(tolower(styler
[startPos
]));
256 int styleNext
= styler
.StyleAt(startPos
);
257 int style
= initStyle
;
258 for (Sci_PositionU i
= startPos
; i
< endPos
; i
++) {
260 chNext
= static_cast<char>(tolower(styler
.SafeGetCharAt(i
+ 1)));
261 int stylePrev
= style
;
263 styleNext
= styler
.StyleAt(i
+ 1);
264 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
265 if (foldComment
&& IsStreamCommentStyle(style
)) {
266 if (!IsStreamCommentStyle(stylePrev
)) {
268 } else if (!IsStreamCommentStyle(styleNext
)) { // && !atEOL) {
269 // Comments don't end at end of line and the next character may be unstyled.
273 else if ((style
& 0xf) == SCE_4GL_BLOCK
&& !isalnum(chNext
)) {
276 else if ((style
& 0xf) == SCE_4GL_END
&& (ch
== 'e' || ch
== 'f')) {
280 int levelUse
= levelCurrent
;
282 levelUse
= levelMinCurrent
;
284 int lev
= levelUse
| levelNext
<< 16;
285 if (visibleChars
== 0 && foldCompact
)
286 lev
|= SC_FOLDLEVELWHITEFLAG
;
287 if (levelUse
< levelNext
)
288 lev
|= SC_FOLDLEVELHEADERFLAG
;
289 if (lev
!= styler
.LevelAt(lineCurrent
)) {
290 styler
.SetLevel(lineCurrent
, lev
);
293 levelCurrent
= levelNext
;
294 levelMinCurrent
= levelCurrent
;
297 if (!isspacechar(ch
))
302 static void Fold4glDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*[],
304 FoldNoBox4glDoc(startPos
, length
, initStyle
, styler
);
307 static const char * const FglWordLists
[] = {
308 "Primary keywords and identifiers",
309 "Secondary keywords and identifiers",
310 "Documentation comment keywords",
312 "Global classes and typedefs",
316 LexerModule
lmProgress(SCLEX_PROGRESS
, Colourise4glDoc
, "progress", Fold4glDoc
, FglWordLists
);