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