Scintilla 4.0.3
[TortoiseGit.git] / ext / scintilla / lexers / LexModula.cxx
blobdea51d7d365bfae96edc6efaec16cb90364ff7e1
1 // -*- coding: utf-8 -*-
2 // Scintilla source code edit control
3 /**
4 * @file LexModula.cxx
5 * @author Dariusz "DKnoto" KnociĊ„ski
6 * @date 2011/02/03
7 * @brief Lexer for Modula-2/3 documents.
8 */
9 // The License.txt file describes the conditions under which this software may
10 // be distributed.
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <assert.h>
17 #include <ctype.h>
19 #include "ILexer.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
23 #include "PropSetSimple.h"
24 #include "WordList.h"
25 #include "LexAccessor.h"
26 #include "Accessor.h"
27 #include "StyleContext.h"
28 #include "CharacterSet.h"
29 #include "LexerModule.h"
31 using namespace Scintilla;
33 #ifdef DEBUG_LEX_MODULA
34 #define DEBUG_STATE( p, c )\
35 fprintf( stderr, "Unknown state: currentPos = %u, char = '%c'\n", static_cast<unsigned int>(p), c );
36 #else
37 #define DEBUG_STATE( p, c )
38 #endif
40 static inline bool IsDigitOfBase( unsigned ch, unsigned base ) {
41 if( ch < '0' || ch > 'f' ) return false;
42 if( base <= 10 ) {
43 if( ch >= ( '0' + base ) ) return false;
44 } else {
45 if( ch > '9' ) {
46 unsigned nb = base - 10;
47 if( ( ch < 'A' ) || ( ch >= ( 'A' + nb ) ) ) {
48 if( ( ch < 'a' ) || ( ch >= ( 'a' + nb ) ) ) {
49 return false;
54 return true;
57 static inline unsigned IsOperator( StyleContext & sc, WordList & op ) {
58 int i;
59 char s[3];
61 s[0] = sc.ch;
62 s[1] = sc.chNext;
63 s[2] = 0;
64 for( i = 0; i < op.Length(); i++ ) {
65 if( ( strlen( op.WordAt(i) ) == 2 ) &&
66 ( s[0] == op.WordAt(i)[0] && s[1] == op.WordAt(i)[1] ) ) {
67 return 2;
70 s[1] = 0;
71 for( i = 0; i < op.Length(); i++ ) {
72 if( ( strlen( op.WordAt(i) ) == 1 ) &&
73 ( s[0] == op.WordAt(i)[0] ) ) {
74 return 1;
77 return 0;
80 static inline bool IsEOL( Accessor &styler, Sci_PositionU curPos ) {
81 unsigned ch = styler.SafeGetCharAt( curPos );
82 if( ( ch == '\r' && styler.SafeGetCharAt( curPos + 1 ) == '\n' ) ||
83 ( ch == '\n' ) ) {
84 return true;
86 return false;
89 static inline bool checkStatement(
90 Accessor &styler,
91 Sci_Position &curPos,
92 const char *stt, bool spaceAfter = true ) {
93 int len = static_cast<int>(strlen( stt ));
94 int i;
95 for( i = 0; i < len; i++ ) {
96 if( styler.SafeGetCharAt( curPos + i ) != stt[i] ) {
97 return false;
100 if( spaceAfter ) {
101 if( ! isspace( styler.SafeGetCharAt( curPos + i ) ) ) {
102 return false;
105 curPos += ( len - 1 );
106 return true;
109 static inline bool checkEndSemicolon(
110 Accessor &styler,
111 Sci_Position &curPos, Sci_Position endPos )
113 const char *stt = "END";
114 int len = static_cast<int>(strlen( stt ));
115 int i;
116 for( i = 0; i < len; i++ ) {
117 if( styler.SafeGetCharAt( curPos + i ) != stt[i] ) {
118 return false;
121 while( isspace( styler.SafeGetCharAt( curPos + i ) ) ) {
122 i++;
123 if( ( curPos + i ) >= endPos ) return false;
125 if( styler.SafeGetCharAt( curPos + i ) != ';' ) {
126 return false;
128 curPos += ( i - 1 );
129 return true;
132 static inline bool checkKeyIdentOper(
134 Accessor &styler,
135 Sci_Position &curPos, Sci_Position endPos,
136 const char *stt, const char etk ) {
137 Sci_Position newPos = curPos;
138 if( ! checkStatement( styler, newPos, stt ) )
139 return false;
140 newPos++;
141 if( newPos >= endPos )
142 return false;
143 if( ! isspace( styler.SafeGetCharAt( newPos ) ) )
144 return false;
145 newPos++;
146 if( newPos >= endPos )
147 return false;
148 while( isspace( styler.SafeGetCharAt( newPos ) ) ) {
149 newPos++;
150 if( newPos >= endPos )
151 return false;
153 if( ! isalpha( styler.SafeGetCharAt( newPos ) ) )
154 return false;
155 newPos++;
156 if( newPos >= endPos )
157 return false;
158 char ch;
159 ch = styler.SafeGetCharAt( newPos );
160 while( isalpha( ch ) || isdigit( ch ) || ch == '_' ) {
161 newPos++;
162 if( newPos >= endPos ) return false;
163 ch = styler.SafeGetCharAt( newPos );
165 while( isspace( styler.SafeGetCharAt( newPos ) ) ) {
166 newPos++;
167 if( newPos >= endPos ) return false;
169 if( styler.SafeGetCharAt( newPos ) != etk )
170 return false;
171 curPos = newPos;
172 return true;
175 static void FoldModulaDoc( Sci_PositionU startPos,
176 Sci_Position length,
177 int , WordList *[],
178 Accessor &styler)
180 Sci_Position curLine = styler.GetLine(startPos);
181 int curLevel = SC_FOLDLEVELBASE;
182 Sci_Position endPos = startPos + length;
183 if( curLine > 0 )
184 curLevel = styler.LevelAt( curLine - 1 ) >> 16;
185 Sci_Position curPos = startPos;
186 int style = styler.StyleAt( curPos );
187 int visChars = 0;
188 int nextLevel = curLevel;
190 while( curPos < endPos ) {
191 if( ! isspace( styler.SafeGetCharAt( curPos ) ) ) visChars++;
193 switch( style ) {
194 case SCE_MODULA_COMMENT:
195 if( checkStatement( styler, curPos, "(*" ) )
196 nextLevel++;
197 else
198 if( checkStatement( styler, curPos, "*)" ) )
199 nextLevel--;
200 break;
202 case SCE_MODULA_DOXYCOMM:
203 if( checkStatement( styler, curPos, "(**", false ) )
204 nextLevel++;
205 else
206 if( checkStatement( styler, curPos, "*)" ) )
207 nextLevel--;
208 break;
210 case SCE_MODULA_KEYWORD:
211 if( checkStatement( styler, curPos, "IF" ) )
212 nextLevel++;
213 else
214 if( checkStatement( styler, curPos, "BEGIN" ) )
215 nextLevel++;
216 else
217 if( checkStatement( styler, curPos, "TRY" ) )
218 nextLevel++;
219 else
220 if( checkStatement( styler, curPos, "LOOP" ) )
221 nextLevel++;
222 else
223 if( checkStatement( styler, curPos, "FOR" ) )
224 nextLevel++;
225 else
226 if( checkStatement( styler, curPos, "WHILE" ) )
227 nextLevel++;
228 else
229 if( checkStatement( styler, curPos, "REPEAT" ) )
230 nextLevel++;
231 else
232 if( checkStatement( styler, curPos, "UNTIL" ) )
233 nextLevel--;
234 else
235 if( checkStatement( styler, curPos, "WITH" ) )
236 nextLevel++;
237 else
238 if( checkStatement( styler, curPos, "CASE" ) )
239 nextLevel++;
240 else
241 if( checkStatement( styler, curPos, "TYPECASE" ) )
242 nextLevel++;
243 else
244 if( checkStatement( styler, curPos, "LOCK" ) )
245 nextLevel++;
246 else
247 if( checkKeyIdentOper( styler, curPos, endPos, "PROCEDURE", '(' ) )
248 nextLevel++;
249 else
250 if( checkKeyIdentOper( styler, curPos, endPos, "END", ';' ) ) {
251 Sci_Position cln = curLine;
252 int clv_old = curLevel;
253 Sci_Position pos;
254 char ch;
255 int clv_new;
256 while( cln > 0 ) {
257 clv_new = styler.LevelAt( cln - 1 ) >> 16;
258 if( clv_new < clv_old ) {
259 nextLevel--;
260 pos = styler.LineStart( cln );
261 while( ( ch = styler.SafeGetCharAt( pos ) ) != '\n' ) {
262 if( ch == 'P' ) {
263 if( styler.StyleAt(pos) == SCE_MODULA_KEYWORD ) {
264 if( checkKeyIdentOper( styler, pos, endPos,
265 "PROCEDURE", '(' ) ) {
266 break;
270 pos++;
272 clv_old = clv_new;
274 cln--;
277 else
278 if( checkKeyIdentOper( styler, curPos, endPos, "END", '.' ) )
279 nextLevel--;
280 else
281 if( checkEndSemicolon( styler, curPos, endPos ) )
282 nextLevel--;
283 else {
284 while( styler.StyleAt( curPos + 1 ) == SCE_MODULA_KEYWORD )
285 curPos++;
287 break;
289 default:
290 break;
293 if( IsEOL( styler, curPos ) || ( curPos == endPos - 1 ) ) {
294 int efectiveLevel = curLevel | nextLevel << 16;
295 if( visChars == 0 )
296 efectiveLevel |= SC_FOLDLEVELWHITEFLAG;
297 if( curLevel < nextLevel )
298 efectiveLevel |= SC_FOLDLEVELHEADERFLAG;
299 if( efectiveLevel != styler.LevelAt(curLine) ) {
300 styler.SetLevel(curLine, efectiveLevel );
302 curLine++;
303 curLevel = nextLevel;
304 if( IsEOL( styler, curPos ) && ( curPos == endPos - 1 ) ) {
305 styler.SetLevel( curLine, ( curLevel | curLevel << 16)
306 | SC_FOLDLEVELWHITEFLAG);
308 visChars = 0;
310 curPos++;
311 style = styler.StyleAt( curPos );
315 static inline bool skipWhiteSpaces( StyleContext & sc ) {
316 while( isspace( sc.ch ) ) {
317 sc.SetState( SCE_MODULA_DEFAULT );
318 if( sc.More() )
319 sc.Forward();
320 else
321 return false;
323 return true;
326 static void ColouriseModulaDoc( Sci_PositionU startPos,
327 Sci_Position length,
328 int initStyle,
329 WordList *wl[],
330 Accessor &styler ) {
331 WordList& keyWords = *wl[0];
332 WordList& reservedWords = *wl[1];
333 WordList& operators = *wl[2];
334 WordList& pragmaWords = *wl[3];
335 WordList& escapeCodes = *wl[4];
336 WordList& doxyKeys = *wl[5];
338 const int BUFLEN = 128;
340 char buf[BUFLEN];
341 int i, kl;
343 Sci_Position charPos = 0;
345 StyleContext sc( startPos, length, initStyle, styler );
347 while( sc.More() ) {
348 switch( sc.state ) {
349 case SCE_MODULA_DEFAULT:
350 if( ! skipWhiteSpaces( sc ) ) break;
352 if( sc.ch == '(' && sc.chNext == '*' ) {
353 if( sc.GetRelative(2) == '*' ) {
354 sc.SetState( SCE_MODULA_DOXYCOMM );
355 sc.Forward();
356 } else {
357 sc.SetState( SCE_MODULA_COMMENT );
359 sc.Forward();
361 else
362 if( isalpha( sc.ch ) ) {
363 if( isupper( sc.ch ) && isupper( sc.chNext ) ) {
364 for( i = 0; i < BUFLEN - 1; i++ ) {
365 buf[i] = sc.GetRelative(i);
366 if( !isalpha( buf[i] ) && !(buf[i] == '_') )
367 break;
369 kl = i;
370 buf[kl] = 0;
372 if( keyWords.InList( buf ) ) {
373 sc.SetState( SCE_MODULA_KEYWORD );
374 sc.Forward( kl );
375 sc.SetState( SCE_MODULA_DEFAULT );
376 continue;
378 else
379 if( reservedWords.InList( buf ) ) {
380 sc.SetState( SCE_MODULA_RESERVED );
381 sc.Forward( kl );
382 sc.SetState( SCE_MODULA_DEFAULT );
383 continue;
384 } else {
385 /** check procedure identifier */
387 } else {
388 for( i = 0; i < BUFLEN - 1; i++ ) {
389 buf[i] = sc.GetRelative(i);
390 if( !isalpha( buf[i] ) &&
391 !isdigit( buf[i] ) &&
392 !(buf[i] == '_') )
393 break;
395 kl = i;
396 buf[kl] = 0;
398 sc.SetState( SCE_MODULA_DEFAULT );
399 sc.Forward( kl );
400 continue;
403 else
404 if( isdigit( sc.ch ) ) {
405 sc.SetState( SCE_MODULA_NUMBER );
406 continue;
408 else
409 if( sc.ch == '\"' ) {
410 sc.SetState( SCE_MODULA_STRING );
412 else
413 if( sc.ch == '\'' ) {
414 charPos = sc.currentPos;
415 sc.SetState( SCE_MODULA_CHAR );
417 else
418 if( sc.ch == '<' && sc.chNext == '*' ) {
419 sc.SetState( SCE_MODULA_PRAGMA );
420 sc.Forward();
421 } else {
422 unsigned len = IsOperator( sc, operators );
423 if( len > 0 ) {
424 sc.SetState( SCE_MODULA_OPERATOR );
425 sc.Forward( len );
426 sc.SetState( SCE_MODULA_DEFAULT );
427 continue;
428 } else {
429 DEBUG_STATE( sc.currentPos, sc.ch );
432 break;
434 case SCE_MODULA_COMMENT:
435 if( sc.ch == '*' && sc.chNext == ')' ) {
436 sc.Forward( 2 );
437 sc.SetState( SCE_MODULA_DEFAULT );
438 continue;
440 break;
442 case SCE_MODULA_DOXYCOMM:
443 switch( sc.ch ) {
444 case '*':
445 if( sc.chNext == ')' ) {
446 sc.Forward( 2 );
447 sc.SetState( SCE_MODULA_DEFAULT );
448 continue;
450 break;
452 case '@':
453 if( islower( sc.chNext ) ) {
454 for( i = 0; i < BUFLEN - 1; i++ ) {
455 buf[i] = sc.GetRelative(i+1);
456 if( isspace( buf[i] ) ) break;
458 buf[i] = 0;
459 kl = i;
461 if( doxyKeys.InList( buf ) ) {
462 sc.SetState( SCE_MODULA_DOXYKEY );
463 sc.Forward( kl + 1 );
464 sc.SetState( SCE_MODULA_DOXYCOMM );
467 break;
469 default:
470 break;
472 break;
474 case SCE_MODULA_NUMBER:
476 buf[0] = sc.ch;
477 for( i = 1; i < BUFLEN - 1; i++ ) {
478 buf[i] = sc.GetRelative(i);
479 if( ! isdigit( buf[i] ) )
480 break;
482 kl = i;
483 buf[kl] = 0;
485 switch( sc.GetRelative(kl) ) {
486 case '_':
488 int base = atoi( buf );
489 if( base < 2 || base > 16 ) {
490 sc.SetState( SCE_MODULA_BADSTR );
491 } else {
492 int imax;
494 kl++;
495 for( i = 0; i < BUFLEN - 1; i++ ) {
496 buf[i] = sc.GetRelative(kl+i);
497 if( ! IsDigitOfBase( buf[i], 16 ) ) {
498 break;
501 imax = i;
502 for( i = 0; i < imax; i++ ) {
503 if( ! IsDigitOfBase( buf[i], base ) ) {
504 sc.SetState( SCE_MODULA_BADSTR );
505 break;
508 kl += imax;
510 sc.SetState( SCE_MODULA_BASENUM );
511 for( i = 0; i < kl; i++ ) {
512 sc.Forward();
514 sc.SetState( SCE_MODULA_DEFAULT );
515 continue;
517 break;
519 case '.':
520 if( sc.GetRelative(kl+1) == '.' ) {
521 kl--;
522 for( i = 0; i < kl; i++ ) {
523 sc.Forward();
525 sc.Forward();
526 sc.SetState( SCE_MODULA_DEFAULT );
527 continue;
528 } else {
529 bool doNext = false;
531 kl++;
533 buf[0] = sc.GetRelative(kl);
534 if( isdigit( buf[0] ) ) {
535 for( i = 0;; i++ ) {
536 if( !isdigit(sc.GetRelative(kl+i)) )
537 break;
539 kl += i;
540 buf[0] = sc.GetRelative(kl);
542 switch( buf[0] )
544 case 'E':
545 case 'e':
546 case 'D':
547 case 'd':
548 case 'X':
549 case 'x':
550 kl++;
551 buf[0] = sc.GetRelative(kl);
552 if( buf[0] == '-' || buf[0] == '+' ) {
553 kl++;
555 buf[0] = sc.GetRelative(kl);
556 if( isdigit( buf[0] ) ) {
557 for( i = 0;; i++ ) {
558 if( !isdigit(sc.GetRelative(kl+i)) ) {
559 buf[0] = sc.GetRelative(kl+i);
560 break;
563 kl += i;
564 doNext = true;
565 } else {
566 sc.SetState( SCE_MODULA_BADSTR );
568 break;
570 default:
571 doNext = true;
572 break;
574 } else {
575 sc.SetState( SCE_MODULA_BADSTR );
578 if( doNext ) {
579 if( ! isspace( buf[0] ) &&
580 buf[0] != ')' &&
581 buf[0] != '>' &&
582 buf[0] != '<' &&
583 buf[0] != '=' &&
584 buf[0] != '#' &&
585 buf[0] != '+' &&
586 buf[0] != '-' &&
587 buf[0] != '*' &&
588 buf[0] != '/' &&
589 buf[0] != ',' &&
590 buf[0] != ';'
592 sc.SetState( SCE_MODULA_BADSTR );
593 } else {
594 kl--;
598 sc.SetState( SCE_MODULA_FLOAT );
599 for( i = 0; i < kl; i++ ) {
600 sc.Forward();
602 sc.SetState( SCE_MODULA_DEFAULT );
603 continue;
604 break;
606 default:
607 for( i = 0; i < kl; i++ ) {
608 sc.Forward();
610 break;
612 sc.SetState( SCE_MODULA_DEFAULT );
613 continue;
615 break;
617 case SCE_MODULA_STRING:
618 if( sc.ch == '\"' ) {
619 sc.Forward();
620 sc.SetState( SCE_MODULA_DEFAULT );
621 continue;
622 } else {
623 if( sc.ch == '\\' ) {
624 i = 1;
625 if( IsDigitOfBase( sc.chNext, 8 ) ) {
626 for( i = 1; i < BUFLEN - 1; i++ ) {
627 if( ! IsDigitOfBase(sc.GetRelative(i+1), 8 ) )
628 break;
630 if( i == 3 ) {
631 sc.SetState( SCE_MODULA_STRSPEC );
632 } else {
633 sc.SetState( SCE_MODULA_BADSTR );
635 } else {
636 buf[0] = sc.chNext;
637 buf[1] = 0;
639 if( escapeCodes.InList( buf ) ) {
640 sc.SetState( SCE_MODULA_STRSPEC );
641 } else {
642 sc.SetState( SCE_MODULA_BADSTR );
645 sc.Forward(i+1);
646 sc.SetState( SCE_MODULA_STRING );
647 continue;
650 break;
652 case SCE_MODULA_CHAR:
653 if( sc.ch == '\'' ) {
654 sc.Forward();
655 sc.SetState( SCE_MODULA_DEFAULT );
656 continue;
658 else
659 if( ( sc.currentPos - charPos ) == 1 ) {
660 if( sc.ch == '\\' ) {
661 i = 1;
662 if( IsDigitOfBase( sc.chNext, 8 ) ) {
663 for( i = 1; i < BUFLEN - 1; i++ ) {
664 if( ! IsDigitOfBase(sc.GetRelative(i+1), 8 ) )
665 break;
667 if( i == 3 ) {
668 sc.SetState( SCE_MODULA_CHARSPEC );
669 } else {
670 sc.SetState( SCE_MODULA_BADSTR );
672 } else {
673 buf[0] = sc.chNext;
674 buf[1] = 0;
676 if( escapeCodes.InList( buf ) ) {
677 sc.SetState( SCE_MODULA_CHARSPEC );
678 } else {
679 sc.SetState( SCE_MODULA_BADSTR );
682 sc.Forward(i+1);
683 sc.SetState( SCE_MODULA_CHAR );
684 continue;
686 } else {
687 sc.SetState( SCE_MODULA_BADSTR );
688 sc.Forward();
689 sc.SetState( SCE_MODULA_CHAR );
690 continue;
692 break;
694 case SCE_MODULA_PRAGMA:
695 if( sc.ch == '*' && sc.chNext == '>' ) {
696 sc.Forward();
697 sc.Forward();
698 sc.SetState( SCE_MODULA_DEFAULT );
699 continue;
701 else
702 if( isupper( sc.ch ) && isupper( sc.chNext ) ) {
703 buf[0] = sc.ch;
704 buf[1] = sc.chNext;
705 for( i = 2; i < BUFLEN - 1; i++ ) {
706 buf[i] = sc.GetRelative(i);
707 if( !isupper( buf[i] ) )
708 break;
710 kl = i;
711 buf[kl] = 0;
712 if( pragmaWords.InList( buf ) ) {
713 sc.SetState( SCE_MODULA_PRGKEY );
714 sc.Forward( kl );
715 sc.SetState( SCE_MODULA_PRAGMA );
716 continue;
719 break;
721 default:
722 break;
724 sc.Forward();
726 sc.Complete();
729 static const char *const modulaWordListDesc[] =
731 "Keywords",
732 "ReservedKeywords",
733 "Operators",
734 "PragmaKeyswords",
735 "EscapeCodes",
736 "DoxygeneKeywords",
740 LexerModule lmModula( SCLEX_MODULA, ColouriseModulaDoc, "modula", FoldModulaDoc,
741 modulaWordListDesc);