1 // -*- coding: utf-8 -*-
2 // Scintilla source code edit control
5 * @author Dariusz "DKnoto" KnociĊski
7 * @brief Lexer for Modula-2/3 documents.
9 // The License.txt file describes the conditions under which this software may
20 #include "Scintilla.h"
23 #include "PropSetSimple.h"
25 #include "LexAccessor.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 );
37 #define DEBUG_STATE( p, c )
40 static inline bool IsDigitOfBase( unsigned ch
, unsigned base
) {
41 if( ch
< '0' || ch
> 'f' ) return false;
43 if( ch
>= ( '0' + base
) ) return false;
46 unsigned nb
= base
- 10;
47 if( ( ch
< 'A' ) || ( ch
>= ( 'A' + nb
) ) ) {
48 if( ( ch
< 'a' ) || ( ch
>= ( 'a' + nb
) ) ) {
57 static inline unsigned IsOperator( StyleContext
& sc
, WordList
& op
) {
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] ) ) {
71 for( i
= 0; i
< op
.Length(); i
++ ) {
72 if( ( strlen( op
.WordAt(i
) ) == 1 ) &&
73 ( s
[0] == op
.WordAt(i
)[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' ) ||
89 static inline bool checkStatement(
92 const char *stt
, bool spaceAfter
= true ) {
93 int len
= static_cast<int>(strlen( stt
));
95 for( i
= 0; i
< len
; i
++ ) {
96 if( styler
.SafeGetCharAt( curPos
+ i
) != stt
[i
] ) {
101 if( ! isspace( styler
.SafeGetCharAt( curPos
+ i
) ) ) {
105 curPos
+= ( len
- 1 );
109 static inline bool checkEndSemicolon(
111 Sci_Position
&curPos
, Sci_Position endPos
)
113 const char *stt
= "END";
114 int len
= static_cast<int>(strlen( stt
));
116 for( i
= 0; i
< len
; i
++ ) {
117 if( styler
.SafeGetCharAt( curPos
+ i
) != stt
[i
] ) {
121 while( isspace( styler
.SafeGetCharAt( curPos
+ i
) ) ) {
123 if( ( curPos
+ i
) >= endPos
) return false;
125 if( styler
.SafeGetCharAt( curPos
+ i
) != ';' ) {
132 static inline bool checkKeyIdentOper(
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
) )
141 if( newPos
>= endPos
)
143 if( ! isspace( styler
.SafeGetCharAt( newPos
) ) )
146 if( newPos
>= endPos
)
148 while( isspace( styler
.SafeGetCharAt( newPos
) ) ) {
150 if( newPos
>= endPos
)
153 if( ! isalpha( styler
.SafeGetCharAt( newPos
) ) )
156 if( newPos
>= endPos
)
159 ch
= styler
.SafeGetCharAt( newPos
);
160 while( isalpha( ch
) || isdigit( ch
) || ch
== '_' ) {
162 if( newPos
>= endPos
) return false;
163 ch
= styler
.SafeGetCharAt( newPos
);
165 while( isspace( styler
.SafeGetCharAt( newPos
) ) ) {
167 if( newPos
>= endPos
) return false;
169 if( styler
.SafeGetCharAt( newPos
) != etk
)
175 static void FoldModulaDoc( Sci_PositionU startPos
,
180 Sci_Position curLine
= styler
.GetLine(startPos
);
181 int curLevel
= SC_FOLDLEVELBASE
;
182 Sci_Position endPos
= startPos
+ length
;
184 curLevel
= styler
.LevelAt( curLine
- 1 ) >> 16;
185 Sci_Position curPos
= startPos
;
186 int style
= styler
.StyleAt( curPos
);
188 int nextLevel
= curLevel
;
190 while( curPos
< endPos
) {
191 if( ! isspace( styler
.SafeGetCharAt( curPos
) ) ) visChars
++;
194 case SCE_MODULA_COMMENT
:
195 if( checkStatement( styler
, curPos
, "(*" ) )
198 if( checkStatement( styler
, curPos
, "*)" ) )
202 case SCE_MODULA_DOXYCOMM
:
203 if( checkStatement( styler
, curPos
, "(**", false ) )
206 if( checkStatement( styler
, curPos
, "*)" ) )
210 case SCE_MODULA_KEYWORD
:
211 if( checkStatement( styler
, curPos
, "IF" ) )
214 if( checkStatement( styler
, curPos
, "BEGIN" ) )
217 if( checkStatement( styler
, curPos
, "TRY" ) )
220 if( checkStatement( styler
, curPos
, "LOOP" ) )
223 if( checkStatement( styler
, curPos
, "FOR" ) )
226 if( checkStatement( styler
, curPos
, "WHILE" ) )
229 if( checkStatement( styler
, curPos
, "REPEAT" ) )
232 if( checkStatement( styler
, curPos
, "UNTIL" ) )
235 if( checkStatement( styler
, curPos
, "WITH" ) )
238 if( checkStatement( styler
, curPos
, "CASE" ) )
241 if( checkStatement( styler
, curPos
, "TYPECASE" ) )
244 if( checkStatement( styler
, curPos
, "LOCK" ) )
247 if( checkKeyIdentOper( styler
, curPos
, endPos
, "PROCEDURE", '(' ) )
250 if( checkKeyIdentOper( styler
, curPos
, endPos
, "END", ';' ) ) {
251 Sci_Position cln
= curLine
;
252 int clv_old
= curLevel
;
257 clv_new
= styler
.LevelAt( cln
- 1 ) >> 16;
258 if( clv_new
< clv_old
) {
260 pos
= styler
.LineStart( cln
);
261 while( ( ch
= styler
.SafeGetCharAt( pos
) ) != '\n' ) {
263 if( styler
.StyleAt(pos
) == SCE_MODULA_KEYWORD
) {
264 if( checkKeyIdentOper( styler
, pos
, endPos
,
265 "PROCEDURE", '(' ) ) {
278 if( checkKeyIdentOper( styler
, curPos
, endPos
, "END", '.' ) )
281 if( checkEndSemicolon( styler
, curPos
, endPos
) )
284 while( styler
.StyleAt( curPos
+ 1 ) == SCE_MODULA_KEYWORD
)
293 if( IsEOL( styler
, curPos
) || ( curPos
== endPos
- 1 ) ) {
294 int efectiveLevel
= curLevel
| nextLevel
<< 16;
296 efectiveLevel
|= SC_FOLDLEVELWHITEFLAG
;
297 if( curLevel
< nextLevel
)
298 efectiveLevel
|= SC_FOLDLEVELHEADERFLAG
;
299 if( efectiveLevel
!= styler
.LevelAt(curLine
) ) {
300 styler
.SetLevel(curLine
, efectiveLevel
);
303 curLevel
= nextLevel
;
304 if( IsEOL( styler
, curPos
) && ( curPos
== endPos
- 1 ) ) {
305 styler
.SetLevel( curLine
, ( curLevel
| curLevel
<< 16)
306 | SC_FOLDLEVELWHITEFLAG
);
311 style
= styler
.StyleAt( curPos
);
315 static inline bool skipWhiteSpaces( StyleContext
& sc
) {
316 while( isspace( sc
.ch
) ) {
317 sc
.SetState( SCE_MODULA_DEFAULT
);
326 static void ColouriseModulaDoc( Sci_PositionU startPos
,
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;
343 Sci_Position charPos
= 0;
345 StyleContext
sc( startPos
, length
, initStyle
, styler
);
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
);
357 sc
.SetState( SCE_MODULA_COMMENT
);
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
] == '_') )
372 if( keyWords
.InList( buf
) ) {
373 sc
.SetState( SCE_MODULA_KEYWORD
);
375 sc
.SetState( SCE_MODULA_DEFAULT
);
379 if( reservedWords
.InList( buf
) ) {
380 sc
.SetState( SCE_MODULA_RESERVED
);
382 sc
.SetState( SCE_MODULA_DEFAULT
);
385 /** check procedure identifier */
388 for( i
= 0; i
< BUFLEN
- 1; i
++ ) {
389 buf
[i
] = sc
.GetRelative(i
);
390 if( !isalpha( buf
[i
] ) &&
391 !isdigit( buf
[i
] ) &&
398 sc
.SetState( SCE_MODULA_DEFAULT
);
404 if( isdigit( sc
.ch
) ) {
405 sc
.SetState( SCE_MODULA_NUMBER
);
409 if( sc
.ch
== '\"' ) {
410 sc
.SetState( SCE_MODULA_STRING
);
413 if( sc
.ch
== '\'' ) {
414 charPos
= sc
.currentPos
;
415 sc
.SetState( SCE_MODULA_CHAR
);
418 if( sc
.ch
== '<' && sc
.chNext
== '*' ) {
419 sc
.SetState( SCE_MODULA_PRAGMA
);
422 unsigned len
= IsOperator( sc
, operators
);
424 sc
.SetState( SCE_MODULA_OPERATOR
);
426 sc
.SetState( SCE_MODULA_DEFAULT
);
429 DEBUG_STATE( sc
.currentPos
, sc
.ch
);
434 case SCE_MODULA_COMMENT
:
435 if( sc
.ch
== '*' && sc
.chNext
== ')' ) {
437 sc
.SetState( SCE_MODULA_DEFAULT
);
442 case SCE_MODULA_DOXYCOMM
:
445 if( sc
.chNext
== ')' ) {
447 sc
.SetState( SCE_MODULA_DEFAULT
);
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;
461 if( doxyKeys
.InList( buf
) ) {
462 sc
.SetState( SCE_MODULA_DOXYKEY
);
463 sc
.Forward( kl
+ 1 );
464 sc
.SetState( SCE_MODULA_DOXYCOMM
);
474 case SCE_MODULA_NUMBER
:
477 for( i
= 1; i
< BUFLEN
- 1; i
++ ) {
478 buf
[i
] = sc
.GetRelative(i
);
479 if( ! isdigit( buf
[i
] ) )
485 switch( sc
.GetRelative(kl
) ) {
488 int base
= atoi( buf
);
489 if( base
< 2 || base
> 16 ) {
490 sc
.SetState( SCE_MODULA_BADSTR
);
495 for( i
= 0; i
< BUFLEN
- 1; i
++ ) {
496 buf
[i
] = sc
.GetRelative(kl
+i
);
497 if( ! IsDigitOfBase( buf
[i
], 16 ) ) {
502 for( i
= 0; i
< imax
; i
++ ) {
503 if( ! IsDigitOfBase( buf
[i
], base
) ) {
504 sc
.SetState( SCE_MODULA_BADSTR
);
510 sc
.SetState( SCE_MODULA_BASENUM
);
511 for( i
= 0; i
< kl
; i
++ ) {
514 sc
.SetState( SCE_MODULA_DEFAULT
);
520 if( sc
.GetRelative(kl
+1) == '.' ) {
522 for( i
= 0; i
< kl
; i
++ ) {
526 sc
.SetState( SCE_MODULA_DEFAULT
);
533 buf
[0] = sc
.GetRelative(kl
);
534 if( isdigit( buf
[0] ) ) {
536 if( !isdigit(sc
.GetRelative(kl
+i
)) )
540 buf
[0] = sc
.GetRelative(kl
);
551 buf
[0] = sc
.GetRelative(kl
);
552 if( buf
[0] == '-' || buf
[0] == '+' ) {
555 buf
[0] = sc
.GetRelative(kl
);
556 if( isdigit( buf
[0] ) ) {
558 if( !isdigit(sc
.GetRelative(kl
+i
)) ) {
559 buf
[0] = sc
.GetRelative(kl
+i
);
566 sc
.SetState( SCE_MODULA_BADSTR
);
575 sc
.SetState( SCE_MODULA_BADSTR
);
579 if( ! isspace( buf
[0] ) &&
592 sc
.SetState( SCE_MODULA_BADSTR
);
598 sc
.SetState( SCE_MODULA_FLOAT
);
599 for( i
= 0; i
< kl
; i
++ ) {
602 sc
.SetState( SCE_MODULA_DEFAULT
);
607 for( i
= 0; i
< kl
; i
++ ) {
612 sc
.SetState( SCE_MODULA_DEFAULT
);
617 case SCE_MODULA_STRING
:
618 if( sc
.ch
== '\"' ) {
620 sc
.SetState( SCE_MODULA_DEFAULT
);
623 if( sc
.ch
== '\\' ) {
625 if( IsDigitOfBase( sc
.chNext
, 8 ) ) {
626 for( i
= 1; i
< BUFLEN
- 1; i
++ ) {
627 if( ! IsDigitOfBase(sc
.GetRelative(i
+1), 8 ) )
631 sc
.SetState( SCE_MODULA_STRSPEC
);
633 sc
.SetState( SCE_MODULA_BADSTR
);
639 if( escapeCodes
.InList( buf
) ) {
640 sc
.SetState( SCE_MODULA_STRSPEC
);
642 sc
.SetState( SCE_MODULA_BADSTR
);
646 sc
.SetState( SCE_MODULA_STRING
);
652 case SCE_MODULA_CHAR
:
653 if( sc
.ch
== '\'' ) {
655 sc
.SetState( SCE_MODULA_DEFAULT
);
659 if( ( sc
.currentPos
- charPos
) == 1 ) {
660 if( sc
.ch
== '\\' ) {
662 if( IsDigitOfBase( sc
.chNext
, 8 ) ) {
663 for( i
= 1; i
< BUFLEN
- 1; i
++ ) {
664 if( ! IsDigitOfBase(sc
.GetRelative(i
+1), 8 ) )
668 sc
.SetState( SCE_MODULA_CHARSPEC
);
670 sc
.SetState( SCE_MODULA_BADSTR
);
676 if( escapeCodes
.InList( buf
) ) {
677 sc
.SetState( SCE_MODULA_CHARSPEC
);
679 sc
.SetState( SCE_MODULA_BADSTR
);
683 sc
.SetState( SCE_MODULA_CHAR
);
687 sc
.SetState( SCE_MODULA_BADSTR
);
689 sc
.SetState( SCE_MODULA_CHAR
);
694 case SCE_MODULA_PRAGMA
:
695 if( sc
.ch
== '*' && sc
.chNext
== '>' ) {
698 sc
.SetState( SCE_MODULA_DEFAULT
);
702 if( isupper( sc
.ch
) && isupper( sc
.chNext
) ) {
705 for( i
= 2; i
< BUFLEN
- 1; i
++ ) {
706 buf
[i
] = sc
.GetRelative(i
);
707 if( !isupper( buf
[i
] ) )
712 if( pragmaWords
.InList( buf
) ) {
713 sc
.SetState( SCE_MODULA_PRGKEY
);
715 sc
.SetState( SCE_MODULA_PRAGMA
);
729 static const char *const modulaWordListDesc
[] =
740 LexerModule
lmModula( SCLEX_MODULA
, ColouriseModulaDoc
, "modula", FoldModulaDoc
,