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