]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/lexers/LexProgress.cxx
simplify code so it always returns the same object
[wxWidgets.git] / src / stc / scintilla / lexers / LexProgress.cxx
CommitLineData
7e0c58e9
RD
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.
8
9/** TODO:
10WebSpeed support in html lexer
11Support "end triggers" expression of the triggers phrase
7e0c58e9
RD
12Support more than 6 comments levels
13**/
14#include <stdlib.h>
15#include <string.h>
7e0c58e9
RD
16#include <stdio.h>
17#include <stdarg.h>
1dcf666d
RD
18#include <assert.h>
19#include <ctype.h>
7e0c58e9 20
1dcf666d
RD
21#include "ILexer.h"
22#include "Scintilla.h"
23#include "SciLexer.h"
7e0c58e9 24
1dcf666d
RD
25#include "WordList.h"
26#include "LexAccessor.h"
7e0c58e9
RD
27#include "Accessor.h"
28#include "StyleContext.h"
1dcf666d
RD
29#include "CharacterSet.h"
30#include "LexerModule.h"
7e0c58e9
RD
31
32#ifdef SCI_NAMESPACE
33using namespace Scintilla;
34#endif
35
36static inline bool IsAWordChar(int ch) {
37 return (ch < 0x80) && (isalnum(ch) || ch == '_');
38}
39
40static inline bool IsAWordStart(int ch) {
41 return (ch < 0x80) && (isalpha(ch) || ch == '_');
42}
43
44enum SentenceStart { SetSentenceStart = 0xf, ResetSentenceStart = 0x10}; // true -> bit = 0
45
46static void Colourise4glDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
47 Accessor &styler) {
48
9e96e16f
RD
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
1dcf666d 53
7e0c58e9
RD
54
55 int visibleChars = 0;
56 int mask;
57
58 StyleContext sc(startPos, length, initStyle, styler);
59
60 for (; sc.More(); sc.Forward()) {
61
62 if (sc.atLineStart) {
63 // Reset states to begining of colourise so no surprises
64 // if different sets of lines lexed.
65 visibleChars = 0;
66 }
67
68 // Handle line continuation generically.
9e96e16f 69 if ((sc.state & 0xf) < SCE_4GL_COMMENT1) {
7e0c58e9 70 if (sc.ch == '~') {
9e96e16f
RD
71 if (sc.chNext > ' ') {
72 // skip special char after ~
7e0c58e9 73 sc.Forward();
9e96e16f 74 continue;
7e0c58e9 75 }
9e96e16f
RD
76 else {
77 // Skip whitespace between ~ and EOL
78 while (sc.More() && (sc.chNext == ' ' || sc.chNext == '\t') ) {
7e0c58e9
RD
79 sc.Forward();
80 }
9e96e16f
RD
81 if (sc.chNext == '\n' || sc.chNext == '\r') {
82 sc.Forward();
83 if (sc.ch == '\r' && sc.chNext == '\n') {
84 sc.Forward();
85 }
86 sc.Forward();
87 continue;
88 }
7e0c58e9
RD
89 }
90 }
9e96e16f 91 }
7e0c58e9
RD
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);
101 }
102 break;
103 case SCE_4GL_IDENTIFIER:
104 if (!IsAWordChar(sc.ch) && sc.ch != '-') {
105 char s[1000];
106 sc.GetCurrentLowered(s, sizeof(s));
9e96e16f 107 if ((((sc.state & 0x10) == 0) && keywords2.InList(s)) || keywords3.InList(s)) {
7e0c58e9
RD
108 sc.ChangeState(SCE_4GL_BLOCK | ResetSentenceStart);
109 }
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);
114 }
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);
118 }
119 else {
120 sc.ChangeState(SCE_4GL_WORD | ResetSentenceStart);
121 }
122 }
123 sc.SetState(SCE_4GL_DEFAULT | (sc.state & 0x10));
124 }
125 break;
126 case SCE_4GL_PREPROCESSOR:
127 if (sc.atLineStart) {
128 sc.SetState(SCE_4GL_DEFAULT & SetSentenceStart);
7e0c58e9 129 }
9e96e16f
RD
130 /* code removed to allow comments inside preprocessor
131 else if (sc.ch == '*' && sc.chNext == '/') {
132 sc.ForwardSetState(SCE_4GL_DEFAULT | sentenceStartState); } */
7e0c58e9
RD
133 break;
134 case SCE_4GL_STRING:
135 if (sc.ch == '\"') {
136 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
137 }
138 break;
139 case SCE_4GL_CHARACTER:
140 if (sc.ch == '\'') {
141 sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
142 }
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);
150 }
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);
156 }
157 }
158 }
159
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))) {
9e96e16f
RD
184 /* This code allows highlight of handles. Alas, it would cause the phrase "last-event:function"
185 to be recognized as a BlockBegin */
1dcf666d 186
7e0c58e9
RD
187 if (sc.ch == ':')
188 sc.SetState(SCE_4GL_OPERATOR & SetSentenceStart);
9e96e16f 189 /* else */
7e0c58e9
RD
190 sc.SetState(SCE_4GL_OPERATOR | ResetSentenceStart);
191 }
192 }
193
194 if (!IsASpace(sc.ch)) {
195 visibleChars++;
196 }
197 }
198 sc.Complete();
199}
200
201static bool IsStreamCommentStyle(int style) {
202 return (style & 0xf) >= SCE_4GL_COMMENT1 ;
203}
204
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 {".
208static 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--;
237 }
238 }
239 else if ((style & 0xf) == SCE_4GL_BLOCK && !isalnum(chNext)) {
240 levelNext++;
241 }
242 else if ((style & 0xf) == SCE_4GL_END && (ch == 'e' || ch == 'f')) {
243 levelNext--;
244 }
245 if (atEOL) {
246 int levelUse = levelCurrent;
247 if (foldAtElse) {
248 levelUse = levelMinCurrent;
249 }
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);
257 }
258 lineCurrent++;
259 levelCurrent = levelNext;
260 levelMinCurrent = levelCurrent;
261 visibleChars = 0;
262 }
263 if (!isspacechar(ch))
264 visibleChars++;
265 }
266}
267
268static void Fold4glDoc(unsigned int startPos, int length, int initStyle, WordList *[],
269 Accessor &styler) {
270 FoldNoBox4glDoc(startPos, length, initStyle, styler);
271}
272
273static 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",
279 0,
280 };
281
9e96e16f 282LexerModule lmProgress(SCLEX_PROGRESS, Colourise4glDoc, "progress", Fold4glDoc, FglWordLists);