notepad-plus-plus/scintilla/lexers/LexOpal.cxx

526 lines
10 KiB
C++

// Scintilla source code edit control
/** @file LexOpal.cxx
** Lexer for OPAL (functional language similar to Haskell)
** Written by Sebastian Pipping <webmaster@hartwork.org>
**/
#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
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<char>( 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( !( isascii( ch ) && 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 != '-' ) &&
!( isascii( 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( isascii( ch ) && isdigit( ch ) )
{
if( !HandleInteger( cur, one_too_much, styler ) ) return;
}
// Keyword
else if( isascii( ch ) && ( 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);