1 // Scintilla source code edit control
2 /** @file LexErlang.cxx
4 ** Written by Peter-Henry Mander, based on Matlab lexer by Jose' Fonseca
6 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
19 #include "StyleContext.h"
21 #include "Scintilla.h"
25 using namespace Scintilla
;
30 o _Param should be a new lexical type
33 static int is_radix(int radix
, int ch
) {
35 if ( 16 < radix
|| 2 > radix
) {
40 } else if ( isxdigit(ch
) ) {
41 digit
= toupper(ch
) - 'A' + 10;
45 if ( digit
< radix
) {
67 NUMERAL_RADIX_LITERAL
,
68 NUMERAL_SPECULATIVE_MANTISSA
,
69 NUMERAL_FLOAT_MANTISSA
,
70 NUMERAL_FLOAT_EXPONENT
,
71 NUMERAL_FLOAT_SIGNED_EXPONENT
,
75 static void ColouriseErlangDoc(unsigned int startPos
, int length
, int initStyle
,
76 WordList
*keywordlists
[], Accessor
&styler
) {
78 WordList
&keywords
= *keywordlists
[0];
80 styler
.StartAt(startPos
);
82 StyleContext
sc(startPos
, length
, initStyle
, styler
);
83 atom_parse_state_t parse_state
= STATE_NULL
;
85 int exponent_digits
= 0;
86 for (; sc
.More(); sc
.Forward()) {
87 if ( STATE_NULL
!= parse_state
) {
88 switch (parse_state
) {
90 sc
.SetState(SCE_ERLANG_DEFAULT
);
94 parse_state
= NODE_NAME_UNQUOTED
;
95 } else if ( !isalnum(sc
.ch
) && sc
.ch
!= '_' ) {
97 sc
.GetCurrent(s
, sizeof(s
));
98 if (keywords
.InList(s
)) {
99 sc
.ChangeState(SCE_ERLANG_KEYWORD
);
100 sc
.SetState(SCE_ERLANG_DEFAULT
);
101 parse_state
= STATE_NULL
;
103 if ( '/' == sc
.ch
) {
104 parse_state
= ATOM_FUN_NAME
;
106 sc
.ChangeState(SCE_ERLANG_ATOM
);
107 sc
.SetState(SCE_ERLANG_DEFAULT
);
108 parse_state
= STATE_NULL
;
115 parse_state
= NODE_NAME_QUOTED
;
116 } else if ( '\'' == sc
.ch
&& '\\' != sc
.chPrev
) {
117 sc
.ChangeState(SCE_ERLANG_ATOM
);
118 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
119 parse_state
= STATE_NULL
;
123 if ( !isdigit(sc
.ch
) ) {
124 sc
.ChangeState(SCE_ERLANG_FUNCTION_NAME
);
125 sc
.SetState(SCE_ERLANG_DEFAULT
);
126 parse_state
= STATE_NULL
;
129 case NODE_NAME_QUOTED
:
130 if ( '@' == sc
.ch
) {
131 sc
.SetState(SCE_ERLANG_DEFAULT
);
132 parse_state
= STATE_NULL
;
133 } else if ( '\'' == sc
.ch
&& '\\' != sc
.chPrev
) {
134 sc
.ChangeState(SCE_ERLANG_NODE_NAME
);
135 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
136 parse_state
= STATE_NULL
;
139 case NODE_NAME_UNQUOTED
:
140 if ( '@' == sc
.ch
) {
141 sc
.SetState(SCE_ERLANG_DEFAULT
);
142 parse_state
= STATE_NULL
;
143 } else if ( !isalnum(sc
.ch
) && sc
.ch
!= '_' ) {
144 sc
.ChangeState(SCE_ERLANG_NODE_NAME
);
145 sc
.SetState(SCE_ERLANG_DEFAULT
);
146 parse_state
= STATE_NULL
;
150 if ( '\'' == sc
.ch
) {
151 parse_state
= RECORD_QUOTED
;
152 } else if (isalpha(sc
.ch
) && islower(sc
.ch
)) {
153 parse_state
= RECORD_UNQUOTED
;
155 sc
.SetState(SCE_ERLANG_DEFAULT
);
156 parse_state
= STATE_NULL
;
160 if ( '\'' == sc
.ch
&& '\\' != sc
.chPrev
) {
161 sc
.ChangeState(SCE_ERLANG_RECORD
);
162 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
163 parse_state
= STATE_NULL
;
166 case RECORD_UNQUOTED
:
167 if ( !isalpha(sc
.ch
) && '_' != sc
.ch
) {
168 sc
.ChangeState(SCE_ERLANG_RECORD
);
169 sc
.SetState(SCE_ERLANG_DEFAULT
);
170 parse_state
= STATE_NULL
;
174 if ( '\'' == sc
.ch
) {
175 parse_state
= MACRO_QUOTED
;
176 } else if (isalpha(sc
.ch
)) {
177 parse_state
= MACRO_UNQUOTED
;
179 sc
.SetState(SCE_ERLANG_DEFAULT
);
180 parse_state
= STATE_NULL
;
184 if ( !isalpha(sc
.ch
) && '_' != sc
.ch
) {
185 sc
.ChangeState(SCE_ERLANG_MACRO
);
186 sc
.SetState(SCE_ERLANG_DEFAULT
);
187 parse_state
= STATE_NULL
;
191 if ( '\'' == sc
.ch
&& '\\' != sc
.chPrev
) {
192 sc
.ChangeState(SCE_ERLANG_MACRO
);
193 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
194 parse_state
= STATE_NULL
;
198 if ( isdigit(sc
.ch
) ) {
200 radix_digits
+= sc
.ch
- '0'; // Assuming ASCII here!
201 } else if ( '#' == sc
.ch
) {
202 if ( 2 > radix_digits
|| 16 < radix_digits
) {
203 sc
.SetState(SCE_ERLANG_DEFAULT
);
204 parse_state
= STATE_NULL
;
206 parse_state
= NUMERAL_RADIX_LITERAL
;
208 } else if ( '.' == sc
.ch
&& isdigit(sc
.chNext
)) {
210 parse_state
= NUMERAL_FLOAT_MANTISSA
;
211 } else if ( 'e' == sc
.ch
|| 'E' == sc
.ch
) {
213 parse_state
= NUMERAL_FLOAT_EXPONENT
;
216 sc
.ChangeState(SCE_ERLANG_NUMBER
);
217 sc
.SetState(SCE_ERLANG_DEFAULT
);
218 parse_state
= STATE_NULL
;
221 case NUMERAL_RADIX_LITERAL
:
222 if ( !is_radix(radix_digits
,sc
.ch
) ) {
224 if ( !isalnum(sc
.ch
) ) {
225 sc
.ChangeState(SCE_ERLANG_NUMBER
);
227 sc
.SetState(SCE_ERLANG_DEFAULT
);
228 parse_state
= STATE_NULL
;
231 case NUMERAL_FLOAT_MANTISSA
:
232 if ( 'e' == sc
.ch
|| 'E' == sc
.ch
) {
234 parse_state
= NUMERAL_FLOAT_EXPONENT
;
235 } else if ( !isdigit(sc
.ch
) ) {
236 sc
.ChangeState(SCE_ERLANG_NUMBER
);
237 sc
.SetState(SCE_ERLANG_DEFAULT
);
238 parse_state
= STATE_NULL
;
241 case NUMERAL_FLOAT_EXPONENT
:
242 if ( '-' == sc
.ch
|| '+' == sc
.ch
) {
243 parse_state
= NUMERAL_FLOAT_SIGNED_EXPONENT
;
244 } else if ( !isdigit(sc
.ch
) ) {
245 if ( 0 < exponent_digits
) {
246 sc
.ChangeState(SCE_ERLANG_NUMBER
);
248 sc
.SetState(SCE_ERLANG_DEFAULT
);
249 parse_state
= STATE_NULL
;
254 case NUMERAL_FLOAT_SIGNED_EXPONENT
:
255 if ( !isdigit(sc
.ch
) ) {
256 if ( 0 < exponent_digits
) {
257 sc
.ChangeState(SCE_ERLANG_NUMBER
);
259 sc
.SetState(SCE_ERLANG_DEFAULT
);
260 parse_state
= STATE_NULL
;
266 if ( !isdigit(sc
.ch
) ) {
267 sc
.ChangeState(SCE_ERLANG_NUMBER
);
268 sc
.SetState(SCE_ERLANG_DEFAULT
);
269 parse_state
= STATE_NULL
;
270 } else if ( '.' == sc
.ch
) {
271 parse_state
= NUMERAL_FLOAT_MANTISSA
;
274 case NUMERAL_SPECULATIVE_MANTISSA
:
275 if ( !isdigit(sc
.ch
) ) {
276 sc
.ChangeState(SCE_ERLANG_OPERATOR
);
277 sc
.SetState(SCE_ERLANG_DEFAULT
);
278 parse_state
= STATE_NULL
;
280 parse_state
= NUMERAL_FLOAT_MANTISSA
;
284 sc
.SetState(SCE_ERLANG_DEFAULT
);
285 parse_state
= STATE_NULL
;
288 } else if (sc
.state
== SCE_ERLANG_OPERATOR
) {
289 if (sc
.chPrev
== '.') {
290 if (sc
.ch
== '*' || sc
.ch
== '/' || sc
.ch
== '\\' || sc
.ch
== '^') {
291 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
292 } else if (sc
.ch
== '\'') {
293 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
295 sc
.SetState(SCE_ERLANG_DEFAULT
);
298 sc
.SetState(SCE_ERLANG_DEFAULT
);
300 } else if (sc
.state
== SCE_ERLANG_VARIABLE
) {
301 if (!isalnum(sc
.ch
) && sc
.ch
!= '_') {
302 sc
.SetState(SCE_ERLANG_DEFAULT
);
304 } else if (sc
.state
== SCE_ERLANG_STRING
) {
305 if (sc
.ch
== '\"' && sc
.chPrev
!= '\\') {
306 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
308 } else if (sc
.state
== SCE_ERLANG_COMMENT
) {
310 sc
.SetState(SCE_ERLANG_DEFAULT
);
312 } else if (sc
.state
== SCE_ERLANG_CHARACTER
) {
313 if ( sc
.chPrev
== '\\' ) {
314 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
315 } else if ( sc
.ch
!= '\\' ) {
316 sc
.ForwardSetState(SCE_ERLANG_DEFAULT
);
320 if (sc
.state
== SCE_ERLANG_DEFAULT
) {
322 sc
.SetState(SCE_ERLANG_COMMENT
);
323 } else if (sc
.ch
== '\"') {
324 sc
.SetState(SCE_ERLANG_STRING
);
325 } else if (sc
.ch
== '#') {
326 parse_state
= RECORD_START
;
327 sc
.SetState(SCE_ERLANG_UNKNOWN
);
328 } else if (sc
.ch
== '?') {
329 parse_state
= MACRO_START
;
330 sc
.SetState(SCE_ERLANG_UNKNOWN
);
331 } else if (sc
.ch
== '$') {
332 sc
.SetState(SCE_ERLANG_CHARACTER
);
333 } else if (sc
.ch
== '\'') {
334 parse_state
= ATOM_QUOTED
;
335 sc
.SetState(SCE_ERLANG_UNKNOWN
);
336 } else if ( isdigit(sc
.ch
) ) {
337 parse_state
= NUMERAL_START
;
338 radix_digits
= sc
.ch
- '0';
339 sc
.SetState(SCE_ERLANG_UNKNOWN
);
340 } else if ( '.' == sc
.ch
) {
341 parse_state
= NUMERAL_SPECULATIVE_MANTISSA
;
342 sc
.SetState(SCE_ERLANG_UNKNOWN
);
343 } else if (isalpha(sc
.ch
) && isupper(sc
.ch
)) {
344 sc
.SetState(SCE_ERLANG_VARIABLE
);
345 } else if (isalpha(sc
.ch
)) {
346 parse_state
= ATOM_UNQUOTED
;
347 sc
.SetState(SCE_ERLANG_UNKNOWN
);
348 } else if (isoperator(static_cast<char>(sc
.ch
)) || sc
.ch
== '\\') {
349 sc
.SetState(SCE_ERLANG_OPERATOR
);
356 static int ClassifyFoldPointErlang(
362 if ( styler
.Match(keyword_start
,"case")
364 styler
.Match(keyword_start
,"fun")
365 && SCE_ERLANG_FUNCTION_NAME
!= styleNext
)
366 || styler
.Match(keyword_start
,"if")
367 || styler
.Match(keyword_start
,"query")
368 || styler
.Match(keyword_start
,"receive")
371 } else if ( styler
.Match(keyword_start
,"end") ) {
378 static void FoldErlangDoc(
379 unsigned int startPos
, int length
, int initStyle
,
380 WordList
** /*keywordlists*/, Accessor
&styler
382 unsigned int endPos
= startPos
+ length
;
383 //~ int visibleChars = 0;
384 int lineCurrent
= styler
.GetLine(startPos
);
385 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
386 int levelCurrent
= levelPrev
;
387 char chNext
= styler
.SafeGetCharAt(startPos
);
388 int styleNext
= styler
.StyleAt(startPos
);
389 int style
= initStyle
;
390 int keyword_start
= 0;
392 bool fold_keywords
= true;
393 bool fold_comments
= true;
394 bool fold_braces
= true;
395 bool fold_function_clauses
= false;
396 bool fold_clauses
= false;
398 //int clause_level = 0;
400 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
402 chNext
= styler
.SafeGetCharAt(i
+ 1);
403 int stylePrev
= style
;
405 styleNext
= styler
.StyleAt(i
+ 1);
406 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
408 if ( (stylePrev
!= SCE_ERLANG_KEYWORD
) && (style
== SCE_ERLANG_KEYWORD
) ) {
411 if ( fold_keywords
) {
412 if ( (stylePrev
== SCE_ERLANG_KEYWORD
)
413 && (style
!= SCE_ERLANG_KEYWORD
)
414 && (style
!= SCE_ERLANG_ATOM
)
416 levelCurrent
+= ClassifyFoldPointErlang(styler
,styleNext
,keyword_start
);
420 if ( fold_comments
) {
421 if (style
== SCE_ERLANG_COMMENT
) {
422 if ((ch
== '%') && (chNext
== '{')) {
424 } else if ((ch
== '%') && (chNext
== '}')) {
430 if ( fold_function_clauses
) {
431 if ( (SC_FOLDLEVELBASE
== levelCurrent
) /*&& (style == SCE_ERLANG_OPERATOR)*/ ) {
432 if ( (ch
== '-') && (chNext
== '>')) {
433 //~ fprintf(stderr,"levelCurrent=%d\n", levelCurrent);
435 //~ if ( 0 < clause_level )
439 //~ if ( (stylePrev != SCE_ERLANG_RECORD)
440 //~ && (style != SCE_ERLANG_NUMBER)
441 //~ && (style != SCE_ERLANG_STRING)
442 //~ && (style != SCE_ERLANG_COMMENT)
444 if ( (SC_FOLDLEVELBASE
+1 == levelCurrent
) && (ch
== '.') ) {
446 //~ if ( 0 == clause_level )
452 if ( fold_clauses
) {
453 if ( (0 < levelCurrent
) && (style
== SCE_ERLANG_OPERATOR
) ) {
454 if ((ch
== '-') && (chNext
== '>')) {
461 if ( (stylePrev
!= SCE_ERLANG_RECORD
)
462 && (style
!= SCE_ERLANG_NUMBER
)
463 && (style
!= SCE_ERLANG_STRING
)
464 && (style
!= SCE_ERLANG_COMMENT
)
470 if ( (stylePrev
== SCE_ERLANG_KEYWORD
)
471 && (style
!= SCE_ERLANG_KEYWORD
)
472 && (style
!= SCE_ERLANG_ATOM
)
474 styler
.Match(keyword_start
,"end") // 'end' counted twice if fold_keywords too
475 || styler
.Match(keyword_start
,"after") )
482 if (style
== SCE_ERLANG_OPERATOR
) {
483 if ( (ch
== '{') || (ch
== '(') || (ch
== '[') ) {
485 } else if ( (ch
== '}') || (ch
== ')') || (ch
== ']') ) {
493 //~ if (visibleChars == 0 && foldCompact)
494 //~ lev |= SC_FOLDLEVELWHITEFLAG;
495 //~ if ((levelCurrent > levelPrev) && (visibleChars > 0))
496 if ((levelCurrent
> levelPrev
)) {
497 lev
|= SC_FOLDLEVELHEADERFLAG
;
499 if (lev
!= styler
.LevelAt(lineCurrent
)) {
500 styler
.SetLevel(lineCurrent
, lev
);
503 levelPrev
= levelCurrent
;
504 //~ visibleChars = 0;
506 //~ if (!isspacechar(ch))
510 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
511 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
512 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
515 static const char * const erlangWordListDesc
[] = {
520 LexerModule
lmErlang(