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"
32 using namespace Scintilla
;
35 #ifdef DEBUG_LEX_MODULA
36 #define DEBUG_STATE( p, c )\
37 fprintf( stderr, "Unknown state: currentPos = %d, char = '%c'\n", p, c );
39 #define DEBUG_STATE( p, c )
42 static inline bool IsDigitOfBase( unsigned ch
, unsigned base
) {
43 if( ch
< '0' || ch
> 'f' ) return false;
45 if( ch
>= ( '0' + base
) ) return false;
48 unsigned nb
= base
- 10;
49 if( ( ch
< 'A' ) || ( ch
>= ( 'A' + nb
) ) ) {
50 if( ( ch
< 'a' ) || ( ch
>= ( 'a' + nb
) ) ) {
59 static inline unsigned IsOperator( StyleContext
& sc
, WordList
& op
) {
66 for( i
= 0; i
< op
.Length(); i
++ ) {
67 if( ( strlen( op
.WordAt(i
) ) == 2 ) &&
68 ( s
[0] == op
.WordAt(i
)[0] && s
[1] == op
.WordAt(i
)[1] ) ) {
73 for( i
= 0; i
< op
.Length(); i
++ ) {
74 if( ( strlen( op
.WordAt(i
) ) == 1 ) &&
75 ( s
[0] == op
.WordAt(i
)[0] ) ) {
82 static inline bool IsEOL( Accessor
&styler
, unsigned curPos
) {
83 unsigned ch
= styler
.SafeGetCharAt( curPos
);
84 if( ( ch
== '\r' && styler
.SafeGetCharAt( curPos
+ 1 ) == '\n' ) ||
91 static inline bool checkStatement(
94 const char *stt
, bool spaceAfter
= true ) {
95 int len
= static_cast<int>(strlen( stt
));
97 for( i
= 0; i
< len
; i
++ ) {
98 if( styler
.SafeGetCharAt( curPos
+ i
) != stt
[i
] ) {
103 if( ! isspace( styler
.SafeGetCharAt( curPos
+ i
) ) ) {
107 curPos
+= ( len
- 1 );
111 static inline bool checkEndSemicolon(
113 int &curPos
, int endPos
)
115 const char *stt
= "END";
116 int len
= static_cast<int>(strlen( stt
));
118 for( i
= 0; i
< len
; i
++ ) {
119 if( styler
.SafeGetCharAt( curPos
+ i
) != stt
[i
] ) {
123 while( isspace( styler
.SafeGetCharAt( curPos
+ i
) ) ) {
125 if( ( curPos
+ i
) >= endPos
) return false;
127 if( styler
.SafeGetCharAt( curPos
+ i
) != ';' ) {
134 static inline bool checkKeyIdentOper(
137 int &curPos
, int endPos
,
138 const char *stt
, const char etk
) {
140 if( ! checkStatement( styler
, newPos
, stt
) )
143 if( newPos
>= endPos
)
145 if( ! isspace( styler
.SafeGetCharAt( newPos
) ) )
148 if( newPos
>= endPos
)
150 while( isspace( styler
.SafeGetCharAt( newPos
) ) ) {
152 if( newPos
>= endPos
)
155 if( ! isalpha( styler
.SafeGetCharAt( newPos
) ) )
158 if( newPos
>= endPos
)
161 ch
= styler
.SafeGetCharAt( newPos
);
162 while( isalpha( ch
) || isdigit( ch
) || ch
== '_' ) {
164 if( newPos
>= endPos
) return false;
165 ch
= styler
.SafeGetCharAt( newPos
);
167 while( isspace( styler
.SafeGetCharAt( newPos
) ) ) {
169 if( newPos
>= endPos
) return false;
171 if( styler
.SafeGetCharAt( newPos
) != etk
)
177 static void FoldModulaDoc( unsigned int startPos
,
182 int curLine
= styler
.GetLine(startPos
);
183 int curLevel
= SC_FOLDLEVELBASE
;
184 int endPos
= startPos
+ length
;
186 curLevel
= styler
.LevelAt( curLine
- 1 ) >> 16;
187 int curPos
= startPos
;
188 int style
= styler
.StyleAt( curPos
);
190 int nextLevel
= curLevel
;
192 while( curPos
< endPos
) {
193 if( ! isspace( styler
.SafeGetCharAt( curPos
) ) ) visChars
++;
196 case SCE_MODULA_COMMENT
:
197 if( checkStatement( styler
, curPos
, "(*" ) )
200 if( checkStatement( styler
, curPos
, "*)" ) )
204 case SCE_MODULA_DOXYCOMM
:
205 if( checkStatement( styler
, curPos
, "(**", false ) )
208 if( checkStatement( styler
, curPos
, "*)" ) )
212 case SCE_MODULA_KEYWORD
:
213 if( checkStatement( styler
, curPos
, "IF" ) )
216 if( checkStatement( styler
, curPos
, "BEGIN" ) )
219 if( checkStatement( styler
, curPos
, "TRY" ) )
222 if( checkStatement( styler
, curPos
, "LOOP" ) )
225 if( checkStatement( styler
, curPos
, "FOR" ) )
228 if( checkStatement( styler
, curPos
, "WHILE" ) )
231 if( checkStatement( styler
, curPos
, "REPEAT" ) )
234 if( checkStatement( styler
, curPos
, "UNTIL" ) )
237 if( checkStatement( styler
, curPos
, "WITH" ) )
240 if( checkStatement( styler
, curPos
, "CASE" ) )
243 if( checkStatement( styler
, curPos
, "TYPECASE" ) )
246 if( checkStatement( styler
, curPos
, "LOCK" ) )
249 if( checkKeyIdentOper( styler
, curPos
, endPos
, "PROCEDURE", '(' ) )
252 if( checkKeyIdentOper( styler
, curPos
, endPos
, "END", ';' ) ) {
254 int clv_old
= curLevel
;
259 clv_new
= styler
.LevelAt( cln
- 1 ) >> 16;
260 if( clv_new
< clv_old
) {
262 pos
= styler
.LineStart( cln
);
263 while( ( ch
= styler
.SafeGetCharAt( pos
) ) != '\n' ) {
265 if( styler
.StyleAt(pos
) == SCE_MODULA_KEYWORD
) {
266 if( checkKeyIdentOper( styler
, pos
, endPos
,
267 "PROCEDURE", '(' ) ) {
280 if( checkKeyIdentOper( styler
, curPos
, endPos
, "END", '.' ) )
283 if( checkEndSemicolon( styler
, curPos
, endPos
) )
286 while( styler
.StyleAt( curPos
+ 1 ) == SCE_MODULA_KEYWORD
)
295 if( IsEOL( styler
, curPos
) || ( curPos
== endPos
- 1 ) ) {
296 int efectiveLevel
= curLevel
| nextLevel
<< 16;
298 efectiveLevel
|= SC_FOLDLEVELWHITEFLAG
;
299 if( curLevel
< nextLevel
)
300 efectiveLevel
|= SC_FOLDLEVELHEADERFLAG
;
301 if( efectiveLevel
!= styler
.LevelAt(curLine
) ) {
302 styler
.SetLevel(curLine
, efectiveLevel
);
305 curLevel
= nextLevel
;
306 if( IsEOL( styler
, curPos
) && ( curPos
== endPos
- 1 ) ) {
307 styler
.SetLevel( curLine
, ( curLevel
| curLevel
<< 16)
308 | SC_FOLDLEVELWHITEFLAG
);
313 style
= styler
.StyleAt( curPos
);
317 static inline bool skipWhiteSpaces( StyleContext
& sc
) {
318 while( isspace( sc
.ch
) ) {
319 sc
.SetState( SCE_MODULA_DEFAULT
);
328 static void ColouriseModulaDoc( unsigned int startPos
,
333 WordList
& keyWords
= *wl
[0];
334 WordList
& reservedWords
= *wl
[1];
335 WordList
& operators
= *wl
[2];
336 WordList
& pragmaWords
= *wl
[3];
337 WordList
& escapeCodes
= *wl
[4];
338 WordList
& doxyKeys
= *wl
[5];
340 const int BUFLEN
= 128;
347 StyleContext
sc( startPos
, length
, initStyle
, styler
);
351 case SCE_MODULA_DEFAULT
:
352 if( ! skipWhiteSpaces( sc
) ) break;
354 if( sc
.ch
== '(' && sc
.chNext
== '*' ) {
355 if( sc
.GetRelative(2) == '*' ) {
356 sc
.SetState( SCE_MODULA_DOXYCOMM
);
359 sc
.SetState( SCE_MODULA_COMMENT
);
364 if( isalpha( sc
.ch
) ) {
365 if( isupper( sc
.ch
) && isupper( sc
.chNext
) ) {
366 for( i
= 0; i
< BUFLEN
- 1; i
++ ) {
367 buf
[i
] = sc
.GetRelative(i
);
368 if( !isalpha( buf
[i
] ) && !(buf
[i
] == '_') )
374 if( keyWords
.InList( buf
) ) {
375 sc
.SetState( SCE_MODULA_KEYWORD
);
377 sc
.SetState( SCE_MODULA_DEFAULT
);
381 if( reservedWords
.InList( buf
) ) {
382 sc
.SetState( SCE_MODULA_RESERVED
);
384 sc
.SetState( SCE_MODULA_DEFAULT
);
387 /** check procedure identifier */
390 for( i
= 0; i
< BUFLEN
- 1; i
++ ) {
391 buf
[i
] = sc
.GetRelative(i
);
392 if( !isalpha( buf
[i
] ) &&
393 !isdigit( buf
[i
] ) &&
400 sc
.SetState( SCE_MODULA_DEFAULT
);
406 if( isdigit( sc
.ch
) ) {
407 sc
.SetState( SCE_MODULA_NUMBER
);
411 if( sc
.ch
== '\"' ) {
412 sc
.SetState( SCE_MODULA_STRING
);
415 if( sc
.ch
== '\'' ) {
416 charPos
= sc
.currentPos
;
417 sc
.SetState( SCE_MODULA_CHAR
);
420 if( sc
.ch
== '<' && sc
.chNext
== '*' ) {
421 sc
.SetState( SCE_MODULA_PRAGMA
);
424 unsigned len
= IsOperator( sc
, operators
);
426 sc
.SetState( SCE_MODULA_OPERATOR
);
428 sc
.SetState( SCE_MODULA_DEFAULT
);
431 DEBUG_STATE( sc
.currentPos
, sc
.ch
);
436 case SCE_MODULA_COMMENT
:
437 if( sc
.ch
== '*' && sc
.chNext
== ')' ) {
439 sc
.SetState( SCE_MODULA_DEFAULT
);
444 case SCE_MODULA_DOXYCOMM
:
447 if( sc
.chNext
== ')' ) {
449 sc
.SetState( SCE_MODULA_DEFAULT
);
455 if( islower( sc
.chNext
) ) {
456 for( i
= 0; i
< BUFLEN
- 1; i
++ ) {
457 buf
[i
] = sc
.GetRelative(i
+1);
458 if( isspace( buf
[i
] ) ) break;
463 if( doxyKeys
.InList( buf
) ) {
464 sc
.SetState( SCE_MODULA_DOXYKEY
);
465 sc
.Forward( kl
+ 1 );
466 sc
.SetState( SCE_MODULA_DOXYCOMM
);
476 case SCE_MODULA_NUMBER
:
479 for( i
= 1; i
< BUFLEN
- 1; i
++ ) {
480 buf
[i
] = sc
.GetRelative(i
);
481 if( ! isdigit( buf
[i
] ) )
487 switch( sc
.GetRelative(kl
) ) {
490 int base
= atoi( buf
);
491 if( base
< 2 || base
> 16 ) {
492 sc
.SetState( SCE_MODULA_BADSTR
);
497 for( i
= 0; i
< BUFLEN
- 1; i
++ ) {
498 buf
[i
] = sc
.GetRelative(kl
+i
);
499 if( ! IsDigitOfBase( buf
[i
], 16 ) ) {
504 for( i
= 0; i
< imax
; i
++ ) {
505 if( ! IsDigitOfBase( buf
[i
], base
) ) {
506 sc
.SetState( SCE_MODULA_BADSTR
);
512 sc
.SetState( SCE_MODULA_BASENUM
);
513 for( i
= 0; i
< kl
; i
++ ) {
516 sc
.SetState( SCE_MODULA_DEFAULT
);
522 if( sc
.GetRelative(kl
+1) == '.' ) {
524 for( i
= 0; i
< kl
; i
++ ) {
528 sc
.SetState( SCE_MODULA_DEFAULT
);
535 buf
[0] = sc
.GetRelative(kl
);
536 if( isdigit( buf
[0] ) ) {
538 if( !isdigit(sc
.GetRelative(kl
+i
)) )
542 buf
[0] = sc
.GetRelative(kl
);
553 buf
[0] = sc
.GetRelative(kl
);
554 if( buf
[0] == '-' || buf
[0] == '+' ) {
557 buf
[0] = sc
.GetRelative(kl
);
558 if( isdigit( buf
[0] ) ) {
560 if( !isdigit(sc
.GetRelative(kl
+i
)) ) {
561 buf
[0] = sc
.GetRelative(kl
+i
);
568 sc
.SetState( SCE_MODULA_BADSTR
);
577 sc
.SetState( SCE_MODULA_BADSTR
);
581 if( ! isspace( buf
[0] ) &&
594 sc
.SetState( SCE_MODULA_BADSTR
);
600 sc
.SetState( SCE_MODULA_FLOAT
);
601 for( i
= 0; i
< kl
; i
++ ) {
604 sc
.SetState( SCE_MODULA_DEFAULT
);
609 for( i
= 0; i
< kl
; i
++ ) {
614 sc
.SetState( SCE_MODULA_DEFAULT
);
619 case SCE_MODULA_STRING
:
620 if( sc
.ch
== '\"' ) {
622 sc
.SetState( SCE_MODULA_DEFAULT
);
625 if( sc
.ch
== '\\' ) {
627 if( IsDigitOfBase( sc
.chNext
, 8 ) ) {
628 for( i
= 1; i
< BUFLEN
- 1; i
++ ) {
629 if( ! IsDigitOfBase(sc
.GetRelative(i
+1), 8 ) )
633 sc
.SetState( SCE_MODULA_STRSPEC
);
635 sc
.SetState( SCE_MODULA_BADSTR
);
641 if( escapeCodes
.InList( buf
) ) {
642 sc
.SetState( SCE_MODULA_STRSPEC
);
644 sc
.SetState( SCE_MODULA_BADSTR
);
648 sc
.SetState( SCE_MODULA_STRING
);
654 case SCE_MODULA_CHAR
:
655 if( sc
.ch
== '\'' ) {
657 sc
.SetState( SCE_MODULA_DEFAULT
);
661 if( ( sc
.currentPos
- charPos
) == 1 ) {
662 if( sc
.ch
== '\\' ) {
664 if( IsDigitOfBase( sc
.chNext
, 8 ) ) {
665 for( i
= 1; i
< BUFLEN
- 1; i
++ ) {
666 if( ! IsDigitOfBase(sc
.GetRelative(i
+1), 8 ) )
670 sc
.SetState( SCE_MODULA_CHARSPEC
);
672 sc
.SetState( SCE_MODULA_BADSTR
);
678 if( escapeCodes
.InList( buf
) ) {
679 sc
.SetState( SCE_MODULA_CHARSPEC
);
681 sc
.SetState( SCE_MODULA_BADSTR
);
685 sc
.SetState( SCE_MODULA_CHAR
);
689 sc
.SetState( SCE_MODULA_BADSTR
);
691 sc
.SetState( SCE_MODULA_CHAR
);
696 case SCE_MODULA_PRAGMA
:
697 if( sc
.ch
== '*' && sc
.chNext
== '>' ) {
700 sc
.SetState( SCE_MODULA_DEFAULT
);
704 if( isupper( sc
.ch
) && isupper( sc
.chNext
) ) {
707 for( i
= 2; i
< BUFLEN
- 1; i
++ ) {
708 buf
[i
] = sc
.GetRelative(i
);
709 if( !isupper( buf
[i
] ) )
714 if( pragmaWords
.InList( buf
) ) {
715 sc
.SetState( SCE_MODULA_PRGKEY
);
717 sc
.SetState( SCE_MODULA_PRAGMA
);
731 static const char *const modulaWordListDesc
[] =
742 LexerModule
lmModula( SCLEX_MODULA
, ColouriseModulaDoc
, "modula", FoldModulaDoc
,