]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexEiffel.cxx
1296fb24506c7787775d2776b5c4201dfedbd6da
[wxWidgets.git] / contrib / src / stc / scintilla / src / LexEiffel.cxx
1 // Scintilla source code edit control
2 /** @file LexEiffel.cxx
3 ** Lexer for Eiffel.
4 **/
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14
15 #include "Platform.h"
16
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "KeyWords.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22
23 inline bool isEiffelOperator(unsigned int ch) {
24 // '.' left out as it is used to make up numbers
25 return ch == '*' || ch == '/' || ch == '\\' || ch == '-' || ch == '+' ||
26 ch == '(' || ch == ')' || ch == '=' ||
27 ch == '{' || ch == '}' || ch == '~' ||
28 ch == '[' || ch == ']' || ch == ';' ||
29 ch == '<' || ch == '>' || ch == ',' ||
30 ch == '.' || ch == '^' || ch == '%' || ch == ':' ||
31 ch == '!' || ch == '@' || ch == '?';
32 }
33
34 static void getRangeLowered(unsigned int start,
35 unsigned int end,
36 Accessor &styler,
37 char *s,
38 unsigned int len) {
39 unsigned int i = 0;
40 while ((i < end - start + 1) && (i < len-1)) {
41 s[i] = static_cast<char>(tolower(styler[start + i]));
42 i++;
43 }
44 s[i] = '\0';
45 }
46
47 inline bool IsASpace(unsigned int ch) {
48 return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
49 }
50
51 inline bool IsAWordChar(unsigned int ch) {
52 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
53 }
54
55 inline bool IsAWordStart(unsigned int ch) {
56 return (ch < 0x80) && (isalnum(ch) || ch == '_');
57 }
58
59 inline bool IsADigit(unsigned int ch) {
60 return (ch >= '0') && (ch <= '9');
61 }
62
63 // All languages handled so far can treat all characters >= 0x80 as one class
64 // which just continues the current token or starts an identifier if in default.
65 // DBCS treated specially as the second character can be < 0x80 and hence
66 // syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
67 class xColouriseContext {
68 Accessor &styler;
69 int lengthDoc;
70 int currentPos;
71 xColouriseContext& operator=(const xColouriseContext&) {
72 return *this;
73 }
74 public:
75 int state;
76 unsigned int chPrev;
77 unsigned int ch;
78 unsigned int chNext;
79
80 xColouriseContext(unsigned int startPos, int length,
81 int initStyle, Accessor &styler_) :
82 styler(styler_),
83 lengthDoc(startPos + length),
84 currentPos(startPos),
85 state(initStyle),
86 chPrev(0),
87 ch(0),
88 chNext(0) {
89 styler.StartAt(startPos);
90 styler.StartSegment(startPos);
91 int pos = currentPos;
92 ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos));
93 if (styler.IsLeadByte(static_cast<char>(ch))) {
94 pos++;
95 ch = ch << 8;
96 ch |= static_cast<unsigned char>(styler.SafeGetCharAt(pos));
97 }
98 chNext = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1));
99 if (styler.IsLeadByte(static_cast<char>(chNext))) {
100 chNext = chNext << 8;
101 chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(pos+2));
102 }
103 }
104 void Complete() {
105 styler.ColourTo(currentPos - 1, state);
106 }
107 bool More() {
108 return currentPos <= lengthDoc;
109 }
110 void Forward() {
111 chPrev = ch;
112 currentPos++;
113 if (ch >= 0x100)
114 currentPos++;
115 ch = chNext;
116 chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+1));
117 if (styler.IsLeadByte(static_cast<char>(chNext))) {
118 chNext = chNext << 8;
119 chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(currentPos + 2));
120 }
121 }
122 void ChangeState(int state_) {
123 state = state_;
124 }
125 void SetState(int state_) {
126 styler.ColourTo(currentPos - 1, state);
127 state = state_;
128 }
129 void GetCurrentLowered(char *s, int len) {
130 getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len);
131 }
132 };
133
134 static void ColouriseEiffelDoc(unsigned int startPos,
135 int length,
136 int initStyle,
137 WordList *keywordlists[],
138 Accessor &styler) {
139
140 WordList &keywords = *keywordlists[0];
141
142 xColouriseContext lc(startPos, length, initStyle, styler);
143
144 for (; lc.More(); lc.Forward()) {
145
146 if (lc.state == SCE_EIFFEL_STRINGEOL) {
147 if (lc.ch != '\r' && lc.ch != '\n') {
148 lc.SetState(SCE_EIFFEL_DEFAULT);
149 }
150 } else if (lc.state == SCE_EIFFEL_OPERATOR) {
151 lc.SetState(SCE_EIFFEL_DEFAULT);
152 } else if (lc.state == SCE_EIFFEL_WORD) {
153 if (!IsAWordChar(lc.ch)) {
154 char s[100];
155 lc.GetCurrentLowered(s, sizeof(s));
156 if (!keywords.InList(s)) {
157 lc.ChangeState(SCE_EIFFEL_IDENTIFIER);
158 }
159 lc.SetState(SCE_EIFFEL_DEFAULT);
160 }
161 } else if (lc.state == SCE_EIFFEL_NUMBER) {
162 if (!IsAWordChar(lc.ch)) {
163 lc.SetState(SCE_EIFFEL_DEFAULT);
164 }
165 } else if (lc.state == SCE_EIFFEL_COMMENTLINE) {
166 if (lc.ch == '\r' || lc.ch == '\n') {
167 lc.SetState(SCE_EIFFEL_DEFAULT);
168 }
169 } else if (lc.state == SCE_EIFFEL_STRING) {
170 if (lc.ch == '%') {
171 lc.Forward();
172 } else if (lc.ch == '\"') {
173 lc.Forward();
174 lc.SetState(SCE_EIFFEL_DEFAULT);
175 }
176 } else if (lc.state == SCE_EIFFEL_CHARACTER) {
177 if (lc.ch == '\r' || lc.ch == '\n') {
178 lc.SetState(SCE_EIFFEL_STRINGEOL);
179 } else if (lc.ch == '%') {
180 lc.Forward();
181 } else if (lc.ch == '\'') {
182 lc.Forward();
183 lc.SetState(SCE_EIFFEL_DEFAULT);
184 }
185 }
186
187 if (lc.state == SCE_EIFFEL_DEFAULT) {
188 if (lc.ch == '-' && lc.chNext == '-') {
189 lc.SetState(SCE_EIFFEL_COMMENTLINE);
190 } else if (lc.ch == '\"') {
191 lc.SetState(SCE_EIFFEL_STRING);
192 } else if (lc.ch == '\'') {
193 lc.SetState(SCE_EIFFEL_CHARACTER);
194 } else if (IsADigit(lc.ch) || (lc.ch == '.')) {
195 lc.SetState(SCE_EIFFEL_NUMBER);
196 } else if (IsAWordStart(lc.ch)) {
197 lc.SetState(SCE_EIFFEL_WORD);
198 } else if (isEiffelOperator(lc.ch)) {
199 lc.SetState(SCE_EIFFEL_OPERATOR);
200 }
201 }
202 }
203 lc.Complete();
204 }
205
206 static bool IsEiffelComment(Accessor &styler, int pos, int len) {
207 return len>1 && styler[pos]=='-' && styler[pos+1]=='-';
208 }
209
210 static void FoldEiffelDocIndent(unsigned int startPos, int length, int,
211 WordList *[], Accessor &styler) {
212 int lengthDoc = startPos + length;
213
214 // Backtrack to previous line in case need to fix its fold status
215 int lineCurrent = styler.GetLine(startPos);
216 if (startPos > 0) {
217 if (lineCurrent > 0) {
218 lineCurrent--;
219 startPos = styler.LineStart(lineCurrent);
220 }
221 }
222 int spaceFlags = 0;
223 int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsEiffelComment);
224 char chNext = styler[startPos];
225 for (int i = startPos; i < lengthDoc; i++) {
226 char ch = chNext;
227 chNext = styler.SafeGetCharAt(i + 1);
228
229 if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
230 int lev = indentCurrent;
231 int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsEiffelComment);
232 if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
233 // Only non whitespace lines can be headers
234 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
235 lev |= SC_FOLDLEVELHEADERFLAG;
236 } else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
237 // Line after is blank so check the next - maybe should continue further?
238 int spaceFlags2 = 0;
239 int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsEiffelComment);
240 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
241 lev |= SC_FOLDLEVELHEADERFLAG;
242 }
243 }
244 }
245 indentCurrent = indentNext;
246 styler.SetLevel(lineCurrent, lev);
247 lineCurrent++;
248 }
249 }
250 }
251
252 static void FoldEiffelDocKeyWords(unsigned int startPos, int length, int /* initStyle */, WordList *[],
253 Accessor &styler) {
254 unsigned int lengthDoc = startPos + length;
255 int visibleChars = 0;
256 int lineCurrent = styler.GetLine(startPos);
257 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
258 int levelCurrent = levelPrev;
259 char chNext = styler[startPos];
260 int stylePrev = 0;
261 int styleNext = styler.StyleAt(startPos);
262 // lastDeferred should be determined by looking back to last keyword in case
263 // the "deferred" is on a line before "class"
264 bool lastDeferred = false;
265 for (unsigned int i = startPos; i < lengthDoc; i++) {
266 char ch = chNext;
267 chNext = styler.SafeGetCharAt(i + 1);
268 int style = styleNext;
269 styleNext = styler.StyleAt(i + 1);
270 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
271 if ((stylePrev != SCE_EIFFEL_WORD) && (style == SCE_EIFFEL_WORD)) {
272 char s[20];
273 unsigned int j = 0;
274 while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
275 s[j] = styler[i + j];
276 j++;
277 }
278 s[j] = '\0';
279
280 if (
281 (strcmp(s, "check") == 0) ||
282 (strcmp(s, "debug") == 0) ||
283 (strcmp(s, "deferred") == 0) ||
284 (strcmp(s, "do") == 0) ||
285 (strcmp(s, "from") == 0) ||
286 (strcmp(s, "if") == 0) ||
287 (strcmp(s, "inspect") == 0) ||
288 (strcmp(s, "once") == 0)
289 )
290 levelCurrent++;
291 if (!lastDeferred && (strcmp(s, "class") == 0))
292 levelCurrent++;
293 if (strcmp(s, "end") == 0)
294 levelCurrent--;
295 lastDeferred = strcmp(s, "deferred") == 0;
296 }
297
298 if (atEOL) {
299 int lev = levelPrev;
300 if (visibleChars == 0)
301 lev |= SC_FOLDLEVELWHITEFLAG;
302 if ((levelCurrent > levelPrev) && (visibleChars > 0))
303 lev |= SC_FOLDLEVELHEADERFLAG;
304 if (lev != styler.LevelAt(lineCurrent)) {
305 styler.SetLevel(lineCurrent, lev);
306 }
307 lineCurrent++;
308 levelPrev = levelCurrent;
309 visibleChars = 0;
310 }
311 if (!isspacechar(ch))
312 visibleChars++;
313 stylePrev = style;
314 }
315 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
316 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
317 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
318 }
319
320 LexerModule lmEiffel(SCLEX_EIFFEL, ColouriseEiffelDoc, "eiffel", FoldEiffelDocIndent);
321 LexerModule lmEiffelkw(SCLEX_EIFFELKW, ColouriseEiffelDoc, "eiffelkw", FoldEiffelDocKeyWords);