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