updated Scintilla to 2.29
[TortoiseGit.git] / ext / scintilla / lexers / LexProgress.cxx
blob452aa7e3076568e12b4fedddb4942121f05bc890
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 Support more than 6 comments levels
13 **/
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <assert.h>
19 #include <ctype.h>
21 #include "ILexer.h"
22 #include "Scintilla.h"
23 #include "SciLexer.h"
25 #include "WordList.h"
26 #include "LexAccessor.h"
27 #include "Accessor.h"
28 #include "StyleContext.h"
29 #include "CharacterSet.h"
30 #include "LexerModule.h"
32 #ifdef SCI_NAMESPACE
33 using namespace Scintilla;
34 #endif
36 static inline bool IsAWordChar(int ch) {
37 return (ch < 0x80) && (isalnum(ch) || ch == '_');
40 static inline bool IsAWordStart(int ch) {
41 return (ch < 0x80) && (isalpha(ch) || ch == '_');
44 enum SentenceStart { SetSentenceStart = 0xf, ResetSentenceStart = 0x10}; // true -> bit = 0
46 static void Colourise4glDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
47 Accessor &styler) {
49 WordList &keywords1 = *keywordlists[0]; // regular keywords
50 WordList &keywords2 = *keywordlists[1]; // block opening keywords, only when SentenceStart
51 WordList &keywords3 = *keywordlists[2]; // block opening keywords
52 //WordList &keywords4 = *keywordlists[3]; // preprocessor keywords. Not implemented
55 int visibleChars = 0;
56 int mask;
58 StyleContext sc(startPos, length, initStyle, styler);
60 for (; sc.More(); sc.Forward()) {
62 if (sc.atLineStart) {
63 // Reset states to begining of colourise so no surprises
64 // if different sets of lines lexed.
65 visibleChars = 0;
68 // Handle line continuation generically.
69 if ((sc.state & 0xf) < SCE_4GL_COMMENT1) {
70 if (sc.ch == '~') {
71 if (sc.chNext > ' ') {
72 // skip special char after ~
73 sc.Forward();
74 continue;
76 else {
77 // Skip whitespace between ~ and EOL
78 while (sc.More() && (sc.chNext == ' ' || sc.chNext == '\t') ) {
79 sc.Forward();
81 if (sc.chNext == '\n' || sc.chNext == '\r') {
82 sc.Forward();
83 if (sc.ch == '\r' && sc.chNext == '\n') {
84 sc.Forward();
86 sc.Forward();
87 continue;
92 // Determine if a new state should be terminated.
93 mask = sc.state & 0x10;
94 switch (sc.state & 0xf) {
95 case SCE_4GL_OPERATOR:
96 sc.SetState(SCE_4GL_DEFAULT | mask);
97 break;
98 case SCE_4GL_NUMBER:
99 if (!(IsADigit(sc.ch))) {
100 sc.SetState(SCE_4GL_DEFAULT | mask);
102 break;
103 case SCE_4GL_IDENTIFIER:
104 if (!IsAWordChar(sc.ch) && sc.ch != '-') {
105 char s[1000];
106 sc.GetCurrentLowered(s, sizeof(s));
107 if ((((sc.state & 0x10) == 0) && keywords2.InList(s)) || keywords3.InList(s)) {
108 sc.ChangeState(SCE_4GL_BLOCK | ResetSentenceStart);
110 else if (keywords1.InList(s)) {
111 if ((s[0] == 'e' && s[1] =='n' && s[2] == 'd' && !isalnum(s[3]) && s[3] != '-') ||
112 (s[0] == 'f' && s[1] =='o' && s[2] == 'r' && s[3] == 'w' && s[4] =='a' && s[5] == 'r' && s[6] == 'd'&& !isalnum(s[7]))) {
113 sc.ChangeState(SCE_4GL_END | ResetSentenceStart);
115 else if ((s[0] == 'e' && s[1] =='l' && s[2] == 's' && s[3] == 'e') ||
116 (s[0] == 't' && s[1] =='h' && s[2] == 'e' && s[3] == 'n')) {
117 sc.ChangeState(SCE_4GL_WORD & SetSentenceStart);
119 else {
120 sc.ChangeState(SCE_4GL_WORD | ResetSentenceStart);
123 sc.SetState(SCE_4GL_DEFAULT | (sc.state & 0x10));
125 break;
126 case SCE_4GL_PREPROCESSOR:
127 if (sc.atLineStart) {
128 sc.SetState(SCE_4GL_DEFAULT & SetSentenceStart);
130 /* code removed to allow comments inside preprocessor
131 else if (sc.ch == '*' && sc.chNext == '/') {
132 sc.ForwardSetState(SCE_4GL_DEFAULT | sentenceStartState); } */
133 break;
134 case SCE_4GL_STRING:
135 if (sc.ch == '\"') {
136 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
138 break;
139 case SCE_4GL_CHARACTER:
140 if (sc.ch == '\'') {
141 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
143 break;
144 default:
145 if ((sc.state & 0xf) >= SCE_4GL_COMMENT1) {
146 if (sc.ch == '*' && sc.chNext == '/') {
147 sc.Forward();
148 if ((sc.state & 0xf) == SCE_4GL_COMMENT1) {
149 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
151 else
152 sc.SetState((sc.state & 0x1f) - 1);
153 } else if (sc.ch == '/' && sc.chNext == '*') {
154 sc.Forward();
155 sc.SetState((sc.state & 0x1f) + 1);
160 // Determine if a new state should be entered.
161 mask = sc.state & 0x10;
162 if ((sc.state & 0xf) == SCE_4GL_DEFAULT) {
163 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
164 sc.SetState(SCE_4GL_NUMBER | ResetSentenceStart);
165 } else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
166 sc.SetState(SCE_4GL_IDENTIFIER | mask);
167 } else if (sc.ch == '/' && sc.chNext == '*') {
168 sc.SetState(SCE_4GL_COMMENT1 | mask);
169 sc.Forward();
170 } else if (sc.ch == '\"') {
171 sc.SetState(SCE_4GL_STRING | ResetSentenceStart);
172 } else if (sc.ch == '\'') {
173 sc.SetState(SCE_4GL_CHARACTER | ResetSentenceStart);
174 } else if (sc.ch == '&' && visibleChars == 0 && ((sc.state & 0x10) == 0)) {
175 sc.SetState(SCE_4GL_PREPROCESSOR | ResetSentenceStart);
176 // Skip whitespace between & and preprocessor word
177 do {
178 sc.Forward();
179 } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
180 // Handle syntactical line termination
181 } else if ((sc.ch == '.' || sc.ch == ':' || sc.ch == '}') && (sc.chNext == ' ' || sc.chNext == '\t' || sc.chNext == '\n' || sc.chNext == '\r')) {
182 sc.SetState(sc.state & SetSentenceStart);
183 } else if (isoperator(static_cast<char>(sc.ch))) {
184 /* This code allows highlight of handles. Alas, it would cause the phrase "last-event:function"
185 to be recognized as a BlockBegin */
187 if (sc.ch == ':')
188 sc.SetState(SCE_4GL_OPERATOR & SetSentenceStart);
189 /* else */
190 sc.SetState(SCE_4GL_OPERATOR | ResetSentenceStart);
194 if (!IsASpace(sc.ch)) {
195 visibleChars++;
198 sc.Complete();
201 static bool IsStreamCommentStyle(int style) {
202 return (style & 0xf) >= SCE_4GL_COMMENT1 ;
205 // Store both the current line's fold level and the next lines in the
206 // level store to make it easy to pick up with each increment
207 // and to make it possible to fiddle the current level for "} else {".
208 static void FoldNoBox4glDoc(unsigned int startPos, int length, int initStyle,
209 Accessor &styler) {
210 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
211 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
212 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
213 unsigned int endPos = startPos + length;
214 int visibleChars = 0;
215 int lineCurrent = styler.GetLine(startPos);
216 int levelCurrent = SC_FOLDLEVELBASE;
217 if (lineCurrent > 0)
218 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
219 int levelMinCurrent = levelCurrent;
220 int levelNext = levelCurrent;
221 char chNext = static_cast<char>(tolower(styler[startPos]));
222 int styleNext = styler.StyleAt(startPos);
223 int style = initStyle;
224 for (unsigned int i = startPos; i < endPos; i++) {
225 char ch = chNext;
226 chNext = static_cast<char>(tolower(styler.SafeGetCharAt(i + 1)));
227 int stylePrev = style;
228 style = styleNext;
229 styleNext = styler.StyleAt(i + 1);
230 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
231 if (foldComment && IsStreamCommentStyle(style)) {
232 if (!IsStreamCommentStyle(stylePrev)) {
233 levelNext++;
234 } else if (!IsStreamCommentStyle(styleNext)) { // && !atEOL) {
235 // Comments don't end at end of line and the next character may be unstyled.
236 levelNext--;
239 else if ((style & 0xf) == SCE_4GL_BLOCK && !isalnum(chNext)) {
240 levelNext++;
242 else if ((style & 0xf) == SCE_4GL_END && (ch == 'e' || ch == 'f')) {
243 levelNext--;
245 if (atEOL) {
246 int levelUse = levelCurrent;
247 if (foldAtElse) {
248 levelUse = levelMinCurrent;
250 int lev = levelUse | levelNext << 16;
251 if (visibleChars == 0 && foldCompact)
252 lev |= SC_FOLDLEVELWHITEFLAG;
253 if (levelUse < levelNext)
254 lev |= SC_FOLDLEVELHEADERFLAG;
255 if (lev != styler.LevelAt(lineCurrent)) {
256 styler.SetLevel(lineCurrent, lev);
258 lineCurrent++;
259 levelCurrent = levelNext;
260 levelMinCurrent = levelCurrent;
261 visibleChars = 0;
263 if (!isspacechar(ch))
264 visibleChars++;
268 static void Fold4glDoc(unsigned int startPos, int length, int initStyle, WordList *[],
269 Accessor &styler) {
270 FoldNoBox4glDoc(startPos, length, initStyle, styler);
273 static const char * const FglWordLists[] = {
274 "Primary keywords and identifiers",
275 "Secondary keywords and identifiers",
276 "Documentation comment keywords",
277 "Unused",
278 "Global classes and typedefs",
282 LexerModule lmProgress(SCLEX_PROGRESS, Colourise4glDoc, "progress", Fold4glDoc, FglWordLists);