Add an UI to enable/disable specific overlay handlers.
[TortoiseGit.git] / ext / scintilla / src / LexErlang.cxx
blobd9d58f9624f761e656c3e2328168272b901fe618
1 // Scintilla source code edit control
2 /** @file LexErlang.cxx
3 ** Lexer for Erlang.
4 ** Written by Peter-Henry Mander, based on Matlab lexer by José Fonseca
5 **/
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.
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
15 #include "Platform.h"
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "StyleContext.h"
20 #include "KeyWords.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
24 #ifdef SCI_NAMESPACE
25 using namespace Scintilla;
26 #endif
29 TODO:
30 o _Param should be a new lexical type
33 static int is_radix(int radix, int ch) {
34 int digit;
35 if ( 16 < radix || 2 > radix ) {
36 return 0;
38 if ( isdigit(ch) ) {
39 digit = ch - '0';
40 } else if ( isxdigit(ch) ) {
41 digit = toupper(ch) - 'A' + 10;
42 } else {
43 return 0;
45 if ( digit < radix ) {
46 return 1;
47 } else {
48 return 0;
52 typedef enum {
53 STATE_NULL,
54 ATOM_UNQUOTED,
55 ATOM_QUOTED,
56 ATOM_FUN_NAME,
57 NODE_NAME_UNQUOTED,
58 NODE_NAME_QUOTED,
59 MACRO_START,
60 MACRO_UNQUOTED,
61 MACRO_QUOTED,
62 RECORD_START,
63 RECORD_UNQUOTED,
64 RECORD_QUOTED,
65 NUMERAL_START,
66 NUMERAL_SIGNED,
67 NUMERAL_RADIX_LITERAL,
68 NUMERAL_SPECULATIVE_MANTISSA,
69 NUMERAL_FLOAT_MANTISSA,
70 NUMERAL_FLOAT_EXPONENT,
71 NUMERAL_FLOAT_SIGNED_EXPONENT,
72 PARSE_ERROR
73 } atom_parse_state_t;
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;
84 int radix_digits = 0;
85 int exponent_digits = 0;
86 for (; sc.More(); sc.Forward()) {
87 if ( STATE_NULL != parse_state ) {
88 switch (parse_state) {
89 case STATE_NULL:
90 sc.SetState(SCE_ERLANG_DEFAULT);
91 break;
92 case ATOM_UNQUOTED:
93 if ( '@' == sc.ch ){
94 parse_state = NODE_NAME_UNQUOTED;
95 } else if ( !isalnum(sc.ch) && sc.ch != '_' ) {
96 char s[100];
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;
102 } else {
103 if ( '/' == sc.ch ) {
104 parse_state = ATOM_FUN_NAME;
105 } else {
106 sc.ChangeState(SCE_ERLANG_ATOM);
107 sc.SetState(SCE_ERLANG_DEFAULT);
108 parse_state = STATE_NULL;
112 break;
113 case ATOM_QUOTED:
114 if ( '@' == sc.ch ){
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;
121 break;
122 case ATOM_FUN_NAME:
123 if ( !isdigit(sc.ch) ) {
124 sc.ChangeState(SCE_ERLANG_FUNCTION_NAME);
125 sc.SetState(SCE_ERLANG_DEFAULT);
126 parse_state = STATE_NULL;
128 break;
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;
138 break;
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;
148 break;
149 case RECORD_START:
150 if ( '\'' == sc.ch ) {
151 parse_state = RECORD_QUOTED;
152 } else if (isalpha(sc.ch) && islower(sc.ch)) {
153 parse_state = RECORD_UNQUOTED;
154 } else { // error
155 sc.SetState(SCE_ERLANG_DEFAULT);
156 parse_state = STATE_NULL;
158 break;
159 case RECORD_QUOTED:
160 if ( '\'' == sc.ch && '\\' != sc.chPrev ) {
161 sc.ChangeState(SCE_ERLANG_RECORD);
162 sc.ForwardSetState(SCE_ERLANG_DEFAULT);
163 parse_state = STATE_NULL;
165 break;
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;
172 break;
173 case MACRO_START:
174 if ( '\'' == sc.ch ) {
175 parse_state = MACRO_QUOTED;
176 } else if (isalpha(sc.ch)) {
177 parse_state = MACRO_UNQUOTED;
178 } else { // error
179 sc.SetState(SCE_ERLANG_DEFAULT);
180 parse_state = STATE_NULL;
182 break;
183 case MACRO_UNQUOTED:
184 if ( !isalpha(sc.ch) && '_' != sc.ch ) {
185 sc.ChangeState(SCE_ERLANG_MACRO);
186 sc.SetState(SCE_ERLANG_DEFAULT);
187 parse_state = STATE_NULL;
189 break;
190 case MACRO_QUOTED:
191 if ( '\'' == sc.ch && '\\' != sc.chPrev ) {
192 sc.ChangeState(SCE_ERLANG_MACRO);
193 sc.ForwardSetState(SCE_ERLANG_DEFAULT);
194 parse_state = STATE_NULL;
196 break;
197 case NUMERAL_START:
198 if ( isdigit(sc.ch) ) {
199 radix_digits *= 10;
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;
205 } else {
206 parse_state = NUMERAL_RADIX_LITERAL;
208 } else if ( '.' == sc.ch && isdigit(sc.chNext)) {
209 radix_digits = 0;
210 parse_state = NUMERAL_FLOAT_MANTISSA;
211 } else if ( 'e' == sc.ch || 'E' == sc.ch ) {
212 exponent_digits = 0;
213 parse_state = NUMERAL_FLOAT_EXPONENT;
214 } else {
215 radix_digits = 0;
216 sc.ChangeState(SCE_ERLANG_NUMBER);
217 sc.SetState(SCE_ERLANG_DEFAULT);
218 parse_state = STATE_NULL;
220 break;
221 case NUMERAL_RADIX_LITERAL:
222 if ( !is_radix(radix_digits,sc.ch) ) {
223 radix_digits = 0;
224 if ( !isalnum(sc.ch) ) {
225 sc.ChangeState(SCE_ERLANG_NUMBER);
227 sc.SetState(SCE_ERLANG_DEFAULT);
228 parse_state = STATE_NULL;
230 break;
231 case NUMERAL_FLOAT_MANTISSA:
232 if ( 'e' == sc.ch || 'E' == sc.ch ) {
233 exponent_digits = 0;
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;
240 break;
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;
250 } else {
251 ++exponent_digits;
253 break;
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;
261 } else {
262 ++exponent_digits;
264 break;
265 case NUMERAL_SIGNED:
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;
273 break;
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;
279 } else {
280 parse_state = NUMERAL_FLOAT_MANTISSA;
282 break;
283 case PARSE_ERROR:
284 sc.SetState(SCE_ERLANG_DEFAULT);
285 parse_state = STATE_NULL;
286 break;
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);
294 } else {
295 sc.SetState(SCE_ERLANG_DEFAULT);
297 } else {
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 ) {
309 if (sc.atLineEnd) {
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) {
321 if (sc.ch == '%') {
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);
353 sc.Complete();
356 static int ClassifyFoldPointErlang(
357 Accessor &styler,
358 int styleNext,
359 int keyword_start
361 int lev = 0;
362 if ( styler.Match(keyword_start,"case")
363 || (
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")
370 ++lev;
371 } else if ( styler.Match(keyword_start,"end") ) {
372 --lev;
374 return lev;
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++) {
401 char ch = chNext;
402 chNext = styler.SafeGetCharAt(i + 1);
403 int stylePrev = style;
404 style = styleNext;
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) ) {
409 keyword_start = i;
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 == '{')) {
423 levelCurrent++;
424 } else if ((ch == '%') && (chNext == '}')) {
425 levelCurrent--;
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);
434 //++clause_level;
435 //~ if ( 0 < clause_level )
436 ++levelCurrent;
439 //~ if ( (stylePrev != SCE_ERLANG_RECORD)
440 //~ && (style != SCE_ERLANG_NUMBER)
441 //~ && (style != SCE_ERLANG_STRING)
442 //~ && (style != SCE_ERLANG_COMMENT)
443 //~ ) {
444 if ( (SC_FOLDLEVELBASE+1 == levelCurrent) && (ch == '.') ) {
445 //--clause_level;
446 //~ if ( 0 == clause_level )
447 --levelCurrent;
449 //~ }
452 if ( fold_clauses ) {
453 if ( (0 < levelCurrent) && (style == SCE_ERLANG_OPERATOR) ) {
454 if ((ch == '-') && (chNext == '>')) {
455 levelCurrent++;
457 if ( (ch == ';') ) {
458 levelCurrent--;
461 if ( (stylePrev != SCE_ERLANG_RECORD)
462 && (style != SCE_ERLANG_NUMBER)
463 && (style != SCE_ERLANG_STRING)
464 && (style != SCE_ERLANG_COMMENT)
466 if ( (ch == '.') ) {
467 levelCurrent--;
470 if ( (stylePrev == SCE_ERLANG_KEYWORD)
471 && (style != SCE_ERLANG_KEYWORD)
472 && (style != SCE_ERLANG_ATOM)
473 && (
474 styler.Match(keyword_start,"end") // 'end' counted twice if fold_keywords too
475 || styler.Match(keyword_start,"after") )
477 levelCurrent--;
481 if ( fold_braces ) {
482 if (style == SCE_ERLANG_OPERATOR) {
483 if ( (ch == '{') || (ch == '(') || (ch == '[') ) {
484 levelCurrent++;
485 } else if ( (ch == '}') || (ch == ')') || (ch == ']') ) {
486 levelCurrent--;
491 if (atEOL) {
492 int lev = levelPrev;
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);
502 lineCurrent++;
503 levelPrev = levelCurrent;
504 //~ visibleChars = 0;
506 //~ if (!isspacechar(ch))
507 //~ visibleChars++;
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[] = {
516 "Keywords",
520 LexerModule lmErlang(
521 SCLEX_ERLANG,
522 ColouriseErlangDoc,
523 "erlang",
524 FoldErlangDoc,
525 erlangWordListDesc);