in ext/scintilla/lexers/LexHaskell.cxx [476:962]
void SCI_METHOD LexerHaskell::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle
,IDocument *pAccess) {
LexAccessor styler(pAccess);
Sci_Position lineCurrent = styler.GetLine(startPos);
HaskellLineInfo hs = HaskellLineInfo(lineCurrent ? styler.GetLineState(lineCurrent-1) : 0);
// Do not leak onto next line
if (initStyle == SCE_HA_STRINGEOL)
initStyle = SCE_HA_DEFAULT;
else if (initStyle == SCE_HA_LITERATE_CODEDELIM)
initStyle = hs.nonexternalStyle;
StyleContext sc(startPos, length, initStyle, styler);
int base = 10;
bool dot = false;
bool inDashes = false;
bool alreadyInTheMiddleOfOperator = false;
assert(!(IsCommentBlockStyle(initStyle) && hs.nestLevel == 0));
while (sc.More()) {
// Check for state end
if (!IsExternalStyle(sc.state)) {
hs.nonexternalStyle = sc.state;
}
// For lexer to work, states should unconditionally forward at least one
// character.
// If they don't, they should still check if they are at line end and
// forward if so.
// If a state forwards more than one character, it should check every time
// that it is not a line end and cease forwarding otherwise.
if (sc.atLineEnd) {
// Remember the line state for future incremental lexing
styler.SetLineState(lineCurrent, hs.ToLineState());
lineCurrent++;
}
// Handle line continuation generically.
if (sc.ch == '\\' && (sc.chNext == '\n' || sc.chNext == '\r')
&& ( sc.state == SCE_HA_STRING
|| sc.state == SCE_HA_PREPROCESSOR)) {
// Remember the line state for future incremental lexing
styler.SetLineState(lineCurrent, hs.ToLineState());
lineCurrent++;
sc.Forward();
if (sc.ch == '\r' && sc.chNext == '\n') {
sc.Forward();
}
sc.Forward();
continue;
}
if (sc.atLineStart) {
if (sc.state == SCE_HA_STRING || sc.state == SCE_HA_CHARACTER) {
// Prevent SCE_HA_STRINGEOL from leaking back to previous line
sc.SetState(sc.state);
}
if (literate && hs.lmode == LITERATE_BIRD) {
if (!IsExternalStyle(sc.state)) {
sc.SetState(SCE_HA_LITERATE_COMMENT);
}
}
}
// External
// Literate
if ( literate && hs.lmode == LITERATE_BIRD && sc.atLineStart
&& sc.ch == '>') {
sc.SetState(SCE_HA_LITERATE_CODEDELIM);
sc.ForwardSetState(hs.nonexternalStyle);
}
else if (literate && hs.lmode == LITERATE_BIRD && sc.atLineStart
&& ( sc.ch == ' ' || sc.ch == '\t'
|| sc.Match("\\begin{code}"))) {
sc.SetState(sc.state);
while ((sc.ch == ' ' || sc.ch == '\t') && sc.More())
sc.Forward();
if (sc.Match("\\begin{code}")) {
sc.Forward(static_cast<int>(strlen("\\begin{code}")));
bool correct = true;
while (!sc.atLineEnd && sc.More()) {
if (sc.ch != ' ' && sc.ch != '\t') {
correct = false;
}
sc.Forward();
}
if (correct) {
sc.ChangeState(SCE_HA_LITERATE_CODEDELIM); // color the line end
hs.lmode = LITERATE_BLOCK;
}
}
}
else if (literate && hs.lmode == LITERATE_BLOCK && sc.atLineStart
&& sc.Match("\\end{code}")) {
sc.SetState(SCE_HA_LITERATE_CODEDELIM);
sc.Forward(static_cast<int>(strlen("\\end{code}")));
while (!sc.atLineEnd && sc.More()) {
sc.Forward();
}
sc.SetState(SCE_HA_LITERATE_COMMENT);
hs.lmode = LITERATE_BIRD;
}
// Preprocessor
else if (sc.atLineStart && sc.ch == '#' && options.cpp
&& (!options.stylingWithinPreprocessor || sc.state == SCE_HA_DEFAULT)) {
sc.SetState(SCE_HA_PREPROCESSOR);
sc.Forward();
}
// Literate
else if (sc.state == SCE_HA_LITERATE_COMMENT) {
sc.Forward();
}
else if (sc.state == SCE_HA_LITERATE_CODEDELIM) {
sc.ForwardSetState(hs.nonexternalStyle);
}
// Preprocessor
else if (sc.state == SCE_HA_PREPROCESSOR) {
if (sc.atLineEnd) {
sc.SetState(options.stylingWithinPreprocessor
? SCE_HA_DEFAULT
: hs.nonexternalStyle);
sc.Forward(); // prevent double counting a line
} else if (options.stylingWithinPreprocessor && !IsHaskellLetter(sc.ch)) {
sc.SetState(SCE_HA_DEFAULT);
} else {
sc.Forward();
}
}
// Haskell
// Operator
else if (sc.state == SCE_HA_OPERATOR) {
int style = SCE_HA_OPERATOR;
if ( sc.ch == ':'
&& !alreadyInTheMiddleOfOperator
// except "::"
&& !( sc.chNext == ':'
&& !IsAnHaskellOperatorChar(sc.GetRelative(2)))) {
style = SCE_HA_CAPITAL;
}
alreadyInTheMiddleOfOperator = false;
while (IsAnHaskellOperatorChar(sc.ch))
sc.Forward();
char s[100];
sc.GetCurrent(s, sizeof(s));
if (reserved_operators.InList(s))
style = SCE_HA_RESERVED_OPERATOR;
sc.ChangeState(style);
sc.SetState(SCE_HA_DEFAULT);
}
// String
else if (sc.state == SCE_HA_STRING) {
if (sc.atLineEnd) {
sc.ChangeState(SCE_HA_STRINGEOL);
sc.ForwardSetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\"') {
sc.Forward();
skipMagicHash(sc, oneHash);
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\\') {
sc.Forward(2);
} else {
sc.Forward();
}
}
// Char
else if (sc.state == SCE_HA_CHARACTER) {
if (sc.atLineEnd) {
sc.ChangeState(SCE_HA_STRINGEOL);
sc.ForwardSetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\'') {
sc.Forward();
skipMagicHash(sc, oneHash);
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\\') {
sc.Forward(2);
} else {
sc.Forward();
}
}
// Number
else if (sc.state == SCE_HA_NUMBER) {
if (sc.atLineEnd) {
sc.SetState(SCE_HA_DEFAULT);
sc.Forward(); // prevent double counting a line
} else if (IsADigit(sc.ch, base)) {
sc.Forward();
} else if (sc.ch=='.' && dot && IsADigit(sc.chNext, base)) {
sc.Forward(2);
dot = false;
} else if ((base == 10) &&
(sc.ch == 'e' || sc.ch == 'E') &&
(IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-')) {
sc.Forward();
if (sc.ch == '+' || sc.ch == '-')
sc.Forward();
} else {
skipMagicHash(sc, twoHashes);
sc.SetState(SCE_HA_DEFAULT);
}
}
// Keyword or Identifier
else if (sc.state == SCE_HA_IDENTIFIER) {
int style = IsHaskellUpperCase(sc.ch) ? SCE_HA_CAPITAL : SCE_HA_IDENTIFIER;
assert(IsAHaskellWordStart(sc.ch));
sc.Forward();
while (sc.More()) {
if (IsAHaskellWordChar(sc.ch)) {
sc.Forward();
} else if (sc.ch == '.' && style == SCE_HA_CAPITAL) {
if (IsHaskellUpperCase(sc.chNext)) {
sc.Forward();
style = SCE_HA_CAPITAL;
} else if (IsAHaskellWordStart(sc.chNext)) {
sc.Forward();
style = SCE_HA_IDENTIFIER;
} else if (IsAnHaskellOperatorChar(sc.chNext)) {
sc.Forward();
style = sc.ch == ':' ? SCE_HA_CAPITAL : SCE_HA_OPERATOR;
while (IsAnHaskellOperatorChar(sc.ch))
sc.Forward();
break;
} else {
break;
}
} else {
break;
}
}
skipMagicHash(sc, unlimitedHashes);
char s[100];
sc.GetCurrent(s, sizeof(s));
KeywordMode new_mode = HA_MODE_DEFAULT;
if (keywords.InList(s)) {
style = SCE_HA_KEYWORD;
} else if (style == SCE_HA_CAPITAL) {
if (hs.mode == HA_MODE_IMPORT1 || hs.mode == HA_MODE_IMPORT3) {
style = SCE_HA_MODULE;
new_mode = HA_MODE_IMPORT2;
} else if (hs.mode == HA_MODE_MODULE) {
style = SCE_HA_MODULE;
}
} else if (hs.mode == HA_MODE_IMPORT1 &&
strcmp(s,"qualified") == 0) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_IMPORT1;
} else if (options.highlightSafe &&
hs.mode == HA_MODE_IMPORT1 &&
strcmp(s,"safe") == 0) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_IMPORT1;
} else if (hs.mode == HA_MODE_IMPORT2) {
if (strcmp(s,"as") == 0) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_IMPORT3;
} else if (strcmp(s,"hiding") == 0) {
style = SCE_HA_KEYWORD;
}
} else if (hs.mode == HA_MODE_TYPE) {
if (strcmp(s,"family") == 0)
style = SCE_HA_KEYWORD;
}
if (hs.mode == HA_MODE_FFI) {
if (ffi.InList(s)) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_FFI;
}
}
sc.ChangeState(style);
sc.SetState(SCE_HA_DEFAULT);
if (strcmp(s,"import") == 0 && hs.mode != HA_MODE_FFI)
new_mode = HA_MODE_IMPORT1;
else if (strcmp(s,"module") == 0)
new_mode = HA_MODE_MODULE;
else if (strcmp(s,"foreign") == 0)
new_mode = HA_MODE_FFI;
else if (strcmp(s,"type") == 0
|| strcmp(s,"data") == 0)
new_mode = HA_MODE_TYPE;
hs.mode = new_mode;
}
// Comments
// Oneliner
else if (sc.state == SCE_HA_COMMENTLINE) {
if (sc.atLineEnd) {
sc.SetState(hs.pragma ? SCE_HA_PRAGMA : SCE_HA_DEFAULT);
sc.Forward(); // prevent double counting a line
} else if (inDashes && sc.ch != '-' && !hs.pragma) {
inDashes = false;
if (IsAnHaskellOperatorChar(sc.ch)) {
alreadyInTheMiddleOfOperator = true;
sc.ChangeState(SCE_HA_OPERATOR);
}
} else {
sc.Forward();
}
}
// Nested
else if (IsCommentBlockStyle(sc.state)) {
if (sc.Match('{','-')) {
sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
sc.Forward(2);
hs.nestLevel++;
} else if (sc.Match('-','}')) {
sc.Forward(2);
assert(hs.nestLevel > 0);
if (hs.nestLevel > 0)
hs.nestLevel--;
sc.SetState(
hs.nestLevel == 0
? (hs.pragma ? SCE_HA_PRAGMA : SCE_HA_DEFAULT)
: CommentBlockStyleFromNestLevel(hs.nestLevel - 1));
} else {
sc.Forward();
}
}
// Pragma
else if (sc.state == SCE_HA_PRAGMA) {
if (sc.Match("#-}")) {
hs.pragma = false;
sc.Forward(3);
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.Match('-','-')) {
sc.SetState(SCE_HA_COMMENTLINE);
sc.Forward(2);
inDashes = false;
} else if (sc.Match('{','-')) {
sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
sc.Forward(2);
hs.nestLevel = 1;
} else {
sc.Forward();
}
}
// New state?
else if (sc.state == SCE_HA_DEFAULT) {
// Digit
if (IsADigit(sc.ch)) {
hs.mode = HA_MODE_DEFAULT;
sc.SetState(SCE_HA_NUMBER);
if (sc.ch == '0' && (sc.chNext == 'X' || sc.chNext == 'x')) {
// Match anything starting with "0x" or "0X", too
sc.Forward(2);
base = 16;
dot = false;
} else if (sc.ch == '0' && (sc.chNext == 'O' || sc.chNext == 'o')) {
// Match anything starting with "0o" or "0O", too
sc.Forward(2);
base = 8;
dot = false;
} else {
sc.Forward();
base = 10;
dot = true;
}
}
// Pragma
else if (sc.Match("{-#")) {
hs.pragma = true;
sc.SetState(SCE_HA_PRAGMA);
sc.Forward(3);
}
// Comment line
else if (sc.Match('-','-')) {
sc.SetState(SCE_HA_COMMENTLINE);
sc.Forward(2);
inDashes = true;
}
// Comment block
else if (sc.Match('{','-')) {
sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
sc.Forward(2);
hs.nestLevel = 1;
}
// String
else if (sc.ch == '\"') {
sc.SetState(SCE_HA_STRING);
sc.Forward();
}
// Character or quoted name or promoted term
else if (sc.ch == '\'') {
hs.mode = HA_MODE_DEFAULT;
sc.SetState(SCE_HA_CHARACTER);
sc.Forward();
if (options.allowQuotes) {
// Quoted type ''T
if (sc.ch=='\'' && IsAHaskellWordStart(sc.chNext)) {
sc.Forward();
sc.ChangeState(SCE_HA_IDENTIFIER);
} else if (sc.chNext != '\'') {
// Quoted name 'n or promoted constructor 'N
if (IsAHaskellWordStart(sc.ch)) {
sc.ChangeState(SCE_HA_IDENTIFIER);
// Promoted constructor operator ':~>
} else if (sc.ch == ':') {
alreadyInTheMiddleOfOperator = false;
sc.ChangeState(SCE_HA_OPERATOR);
// Promoted list or tuple '[T]
} else if (sc.ch == '[' || sc.ch== '(') {
sc.ChangeState(SCE_HA_OPERATOR);
sc.ForwardSetState(SCE_HA_DEFAULT);
}
}
}
}
// Operator starting with '?' or an implicit parameter
else if (sc.ch == '?') {
hs.mode = HA_MODE_DEFAULT;
alreadyInTheMiddleOfOperator = false;
sc.SetState(SCE_HA_OPERATOR);
if ( options.implicitParams
&& IsAHaskellWordStart(sc.chNext)
&& !IsHaskellUpperCase(sc.chNext)) {
sc.Forward();
sc.ChangeState(SCE_HA_IDENTIFIER);
}
}
// Operator
else if (IsAnHaskellOperatorChar(sc.ch)) {
hs.mode = HA_MODE_DEFAULT;
sc.SetState(SCE_HA_OPERATOR);
}
// Braces and punctuation
else if (sc.ch == ',' || sc.ch == ';'
|| sc.ch == '(' || sc.ch == ')'
|| sc.ch == '[' || sc.ch == ']'
|| sc.ch == '{' || sc.ch == '}') {
sc.SetState(SCE_HA_OPERATOR);
sc.ForwardSetState(SCE_HA_DEFAULT);
}
// Keyword or Identifier
else if (IsAHaskellWordStart(sc.ch)) {
sc.SetState(SCE_HA_IDENTIFIER);
// Something we don't care about
} else {
sc.Forward();
}
}
// This branch should never be reached.
else {
assert(false);
sc.Forward();
}
}
sc.Complete();
}