Update Scintilla to 3.6.6
[TortoiseGit.git] / ext / scintilla / lexers / LexProgress.cxx
blob94a8a140fc8c18554d7ff995b81dc1c1b0f0c99a
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>
5 **/
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.
9 /** TODO:
10 WebSpeed support in html lexer
11 Support "end triggers" expression of the triggers phrase
12 **/
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <assert.h>
18 #include <ctype.h>
20 #include "ILexer.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
24 #include "WordList.h"
25 #include "LexAccessor.h"
26 #include "Accessor.h"
27 #include "StyleContext.h"
28 #include "CharacterSet.h"
29 #include "LexerModule.h"
31 #ifdef SCI_NAMESPACE
32 using namespace Scintilla;
33 #endif
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[],
46 Accessor &styler) {
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;
67 int visibleChars = 0;
68 int mask;
70 StyleContext sc(startPos, length, initStyle, styler);
72 for (; sc.More(); sc.Forward()) {
74 if (sc.atLineStart) {
75 // Reset states to begining of colourise so no surprises
76 // if different sets of lines lexed.
77 visibleChars = 0;
80 if (sc.atLineEnd) {
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);
87 } else {
88 // Reset the line state
89 styler.SetLineState(currentLine, 0);
93 // Handle line continuation generically.
94 if ((sc.state & 0xf) < SCE_4GL_COMMENT1) {
95 if (sc.ch == '~') {
96 if (sc.chNext > ' ') {
97 // skip special char after ~
98 sc.Forward();
99 continue;
101 else {
102 // Skip whitespace between ~ and EOL
103 while (sc.More() && (sc.chNext == ' ' || sc.chNext == '\t') ) {
104 sc.Forward();
106 if (sc.chNext == '\n' || sc.chNext == '\r') {
107 sc.Forward();
108 if (sc.ch == '\r' && sc.chNext == '\n') {
109 sc.Forward();
111 sc.Forward();
112 continue;
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);
122 break;
123 case SCE_4GL_NUMBER:
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);
129 break;
130 case SCE_4GL_IDENTIFIER:
131 if (!IsAWordChar(sc.ch) && sc.ch != '-') {
132 char s[1000];
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);
146 else {
147 sc.ChangeState(SCE_4GL_WORD | ResetSentenceStart);
150 sc.SetState(SCE_4GL_DEFAULT | (sc.state & 0x10));
152 break;
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); } */
160 break;
161 case SCE_4GL_STRING:
162 if (sc.ch == '\"') {
163 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
165 break;
166 case SCE_4GL_CHARACTER:
167 if (sc.ch == '\'') {
168 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
170 break;
171 case SCE_4GL_COMMENT1:
172 if (sc.Match('/', '*')) {
173 blockCommentLevel++;
174 sc.Forward();
175 } else if (sc.Match('*', '/') && blockCommentLevel > 0) {
176 blockCommentLevel--;
177 sc.Forward();
178 if (blockCommentLevel == 0) {
179 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
182 break;
183 case SCE_4GL_COMMENT2:
184 if (sc.atLineEnd) {
185 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
187 break;
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);
200 sc.Forward();
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
211 do {
212 sc.Forward();
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 */
221 if (sc.ch == ':')
222 sc.SetState(SCE_4GL_OPERATOR & SetSentenceStart);
223 /* else */
224 sc.SetState(SCE_4GL_OPERATOR | ResetSentenceStart);
228 if (!IsASpace(sc.ch)) {
229 visibleChars++;
232 sc.Complete();
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,
243 Accessor &styler) {
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;
251 if (lineCurrent > 0)
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++) {
259 char ch = chNext;
260 chNext = static_cast<char>(tolower(styler.SafeGetCharAt(i + 1)));
261 int stylePrev = style;
262 style = styleNext;
263 styleNext = styler.StyleAt(i + 1);
264 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
265 if (foldComment && IsStreamCommentStyle(style)) {
266 if (!IsStreamCommentStyle(stylePrev)) {
267 levelNext++;
268 } else if (!IsStreamCommentStyle(styleNext)) { // && !atEOL) {
269 // Comments don't end at end of line and the next character may be unstyled.
270 levelNext--;
273 else if ((style & 0xf) == SCE_4GL_BLOCK && !isalnum(chNext)) {
274 levelNext++;
276 else if ((style & 0xf) == SCE_4GL_END && (ch == 'e' || ch == 'f')) {
277 levelNext--;
279 if (atEOL) {
280 int levelUse = levelCurrent;
281 if (foldAtElse) {
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);
292 lineCurrent++;
293 levelCurrent = levelNext;
294 levelMinCurrent = levelCurrent;
295 visibleChars = 0;
297 if (!isspacechar(ch))
298 visibleChars++;
302 static void Fold4glDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[],
303 Accessor &styler) {
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",
311 "Unused",
312 "Global classes and typedefs",
316 LexerModule lmProgress(SCLEX_PROGRESS, Colourise4glDoc, "progress", Fold4glDoc, FglWordLists);