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