// Scintilla source code edit control /** @file LexOpal.cxx ** Lexer for OPAL (functional language similar to Haskell) ** Written by Sebastian Pipping **/ #include #include #include #include #include #include "Platform.h" #include "PropSet.h" #include "Accessor.h" #include "KeyWords.h" #include "Scintilla.h" #include "SciLexer.h" #include "StyleContext.h" inline static void getRange( unsigned int start, unsigned int end, Accessor & styler, char * s, unsigned int len ) { unsigned int i = 0; while( ( i < end - start + 1 ) && ( i < len - 1 ) ) { s[i] = static_cast( styler[ start + i ] ); i++; } s[ i ] = '\0'; } inline bool HandleString( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { char ch; // Wait for string to close bool even_backslash_count = true; // Without gaps in between cur++; // Skip initial quote for( ; ; ) { if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_STRING ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ( ch == '\015' ) || ( ch == '\012' ) ) // Deny multi-line strings { styler.ColourTo( cur - 1, SCE_OPAL_STRING ); styler.StartSegment( cur ); return true; } else { if( even_backslash_count ) { if( ch == '"' ) { styler.ColourTo( cur, SCE_OPAL_STRING ); cur++; if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( ch == '\\' ) { even_backslash_count = false; } } else { even_backslash_count = true; } } cur++; } } inline bool HandleCommentBlock( unsigned int & cur, unsigned int one_too_much, Accessor & styler, bool could_fail ) { char ch; if( could_fail ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ch != '*' ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); styler.StartSegment( cur ); return true; } } // Wait for comment close cur++; bool star_found = false; for( ; ; ) { if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_BLOCK ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( star_found ) { if( ch == '/' ) { styler.ColourTo( cur, SCE_OPAL_COMMENT_BLOCK ); cur++; if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( ch != '*' ) { star_found = false; } } else if( ch == '*' ) { star_found = true; } cur++; } } inline bool HandleCommentLine( unsigned int & cur, unsigned int one_too_much, Accessor & styler, bool could_fail ) { char ch; if( could_fail ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ch != '-' ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); styler.StartSegment( cur ); return true; } cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ( ch != ' ' ) && ( ch != '\t' ) ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); styler.StartSegment( cur ); return true; } } // Wait for end of line bool fifteen_found = false; for( ; ; ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( fifteen_found ) { /* if( ch == '\012' ) { // One newline on Windows (015, 012) } else { // One newline on MAC (015) and another char } */ cur--; styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); styler.StartSegment( cur ); return true; } else { if( ch == '\015' ) { fifteen_found = true; } else if( ch == '\012' ) { // One newline on Linux (012) styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); styler.StartSegment( cur ); return true; } } } } inline bool HandlePar( unsigned int & cur, Accessor & styler ) { styler.ColourTo( cur, SCE_OPAL_PAR ); cur++; styler.StartSegment( cur ); return true; } inline bool HandleSpace( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { char ch; cur++; for( ; ; ) { if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_SPACE ); return false; } ch = styler.SafeGetCharAt( cur ); switch( ch ) { case ' ': case '\t': case '\015': case '\012': cur++; break; default: styler.ColourTo( cur - 1, SCE_OPAL_SPACE ); styler.StartSegment( cur ); return true; } } } inline bool HandleInteger( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { char ch; for( ; ; ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_INTEGER ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( !isdigit( ch ) ) { styler.ColourTo( cur - 1, SCE_OPAL_INTEGER ); styler.StartSegment( cur ); return true; } } } inline bool HandleWord( unsigned int & cur, unsigned int one_too_much, Accessor & styler, WordList * keywordlists[] ) { char ch; const unsigned int beg = cur; cur++; for( ; ; ) { ch = styler.SafeGetCharAt( cur ); if( ( ch != '_' ) && ( ch != '-' ) && !islower( ch ) && !isupper( ch ) && !isdigit( ch ) ) break; cur++; if( cur >= one_too_much ) { break; } } const int ide_len = cur - beg + 1; char * ide = new char[ ide_len ]; getRange( beg, cur, styler, ide, ide_len ); WordList & keywords = *keywordlists[ 0 ]; WordList & classwords = *keywordlists[ 1 ]; if( keywords.InList( ide ) ) // Keyword { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_KEYWORD ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( classwords.InList( ide ) ) // Sort { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_SORT ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( !strcmp( ide, "true" ) || !strcmp( ide, "false" ) ) // Bool const { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_BOOL_CONST ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else // Unknown keyword { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } } inline bool HandleSkip( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { cur++; styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } static void ColouriseOpalDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor & styler ) { styler.StartAt( startPos ); styler.StartSegment( startPos ); unsigned int & cur = startPos; const unsigned int one_too_much = startPos + length; int state = initStyle; for( ; ; ) { switch( state ) { case SCE_OPAL_KEYWORD: case SCE_OPAL_SORT: if( !HandleWord( cur, one_too_much, styler, keywordlists ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_INTEGER: if( !HandleInteger( cur, one_too_much, styler ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_COMMENT_BLOCK: if( !HandleCommentBlock( cur, one_too_much, styler, false ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_COMMENT_LINE: if( !HandleCommentLine( cur, one_too_much, styler, false ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_STRING: if( !HandleString( cur, one_too_much, styler ) ) return; state = SCE_OPAL_DEFAULT; break; default: // SCE_OPAL_DEFAULT: { char ch = styler.SafeGetCharAt( cur ); switch( ch ) { // String case '"': if( !HandleString( cur, one_too_much, styler ) ) return; break; // Comment block case '/': if( !HandleCommentBlock( cur, one_too_much, styler, true ) ) return; break; // Comment line case '-': if( !HandleCommentLine( cur, one_too_much, styler, true ) ) return; break; // Par case '(': case ')': case '[': case ']': case '{': case '}': if( !HandlePar( cur, styler ) ) return; break; // Whitespace case ' ': case '\t': case '\015': case '\012': if( !HandleSpace( cur, one_too_much, styler ) ) return; break; default: { // Integer if( isdigit( ch ) ) { if( !HandleInteger( cur, one_too_much, styler ) ) return; } // Keyword else if( islower( ch ) || isupper( ch ) ) { if( !HandleWord( cur, one_too_much, styler, keywordlists ) ) return; } // Skip else { if( !HandleSkip( cur, one_too_much, styler ) ) return; } } } break; } } } } static const char * const opalWordListDesc[] = { "Keywords", "Sorts", 0 }; LexerModule lmOpal(SCLEX_OPAL, ColouriseOpalDoc, "opal", NULL, opalWordListDesc);