mirror of
				https://github.com/notepad-plus-plus/notepad-plus-plus.git
				synced 2025-10-31 11:34:05 +01:00 
			
		
		
		
	git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@742 f5eea248-9336-0410-98b8-ebc06183d4e3
		
			
				
	
	
		
			624 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			624 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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.
 | |
|  ** Enhanced by Etienne 'Lenain' Girondel (lenaing@gmail.com)
 | |
|  ** Originally wrote by Peter-Henry Mander,
 | |
|  ** based on Matlab lexer by José Fonseca.
 | |
|  **/
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| #include <stdarg.h>
 | |
| #include <assert.h>
 | |
| #include <ctype.h>
 | |
| 
 | |
| #include "ILexer.h"
 | |
| #include "Scintilla.h"
 | |
| #include "SciLexer.h"
 | |
| 
 | |
| #include "WordList.h"
 | |
| #include "LexAccessor.h"
 | |
| #include "Accessor.h"
 | |
| #include "StyleContext.h"
 | |
| #include "CharacterSet.h"
 | |
| #include "LexerModule.h"
 | |
| 
 | |
| #ifdef SCI_NAMESPACE
 | |
| using namespace Scintilla;
 | |
| #endif
 | |
| 
 | |
| static int is_radix(int radix, int ch) {
 | |
| 	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,
 | |
| 	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) {
 | |
| 
 | |
| 	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);
 | |
| 
 | |
| 	for (; sc.More(); sc.Forward()) {
 | |
| 		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();
 | |
| 					}
 | |
| 				}
 | |
| 				// 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;
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 		} /* 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;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (sc.state == SCE_ERLANG_DEFAULT) {
 | |
| 			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 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;
 | |
| 	}
 | |
| 
 | |
| 	return lev;
 | |
| }
 | |
| 
 | |
| static void FoldErlangDoc(
 | |
| 	unsigned int startPos, int length, int initStyle,
 | |
| 	WordList** /*keywordlists*/, Accessor &styler
 | |
| ) {
 | |
| 	unsigned int endPos = startPos + length;
 | |
| 	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;
 | |
| 	char ch;
 | |
| 	char chNext = styler.SafeGetCharAt(startPos);
 | |
| 	bool atEOL;
 | |
| 
 | |
| 	for (unsigned int i = startPos; i < endPos; i++) {
 | |
| 		ch = chNext;
 | |
| 		chNext = styler.SafeGetCharAt(i + 1);
 | |
| 
 | |
| 		// Get styles
 | |
| 		stylePrev = style;
 | |
| 		style = styleNext;
 | |
| 		styleNext = styler.StyleAt(i + 1);
 | |
| 		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) {
 | |
| 			lev = previousLevel;
 | |
| 
 | |
| 			if (currentLevel > previousLevel)
 | |
| 				lev |= SC_FOLDLEVELHEADERFLAG;
 | |
| 
 | |
| 			if (lev != styler.LevelAt(currentLine))
 | |
| 				styler.SetLevel(currentLine, lev);
 | |
| 
 | |
| 			currentLine++;
 | |
| 			previousLevel = currentLevel;
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
 | |
| 	styler.SetLevel(currentLine,
 | |
| 					previousLevel
 | |
| 					| (styler.LevelAt(currentLine) & ~SC_FOLDLEVELNUMBERMASK));
 | |
| }
 | |
| 
 | |
| static const char * const erlangWordListDesc[] = {
 | |
| 	"Erlang Reserved words",
 | |
| 	"Erlang BIFs",
 | |
| 	"Erlang Preprocessor",
 | |
| 	"Erlang Module Attributes",
 | |
| 	"Erlang Documentation",
 | |
| 	"Erlang Documentation Macro",
 | |
| 	0
 | |
| };
 | |
| 
 | |
| LexerModule lmErlang(
 | |
| 	SCLEX_ERLANG,
 | |
| 	ColouriseErlangDoc,
 | |
| 	"erlang",
 | |
| 	FoldErlangDoc,
 | |
| 	erlangWordListDesc);
 |