diff options
Diffstat (limited to 'src/LexErlang.cxx')
-rw-r--r-- | src/LexErlang.cxx | 993 |
1 files changed, 543 insertions, 450 deletions
diff --git a/src/LexErlang.cxx b/src/LexErlang.cxx index 809dcefe9..45577bda4 100644 --- a/src/LexErlang.cxx +++ b/src/LexErlang.cxx @@ -1,10 +1,12 @@ // Scintilla source code edit control +// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. /** @file LexErlang.cxx ** Lexer for Erlang. - ** Written by Peter-Henry Mander, based on Matlab lexer by José Fonseca + ** Enhanced by Etienne 'Lenain' Girondel (lenaing@gmail.com) + ** Originally wrote by Peter-Henry Mander, + ** based on Matlab lexer by José Fonseca. **/ -// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> -// The License.txt file describes the conditions under which this software may be distributed. #include <stdlib.h> #include <string.h> @@ -13,7 +15,6 @@ #include <stdarg.h> #include "Platform.h" - #include "PropSet.h" #include "Accessor.h" #include "StyleContext.h" @@ -25,502 +26,594 @@ using namespace Scintilla; #endif -/* - TODO: - o _Param should be a new lexical type -*/ - static int is_radix(int radix, int ch) { - int digit; - if ( 16 < radix || 2 > radix ) { - return 0; - } - if ( isdigit(ch) ) { - digit = ch - '0'; - } else if ( isxdigit(ch) ) { - digit = toupper(ch) - 'A' + 10; - } else { - return 0; - } - if ( digit < radix ) { - return 1; - } else { - return 0; - } + int digit; + + if (36 < radix || 2 > radix) + return 0; + + if (isdigit(ch)) { + digit = ch - '0'; + } else if (isalnum(ch)) { + digit = toupper(ch) - 'A' + 10; + } else { + return 0; + } + + return (digit < radix); } typedef enum { - STATE_NULL, - ATOM_UNQUOTED, - ATOM_QUOTED, - ATOM_FUN_NAME, - NODE_NAME_UNQUOTED, - NODE_NAME_QUOTED, - MACRO_START, - MACRO_UNQUOTED, - MACRO_QUOTED, - RECORD_START, - RECORD_UNQUOTED, - RECORD_QUOTED, - NUMERAL_START, - NUMERAL_SIGNED, - NUMERAL_RADIX_LITERAL, - NUMERAL_SPECULATIVE_MANTISSA, - NUMERAL_FLOAT_MANTISSA, - NUMERAL_FLOAT_EXPONENT, - NUMERAL_FLOAT_SIGNED_EXPONENT, - PARSE_ERROR + STATE_NULL, + COMMENT, + COMMENT_FUNCTION, + COMMENT_MODULE, + COMMENT_DOC, + COMMENT_DOC_MACRO, + ATOM_UNQUOTED, + ATOM_QUOTED, + NODE_NAME_UNQUOTED, + NODE_NAME_QUOTED, + MACRO_START, + MACRO_UNQUOTED, + MACRO_QUOTED, + RECORD_START, + RECORD_UNQUOTED, + RECORD_QUOTED, + NUMERAL_START, + NUMERAL_BASE_VALUE, + NUMERAL_FLOAT, + NUMERAL_EXPONENT, + PREPROCESSOR } atom_parse_state_t; +static inline bool IsAWordChar(const int ch) { + return (ch < 0x80) && (ch != ' ') && (isalnum(ch) || ch == '_'); +} + static void ColouriseErlangDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler) { + WordList *keywordlists[], Accessor &styler) { - WordList &keywords = *keywordlists[0]; + StyleContext sc(startPos, length, initStyle, styler); + WordList &reservedWords = *keywordlists[0]; + WordList &erlangBIFs = *keywordlists[1]; + WordList &erlangPreproc = *keywordlists[2]; + WordList &erlangModulesAtt = *keywordlists[3]; + WordList &erlangDoc = *keywordlists[4]; + WordList &erlangDocMacro = *keywordlists[5]; + int radix_digits = 0; + int exponent_digits = 0; + atom_parse_state_t parse_state = STATE_NULL; + atom_parse_state_t old_parse_state = STATE_NULL; + bool to_late_to_comment = false; + char cur[100]; + int old_style = SCE_ERLANG_DEFAULT; styler.StartAt(startPos); - StyleContext sc(startPos, length, initStyle, styler); - atom_parse_state_t parse_state = STATE_NULL; - int radix_digits = 0; - int exponent_digits = 0; for (; sc.More(); sc.Forward()) { - if ( STATE_NULL != parse_state ) { - switch (parse_state) { - case STATE_NULL: - sc.SetState(SCE_ERLANG_DEFAULT); - break; - case ATOM_UNQUOTED: - if ( '@' == sc.ch ){ - parse_state = NODE_NAME_UNQUOTED; - } else if ( !isalnum(sc.ch) && sc.ch != '_' ) { - char s[100]; - sc.GetCurrent(s, sizeof(s)); - if (keywords.InList(s)) { - sc.ChangeState(SCE_ERLANG_KEYWORD); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else { - if ( '/' == sc.ch ) { - parse_state = ATOM_FUN_NAME; - } else { - sc.ChangeState(SCE_ERLANG_ATOM); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - } - } - break; - case ATOM_QUOTED: - if ( '@' == sc.ch ){ - parse_state = NODE_NAME_QUOTED; - } else if ( '\'' == sc.ch && '\\' != sc.chPrev ) { - sc.ChangeState(SCE_ERLANG_ATOM); - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case ATOM_FUN_NAME: - if ( !isdigit(sc.ch) ) { - sc.ChangeState(SCE_ERLANG_FUNCTION_NAME); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case NODE_NAME_QUOTED: - if ( '@' == sc.ch ) { - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else if ( '\'' == sc.ch && '\\' != sc.chPrev ) { - sc.ChangeState(SCE_ERLANG_NODE_NAME); - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case NODE_NAME_UNQUOTED: - if ( '@' == sc.ch ) { - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else if ( !isalnum(sc.ch) && sc.ch != '_' ) { - sc.ChangeState(SCE_ERLANG_NODE_NAME); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case RECORD_START: - if ( '\'' == sc.ch ) { - parse_state = RECORD_QUOTED; - } else if (isalpha(sc.ch) && islower(sc.ch)) { - parse_state = RECORD_UNQUOTED; - } else { // error - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case RECORD_QUOTED: - if ( '\'' == sc.ch && '\\' != sc.chPrev ) { - sc.ChangeState(SCE_ERLANG_RECORD); - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case RECORD_UNQUOTED: - if ( !isalpha(sc.ch) && '_' != sc.ch ) { - sc.ChangeState(SCE_ERLANG_RECORD); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case MACRO_START: - if ( '\'' == sc.ch ) { - parse_state = MACRO_QUOTED; - } else if (isalpha(sc.ch)) { - parse_state = MACRO_UNQUOTED; - } else { // error - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case MACRO_UNQUOTED: - if ( !isalpha(sc.ch) && '_' != sc.ch ) { - sc.ChangeState(SCE_ERLANG_MACRO); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case MACRO_QUOTED: - if ( '\'' == sc.ch && '\\' != sc.chPrev ) { - sc.ChangeState(SCE_ERLANG_MACRO); - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case NUMERAL_START: - if ( isdigit(sc.ch) ) { - radix_digits *= 10; - radix_digits += sc.ch - '0'; // Assuming ASCII here! - } else if ( '#' == sc.ch ) { - if ( 2 > radix_digits || 16 < radix_digits) { - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else { - parse_state = NUMERAL_RADIX_LITERAL; - } - } else if ( '.' == sc.ch && isdigit(sc.chNext)) { - radix_digits = 0; - parse_state = NUMERAL_FLOAT_MANTISSA; - } else if ( 'e' == sc.ch || 'E' == sc.ch ) { - exponent_digits = 0; - parse_state = NUMERAL_FLOAT_EXPONENT; - } else { - radix_digits = 0; - sc.ChangeState(SCE_ERLANG_NUMBER); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case NUMERAL_RADIX_LITERAL: - if ( !is_radix(radix_digits,sc.ch) ) { - radix_digits = 0; - if ( !isalnum(sc.ch) ) { - sc.ChangeState(SCE_ERLANG_NUMBER); - } - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case NUMERAL_FLOAT_MANTISSA: - if ( 'e' == sc.ch || 'E' == sc.ch ) { - exponent_digits = 0; - parse_state = NUMERAL_FLOAT_EXPONENT; - } else if ( !isdigit(sc.ch) ) { - sc.ChangeState(SCE_ERLANG_NUMBER); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } - break; - case NUMERAL_FLOAT_EXPONENT: - if ( '-' == sc.ch || '+' == sc.ch ) { - parse_state = NUMERAL_FLOAT_SIGNED_EXPONENT; - } else if ( !isdigit(sc.ch) ) { - if ( 0 < exponent_digits ) { - sc.ChangeState(SCE_ERLANG_NUMBER); - } - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else { - ++exponent_digits; - } - break; - case NUMERAL_FLOAT_SIGNED_EXPONENT: - if ( !isdigit(sc.ch) ) { - if ( 0 < exponent_digits ) { - sc.ChangeState(SCE_ERLANG_NUMBER); - } - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else { - ++exponent_digits; - } - break; - case NUMERAL_SIGNED: - if ( !isdigit(sc.ch) ) { - sc.ChangeState(SCE_ERLANG_NUMBER); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else if ( '.' == sc.ch ) { - parse_state = NUMERAL_FLOAT_MANTISSA; - } - break; - case NUMERAL_SPECULATIVE_MANTISSA: - if ( !isdigit(sc.ch) ) { - sc.ChangeState(SCE_ERLANG_OPERATOR); - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - } else { - parse_state = NUMERAL_FLOAT_MANTISSA; - } - break; - case PARSE_ERROR: - sc.SetState(SCE_ERLANG_DEFAULT); - parse_state = STATE_NULL; - break; - } - } else if (sc.state == SCE_ERLANG_OPERATOR) { - if (sc.chPrev == '.') { - if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' || sc.ch == '^') { - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - } else if (sc.ch == '\'') { - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - } else { - sc.SetState(SCE_ERLANG_DEFAULT); + int style = SCE_ERLANG_DEFAULT; + if (STATE_NULL != parse_state) { + + switch (parse_state) { + + case STATE_NULL : sc.SetState(SCE_ERLANG_DEFAULT); break; + + /* COMMENTS ------------------------------------------------------*/ + case COMMENT : { + if (sc.ch != '%') { + to_late_to_comment = true; + } else if (!to_late_to_comment && sc.ch == '%') { + // Switch to comment level 2 (Function) + sc.ChangeState(SCE_ERLANG_COMMENT_FUNCTION); + old_style = SCE_ERLANG_COMMENT_FUNCTION; + parse_state = COMMENT_FUNCTION; + sc.Forward(); + } } - } else { - sc.SetState(SCE_ERLANG_DEFAULT); - } - } else if (sc.state == SCE_ERLANG_VARIABLE) { - if (!isalnum(sc.ch) && sc.ch != '_') { - sc.SetState(SCE_ERLANG_DEFAULT); - } - } else if (sc.state == SCE_ERLANG_STRING) { - if (sc.ch == '\"' && sc.chPrev != '\\') { - sc.ForwardSetState(SCE_ERLANG_DEFAULT); + // V--- Falling through! + case COMMENT_FUNCTION : { + if (sc.ch != '%') { + to_late_to_comment = true; + } else if (!to_late_to_comment && sc.ch == '%') { + // Switch to comment level 3 (Module) + sc.ChangeState(SCE_ERLANG_COMMENT_MODULE); + old_style = SCE_ERLANG_COMMENT_MODULE; + parse_state = COMMENT_MODULE; + sc.Forward(); + } + } + // V--- Falling through! + case COMMENT_MODULE : { + if (parse_state != COMMENT) { + // Search for comment documentation + if (sc.chNext == '@') { + old_parse_state = parse_state; + parse_state = ('{' == sc.ch) + ? COMMENT_DOC_MACRO + : COMMENT_DOC; + sc.ForwardSetState(sc.state); + } + } + + // All comments types fall here. + if (sc.atLineEnd) { + to_late_to_comment = false; + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + case COMMENT_DOC : + // V--- Falling through! + case COMMENT_DOC_MACRO : { + + if (!isalnum(sc.ch)) { + // Try to match documentation comment + sc.GetCurrent(cur, sizeof(cur)); + + if (parse_state == COMMENT_DOC_MACRO + && erlangDocMacro.InList(cur)) { + sc.ChangeState(SCE_ERLANG_COMMENT_DOC_MACRO); + while (sc.ch != '}' && !sc.atLineEnd) + sc.Forward(); + } else if (erlangDoc.InList(cur)) { + sc.ChangeState(SCE_ERLANG_COMMENT_DOC); + } else { + sc.ChangeState(old_style); + } + + // Switch back to old state + sc.SetState(old_style); + parse_state = old_parse_state; + } + + if (sc.atLineEnd) { + to_late_to_comment = false; + sc.ChangeState(old_style); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* -------------------------------------------------------------- */ + /* Atoms ---------------------------------------------------------*/ + case ATOM_UNQUOTED : { + if ('@' == sc.ch){ + parse_state = NODE_NAME_UNQUOTED; + } else if (sc.ch == ':') { + // Searching for module name + if (sc.chNext == ' ') { + // error + sc.ChangeState(SCE_ERLANG_UNKNOWN); + parse_state = STATE_NULL; + } else { + sc.Forward(); + if (isalnum(sc.ch)) { + sc.GetCurrent(cur, sizeof(cur)); + sc.ChangeState(SCE_ERLANG_MODULES); + sc.SetState(SCE_ERLANG_MODULES); + } + } + } else if (!IsAWordChar(sc.ch)) { + + sc.GetCurrent(cur, sizeof(cur)); + if (reservedWords.InList(cur)) { + style = SCE_ERLANG_KEYWORD; + } else if (erlangBIFs.InList(cur) + && strcmp(cur,"erlang:")){ + style = SCE_ERLANG_BIFS; + } else if (sc.ch == '(' || '/' == sc.ch){ + style = SCE_ERLANG_FUNCTION_NAME; + } else { + style = SCE_ERLANG_ATOM; + } + + sc.ChangeState(style); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + + } break; + + case ATOM_QUOTED : { + if ( '@' == sc.ch ){ + parse_state = NODE_NAME_QUOTED; + } else if ('\'' == sc.ch && '\\' != sc.chPrev) { + sc.ChangeState(SCE_ERLANG_ATOM); + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* -------------------------------------------------------------- */ + /* Node names ----------------------------------------------------*/ + case NODE_NAME_UNQUOTED : { + if ('@' == sc.ch) { + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } else if (!IsAWordChar(sc.ch)) { + sc.ChangeState(SCE_ERLANG_NODE_NAME); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + case NODE_NAME_QUOTED : { + if ('@' == sc.ch) { + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } else if ('\'' == sc.ch && '\\' != sc.chPrev) { + sc.ChangeState(SCE_ERLANG_NODE_NAME_QUOTED); + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* -------------------------------------------------------------- */ + /* Records -------------------------------------------------------*/ + case RECORD_START : { + if ('\'' == sc.ch) { + parse_state = RECORD_QUOTED; + } else if (isalpha(sc.ch) && islower(sc.ch)) { + parse_state = RECORD_UNQUOTED; + } else { // error + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + case RECORD_UNQUOTED : { + if (!IsAWordChar(sc.ch)) { + sc.ChangeState(SCE_ERLANG_RECORD); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + case RECORD_QUOTED : { + if ('\'' == sc.ch && '\\' != sc.chPrev) { + sc.ChangeState(SCE_ERLANG_RECORD_QUOTED); + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* -------------------------------------------------------------- */ + /* Macros --------------------------------------------------------*/ + case MACRO_START : { + if ('\'' == sc.ch) { + parse_state = MACRO_QUOTED; + } else if (isalpha(sc.ch)) { + parse_state = MACRO_UNQUOTED; + } else { // error + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + case MACRO_UNQUOTED : { + if (!IsAWordChar(sc.ch)) { + sc.ChangeState(SCE_ERLANG_MACRO); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + case MACRO_QUOTED : { + if ('\'' == sc.ch && '\\' != sc.chPrev) { + sc.ChangeState(SCE_ERLANG_MACRO_QUOTED); + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* -------------------------------------------------------------- */ + /* Numerics ------------------------------------------------------*/ + /* Simple integer */ + case NUMERAL_START : { + if (isdigit(sc.ch)) { + radix_digits *= 10; + radix_digits += sc.ch - '0'; // Assuming ASCII here! + } else if ('#' == sc.ch) { + if (2 > radix_digits || 36 < radix_digits) { + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } else { + parse_state = NUMERAL_BASE_VALUE; + } + } else if ('.' == sc.ch && isdigit(sc.chNext)) { + radix_digits = 0; + parse_state = NUMERAL_FLOAT; + } else if ('e' == sc.ch || 'E' == sc.ch) { + exponent_digits = 0; + parse_state = NUMERAL_EXPONENT; + } else { + radix_digits = 0; + sc.ChangeState(SCE_ERLANG_NUMBER); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* Integer in other base than 10 (x#yyy) */ + case NUMERAL_BASE_VALUE : { + if (!is_radix(radix_digits,sc.ch)) { + radix_digits = 0; + + if (!isalnum(sc.ch)) + sc.ChangeState(SCE_ERLANG_NUMBER); + + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* Float (x.yyy) */ + case NUMERAL_FLOAT : { + if ('e' == sc.ch || 'E' == sc.ch) { + exponent_digits = 0; + parse_state = NUMERAL_EXPONENT; + } else if (!isdigit(sc.ch)) { + sc.ChangeState(SCE_ERLANG_NUMBER); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + + /* Exponent, either integer or float (xEyy, x.yyEzzz) */ + case NUMERAL_EXPONENT : { + if (('-' == sc.ch || '+' == sc.ch) + && (isdigit(sc.chNext))) { + sc.Forward(); + } else if (!isdigit(sc.ch)) { + if (0 < exponent_digits) + sc.ChangeState(SCE_ERLANG_NUMBER); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } else { + ++exponent_digits; + } + } break; + + /* -------------------------------------------------------------- */ + /* Preprocessor --------------------------------------------------*/ + case PREPROCESSOR : { + if (!IsAWordChar(sc.ch)) { + + sc.GetCurrent(cur, sizeof(cur)); + if (erlangPreproc.InList(cur)) { + style = SCE_ERLANG_PREPROC; + } else if (erlangModulesAtt.InList(cur)) { + style = SCE_ERLANG_MODULES_ATT; + } + + sc.ChangeState(style); + sc.SetState(SCE_ERLANG_DEFAULT); + parse_state = STATE_NULL; + } + } break; + } - } else if (sc.state == SCE_ERLANG_COMMENT ) { - if (sc.atLineEnd) { - sc.SetState(SCE_ERLANG_DEFAULT); + + } /* End of : STATE_NULL != parse_state */ + else + { + switch (sc.state) { + case SCE_ERLANG_VARIABLE : { + if (!IsAWordChar(sc.ch)) + sc.SetState(SCE_ERLANG_DEFAULT); + } break; + case SCE_ERLANG_STRING : { + if (sc.ch == '\"' && sc.chPrev != '\\') + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + } break; + case SCE_ERLANG_COMMENT : { + if (sc.atLineEnd) + sc.SetState(SCE_ERLANG_DEFAULT); + } break; + case SCE_ERLANG_CHARACTER : { + if (sc.chPrev == '\\') { + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + } else if (sc.ch != '\\') { + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + } + } break; + case SCE_ERLANG_OPERATOR : { + if (sc.chPrev == '.') { + if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' + || sc.ch == '^') { + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + } else if (sc.ch == '\'') { + sc.ForwardSetState(SCE_ERLANG_DEFAULT); + } else { + sc.SetState(SCE_ERLANG_DEFAULT); + } + } else { + sc.SetState(SCE_ERLANG_DEFAULT); + } + } break; } - } else if (sc.state == SCE_ERLANG_CHARACTER ) { - if ( sc.chPrev == '\\' ) { - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - } else if ( sc.ch != '\\' ) { - sc.ForwardSetState(SCE_ERLANG_DEFAULT); - } - } + } if (sc.state == SCE_ERLANG_DEFAULT) { - if (sc.ch == '%') { - sc.SetState(SCE_ERLANG_COMMENT); - } else if (sc.ch == '\"') { - sc.SetState(SCE_ERLANG_STRING); - } else if (sc.ch == '#') { - parse_state = RECORD_START; - sc.SetState(SCE_ERLANG_UNKNOWN); - } else if (sc.ch == '?') { - parse_state = MACRO_START; - sc.SetState(SCE_ERLANG_UNKNOWN); - } else if (sc.ch == '$') { - sc.SetState(SCE_ERLANG_CHARACTER); - } else if (sc.ch == '\'') { - parse_state = ATOM_QUOTED; - sc.SetState(SCE_ERLANG_UNKNOWN); - } else if ( isdigit(sc.ch) ) { - parse_state = NUMERAL_START; - radix_digits = sc.ch - '0'; - sc.SetState(SCE_ERLANG_UNKNOWN); - } else if ( '.' == sc.ch ) { - parse_state = NUMERAL_SPECULATIVE_MANTISSA; - sc.SetState(SCE_ERLANG_UNKNOWN); - } else if (isalpha(sc.ch) && isupper(sc.ch)) { - sc.SetState(SCE_ERLANG_VARIABLE); - } else if (isalpha(sc.ch)) { - parse_state = ATOM_UNQUOTED; - sc.SetState(SCE_ERLANG_UNKNOWN); - } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '\\') { - sc.SetState(SCE_ERLANG_OPERATOR); + bool no_new_state = false; + + switch (sc.ch) { + case '\"' : sc.SetState(SCE_ERLANG_STRING); break; + case '$' : sc.SetState(SCE_ERLANG_CHARACTER); break; + case '%' : { + parse_state = COMMENT; + sc.SetState(SCE_ERLANG_COMMENT); + } break; + case '#' : { + parse_state = RECORD_START; + sc.SetState(SCE_ERLANG_UNKNOWN); + } break; + case '?' : { + parse_state = MACRO_START; + sc.SetState(SCE_ERLANG_UNKNOWN); + } break; + case '\'' : { + parse_state = ATOM_QUOTED; + sc.SetState(SCE_ERLANG_UNKNOWN); + } break; + case '+' : + case '-' : { + if (IsADigit(sc.chNext)) { + parse_state = NUMERAL_START; + radix_digits = 0; + sc.SetState(SCE_ERLANG_UNKNOWN); + } else if (sc.ch != '+') { + parse_state = PREPROCESSOR; + sc.SetState(SCE_ERLANG_UNKNOWN); + } + } break; + default : no_new_state = true; + } + + if (no_new_state) { + if (isdigit(sc.ch)) { + parse_state = NUMERAL_START; + radix_digits = sc.ch - '0'; + sc.SetState(SCE_ERLANG_UNKNOWN); + } else if (isupper(sc.ch) || '_' == sc.ch) { + sc.SetState(SCE_ERLANG_VARIABLE); + } else if (isalpha(sc.ch)) { + parse_state = ATOM_UNQUOTED; + sc.SetState(SCE_ERLANG_UNKNOWN); + } else if (isoperator(static_cast<char>(sc.ch)) + || sc.ch == '\\') { + sc.SetState(SCE_ERLANG_OPERATOR); + } } } + } sc.Complete(); } -static int ClassifyFoldPointErlang( - Accessor &styler, - int styleNext, - int keyword_start +static int ClassifyErlangFoldPoint( + Accessor &styler, + int styleNext, + int keyword_start ) { int lev = 0; - if ( styler.Match(keyword_start,"case") - || ( - styler.Match(keyword_start,"fun") - && SCE_ERLANG_FUNCTION_NAME != styleNext) - || styler.Match(keyword_start,"if") - || styler.Match(keyword_start,"query") - || styler.Match(keyword_start,"receive") - ) { - ++lev; - } else if ( styler.Match(keyword_start,"end") ) { - --lev; - } + if (styler.Match(keyword_start,"case") + || ( + styler.Match(keyword_start,"fun") + && (SCE_ERLANG_FUNCTION_NAME != styleNext) + ) + || styler.Match(keyword_start,"if") + || styler.Match(keyword_start,"query") + || styler.Match(keyword_start,"receive") + ) { + ++lev; + } else if (styler.Match(keyword_start,"end")) { + --lev; + } + return lev; } - static void FoldErlangDoc( - unsigned int startPos, int length, int initStyle, - WordList** /*keywordlists*/, Accessor &styler + unsigned int startPos, int length, int initStyle, + WordList** /*keywordlists*/, Accessor &styler ) { unsigned int endPos = startPos + length; - //~ int visibleChars = 0; - int lineCurrent = styler.GetLine(startPos); - int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; - int levelCurrent = levelPrev; - char chNext = styler.SafeGetCharAt(startPos); + int currentLine = styler.GetLine(startPos); + int lev; + int previousLevel = styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK; + int currentLevel = previousLevel; int styleNext = styler.StyleAt(startPos); int style = initStyle; + int stylePrev; int keyword_start = 0; - - bool fold_keywords = true; - bool fold_comments = true; - bool fold_braces = true; - bool fold_function_clauses = false; - bool fold_clauses = false; - - //int clause_level = 0; + char ch; + char chNext = styler.SafeGetCharAt(startPos); + bool atEOL; for (unsigned int i = startPos; i < endPos; i++) { - char ch = chNext; + ch = chNext; chNext = styler.SafeGetCharAt(i + 1); - int stylePrev = style; + + // Get styles + stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); - bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); - - if ( (stylePrev != SCE_ERLANG_KEYWORD) && (style == SCE_ERLANG_KEYWORD) ) { - keyword_start = i; - } - if ( fold_keywords ) { - if ( (stylePrev == SCE_ERLANG_KEYWORD) - && (style != SCE_ERLANG_KEYWORD) - && (style != SCE_ERLANG_ATOM) - ) { - levelCurrent += ClassifyFoldPointErlang(styler,styleNext,keyword_start); - } - } - - if ( fold_comments ) { - if (style == SCE_ERLANG_COMMENT) { - if ((ch == '%') && (chNext == '{')) { - levelCurrent++; - } else if ((ch == '%') && (chNext == '}')) { - levelCurrent--; - } - } - } - - if ( fold_function_clauses ) { - if ( (SC_FOLDLEVELBASE == levelCurrent) /*&& (style == SCE_ERLANG_OPERATOR)*/ ) { - if ( (ch == '-') && (chNext == '>')) { - //~ fprintf(stderr,"levelCurrent=%d\n", levelCurrent); - //++clause_level; - //~ if ( 0 < clause_level ) - ++levelCurrent; - } - } - //~ if ( (stylePrev != SCE_ERLANG_RECORD) - //~ && (style != SCE_ERLANG_NUMBER) - //~ && (style != SCE_ERLANG_STRING) - //~ && (style != SCE_ERLANG_COMMENT) - //~ ) { - if ( (SC_FOLDLEVELBASE+1 == levelCurrent) && (ch == '.') ) { - //--clause_level; - //~ if ( 0 == clause_level ) - --levelCurrent; - } - //~ } - } - - if ( fold_clauses ) { - if ( (0 < levelCurrent) && (style == SCE_ERLANG_OPERATOR) ) { - if ((ch == '-') && (chNext == '>')) { - levelCurrent++; - } - if ( (ch == ';') ) { - levelCurrent--; - } - } - if ( (stylePrev != SCE_ERLANG_RECORD) - && (style != SCE_ERLANG_NUMBER) - && (style != SCE_ERLANG_STRING) - && (style != SCE_ERLANG_COMMENT) - ) { - if ( (ch == '.') ) { - levelCurrent--; - } - } - if ( (stylePrev == SCE_ERLANG_KEYWORD) - && (style != SCE_ERLANG_KEYWORD) - && (style != SCE_ERLANG_ATOM) - && ( - styler.Match(keyword_start,"end") // 'end' counted twice if fold_keywords too - || styler.Match(keyword_start,"after") ) - ) { - levelCurrent--; - } - } - - if ( fold_braces ) { - if (style == SCE_ERLANG_OPERATOR) { - if ( (ch == '{') || (ch == '(') || (ch == '[') ) { - levelCurrent++; - } else if ( (ch == '}') || (ch == ')') || (ch == ']') ) { - levelCurrent--; - } - } - } + atEOL = ((ch == '\r') && (chNext != '\n')) || (ch == '\n'); + + if (stylePrev != SCE_ERLANG_KEYWORD + && style == SCE_ERLANG_KEYWORD) { + keyword_start = i; + } + + // Fold on keywords + if (stylePrev == SCE_ERLANG_KEYWORD + && style != SCE_ERLANG_KEYWORD + && style != SCE_ERLANG_ATOM + ) { + currentLevel += ClassifyErlangFoldPoint(styler, + styleNext, + keyword_start); + } + + // Fold on comments + if (style == SCE_ERLANG_COMMENT + || style == SCE_ERLANG_COMMENT_MODULE + || style == SCE_ERLANG_COMMENT_FUNCTION) { + + if (ch == '%' && chNext == '{') { + currentLevel++; + } else if (ch == '%' && chNext == '}') { + currentLevel--; + } + } + + // Fold on braces + if (style == SCE_ERLANG_OPERATOR) { + if (ch == '{' || ch == '(' || ch == '[') { + currentLevel++; + } else if (ch == '}' || ch == ')' || ch == ']') { + currentLevel--; + } + } + if (atEOL) { - int lev = levelPrev; - //~ if (visibleChars == 0 && foldCompact) - //~ lev |= SC_FOLDLEVELWHITEFLAG; - //~ if ((levelCurrent > levelPrev) && (visibleChars > 0)) - if ((levelCurrent > levelPrev)) { + lev = previousLevel; + + if (currentLevel > previousLevel) lev |= SC_FOLDLEVELHEADERFLAG; - } - if (lev != styler.LevelAt(lineCurrent)) { - styler.SetLevel(lineCurrent, lev); - } - lineCurrent++; - levelPrev = levelCurrent; - //~ visibleChars = 0; + + if (lev != styler.LevelAt(currentLine)) + styler.SetLevel(currentLine, lev); + + currentLine++; + previousLevel = currentLevel; } - //~ if (!isspacechar(ch)) - //~ visibleChars++; } + // Fill in the real level of the next line, keeping the current flags as they will be filled in later - int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; - styler.SetLevel(lineCurrent, levelPrev | flagsNext); + styler.SetLevel(currentLine, + previousLevel + | (styler.LevelAt(currentLine) & ~SC_FOLDLEVELNUMBERMASK)); } static const char * const erlangWordListDesc[] = { - "Keywords", + "Erlang Reserved words", + "Erlang BIFs", + "Erlang Preprocessor", + "Erlang Module Attributes", + "Erlang Documentation", + "Erlang Documentation Macro", 0 }; LexerModule lmErlang( - SCLEX_ERLANG, - ColouriseErlangDoc, - "erlang", - FoldErlangDoc, - erlangWordListDesc); - + SCLEX_ERLANG, + ColouriseErlangDoc, + "erlang", + FoldErlangDoc, + erlangWordListDesc); |