diff options
Diffstat (limited to 'src/LexLisp.cxx')
-rw-r--r-- | src/LexLisp.cxx | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/LexLisp.cxx b/src/LexLisp.cxx new file mode 100644 index 000000000..0fa1dcb31 --- /dev/null +++ b/src/LexLisp.cxx @@ -0,0 +1,208 @@ +// 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" + + +inline bool isLispoperator(char ch) { + if (isascii(ch) && isalnum(ch)) + return false; + if (ch == '\'' || ch == '(' || ch == ')' ) + return true; + return false; +} + +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, 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; + } + } + styler.ColourTo(end, chAttr); + return; +} + + +static void ColouriseLispDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + + WordList &keywords = *keywordlists[0]; + + styler.StartAt(startPos); + + int state = initStyle; + int styleBeforeLineStart = initStyle; + if (state == SCE_LISP_STRINGEOL) // Does not leak onto next line + state = SCE_LISP_DEFAULT; + char chPrev = ' '; + char chNext = styler[startPos]; + char chPrevNonWhite = ' '; + unsigned int lengthDoc = startPos + length; + int visibleChars = 0; + 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 (atEOL) { + // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) + // Avoid triggering two times on Dos/Win + // End of line + if (state == SCE_LISP_STRINGEOL) { + styler.ColourTo(i, state); + state = SCE_LISP_DEFAULT; + } + } + + if (styler.IsLeadByte(ch)) { + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + if (state == SCE_LISP_DEFAULT) { + 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); + } + + else if (ch == '\"') { + state = SCE_LISP_STRING; + } + } else if (state == SCE_LISP_IDENTIFIER) { + if (!isLispwordstart(ch)) { + classifyWordLisp(styler.GetStartSegment(), i - 1, keywords, styler); + state = SCE_LISP_DEFAULT; + } /*else*/ + if (isLispoperator(ch) || ch=='\'') { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_LISP_OPERATOR); + } + + } else { + if (state == SCE_LISP_COMMENT) { + if (atEOL) { + styler.ColourTo(i - 1, state); + state = SCE_LISP_DEFAULT; + } + } else if (state == SCE_LISP_STRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourTo(i, state); + state = SCE_LISP_DEFAULT; + } else if ((chNext == '\r' || chNext == '\n') && (chPrev != '\\')) { + styler.ColourTo(i - 1, SCE_LISP_STRINGEOL); + state = SCE_LISP_STRINGEOL; + } + } + } + + if (atEOL) { + styleBeforeLineStart = state; + visibleChars = 0; + } + if (!isspacechar(ch)) + visibleChars++; + + chPrev = ch; + if (ch != ' ' && ch != '\t') + chPrevNonWhite = ch; + } + 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); + int style = initStyle; + for (unsigned int i = startPos; i < lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + 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); +} + +LexerModule lmLISP(SCLEX_LISP, ColouriseLispDoc, "lisp", FoldLispDoc); |