]>
Commit | Line | Data |
---|---|---|
1 | // Scintilla source code edit control | |
2 | /** @file LexOpal.cxx | |
3 | ** Lexer for OPAL (functional language similar to Haskell) | |
4 | ** Written by Sebastian Pipping <webmaster@hartwork.org> | |
5 | **/ | |
6 | ||
7 | #include <stdlib.h> | |
8 | #include <string.h> | |
9 | #include <stdio.h> | |
10 | #include <stdarg.h> | |
11 | #include <assert.h> | |
12 | #include <ctype.h> | |
13 | ||
14 | #include "ILexer.h" | |
15 | #include "Scintilla.h" | |
16 | #include "SciLexer.h" | |
17 | ||
18 | #include "WordList.h" | |
19 | #include "LexAccessor.h" | |
20 | #include "Accessor.h" | |
21 | #include "StyleContext.h" | |
22 | #include "CharacterSet.h" | |
23 | #include "LexerModule.h" | |
24 | ||
25 | #ifdef SCI_NAMESPACE | |
26 | using namespace Scintilla; | |
27 | #endif | |
28 | ||
29 | inline static void getRange( unsigned int start, unsigned int end, Accessor & styler, char * s, unsigned int len ) | |
30 | { | |
31 | unsigned int i = 0; | |
32 | while( ( i < end - start + 1 ) && ( i < len - 1 ) ) | |
33 | { | |
34 | s[i] = static_cast<char>( styler[ start + i ] ); | |
35 | i++; | |
36 | } | |
37 | s[ i ] = '\0'; | |
38 | } | |
39 | ||
40 | inline bool HandleString( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) | |
41 | { | |
42 | char ch; | |
43 | ||
44 | // Wait for string to close | |
45 | bool even_backslash_count = true; // Without gaps in between | |
46 | cur++; // Skip initial quote | |
47 | for( ; ; ) | |
48 | { | |
49 | if( cur >= one_too_much ) | |
50 | { | |
51 | styler.ColourTo( cur - 1, SCE_OPAL_STRING ); | |
52 | return false; // STOP | |
53 | } | |
54 | ||
55 | ch = styler.SafeGetCharAt( cur ); | |
56 | if( ( ch == '\015' ) || ( ch == '\012' ) ) // Deny multi-line strings | |
57 | { | |
58 | styler.ColourTo( cur - 1, SCE_OPAL_STRING ); | |
59 | styler.StartSegment( cur ); | |
60 | return true; | |
61 | } | |
62 | else | |
63 | { | |
64 | if( even_backslash_count ) | |
65 | { | |
66 | if( ch == '"' ) | |
67 | { | |
68 | styler.ColourTo( cur, SCE_OPAL_STRING ); | |
69 | cur++; | |
70 | if( cur >= one_too_much ) | |
71 | { | |
72 | return false; // STOP | |
73 | } | |
74 | else | |
75 | { | |
76 | styler.StartSegment( cur ); | |
77 | return true; | |
78 | } | |
79 | } | |
80 | else if( ch == '\\' ) | |
81 | { | |
82 | even_backslash_count = false; | |
83 | } | |
84 | } | |
85 | else | |
86 | { | |
87 | even_backslash_count = true; | |
88 | } | |
89 | } | |
90 | ||
91 | cur++; | |
92 | } | |
93 | } | |
94 | ||
95 | inline bool HandleCommentBlock( unsigned int & cur, unsigned int one_too_much, Accessor & styler, bool could_fail ) | |
96 | { | |
97 | char ch; | |
98 | ||
99 | if( could_fail ) | |
100 | { | |
101 | cur++; | |
102 | if( cur >= one_too_much ) | |
103 | { | |
104 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
105 | return false; // STOP | |
106 | } | |
107 | ||
108 | ch = styler.SafeGetCharAt( cur ); | |
109 | if( ch != '*' ) | |
110 | { | |
111 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
112 | styler.StartSegment( cur ); | |
113 | return true; | |
114 | } | |
115 | } | |
116 | ||
117 | // Wait for comment close | |
118 | cur++; | |
119 | bool star_found = false; | |
120 | for( ; ; ) | |
121 | { | |
122 | if( cur >= one_too_much ) | |
123 | { | |
124 | styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_BLOCK ); | |
125 | return false; // STOP | |
126 | } | |
127 | ||
128 | ch = styler.SafeGetCharAt( cur ); | |
129 | if( star_found ) | |
130 | { | |
131 | if( ch == '/' ) | |
132 | { | |
133 | styler.ColourTo( cur, SCE_OPAL_COMMENT_BLOCK ); | |
134 | cur++; | |
135 | if( cur >= one_too_much ) | |
136 | { | |
137 | return false; // STOP | |
138 | } | |
139 | else | |
140 | { | |
141 | styler.StartSegment( cur ); | |
142 | return true; | |
143 | } | |
144 | } | |
145 | else if( ch != '*' ) | |
146 | { | |
147 | star_found = false; | |
148 | } | |
149 | } | |
150 | else if( ch == '*' ) | |
151 | { | |
152 | star_found = true; | |
153 | } | |
154 | cur++; | |
155 | } | |
156 | } | |
157 | ||
158 | inline bool HandleCommentLine( unsigned int & cur, unsigned int one_too_much, Accessor & styler, bool could_fail ) | |
159 | { | |
160 | char ch; | |
161 | ||
162 | if( could_fail ) | |
163 | { | |
164 | cur++; | |
165 | if( cur >= one_too_much ) | |
166 | { | |
167 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
168 | return false; // STOP | |
169 | } | |
170 | ||
171 | ch = styler.SafeGetCharAt( cur ); | |
172 | if( ch != '-' ) | |
173 | { | |
174 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
175 | styler.StartSegment( cur ); | |
176 | return true; | |
177 | } | |
178 | ||
179 | cur++; | |
180 | if( cur >= one_too_much ) | |
181 | { | |
182 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
183 | return false; // STOP | |
184 | } | |
185 | ||
186 | ch = styler.SafeGetCharAt( cur ); | |
187 | if( ( ch != ' ' ) && ( ch != '\t' ) ) | |
188 | { | |
189 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
190 | styler.StartSegment( cur ); | |
191 | return true; | |
192 | } | |
193 | } | |
194 | ||
195 | // Wait for end of line | |
196 | bool fifteen_found = false; | |
197 | ||
198 | for( ; ; ) | |
199 | { | |
200 | cur++; | |
201 | ||
202 | if( cur >= one_too_much ) | |
203 | { | |
204 | styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); | |
205 | return false; // STOP | |
206 | } | |
207 | ||
208 | ch = styler.SafeGetCharAt( cur ); | |
209 | if( fifteen_found ) | |
210 | { | |
211 | /* | |
212 | if( ch == '\012' ) | |
213 | { | |
214 | // One newline on Windows (015, 012) | |
215 | } | |
216 | else | |
217 | { | |
218 | // One newline on MAC (015) and another char | |
219 | } | |
220 | */ | |
221 | cur--; | |
222 | styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); | |
223 | styler.StartSegment( cur ); | |
224 | return true; | |
225 | } | |
226 | else | |
227 | { | |
228 | if( ch == '\015' ) | |
229 | { | |
230 | fifteen_found = true; | |
231 | } | |
232 | else if( ch == '\012' ) | |
233 | { | |
234 | // One newline on Linux (012) | |
235 | styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); | |
236 | styler.StartSegment( cur ); | |
237 | return true; | |
238 | } | |
239 | } | |
240 | } | |
241 | } | |
242 | ||
243 | inline bool HandlePar( unsigned int & cur, Accessor & styler ) | |
244 | { | |
245 | styler.ColourTo( cur, SCE_OPAL_PAR ); | |
246 | ||
247 | cur++; | |
248 | ||
249 | styler.StartSegment( cur ); | |
250 | return true; | |
251 | } | |
252 | ||
253 | inline bool HandleSpace( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) | |
254 | { | |
255 | char ch; | |
256 | ||
257 | cur++; | |
258 | for( ; ; ) | |
259 | { | |
260 | if( cur >= one_too_much ) | |
261 | { | |
262 | styler.ColourTo( cur - 1, SCE_OPAL_SPACE ); | |
263 | return false; | |
264 | } | |
265 | ||
266 | ch = styler.SafeGetCharAt( cur ); | |
267 | switch( ch ) | |
268 | { | |
269 | case ' ': | |
270 | case '\t': | |
271 | case '\015': | |
272 | case '\012': | |
273 | cur++; | |
274 | break; | |
275 | ||
276 | default: | |
277 | styler.ColourTo( cur - 1, SCE_OPAL_SPACE ); | |
278 | styler.StartSegment( cur ); | |
279 | return true; | |
280 | } | |
281 | } | |
282 | } | |
283 | ||
284 | inline bool HandleInteger( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) | |
285 | { | |
286 | char ch; | |
287 | ||
288 | for( ; ; ) | |
289 | { | |
290 | cur++; | |
291 | if( cur >= one_too_much ) | |
292 | { | |
293 | styler.ColourTo( cur - 1, SCE_OPAL_INTEGER ); | |
294 | return false; // STOP | |
295 | } | |
296 | ||
297 | ch = styler.SafeGetCharAt( cur ); | |
298 | if( !( isascii( ch ) && isdigit( ch ) ) ) | |
299 | { | |
300 | styler.ColourTo( cur - 1, SCE_OPAL_INTEGER ); | |
301 | styler.StartSegment( cur ); | |
302 | return true; | |
303 | } | |
304 | } | |
305 | } | |
306 | ||
307 | inline bool HandleWord( unsigned int & cur, unsigned int one_too_much, Accessor & styler, WordList * keywordlists[] ) | |
308 | { | |
309 | char ch; | |
310 | const unsigned int beg = cur; | |
311 | ||
312 | cur++; | |
313 | for( ; ; ) | |
314 | { | |
315 | ch = styler.SafeGetCharAt( cur ); | |
316 | if( ( ch != '_' ) && ( ch != '-' ) && | |
317 | !( isascii( ch ) && ( islower( ch ) || isupper( ch ) || isdigit( ch ) ) ) ) break; | |
318 | ||
319 | cur++; | |
320 | if( cur >= one_too_much ) | |
321 | { | |
322 | break; | |
323 | } | |
324 | } | |
325 | ||
326 | const int ide_len = cur - beg + 1; | |
327 | char * ide = new char[ ide_len ]; | |
328 | getRange( beg, cur, styler, ide, ide_len ); | |
329 | ||
330 | WordList & keywords = *keywordlists[ 0 ]; | |
331 | WordList & classwords = *keywordlists[ 1 ]; | |
332 | ||
333 | if( keywords.InList( ide ) ) // Keyword | |
334 | { | |
335 | delete [] ide; | |
336 | ||
337 | styler.ColourTo( cur - 1, SCE_OPAL_KEYWORD ); | |
338 | if( cur >= one_too_much ) | |
339 | { | |
340 | return false; // STOP | |
341 | } | |
342 | else | |
343 | { | |
344 | styler.StartSegment( cur ); | |
345 | return true; | |
346 | } | |
347 | } | |
348 | else if( classwords.InList( ide ) ) // Sort | |
349 | { | |
350 | delete [] ide; | |
351 | ||
352 | styler.ColourTo( cur - 1, SCE_OPAL_SORT ); | |
353 | if( cur >= one_too_much ) | |
354 | { | |
355 | return false; // STOP | |
356 | } | |
357 | else | |
358 | { | |
359 | styler.StartSegment( cur ); | |
360 | return true; | |
361 | } | |
362 | } | |
363 | else if( !strcmp( ide, "true" ) || !strcmp( ide, "false" ) ) // Bool const | |
364 | { | |
365 | delete [] ide; | |
366 | ||
367 | styler.ColourTo( cur - 1, SCE_OPAL_BOOL_CONST ); | |
368 | if( cur >= one_too_much ) | |
369 | { | |
370 | return false; // STOP | |
371 | } | |
372 | else | |
373 | { | |
374 | styler.StartSegment( cur ); | |
375 | return true; | |
376 | } | |
377 | } | |
378 | else // Unknown keyword | |
379 | { | |
380 | delete [] ide; | |
381 | ||
382 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
383 | if( cur >= one_too_much ) | |
384 | { | |
385 | return false; // STOP | |
386 | } | |
387 | else | |
388 | { | |
389 | styler.StartSegment( cur ); | |
390 | return true; | |
391 | } | |
392 | } | |
393 | ||
394 | } | |
395 | ||
396 | inline bool HandleSkip( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) | |
397 | { | |
398 | cur++; | |
399 | styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); | |
400 | if( cur >= one_too_much ) | |
401 | { | |
402 | return false; // STOP | |
403 | } | |
404 | else | |
405 | { | |
406 | styler.StartSegment( cur ); | |
407 | return true; | |
408 | } | |
409 | } | |
410 | ||
411 | static void ColouriseOpalDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor & styler ) | |
412 | { | |
413 | styler.StartAt( startPos ); | |
414 | styler.StartSegment( startPos ); | |
415 | ||
416 | unsigned int & cur = startPos; | |
417 | const unsigned int one_too_much = startPos + length; | |
418 | ||
419 | int state = initStyle; | |
420 | ||
421 | for( ; ; ) | |
422 | { | |
423 | switch( state ) | |
424 | { | |
425 | case SCE_OPAL_KEYWORD: | |
426 | case SCE_OPAL_SORT: | |
427 | if( !HandleWord( cur, one_too_much, styler, keywordlists ) ) return; | |
428 | state = SCE_OPAL_DEFAULT; | |
429 | break; | |
430 | ||
431 | case SCE_OPAL_INTEGER: | |
432 | if( !HandleInteger( cur, one_too_much, styler ) ) return; | |
433 | state = SCE_OPAL_DEFAULT; | |
434 | break; | |
435 | ||
436 | case SCE_OPAL_COMMENT_BLOCK: | |
437 | if( !HandleCommentBlock( cur, one_too_much, styler, false ) ) return; | |
438 | state = SCE_OPAL_DEFAULT; | |
439 | break; | |
440 | ||
441 | case SCE_OPAL_COMMENT_LINE: | |
442 | if( !HandleCommentLine( cur, one_too_much, styler, false ) ) return; | |
443 | state = SCE_OPAL_DEFAULT; | |
444 | break; | |
445 | ||
446 | case SCE_OPAL_STRING: | |
447 | if( !HandleString( cur, one_too_much, styler ) ) return; | |
448 | state = SCE_OPAL_DEFAULT; | |
449 | break; | |
450 | ||
451 | default: // SCE_OPAL_DEFAULT: | |
452 | { | |
453 | char ch = styler.SafeGetCharAt( cur ); | |
454 | ||
455 | switch( ch ) | |
456 | { | |
457 | // String | |
458 | case '"': | |
459 | if( !HandleString( cur, one_too_much, styler ) ) return; | |
460 | break; | |
461 | ||
462 | // Comment block | |
463 | case '/': | |
464 | if( !HandleCommentBlock( cur, one_too_much, styler, true ) ) return; | |
465 | break; | |
466 | ||
467 | // Comment line | |
468 | case '-': | |
469 | if( !HandleCommentLine( cur, one_too_much, styler, true ) ) return; | |
470 | break; | |
471 | ||
472 | // Par | |
473 | case '(': | |
474 | case ')': | |
475 | case '[': | |
476 | case ']': | |
477 | case '{': | |
478 | case '}': | |
479 | if( !HandlePar( cur, styler ) ) return; | |
480 | break; | |
481 | ||
482 | // Whitespace | |
483 | case ' ': | |
484 | case '\t': | |
485 | case '\015': | |
486 | case '\012': | |
487 | if( !HandleSpace( cur, one_too_much, styler ) ) return; | |
488 | break; | |
489 | ||
490 | default: | |
491 | { | |
492 | // Integer | |
493 | if( isascii( ch ) && isdigit( ch ) ) | |
494 | { | |
495 | if( !HandleInteger( cur, one_too_much, styler ) ) return; | |
496 | } | |
497 | ||
498 | // Keyword | |
499 | else if( isascii( ch ) && ( islower( ch ) || isupper( ch ) ) ) | |
500 | { | |
501 | if( !HandleWord( cur, one_too_much, styler, keywordlists ) ) return; | |
502 | ||
503 | } | |
504 | ||
505 | // Skip | |
506 | else | |
507 | { | |
508 | if( !HandleSkip( cur, one_too_much, styler ) ) return; | |
509 | } | |
510 | } | |
511 | } | |
512 | ||
513 | break; | |
514 | } | |
515 | } | |
516 | } | |
517 | } | |
518 | ||
519 | static const char * const opalWordListDesc[] = { | |
520 | "Keywords", | |
521 | "Sorts", | |
522 | 0 | |
523 | }; | |
524 | ||
525 | LexerModule lmOpal(SCLEX_OPAL, ColouriseOpalDoc, "opal", NULL, opalWordListDesc); |