in ext/scintilla/lexers/LexNim.cxx [313:719]
void SCI_METHOD LexerNim::Lex(Sci_PositionU startPos, Sci_Position length,
int initStyle, IDocument *pAccess) {
// No one likes a leaky string
if (initStyle == SCE_NIM_STRINGEOL) {
initStyle = SCE_NIM_DEFAULT;
}
Accessor styler(pAccess, NULL);
StyleContext sc(startPos, length, initStyle, styler);
// Nim supports nested block comments!
Sci_Position lineCurrent = styler.GetLine(startPos);
int commentNestLevel = lineCurrent > 0 ? styler.GetLineState(lineCurrent - 1) : 0;
int numType = NumType::Decimal;
int decimalCount = 0;
bool funcNameExists = false;
bool isStylingRawString = false;
bool isStylingRawStringIdent = false;
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart) {
if (sc.state == SCE_NIM_STRING) {
sc.SetState(SCE_NIM_STRING);
}
lineCurrent = styler.GetLine(sc.currentPos);
styler.SetLineState(lineCurrent, commentNestLevel);
}
// Handle string line continuation
if (sc.ch == '\\' && (sc.chNext == '\n' || sc.chNext == '\r') &&
(sc.state == SCE_NIM_STRING || sc.state == SCE_NIM_CHARACTER) && !isStylingRawString) {
sc.Forward();
if (sc.ch == '\r' && sc.chNext == '\n') {
sc.Forward();
}
continue;
}
switch (sc.state) {
case SCE_NIM_OPERATOR:
funcNameExists = false;
sc.SetState(SCE_NIM_DEFAULT);
break;
case SCE_NIM_NUMBER:
// For a type suffix, such as 0x80'u8
if (sc.ch == '\'') {
if (sc.chNext == 'i' || sc.chNext == 'I' ||
sc.chNext == 'u' || sc.chNext == 'U' ||
sc.chNext == 'f' || sc.chNext == 'F' ||
sc.chNext == 'd' || sc.chNext == 'D') {
sc.Forward(2);
}
} else if (sc.ch == '.') {
if (IsADigit(sc.chNext)) {
sc.Forward();
} else if (numType <= NumType::Exponent) {
sc.SetState(SCE_NIM_OPERATOR);
break;
} else {
decimalCount++;
if (numType == NumType::Decimal) {
if (decimalCount <= 1 && !IsAWordChar(sc.chNext)) {
break;
}
} else if (numType == NumType::Hexadecimal) {
if (decimalCount <= 1 && IsADigit(sc.chNext, 16)) {
break;
}
sc.SetState(SCE_NIM_OPERATOR);
break;
}
}
} else if (sc.ch == '_') {
// Accept only one underscore between digits
if (IsADigit(sc.chNext)) {
sc.Forward();
}
} else if (numType == NumType::Decimal) {
if (sc.chPrev != '\'' && (sc.ch == 'e' || sc.ch == 'E')) {
numType = NumType::Exponent;
if (sc.chNext == '-' || sc.chNext == '+') {
sc.Forward();
}
break;
}
if (IsADigit(sc.ch)) {
break;
}
} else if (numType == NumType::Hexadecimal) {
if (IsADigit(sc.ch, 16)) {
break;
}
} else if (IsADigit(sc.ch)) {
if (numType == NumType::Exponent) {
break;
}
if (numType == NumType::Octal) {
// Accept only 0-7
if (sc.ch <= '7') {
break;
}
} else if (numType == NumType::Binary) {
// Accept only 0 and 1
if (sc.ch <= '1') {
break;
}
}
numType = NumType::FormatError;
break;
}
sc.ChangeState(GetNumStyle(numType));
sc.SetState(SCE_NIM_DEFAULT);
break;
case SCE_NIM_IDENTIFIER:
if (sc.ch == '.' || !IsAWordChar(sc.ch)) {
char s[100];
sc.GetCurrent(s, sizeof(s));
int style = SCE_NIM_IDENTIFIER;
if (keywords.InList(s) && !funcNameExists) {
// Prevent styling keywords if they are sub-identifiers
Sci_Position segStart = styler.GetStartSegment() - 1;
if (segStart < 0 || styler.SafeGetCharAt(segStart, '\0') != '.') {
style = SCE_NIM_WORD;
}
} else if (funcNameExists) {
style = SCE_NIM_FUNCNAME;
}
sc.ChangeState(style);
sc.SetState(SCE_NIM_DEFAULT);
if (style == SCE_NIM_WORD) {
funcNameExists = IsFuncName(s);
} else {
funcNameExists = false;
}
}
if (IsAlphaNumeric(sc.ch) && sc.chNext == '\"') {
isStylingRawStringIdent = true;
if (options.highlightRawStrIdent) {
if (styler.SafeGetCharAt(sc.currentPos + 2) == '\"' &&
styler.SafeGetCharAt(sc.currentPos + 3) == '\"') {
sc.ChangeState(SCE_NIM_TRIPLEDOUBLE);
} else {
sc.ChangeState(SCE_NIM_STRING);
}
}
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
break;
case SCE_NIM_FUNCNAME:
if (sc.ch == '`') {
funcNameExists = false;
sc.ForwardSetState(SCE_NIM_DEFAULT);
} else if (sc.atLineEnd) {
// Prevent leaking the style to the next line if not closed
funcNameExists = false;
sc.ChangeState(SCE_NIM_STRINGEOL);
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
break;
case SCE_NIM_COMMENT:
if (sc.Match(']', '#')) {
if (commentNestLevel > 0) {
commentNestLevel--;
}
lineCurrent = styler.GetLine(sc.currentPos);
styler.SetLineState(lineCurrent, commentNestLevel);
sc.Forward();
if (commentNestLevel == 0) {
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
} else if (sc.Match('#', '[')) {
commentNestLevel++;
lineCurrent = styler.GetLine(sc.currentPos);
styler.SetLineState(lineCurrent, commentNestLevel);
}
break;
case SCE_NIM_COMMENTDOC:
if (sc.Match("]##")) {
if (commentNestLevel > 0) {
commentNestLevel--;
}
lineCurrent = styler.GetLine(sc.currentPos);
styler.SetLineState(lineCurrent, commentNestLevel);
sc.Forward(2);
if (commentNestLevel == 0) {
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
} else if (sc.Match("##[")) {
commentNestLevel++;
lineCurrent = styler.GetLine(sc.currentPos);
styler.SetLineState(lineCurrent, commentNestLevel);
}
break;
case SCE_NIM_COMMENTLINE:
case SCE_NIM_COMMENTLINEDOC:
if (sc.atLineStart) {
sc.SetState(SCE_NIM_DEFAULT);
}
break;
case SCE_NIM_STRING:
if (!isStylingRawStringIdent && !isStylingRawString && sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (isStylingRawString && sc.ch == '\"' && sc.chNext == '\"') {
// Forward in situations such as r"a""bc\" so that "bc\" wouldn't be
// considered a string of its own
sc.Forward();
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_NIM_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_NIM_STRINGEOL);
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
break;
case SCE_NIM_CHARACTER:
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_NIM_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_NIM_STRINGEOL);
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
break;
case SCE_NIM_BACKTICKS:
if (sc.ch == '`' ) {
sc.ForwardSetState(SCE_NIM_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_NIM_STRINGEOL);
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
break;
case SCE_NIM_TRIPLEDOUBLE:
if (sc.Match(R"(""")")) {
// Outright forward all " after the closing """ as a triple double
//
// A valid example where this is needed is: """8 double quotes->""""""""
// You can have as many """ at the end as you wish, as long as the actual
// closing literal is there
while (sc.ch == '"') {
sc.Forward();
}
sc.SetState(SCE_NIM_DEFAULT);
}
break;
case SCE_NIM_TRIPLE:
if (sc.Match("'''")) {
sc.Forward(2);
sc.ForwardSetState(SCE_NIM_DEFAULT);
}
break;
}
if (sc.state == SCE_NIM_DEFAULT) {
// Number
if (IsADigit(sc.ch)) {
sc.SetState(SCE_NIM_NUMBER);
numType = NumType::Decimal;
decimalCount = 0;
if (sc.ch == '0') {
if (IsNumHex(sc)) {
numType = NumType::Hexadecimal;
} else if (IsNumBinary(sc)) {
numType = NumType::Binary;
} else if (IsNumOctal(sc)) {
numType = NumType::Octal;
}
if (numType != NumType::Decimal) {
sc.Forward();
}
}
}
// Raw string
else if (IsAlphaNumeric(sc.ch) && sc.chNext == '\"') {
isStylingRawString = true;
// Triple doubles can be raw strings too. How sweet
if (styler.SafeGetCharAt(sc.currentPos + 2) == '\"' &&
styler.SafeGetCharAt(sc.currentPos + 3) == '\"') {
sc.SetState(SCE_NIM_TRIPLEDOUBLE);
} else {
sc.SetState(SCE_NIM_STRING);
}
int rawStrStyle = options.highlightRawStrIdent ? IsLetter(sc.ch) :
(sc.ch == 'r' || sc.ch == 'R');
if (rawStrStyle) {
sc.Forward();
if (sc.state == SCE_NIM_TRIPLEDOUBLE) {
sc.Forward(2);
}
} else {
// Anything other than r/R is considered a general raw string identifier
isStylingRawStringIdent = true;
sc.SetState(SCE_NIM_IDENTIFIER);
}
}
// String and triple double literal
else if (sc.ch == '\"') {
isStylingRawString = false;
if (sc.Match(R"(""")")) {
sc.SetState(SCE_NIM_TRIPLEDOUBLE);
// Keep forwarding until the total opening literal count is 5
// A valid example where this is needed is: """""<-5 double quotes"""
while (sc.ch == '"') {
sc.Forward();
if (sc.Match(R"(""")")) {
sc.Forward();
break;
}
}
} else {
sc.SetState(SCE_NIM_STRING);
}
}
// Charecter and triple literal
else if (sc.ch == '\'') {
if (sc.Match("'''")) {
sc.SetState(SCE_NIM_TRIPLE);
} else {
sc.SetState(SCE_NIM_CHARACTER);
}
}
// Operator definition
else if (sc.ch == '`') {
if (funcNameExists) {
sc.SetState(SCE_NIM_FUNCNAME);
} else {
sc.SetState(SCE_NIM_BACKTICKS);
}
}
// Keyword
else if (iswordstart(sc.ch)) {
sc.SetState(SCE_NIM_IDENTIFIER);
}
// Comments
else if (sc.ch == '#') {
if (sc.Match("##[") || sc.Match("#[")) {
commentNestLevel++;
lineCurrent = styler.GetLine(sc.currentPos);
styler.SetLineState(lineCurrent, commentNestLevel);
}
if (sc.Match("##[")) {
sc.SetState(SCE_NIM_COMMENTDOC);
sc.Forward();
} else if (sc.Match("#[")) {
sc.SetState(SCE_NIM_COMMENT);
sc.Forward();
} else if (sc.Match("##")) {
sc.SetState(SCE_NIM_COMMENTLINEDOC);
} else {
sc.SetState(SCE_NIM_COMMENTLINE);
}
}
// Operators
else if (strchr("()[]{}:=;-\\/&%$!+<>|^?,.*~@", sc.ch)) {
sc.SetState(SCE_NIM_OPERATOR);
}
}
if (sc.atLineEnd) {
funcNameExists = false;
isStylingRawString = false;
isStylingRawStringIdent = false;
}
}
sc.Complete();
}