diff options
author | nyamatongwe <unknown> | 2005-02-10 13:17:30 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2005-02-10 13:17:30 +0000 |
commit | 13751eb229ef06302b01bf0f715cdae53219dbdf (patch) | |
tree | 59a205db67bc95b3e0217ae35e96d9ea016b11f9 /src | |
parent | 6eee037fe180acd217d783aebb1e0aafda3b64b2 (diff) | |
download | scintilla-mirror-13751eb229ef06302b01bf0f715cdae53219dbdf.tar.gz |
Lexers added for Objective Caml, PureBasic and BlitzBasic.
Diffstat (limited to 'src')
-rw-r--r-- | src/KeyWords.cxx | 3 | ||||
-rw-r--r-- | src/LexBasic.cxx | 325 | ||||
-rw-r--r-- | src/LexCaml.cxx | 389 |
3 files changed, 717 insertions, 0 deletions
diff --git a/src/KeyWords.cxx b/src/KeyWords.cxx index 66e82094c..858eb54a3 100644 --- a/src/KeyWords.cxx +++ b/src/KeyWords.cxx @@ -137,7 +137,10 @@ int Scintilla_LinkLexers() { LINK_LEXER(lmAVE); LINK_LEXER(lmBaan); LINK_LEXER(lmBash); + LINK_LEXER(lmBlitzBasic); + LINK_LEXER(lmPureBasic); LINK_LEXER(lmBullant); + LINK_LEXER(lmCaml); LINK_LEXER(lmClw); LINK_LEXER(lmClwNoCase); LINK_LEXER(lmConf); diff --git a/src/LexBasic.cxx b/src/LexBasic.cxx new file mode 100644 index 000000000..b8f83f171 --- /dev/null +++ b/src/LexBasic.cxx @@ -0,0 +1,325 @@ +// Scintilla source code edit control +/** @file LexBB.cxx + ** Lexer for BlitzBasic. + **/ +// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +// This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics +// and derivatives. Once they diverge enough, might want to split it into multiple +// lexers for more code clearity. +// +// Mail me (elias <at> users <dot> sf <dot> net) for any bugs. + +// Folding only works for simple things like functions or types. + +// You may want to have a look at my ctags lexer as well, if you additionally to coloring +// and folding need to extract things like label tags in your editor. + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +/* Bits: + * 1 - whitespace + * 2 - operator + * 4 - identifier + * 8 - decimal digit + * 16 - hex digit + * 32 - bin digit + */ +static int character_classification[128] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2, + 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2, + 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4, + 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0 +}; + +static bool IsSpace(int c) { + return c < 128 && (character_classification[c] & 1); +} + +static bool IsOperator(int c) { + return c < 128 && (character_classification[c] & 2); +} + +static bool IsIdentifier(int c) { + return c < 128 && (character_classification[c] & 4); +} + +static bool IsDigit(int c) { + return c < 128 && (character_classification[c] & 8); +} + +static bool IsHexDigit(int c) { + return c < 128 && (character_classification[c] & 16); +} + +static bool IsBinDigit(int c) { + return c < 128 && (character_classification[c] & 32); +} + +static int LowerCase(int c) +{ + if (c >= 'A' && c <= 'Z') + return 'a' + c - 'A'; + return c; +} + +static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle, + WordList *keywordlists[], Accessor &styler) { + bool wasfirst = true, isfirst = true; // true if first token in a line + styler.StartAt(startPos); + + StyleContext sc(startPos, length, initStyle, styler); + + // Can't use sc.More() here else we miss the last character + for (; ; sc.Forward()) { + if (sc.state == SCE_B_IDENTIFIER) { + if (!IsIdentifier(sc.ch)) { + // Labels + if (wasfirst && sc.Match(':')) { + sc.ChangeState(SCE_B_LABEL); + sc.ForwardSetState(SCE_B_DEFAULT); + } else { + char s[100]; + int kstates[4] = { + SCE_B_KEYWORD, + SCE_B_KEYWORD2, + SCE_B_KEYWORD3, + SCE_B_KEYWORD4, + }; + sc.GetCurrentLowered(s, sizeof(s)); + for (int i = 0; i < 4; i++) { + if (keywordlists[i]->InList(s)) { + sc.ChangeState(kstates[i]); + } + } + // Types, must set them as operator else they will be + // matched as number/constant + if (sc.Match('.') || sc.Match('$') || sc.Match('%') || + sc.Match('#')) { + sc.SetState(SCE_B_OPERATOR); + } else { + sc.SetState(SCE_B_DEFAULT); + } + } + } + } else if (sc.state == SCE_B_OPERATOR) { + if (!IsOperator(sc.ch) || sc.Match('#')) + sc.SetState(SCE_B_DEFAULT); + } else if (sc.state == SCE_B_LABEL) { + if (!IsIdentifier(sc.ch)) + sc.SetState(SCE_B_DEFAULT); + } else if (sc.state == SCE_B_CONSTANT) { + if (!IsIdentifier(sc.ch)) + sc.SetState(SCE_B_DEFAULT); + } else if (sc.state == SCE_B_NUMBER) { + if (!IsDigit(sc.ch)) + sc.SetState(SCE_B_DEFAULT); + } else if (sc.state == SCE_B_HEXNUMBER) { + if (!IsHexDigit(sc.ch)) + sc.SetState(SCE_B_DEFAULT); + } else if (sc.state == SCE_B_BINNUMBER) { + if (!IsBinDigit(sc.ch)) + sc.SetState(SCE_B_DEFAULT); + } else if (sc.state == SCE_B_STRING) { + if (sc.ch == '"') { + sc.ForwardSetState(SCE_B_DEFAULT); + } + if (sc.atLineEnd) { + sc.ChangeState(SCE_B_ERROR); + sc.SetState(SCE_B_DEFAULT); + } + } else if (sc.state == SCE_B_COMMENT) { + if (sc.atLineEnd) { + sc.SetState(SCE_B_DEFAULT); + } + } + + if (sc.atLineStart) + isfirst = true; + + if (sc.state == SCE_B_DEFAULT || sc.state == SCE_B_ERROR) { + if (isfirst && sc.Match('.')) { + sc.SetState(SCE_B_LABEL); + } else if (sc.Match(';')) { + sc.SetState(SCE_B_COMMENT); + } else if (sc.Match('"')) { + sc.SetState(SCE_B_STRING); + } else if (IsDigit(sc.ch)) { + sc.SetState(SCE_B_NUMBER); + } else if (sc.Match('$')) { + sc.SetState(SCE_B_HEXNUMBER); + } else if (sc.Match('%')) { + sc.SetState(SCE_B_BINNUMBER); + } else if (sc.Match('#')) { + sc.SetState(SCE_B_CONSTANT); + } else if (IsOperator(sc.ch)) { + sc.SetState(SCE_B_OPERATOR); + } else if (IsIdentifier(sc.ch)) { + wasfirst = isfirst; + sc.SetState(SCE_B_IDENTIFIER); + } else if (!IsSpace(sc.ch)) { + sc.SetState(SCE_B_ERROR); + } + } + + if (!IsSpace(sc.ch)) + isfirst = false; + + if (!sc.More()) + break; + } + sc.Complete(); +} + +static int CheckBlitzFoldPoint(char const *token, int &level) { + if (!strcmp(token, "function") || + !strcmp(token, "type")) { + level |= SC_FOLDLEVELHEADERFLAG; + return 1; + } + if (!strcmp(token, "end function") || + !strcmp(token, "end type")) { + return -1; + } + return 0; +} + +static int CheckPureFoldPoint(char const *token, int &level) { + if (!strcmp(token, "procedure") || + !strcmp(token, "enumeration") || + !strcmp(token, "interface") || + !strcmp(token, "structure")) { + level |= SC_FOLDLEVELHEADERFLAG; + return 1; + } + if (!strcmp(token, "endprocedure") || + !strcmp(token, "endenumeration") || + !strcmp(token, "endinterface") || + !strcmp(token, "endstructure")) { + return -1; + } + return 0; +} + +static void FoldBasicDoc(unsigned int startPos, int length, + Accessor &styler, int (*CheckFoldPoint)(char const *, int &)) { + int line = styler.GetLine(startPos); + int level = styler.LevelAt(line); + int go = 0, done = 0; + int endPos = startPos + length; + char word[256]; + int wordlen = 0; + int i; + bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + // Scan for tokens at the start of the line (they may include + // whitespace, for tokens like "End Function" + for (i = startPos; i < endPos; i++) { + int c = styler.SafeGetCharAt(i); + if (!done && !go) { + if (wordlen) { // are we scanning a token already? + word[wordlen] = static_cast<char>(LowerCase(c)); + if (!IsIdentifier(c)) { // done with token + word[wordlen] = '\0'; + go = CheckFoldPoint(word, level); + if (!go) { + // Treat any whitespace as single blank, for + // things like "End Function". + if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) { + word[wordlen] = ' '; + if (wordlen < 255) + wordlen++; + } + else // done with this line + done = 1; + } + } else if (wordlen < 255) { + wordlen++; + } + } else { // start scanning at first non-whitespace character + if (!IsSpace(c)) { + if (IsIdentifier(c)) { + word[0] = static_cast<char>(LowerCase(c)); + wordlen = 1; + } else // done with this line + done = 1; + } + } + } + if (c == '\n') { // line end + if (!done && wordlen == 0 && foldCompact) // line was only space + level |= SC_FOLDLEVELWHITEFLAG; + if (level != styler.LevelAt(line)) + styler.SetLevel(line, level); + level += go; + line++; + // reset state + wordlen = 0; + level &= ~SC_FOLDLEVELHEADERFLAG; + level &= ~SC_FOLDLEVELWHITEFLAG; + go = 0; + done = 0; + } + } +} + +static void ColouriseBlitzBasicDoc(unsigned int startPos, int length, int initStyle, + WordList *keywordlists[], Accessor &styler) { + ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler); +} + +static void ColourisePureBasicDoc(unsigned int startPos, int length, int initStyle, + WordList *keywordlists[], Accessor &styler) { + ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler); +} + +static void FoldBlitzBasicDoc(unsigned int startPos, int length, int, + WordList *[], Accessor &styler) { + FoldBasicDoc(startPos, length, styler, CheckBlitzFoldPoint); +} + +static void FoldPureBasicDoc(unsigned int startPos, int length, int, + WordList *[], Accessor &styler) { + FoldBasicDoc(startPos, length, styler, CheckPureFoldPoint); +} + +static const char * const blitzbasicWordListDesc[] = { + "BlitzBasic Keywords", + "user1", + "user2", + "user3", + 0 +}; + +static const char * const purebasicWordListDesc[] = { + "PureBasic Keywords", + "PureBasic PreProcessor Keywords", + "user defined 1", + "user defined 2", + 0 +}; + +LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, ColouriseBlitzBasicDoc, "blitzbasic", + FoldBlitzBasicDoc, blitzbasicWordListDesc); + +LexerModule lmPureBasic(SCLEX_PUREBASIC, ColourisePureBasicDoc, "purebasic", + FoldPureBasicDoc, purebasicWordListDesc); + diff --git a/src/LexCaml.cxx b/src/LexCaml.cxx new file mode 100644 index 000000000..ac1bfba5d --- /dev/null +++ b/src/LexCaml.cxx @@ -0,0 +1,389 @@ +// Scintilla source code edit control +/** @file LexCaml.cxx + ** Lexer for Objective Caml. + **/ +// Copyright 2005 by Robert Roessler <robertr@rftp.com> +// The License.txt file describes the conditions under which this software may be distributed. +/* Release History + 20050204 Initial release. + 20050205 Quick compiler standards/"cleanliness" adjustment. + 20050206 Added cast for IsLeadByte(). + 20050209 Changes to "external" build support. +*/ + +#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 "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +// Since the Microsoft __iscsym[f] funcs are not ANSI... +inline int iscaml(int c) {return isalnum(c) || c == '_';} +inline int iscamlf(int c) {return isalpha(c) || c == '_';} + +#ifdef BUILD_AS_EXTERNAL_LEXER +/* + (actually seems to work!) +*/ +#include "WindowAccessor.h" +#include "ExternalLexer.h" + +#if PLAT_WIN +#include <windows.h> +#endif + +static void ColouriseCamlDoc( + unsigned int startPos, int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler); + +static void FoldCamlDoc( + unsigned int startPos, int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler); + +static void InternalLexOrFold(int lexOrFold, unsigned int startPos, int length, + int initStyle, char *words[], WindowID window, char *props); + +static const char* LexerName = "caml"; + +#ifdef TRACE +void Platform::DebugPrintf(const char *format, ...) { + char buffer[2000]; + va_list pArguments; + va_start(pArguments, format); + vsprintf(buffer,format,pArguments); + va_end(pArguments); + Platform::DebugDisplay(buffer); +} +#else +void Platform::DebugPrintf(const char *, ...) { +} +#endif + +bool Platform::IsDBCSLeadByte(int codePage, char ch) { + return ::IsDBCSLeadByteEx(codePage, ch) != 0; +} + +long Platform::SendScintilla(WindowID w, unsigned int msg, unsigned long wParam, long lParam) { + return ::SendMessage(reinterpret_cast<HWND>(w), msg, wParam, lParam); +} + +long Platform::SendScintillaPointer(WindowID w, unsigned int msg, unsigned long wParam, void *lParam) { + return ::SendMessage(reinterpret_cast<HWND>(w), msg, wParam, + reinterpret_cast<LPARAM>(lParam)); +} + +void EXT_LEXER_DECL Fold(unsigned int lexer, unsigned int startPos, int length, + int initStyle, char *words[], WindowID window, char *props) +{ + // below useless evaluation(s) to supress "not used" warnings + lexer; + // build expected data structures and do the Fold + InternalLexOrFold(1, startPos, length, initStyle, words, window, props); + +} + +int EXT_LEXER_DECL GetLexerCount() +{ + return 1; // just us [Objective] Caml lexers here! +} + +void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int buflength) +{ + // below useless evaluation(s) to supress "not used" warnings + Index; + // return as much of our lexer name as will fit (what's up with Index?) + if (buflength > 0) { + buflength--; + int n = strlen(LexerName); + if (n > buflength) + n = buflength; + memcpy(name, LexerName, n), name[n] = '\0'; + } +} + +void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, + int initStyle, char *words[], WindowID window, char *props) +{ + // below useless evaluation(s) to supress "not used" warnings + lexer; + // build expected data structures and do the Lex + InternalLexOrFold(0, startPos, length, initStyle, words, window, props); +} + +static void InternalLexOrFold(int foldOrLex, unsigned int startPos, int length, + int initStyle, char *words[], WindowID window, char *props) +{ + // create and initialize a WindowAccessor (including contained PropSet) + PropSet ps; + ps.SetMultiple(props); + WindowAccessor wa(window, ps); + // create and initialize WordList(s) + int nWL = 0; + for (; words[nWL]; nWL++) ; // count # of WordList PTRs needed + WordList** wl = new WordList* [nWL + 1];// alloc WordList PTRs + int i = 0; + for (; i < nWL; i++) { + wl[i] = new WordList(); // (works or THROWS bad_alloc EXCEPTION) + wl[i]->Set(words[i]); + } + wl[i] = 0; + // call our "internal" folder/lexer (... then do Flush!) + if (foldOrLex) + FoldCamlDoc(startPos, length, initStyle, wl, wa); + else + ColouriseCamlDoc(startPos, length, initStyle, wl, wa); + wa.Flush(); + // clean up before leaving + for (i = nWL - 1; i >= 0; i--) + delete wl[i]; + delete [] wl; +} + +static +#endif /* BUILD_AS_EXTERNAL_LEXER */ + +void ColouriseCamlDoc( + unsigned int startPos, int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler) +{ + // initialize styler + styler.StartAt(startPos); + styler.StartSegment(startPos); + // set up [initial] state info (terminating states that shouldn't "bleed") + int state = initStyle, nesting = 0; + if (state < SCE_CAML_STRING) + state = SCE_CAML_DEFAULT; + if (state >= SCE_CAML_COMMENT) + nesting = state - SCE_CAML_COMMENT; + int chLast = startPos? static_cast<unsigned char>(styler[startPos - 1]): ' '; + int chNext = static_cast<unsigned char>(styler[startPos]); + + int chBase = 'd', chToken = 0, chLit = 0, chSkip; + WordList& keywords = *keywordlists[0]; + WordList& keywords2 = *keywordlists[1]; + + // foreach char in range... + unsigned int i = startPos; + for (unsigned int endPos = startPos + length; i < endPos; i += chSkip) { + // set up [per-char] state info + int ch = chNext; + chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1)); + int state2 = -1; // (ASSUME no state change) + int chColor = i - 1;// (ASSUME standard coloring range) + chSkip = 1; // (ASSUME scanner "eats" 1 char) + + // this may be the correct thing to do... or not + if (styler.IsLeadByte(static_cast<char>(ch))) { + chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), + chSkip++; + continue; + } + + // step state machine + switch (state) { + case SCE_CAML_DEFAULT: + // it's wide open; what do we have? + if (iscamlf(ch)) + state2 = SCE_CAML_IDENTIFIER, chToken = i; + else if (ch == '`') + state2 = SCE_CAML_TAGNAME, chToken = i; + else if (ch == '#' && isdigit(chNext)) + state2 = SCE_CAML_LINENUM, chToken = i; + else if (isdigit(ch)) { + state2 = SCE_CAML_NUMBER, + chBase = strchr("xXoObB", chNext)? chNext: 'd'; + if (chBase != 'd') + ch = chNext, + chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), + chSkip++; + } else if (ch == '\'') /* (char literal?) */ + state2 = SCE_CAML_CHAR, chToken = i, chLit = 0; + else if (ch == '\"') + state2 = SCE_CAML_STRING; + else if (ch == '(' && chNext == '*') + state2 = SCE_CAML_COMMENT, + ch = ' ', // (make SURE "(*)" isn't seen as a closed comment) + chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), + chSkip++, nesting = 0; + else if (strchr("!?~" /* Caml "prefix-symbol" */ + "=<>@^|&+-*/$%" /* Caml "infix-symbol" */ + "()[]{};,:.#", ch)) /* Caml "bracket" or ;,:.# */ + state2 = SCE_CAML_OPERATOR, chToken = i; + break; + + case SCE_CAML_IDENTIFIER: + // [try to] interpret as [additional] identifier char + if (!(iscaml(ch) || ch == '\'')) { + const int n = i - chToken; + if (n < 24) { + // length is believable as keyword, [re-]construct token + char t[24]; + int p = 0; + for (int q = chToken; p < n; p++, q++) + t[p] = styler[q]; + t[p] = '\0'; + // special-case "_" token as KEYWORD + if ((n == 1 && chLast == '_') || keywords.InList(t)) + state = SCE_CAML_KEYWORD; + else if (keywords2.InList(t)) + state = SCE_CAML_KEYWORD2; + } + state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; + } + break; + + case SCE_CAML_TAGNAME: + // [try to] interpret as [additional] tagname char + if (!(iscaml(ch) || ch == '\'')) + state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; + break; + + /*case SCE_CAML_KEYWORD: + case SCE_CAML_KEYWORD2: + // [try to] interpret as [additional] keyword char + if (!iscaml(ch)) + state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; + break;*/ + + case SCE_CAML_LINENUM: + // [try to] interpret as [additional] linenum directive char + if (!isdigit(ch)) + state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; + break; + + case SCE_CAML_OPERATOR: { + // [try to] interpret as [additional] operator char + char* o = 0; + if (iscaml(ch) || isspace(ch) /* ident or whitespace */ + || ((o = strchr(")]};,\'\"`#", ch)) != 0)/* "termination" chars */ + || !strchr("!$%&*+-./:<=>?@^|~", ch)/* "operator" chars */) { + // check for INCLUSIVE termination + if (o && strchr(")]};,", ch)) { + if ((ch == ')' && chLast == '(') || (ch == ']' && chLast == '[')) + // special-case "()" and "[]" tokens as KEYWORDS + state = SCE_CAML_KEYWORD; + chColor++; + } else + chNext = ch, chSkip--; + state2 = SCE_CAML_DEFAULT; + } + break; + } + + case SCE_CAML_NUMBER: + // [try to] interpret as [additional] numeric literal char + // N.B. - improperly accepts "extra" digits in base 2 or 8 literals + if (isdigit(ch) || ch == '_' + || ((chBase == 'x' || chBase == 'X') && isxdigit(ch))) + break; + // how about an integer suffix? + if ((ch == 'l' || ch == 'L' || ch == 'n') + && (isdigit(chLast) || chLast == '_')) + break; + // or a floating-point literal? + if (ch == '.' && (isdigit(chLast) || chLast == '_')) + break; + // with an exponent? (I) + if ((ch == 'e' || ch == 'E') + && (isdigit(chLast) || chLast == '_' || chLast == '.')) + break; + // with an exponent? (II) + if ((ch == '+' || ch == '-') && (chLast == 'e' || chLast == 'E')) + break; + // it looks like we have run out of number + state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; + break; + + case SCE_CAML_CHAR: + // [try to] interpret as [additional] char literal char + if (ch == '\\') { + chLit = 1; // (definitely IS a char literal) + if (chLast == '\\') + ch = ' '; // (so termination test isn't fooled) + // should we be terminating - one way or another? + } else if ((ch == '\'' && chLast != '\\') || ch == '\r' || ch == '\n') { + state2 = SCE_CAML_DEFAULT; + if (ch == '\'') + chColor++; + else + state = SCE_CAML_IDENTIFIER; + // ... maybe a char literal, maybe not + } else if (chLit < 1 && i - chToken >= 2) + state = SCE_CAML_IDENTIFIER, chNext = ch, chSkip--; + break; + + case SCE_CAML_STRING: + // [try to] interpret as [additional] string literal char + if (ch == '\\' && chLast == '\\') + ch = ' '; // (so '\\' doesn't cause us trouble) + else if (ch == '\"' && chLast != '\\') + state2 = SCE_CAML_DEFAULT, chColor++; + break; + + case SCE_CAML_COMMENT: + case SCE_CAML_COMMENT+1: + case SCE_CAML_COMMENT+2: + case SCE_CAML_COMMENT+3: + // we're IN a comment - does this start a NESTED comment? + if (ch == '(' && chNext == '*') + state2 = state + 1, + ch = ' ', // (make SURE "(*)" isn't seen as a closed comment) + chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), + chSkip++, nesting++; + // [try to] interpret as [additional] comment char + else if (ch == ')' && chLast == '*') + state2 = nesting? (state - 1): SCE_CAML_DEFAULT, chColor++, nesting--; + break; + } + + // handle state change and char coloring as required + if (state2 >= 0) { + if (chColor > 0) + styler.ColourTo(chColor, state); + state = state2; + } + chLast = ch; + } + + // do terminal char coloring (JIC) + styler.ColourTo(i, state); +// styler.Flush(); // (is this always called by calling code?) +} + +#ifdef BUILD_AS_EXTERNAL_LEXER +static +#endif /* BUILD_AS_EXTERNAL_LEXER */ +void FoldCamlDoc( + unsigned int startPos, int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler) +{ + // below useless evaluation(s) to supress "not used" warnings + startPos || length || initStyle || keywordlists[0] || styler.Length(); +} + +static const char * const camlWordListDesc[] = { + "Keywords", // primary Objective Caml keywords + "Keywords2", // "optional" keywords (typically from Pervasives) + 0 +}; + +#ifndef BUILD_AS_EXTERNAL_LEXER +LexerModule lmCaml(SCLEX_CAML, ColouriseCamlDoc, "caml", FoldCamlDoc, camlWordListDesc); +#endif /* BUILD_AS_EXTERNAL_LEXER */ |