You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
8.0 KiB
275 lines
8.0 KiB
// Scintilla source code edit control |
|
/** @file LexLisp.cxx |
|
** Lexer for Lisp. |
|
** Written by Alexey Yutkin. |
|
**/ |
|
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> |
|
// The License.txt file describes the conditions under which this software may be distributed. |
|
|
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <ctype.h> |
|
#include <stdio.h> |
|
#include <stdarg.h> |
|
|
|
#include "Platform.h" |
|
|
|
#include "PropSet.h" |
|
#include "Accessor.h" |
|
#include "KeyWords.h" |
|
#include "Scintilla.h" |
|
#include "SciLexer.h" |
|
#include "StyleContext.h" |
|
|
|
#define SCE_LISP_CHARACTER 29 |
|
#define SCE_LISP_MACRO 30 |
|
#define SCE_LISP_MACRO_DISPATCH 31 |
|
|
|
static inline bool isLispoperator(char ch) { |
|
if (isascii(ch) && isalnum(ch)) |
|
return false; |
|
if (ch == '\'' || ch == '`' || ch == '(' || ch == ')' ) |
|
return true; |
|
return false; |
|
} |
|
|
|
static inline bool isLispwordstart(char ch) { |
|
return isascii(ch) && ch != ';' && !isspacechar(ch) && !isLispoperator(ch) && |
|
ch != '\n' && ch != '\r' && ch != '\"'; |
|
} |
|
|
|
|
|
static void classifyWordLisp(unsigned int start, unsigned int end, WordList &keywords, WordList &keywords_kw, Accessor &styler) { |
|
PLATFORM_ASSERT(end >= start); |
|
char s[100]; |
|
unsigned int i; |
|
bool digit_flag = true; |
|
for (i = 0; (i < end - start + 1) && (i < 99); i++) { |
|
s[i] = styler[start + i]; |
|
s[i + 1] = '\0'; |
|
if (!isdigit(s[i]) && (s[i] != '.')) digit_flag = false; |
|
} |
|
char chAttr = SCE_LISP_IDENTIFIER; |
|
|
|
if(digit_flag) chAttr = SCE_LISP_NUMBER; |
|
else { |
|
if (keywords.InList(s)) { |
|
chAttr = SCE_LISP_KEYWORD; |
|
} else if (keywords_kw.InList(s)) { |
|
chAttr = SCE_LISP_KEYWORD_KW; |
|
} else if ((s[0] == '*' && s[i-1] == '*') || |
|
(s[0] == '+' && s[i-1] == '+')) { |
|
chAttr = SCE_LISP_SPECIAL; |
|
} |
|
} |
|
styler.ColourTo(end, chAttr); |
|
return; |
|
} |
|
|
|
|
|
static void ColouriseLispDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], |
|
Accessor &styler) { |
|
|
|
WordList &keywords = *keywordlists[0]; |
|
WordList &keywords_kw = *keywordlists[1]; |
|
|
|
styler.StartAt(startPos); |
|
|
|
int state = initStyle, radix = -1; |
|
char chNext = styler[startPos]; |
|
unsigned int lengthDoc = startPos + length; |
|
styler.StartSegment(startPos); |
|
for (unsigned int i = startPos; i < lengthDoc; i++) { |
|
char ch = chNext; |
|
chNext = styler.SafeGetCharAt(i + 1); |
|
|
|
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); |
|
|
|
if (styler.IsLeadByte(ch)) { |
|
chNext = styler.SafeGetCharAt(i + 2); |
|
i += 1; |
|
continue; |
|
} |
|
|
|
if (state == SCE_LISP_DEFAULT) { |
|
if (ch == '#') { |
|
styler.ColourTo(i - 1, state); |
|
radix = -1; |
|
state = SCE_LISP_MACRO_DISPATCH; |
|
} else if (isLispwordstart(ch)) { |
|
styler.ColourTo(i - 1, state); |
|
state = SCE_LISP_IDENTIFIER; |
|
} |
|
else if (ch == ';') { |
|
styler.ColourTo(i - 1, state); |
|
state = SCE_LISP_COMMENT; |
|
} |
|
else if (isLispoperator(ch) || ch=='\'') { |
|
styler.ColourTo(i - 1, state); |
|
styler.ColourTo(i, SCE_LISP_OPERATOR); |
|
if (ch=='\'' && isLispwordstart(chNext)) { |
|
state = SCE_LISP_SYMBOL; |
|
} |
|
} |
|
else if (ch == '\"') { |
|
styler.ColourTo(i - 1, state); |
|
state = SCE_LISP_STRING; |
|
} |
|
} else if (state == SCE_LISP_IDENTIFIER || state == SCE_LISP_SYMBOL) { |
|
if (!isLispwordstart(ch)) { |
|
if (state == SCE_LISP_IDENTIFIER) { |
|
classifyWordLisp(styler.GetStartSegment(), i - 1, keywords, keywords_kw, styler); |
|
} else { |
|
styler.ColourTo(i - 1, state); |
|
} |
|
state = SCE_LISP_DEFAULT; |
|
} /*else*/ |
|
if (isLispoperator(ch) || ch=='\'') { |
|
styler.ColourTo(i - 1, state); |
|
styler.ColourTo(i, SCE_LISP_OPERATOR); |
|
if (ch=='\'' && isLispwordstart(chNext)) { |
|
state = SCE_LISP_SYMBOL; |
|
} |
|
} |
|
} else if (state == SCE_LISP_MACRO_DISPATCH) { |
|
if (!isdigit(ch)) { |
|
if (ch != 'r' && ch != 'R' && (i - styler.GetStartSegment()) > 1) { |
|
state = SCE_LISP_DEFAULT; |
|
} else { |
|
switch (ch) { |
|
case '|': state = SCE_LISP_MULTI_COMMENT; break; |
|
case 'o': |
|
case 'O': radix = 8; state = SCE_LISP_MACRO; break; |
|
case 'x': |
|
case 'X': radix = 16; state = SCE_LISP_MACRO; break; |
|
case 'b': |
|
case 'B': radix = 2; state = SCE_LISP_MACRO; break; |
|
case '\\': state = SCE_LISP_CHARACTER; break; |
|
case ':': |
|
case '-': |
|
case '+': state = SCE_LISP_MACRO; break; |
|
case '\'': if (isLispwordstart(chNext)) { |
|
state = SCE_LISP_SPECIAL; |
|
} else { |
|
styler.ColourTo(i - 1, SCE_LISP_DEFAULT); |
|
styler.ColourTo(i, SCE_LISP_OPERATOR); |
|
state = SCE_LISP_DEFAULT; |
|
} |
|
break; |
|
default: if (isLispoperator(ch)) { |
|
styler.ColourTo(i - 1, SCE_LISP_DEFAULT); |
|
styler.ColourTo(i, SCE_LISP_OPERATOR); |
|
} |
|
state = SCE_LISP_DEFAULT; |
|
break; |
|
} |
|
} |
|
} |
|
} else if (state == SCE_LISP_MACRO) { |
|
if (isLispwordstart(ch) && (radix == -1 || IsADigit(ch, radix))) { |
|
state = SCE_LISP_SPECIAL; |
|
} else { |
|
state = SCE_LISP_DEFAULT; |
|
} |
|
} else if (state == SCE_LISP_CHARACTER) { |
|
if (isLispoperator(ch)) { |
|
styler.ColourTo(i, SCE_LISP_SPECIAL); |
|
state = SCE_LISP_DEFAULT; |
|
} else if (isLispwordstart(ch)) { |
|
styler.ColourTo(i, SCE_LISP_SPECIAL); |
|
state = SCE_LISP_SPECIAL; |
|
} else { |
|
state = SCE_LISP_DEFAULT; |
|
} |
|
} else if (state == SCE_LISP_SPECIAL) { |
|
if (!isLispwordstart(ch) || (radix != -1 && !IsADigit(ch, radix))) { |
|
styler.ColourTo(i - 1, state); |
|
state = SCE_LISP_DEFAULT; |
|
} |
|
if (isLispoperator(ch) || ch=='\'') { |
|
styler.ColourTo(i - 1, state); |
|
styler.ColourTo(i, SCE_LISP_OPERATOR); |
|
if (ch=='\'' && isLispwordstart(chNext)) { |
|
state = SCE_LISP_SYMBOL; |
|
} |
|
} |
|
} else { |
|
if (state == SCE_LISP_COMMENT) { |
|
if (atEOL) { |
|
styler.ColourTo(i - 1, state); |
|
state = SCE_LISP_DEFAULT; |
|
} |
|
} else if (state == SCE_LISP_MULTI_COMMENT) { |
|
if (ch == '|' && chNext == '#') { |
|
i++; |
|
chNext = styler.SafeGetCharAt(i + 1); |
|
styler.ColourTo(i, state); |
|
state = SCE_LISP_DEFAULT; |
|
} |
|
} else if (state == SCE_LISP_STRING) { |
|
if (ch == '\\') { |
|
if (chNext == '\"' || chNext == '\'' || chNext == '\\') { |
|
i++; |
|
chNext = styler.SafeGetCharAt(i + 1); |
|
} |
|
} else if (ch == '\"') { |
|
styler.ColourTo(i, state); |
|
state = SCE_LISP_DEFAULT; |
|
} |
|
} |
|
} |
|
|
|
} |
|
styler.ColourTo(lengthDoc - 1, state); |
|
} |
|
|
|
static void FoldLispDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[], |
|
Accessor &styler) { |
|
unsigned int lengthDoc = startPos + length; |
|
int visibleChars = 0; |
|
int lineCurrent = styler.GetLine(startPos); |
|
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; |
|
int levelCurrent = levelPrev; |
|
char chNext = styler[startPos]; |
|
int styleNext = styler.StyleAt(startPos); |
|
for (unsigned int i = startPos; i < lengthDoc; i++) { |
|
char ch = chNext; |
|
chNext = styler.SafeGetCharAt(i + 1); |
|
int style = styleNext; |
|
styleNext = styler.StyleAt(i + 1); |
|
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); |
|
if (style == SCE_LISP_OPERATOR) { |
|
if (ch == '(') { |
|
levelCurrent++; |
|
} else if (ch == ')') { |
|
levelCurrent--; |
|
} |
|
} |
|
if (atEOL) { |
|
int lev = levelPrev; |
|
if (visibleChars == 0) |
|
lev |= SC_FOLDLEVELWHITEFLAG; |
|
if ((levelCurrent > levelPrev) && (visibleChars > 0)) |
|
lev |= SC_FOLDLEVELHEADERFLAG; |
|
if (lev != styler.LevelAt(lineCurrent)) { |
|
styler.SetLevel(lineCurrent, lev); |
|
} |
|
lineCurrent++; |
|
levelPrev = levelCurrent; |
|
visibleChars = 0; |
|
} |
|
if (!isspacechar(ch)) |
|
visibleChars++; |
|
} |
|
// Fill in the real level of the next line, keeping the current flags as they will be filled in later |
|
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; |
|
styler.SetLevel(lineCurrent, levelPrev | flagsNext); |
|
} |
|
|
|
static const char * const lispWordListDesc[] = { |
|
"Functions and special operators", |
|
"Keywords", |
|
0 |
|
}; |
|
|
|
LexerModule lmLISP(SCLEX_LISP, ColouriseLispDoc, "lisp", FoldLispDoc, lispWordListDesc);
|
|
|