]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexMagik.cxx
Compilation fix for wxMSW with wxUSE_MSGBOX_HOOK==0.
[wxWidgets.git] / src / stc / scintilla / lexers / LexMagik.cxx
1 // Scintilla source code edit control
2 /**
3 * @file LexMagik.cxx
4 * Lexer for GE(r) Smallworld(tm) MagikSF
5 */
6 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
30
31 /**
32 * Is it a core character (C isalpha(), exclamation and question mark)
33 *
34 * \param ch The character
35 * \return True if ch is a character, False otherwise
36 */
37 static inline bool IsAlphaCore(int ch) {
38 return (isalpha(ch) || ch == '!' || ch == '?');
39 }
40
41 /**
42 * Is it a character (IsAlphaCore() and underscore)
43 *
44 * \param ch The character
45 * \return True if ch is a character, False otherwise
46 */
47 static inline bool IsAlpha(int ch) {
48 return (IsAlphaCore(ch) || ch == '_');
49 }
50
51 /**
52 * Is it a symbolic character (IsAlpha() and colon)
53 *
54 * \param ch The character
55 * \return True if ch is a character, False otherwise
56 */
57 static inline bool IsAlphaSym(int ch) {
58 return (IsAlpha(ch) || ch == ':');
59 }
60
61 /**
62 * Is it a numerical character (IsAlpha() and 0 - 9)
63 *
64 * \param ch The character
65 * \return True if ch is a character, False otherwise
66 */
67 static inline bool IsAlNum(int ch) {
68 return ((ch >= '0' && ch <= '9') || IsAlpha(ch));
69 }
70
71 /**
72 * Is it a symbolic numerical character (IsAlNum() and colon)
73 *
74 * \param ch The character
75 * \return True if ch is a character, False otherwise
76 */
77 static inline bool IsAlNumSym(int ch) {
78 return (IsAlNum(ch) || ch == ':');
79 }
80
81 /**
82 * The lexer function
83 *
84 * \param startPos Where to start scanning
85 * \param length Where to scan to
86 * \param initStyle The style at the initial point, not used in this folder
87 * \param keywordslists The keywordslists, currently, number 5 is used
88 * \param styler The styler
89 */
90 static void ColouriseMagikDoc(unsigned int startPos, int length, int initStyle,
91 WordList *keywordlists[], Accessor &styler) {
92 styler.StartAt(startPos);
93
94 WordList &keywords = *keywordlists[0];
95 WordList &pragmatics = *keywordlists[1];
96 WordList &containers = *keywordlists[2];
97 WordList &flow = *keywordlists[3];
98 WordList &characters = *keywordlists[4];
99
100 StyleContext sc(startPos, length, initStyle, styler);
101
102
103 for (; sc.More(); sc.Forward()) {
104
105 repeat:
106
107 if(sc.ch == '#') {
108 if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT);
109 else sc.SetState(SCE_MAGIK_COMMENT);
110 for(; sc.More() && !(sc.atLineEnd); sc.Forward());
111 sc.SetState(SCE_MAGIK_DEFAULT);
112 goto repeat;
113 }
114
115 if(sc.ch == '"') {
116 sc.SetState(SCE_MAGIK_STRING);
117
118 if(sc.More())
119 {
120 sc.Forward();
121 for(; sc.More() && sc.ch != '"'; sc.Forward());
122 }
123
124 sc.ForwardSetState(SCE_MAGIK_DEFAULT);
125 goto repeat;
126 }
127
128 // The default state
129 if(sc.state == SCE_MAGIK_DEFAULT) {
130
131 // A certain keyword has been detected
132 if (sc.ch == '_' && (
133 sc.currentPos == 0 || !IsAlNum(sc.chPrev))) {
134 char keyword[50];
135 memset(keyword, '\0', 50);
136
137 for(
138 int scanPosition = 0;
139 scanPosition < 50;
140 scanPosition++) {
141 char keywordChar = static_cast<char>(
142 tolower(styler.SafeGetCharAt(
143 scanPosition +
144 static_cast<int>(sc.currentPos+1), ' ')));
145 if(IsAlpha(keywordChar)) {
146 keyword[scanPosition] = keywordChar;
147 } else {
148 break;
149 }
150 }
151
152 // It is a pragma
153 if(pragmatics.InList(keyword)) {
154 sc.SetState(SCE_MAGIK_PRAGMA);
155 }
156
157 // it is a normal keyword like _local, _self, etc.
158 else if(keywords.InList(keyword)) {
159 sc.SetState(SCE_MAGIK_KEYWORD);
160 }
161
162 // It is a container keyword, such as _method, _proc, etc.
163 else if(containers.InList(keyword)) {
164 sc.SetState(SCE_MAGIK_CONTAINER);
165 }
166
167 // It is a flow keyword, such as _for, _if, _try, etc.
168 else if(flow.InList(keyword)) {
169 sc.SetState(SCE_MAGIK_FLOW);
170 }
171
172 // Interpret as unknown keyword
173 else {
174 sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD);
175 }
176 }
177
178 // Symbolic expression
179 else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) {
180 sc.SetState(SCE_MAGIK_SYMBOL);
181 bool firstTrip = true;
182 for(sc.Forward(); sc.More(); sc.Forward()) {
183 if(firstTrip && IsAlphaSym(sc.ch));
184 else if(!firstTrip && IsAlNumSym(sc.ch));
185 else if(sc.ch == '|') {
186 for(sc.Forward();
187 sc.More() && sc.ch != '|';
188 sc.Forward());
189 }
190 else break;
191
192 firstTrip = false;
193 }
194 sc.SetState(SCE_MAGIK_DEFAULT);
195 goto repeat;
196 }
197
198 // Identifier (label) expression
199 else if(sc.ch == '@') {
200 sc.SetState(SCE_MAGIK_IDENTIFIER);
201 bool firstTrip = true;
202 for(sc.Forward(); sc.More(); sc.Forward()) {
203 if(firstTrip && IsAlphaCore(sc.ch)) {
204 firstTrip = false;
205 }
206 else if(!firstTrip && IsAlpha(sc.ch));
207 else break;
208 }
209 sc.SetState(SCE_MAGIK_DEFAULT);
210 goto repeat;
211 }
212
213 // Start of a character
214 else if(sc.ch == '%') {
215 sc.SetState(SCE_MAGIK_CHARACTER);
216 sc.Forward();
217 char keyword[50];
218 memset(keyword, '\0', 50);
219
220 for(
221 int scanPosition = 0;
222 scanPosition < 50;
223 scanPosition++) {
224 char keywordChar = static_cast<char>(
225 tolower(styler.SafeGetCharAt(
226 scanPosition +
227 static_cast<int>(sc.currentPos), ' ')));
228 if(IsAlpha(keywordChar)) {
229 keyword[scanPosition] = keywordChar;
230 } else {
231 break;
232 }
233 }
234
235 if(characters.InList(keyword)) {
236 sc.Forward(static_cast<int>(strlen(keyword)));
237 } else {
238 sc.Forward();
239 }
240
241 sc.SetState(SCE_MAGIK_DEFAULT);
242 goto repeat;
243 }
244
245 // Operators
246 else if(
247 sc.ch == '>' ||
248 sc.ch == '<' ||
249 sc.ch == '.' ||
250 sc.ch == ',' ||
251 sc.ch == '+' ||
252 sc.ch == '-' ||
253 sc.ch == '/' ||
254 sc.ch == '*' ||
255 sc.ch == '~' ||
256 sc.ch == '$' ||
257 sc.ch == '=') {
258 sc.SetState(SCE_MAGIK_OPERATOR);
259 }
260
261 // Braces
262 else if(sc.ch == '(' || sc.ch == ')') {
263 sc.SetState(SCE_MAGIK_BRACE_BLOCK);
264 }
265
266 // Brackets
267 else if(sc.ch == '{' || sc.ch == '}') {
268 sc.SetState(SCE_MAGIK_BRACKET_BLOCK);
269 }
270
271 // Square Brackets
272 else if(sc.ch == '[' || sc.ch == ']') {
273 sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK);
274 }
275
276
277 }
278
279 // It is an operator
280 else if(
281 sc.state == SCE_MAGIK_OPERATOR ||
282 sc.state == SCE_MAGIK_BRACE_BLOCK ||
283 sc.state == SCE_MAGIK_BRACKET_BLOCK ||
284 sc.state == SCE_MAGIK_SQBRACKET_BLOCK) {
285 sc.SetState(SCE_MAGIK_DEFAULT);
286 goto repeat;
287 }
288
289 // It is the pragma state
290 else if(sc.state == SCE_MAGIK_PRAGMA) {
291 if(!IsAlpha(sc.ch)) {
292 sc.SetState(SCE_MAGIK_DEFAULT);
293 goto repeat;
294 }
295 }
296
297 // It is the keyword state
298 else if(
299 sc.state == SCE_MAGIK_KEYWORD ||
300 sc.state == SCE_MAGIK_CONTAINER ||
301 sc.state == SCE_MAGIK_FLOW ||
302 sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) {
303 if(!IsAlpha(sc.ch)) {
304 sc.SetState(SCE_MAGIK_DEFAULT);
305 goto repeat;
306 }
307 }
308 }
309
310 sc.Complete();
311 }
312
313 /**
314 * The word list description
315 */
316 static const char * const magikWordListDesc[] = {
317 "Accessors (local, global, self, super, thisthread)",
318 "Pragmatic (pragma, private)",
319 "Containers (method, block, proc)",
320 "Flow (if, then, elif, else)",
321 "Characters (space, tab, newline, return)",
322 "Fold Containers (method, proc, block, if, loop)",
323 0};
324
325 /**
326 * This function detects keywords which are able to have a body. Note that it
327 * uses the Fold Containers word description, not the containers description. It
328 * only works when the style at that particular position is set on Containers
329 * or Flow (number 3 or 4).
330 *
331 * \param keywordslist The list of keywords that are scanned, they should only
332 * contain the start keywords, not the end keywords
333 * \param The actual keyword
334 * \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword
335 * 0 otherwise
336 */
337 static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) {
338 if(
339 strlen(keyword) > 3 &&
340 keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') {
341 if (keywordslist.InList(keyword + 3)) {
342 return -1;
343 }
344
345 } else {
346 if(keywordslist.InList(keyword)) {
347 return 1;
348 }
349 }
350
351 return 0;
352 }
353
354 /**
355 * The folding function
356 *
357 * \param startPos Where to start scanning
358 * \param length Where to scan to
359 * \param keywordslists The keywordslists, currently, number 5 is used
360 * \param styler The styler
361 */
362 static void FoldMagikDoc(unsigned int startPos, int length, int,
363 WordList *keywordslists[], Accessor &styler) {
364
365 bool compact = styler.GetPropertyInt("fold.compact") != 0;
366
367 WordList &foldingElements = *keywordslists[5];
368 int endPos = startPos + length;
369 int line = styler.GetLine(startPos);
370 int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;
371 int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
372
373 for(
374 int currentPos = startPos;
375 currentPos < endPos;
376 currentPos++) {
377 char currentState = styler.StyleAt(currentPos);
378 char c = styler.SafeGetCharAt(currentPos, ' ');
379 int prevLine = styler.GetLine(currentPos - 1);
380 line = styler.GetLine(currentPos);
381
382 // Default situation
383 if(prevLine < line) {
384 styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG);
385 flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
386 }
387
388 if(
389 (
390 currentState == SCE_MAGIK_CONTAINER ||
391 currentState == SCE_MAGIK_FLOW
392 ) &&
393 c == '_') {
394
395 char keyword[50];
396 memset(keyword, '\0', 50);
397
398 for(
399 int scanPosition = 0;
400 scanPosition < 50;
401 scanPosition++) {
402 char keywordChar = static_cast<char>(
403 tolower(styler.SafeGetCharAt(
404 scanPosition +
405 currentPos + 1, ' ')));
406 if(IsAlpha(keywordChar)) {
407 keyword[scanPosition] = keywordChar;
408 } else {
409 break;
410 }
411 }
412
413 if(IsFoldingContainer(foldingElements, keyword) > 0) {
414 styler.SetLevel(
415 line,
416 styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
417 level++;
418 } else if(IsFoldingContainer(foldingElements, keyword) < 0) {
419 styler.SetLevel(line, styler.LevelAt(line));
420 level--;
421 }
422 }
423
424 if(
425 compact && (
426 currentState == SCE_MAGIK_BRACE_BLOCK ||
427 currentState == SCE_MAGIK_BRACKET_BLOCK ||
428 currentState == SCE_MAGIK_SQBRACKET_BLOCK)) {
429 if(c == '{' || c == '[' || c == '(') {
430 styler.SetLevel(
431 line,
432 styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
433 level++;
434 } else if(c == '}' || c == ']' || c == ')') {
435 styler.SetLevel(line, styler.LevelAt(line));
436 level--;
437 }
438 }
439 }
440
441 }
442
443 /**
444 * Injecting the module
445 */
446 LexerModule lmMagikSF(
447 SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc);
448