diff options
Diffstat (limited to 'lexers/LexHollywood.cxx')
-rw-r--r-- | lexers/LexHollywood.cxx | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/lexers/LexHollywood.cxx b/lexers/LexHollywood.cxx new file mode 100644 index 000000000..41c295686 --- /dev/null +++ b/lexers/LexHollywood.cxx @@ -0,0 +1,512 @@ +// Scintilla source code edit control +/** @file LexHollywood.cxx + ** Lexer for Hollywood + ** Written by Andreas Falkenhahn, based on the BlitzBasic/PureBasic/Lua lexers + ** Thanks to Nicholai Benalal + ** For more information on Hollywood, see http://www.hollywood-mal.com/ + ** Mail me (andreas <at> airsoftsoftwair <dot> de) for any bugs. + ** This code is subject to the same license terms as the rest of the Scintilla project: + ** The License.txt file describes the conditions under which this software may be distributed. + **/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include <ctype.h> + +#include <string> +#include <map> + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "WordList.h" +#include "LexAccessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" +#include "OptionSet.h" +#include "DefaultLexer.h" + +using namespace Scintilla; + +/* Bits: + * 1 - whitespace + * 2 - operator + * 4 - identifier + * 8 - decimal digit + * 16 - hex digit + * 32 - bin digit + * 64 - letter + */ +static int character_classification[128] = +{ + 0, // NUL ($0) + 0, // SOH ($1) + 0, // STX ($2) + 0, // ETX ($3) + 0, // EOT ($4) + 0, // ENQ ($5) + 0, // ACK ($6) + 0, // BEL ($7) + 0, // BS ($8) + 1, // HT ($9) + 1, // LF ($A) + 0, // VT ($B) + 0, // FF ($C) + 1, // CR ($D) + 0, // SO ($E) + 0, // SI ($F) + 0, // DLE ($10) + 0, // DC1 ($11) + 0, // DC2 ($12) + 0, // DC3 ($13) + 0, // DC4 ($14) + 0, // NAK ($15) + 0, // SYN ($16) + 0, // ETB ($17) + 0, // CAN ($18) + 0, // EM ($19) + 0, // SUB ($1A) + 0, // ESC ($1B) + 0, // FS ($1C) + 0, // GS ($1D) + 0, // RS ($1E) + 0, // US ($1F) + 1, // space ($20) + 4, // ! ($21) + 0, // " ($22) + 0, // # ($23) + 4, // $ ($24) + 2, // % ($25) + 2, // & ($26) + 2, // ' ($27) + 2, // ( ($28) + 2, // ) ($29) + 2, // * ($2A) + 2, // + ($2B) + 2, // , ($2C) + 2, // - ($2D) + // NB: we treat "." as an identifier although it is also an operator and a decimal digit + // the reason why we treat it as an identifier is to support syntax highlighting for + // plugin commands which always use a "." in their names, e.g. pdf.OpenDocument(); + // we handle the decimal digit case manually below so that 3.1415 and .123 is styled correctly + // the collateral damage of treating "." as an identifier is that "." is never styled + // SCE_HOLLYWOOD_OPERATOR + 4, // . ($2E) + 2, // / ($2F) + 28, // 0 ($30) + 28, // 1 ($31) + 28, // 2 ($32) + 28, // 3 ($33) + 28, // 4 ($34) + 28, // 5 ($35) + 28, // 6 ($36) + 28, // 7 ($37) + 28, // 8 ($38) + 28, // 9 ($39) + 2, // : ($3A) + 2, // ; ($3B) + 2, // < ($3C) + 2, // = ($3D) + 2, // > ($3E) + 2, // ? ($3F) + 0, // @ ($40) + 84, // A ($41) + 84, // B ($42) + 84, // C ($43) + 84, // D ($44) + 84, // E ($45) + 84, // F ($46) + 68, // G ($47) + 68, // H ($48) + 68, // I ($49) + 68, // J ($4A) + 68, // K ($4B) + 68, // L ($4C) + 68, // M ($4D) + 68, // N ($4E) + 68, // O ($4F) + 68, // P ($50) + 68, // Q ($51) + 68, // R ($52) + 68, // S ($53) + 68, // T ($54) + 68, // U ($55) + 68, // V ($56) + 68, // W ($57) + 68, // X ($58) + 68, // Y ($59) + 68, // Z ($5A) + 2, // [ ($5B) + 2, // \ ($5C) + 2, // ] ($5D) + 2, // ^ ($5E) + 68, // _ ($5F) + 2, // ` ($60) + 84, // a ($61) + 84, // b ($62) + 84, // c ($63) + 84, // d ($64) + 84, // e ($65) + 84, // f ($66) + 68, // g ($67) + 68, // h ($68) + 68, // i ($69) + 68, // j ($6A) + 68, // k ($6B) + 68, // l ($6C) + 68, // m ($6D) + 68, // n ($6E) + 68, // o ($6F) + 68, // p ($70) + 68, // q ($71) + 68, // r ($72) + 68, // s ($73) + 68, // t ($74) + 68, // u ($75) + 68, // v ($76) + 68, // w ($77) + 68, // x ($78) + 68, // y ($79) + 68, // z ($7A) + 2, // { ($7B) + 2, // | ($7C) + 2, // } ($7D) + 2, // ~ ($7E) + 0, //  ($7F) +}; + +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 int LowerCase(int c) +{ + if (c >= 'A' && c <= 'Z') + return 'a' + c - 'A'; + return c; +} + +static int CheckHollywoodFoldPoint(char const *token) { + if (!strcmp(token, "function")) { + return 1; + } + if (!strcmp(token, "endfunction")) { + return -1; + } + return 0; +} + +// An individual named option for use in an OptionSet + +// Options used for LexerHollywood +struct OptionsHollywood { + bool fold; + bool foldCompact; + OptionsHollywood() { + fold = false; + foldCompact = false; + } +}; + +static const char * const hollywoodWordListDesc[] = { + "Hollywood keywords", + "Hollywood standard API functions", + "Hollywood plugin API functions", + "Hollywood plugin methods", + 0 +}; + +struct OptionSetHollywood : public OptionSet<OptionsHollywood> { + OptionSetHollywood(const char * const wordListDescriptions[]) { + DefineProperty("fold", &OptionsHollywood::fold); + DefineProperty("fold.compact", &OptionsHollywood::foldCompact); + DefineWordListSets(wordListDescriptions); + } +}; + +class LexerHollywood : public DefaultLexer { + int (*CheckFoldPoint)(char const *); + WordList keywordlists[4]; + OptionsHollywood options; + OptionSetHollywood osHollywood; +public: + LexerHollywood(int (*CheckFoldPoint_)(char const *), const char * const wordListDescriptions[]) : + CheckFoldPoint(CheckFoldPoint_), + osHollywood(wordListDescriptions) { + } + virtual ~LexerHollywood() { + } + void SCI_METHOD Release() { + delete this; + } + int SCI_METHOD Version() const { + return lvRelease4; + } + const char * SCI_METHOD PropertyNames() { + return osHollywood.PropertyNames(); + } + int SCI_METHOD PropertyType(const char *name) { + return osHollywood.PropertyType(name); + } + const char * SCI_METHOD DescribeProperty(const char *name) { + return osHollywood.DescribeProperty(name); + } + Sci_Position SCI_METHOD PropertySet(const char *key, const char *val); + const char * SCI_METHOD DescribeWordListSets() { + return osHollywood.DescribeWordListSets(); + } + Sci_Position SCI_METHOD WordListSet(int n, const char *wl); + void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess); + void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess); + + void * SCI_METHOD PrivateCall(int, void *) { + return 0; + } + static ILexer4 *LexerFactoryHollywood() { + return new LexerHollywood(CheckHollywoodFoldPoint, hollywoodWordListDesc); + } +}; + +Sci_Position SCI_METHOD LexerHollywood::PropertySet(const char *key, const char *val) { + if (osHollywood.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +Sci_Position SCI_METHOD LexerHollywood::WordListSet(int n, const char *wl) { + WordList *wordListN = 0; + switch (n) { + case 0: + wordListN = &keywordlists[0]; + break; + case 1: + wordListN = &keywordlists[1]; + break; + case 2: + wordListN = &keywordlists[2]; + break; + case 3: + wordListN = &keywordlists[3]; + break; + } + Sci_Position firstModification = -1; + if (wordListN) { + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + } + } + return firstModification; +} + +void SCI_METHOD LexerHollywood::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) { + LexAccessor styler(pAccess); + + styler.StartAt(startPos); + bool inString = false; + + StyleContext sc(startPos, length, initStyle, styler); + + // Can't use sc.More() here else we miss the last character + for (; ; sc.Forward()) + { + if (sc.atLineStart) inString = false; + + if (sc.ch == '\"' && sc.chPrev != '\\') inString = !inString; + + if (sc.state == SCE_HOLLYWOOD_IDENTIFIER) { + if (!IsIdentifier(sc.ch)) { + char s[100]; + int kstates[4] = { + SCE_HOLLYWOOD_KEYWORD, + SCE_HOLLYWOOD_STDAPI, + SCE_HOLLYWOOD_PLUGINAPI, + SCE_HOLLYWOOD_PLUGINMETHOD, + }; + sc.GetCurrentLowered(s, sizeof(s)); + for (int i = 0; i < 4; i++) { + if (keywordlists[i].InList(s)) { + sc.ChangeState(kstates[i]); + } + } + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + } + } else if (sc.state == SCE_HOLLYWOOD_OPERATOR) { + + // always reset to default on operators because otherwise + // comments won't be recognized in sequences like "+/* Hello*/" + // --> "+/*" would be recognized as a sequence of operators + + // if (!IsOperator(sc.ch)) sc.SetState(SCE_HOLLYWOOD_DEFAULT); + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + + } else if (sc.state == SCE_HOLLYWOOD_PREPROCESSOR) { + if (!IsIdentifier(sc.ch)) + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + } else if (sc.state == SCE_HOLLYWOOD_CONSTANT) { + if (!IsIdentifier(sc.ch)) + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + } else if (sc.state == SCE_HOLLYWOOD_NUMBER) { + if (!IsDigit(sc.ch) && sc.ch != '.') + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + } else if (sc.state == SCE_HOLLYWOOD_HEXNUMBER) { + if (!IsHexDigit(sc.ch)) + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + } else if (sc.state == SCE_HOLLYWOOD_STRING) { + if (sc.ch == '"') { + sc.ForwardSetState(SCE_HOLLYWOOD_DEFAULT); + } + if (sc.atLineEnd) { + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + } + } else if (sc.state == SCE_HOLLYWOOD_COMMENT) { + if (sc.atLineEnd) { + sc.SetState(SCE_HOLLYWOOD_DEFAULT); + } + } else if (sc.state == SCE_HOLLYWOOD_COMMENTBLOCK) { + if (sc.Match("*/") && !inString) { + sc.Forward(); + sc.ForwardSetState(SCE_HOLLYWOOD_DEFAULT); + } + } else if (sc.state == SCE_HOLLYWOOD_STRINGBLOCK) { + if (sc.Match("]]") && !inString) { + sc.Forward(); + sc.ForwardSetState(SCE_HOLLYWOOD_DEFAULT); + } + } + + if (sc.state == SCE_HOLLYWOOD_DEFAULT) { + if (sc.Match(';')) { + sc.SetState(SCE_HOLLYWOOD_COMMENT); + } else if (sc.Match("/*")) { + sc.SetState(SCE_HOLLYWOOD_COMMENTBLOCK); + sc.Forward(); + } else if (sc.Match("[[")) { + sc.SetState(SCE_HOLLYWOOD_STRINGBLOCK); + sc.Forward(); + } else if (sc.Match('"')) { + sc.SetState(SCE_HOLLYWOOD_STRING); + } else if (sc.Match('$')) { + sc.SetState(SCE_HOLLYWOOD_HEXNUMBER); + } else if (sc.Match("0x") || sc.Match("0X")) { // must be before IsDigit() because of 0x + sc.SetState(SCE_HOLLYWOOD_HEXNUMBER); + sc.Forward(); + } else if (sc.ch == '.' && (sc.chNext >= '0' && sc.chNext <= '9')) { // ".1234" style numbers + sc.SetState(SCE_HOLLYWOOD_NUMBER); + sc.Forward(); + } else if (IsDigit(sc.ch)) { + sc.SetState(SCE_HOLLYWOOD_NUMBER); + } else if (sc.Match('#')) { + sc.SetState(SCE_HOLLYWOOD_CONSTANT); + } else if (sc.Match('@')) { + sc.SetState(SCE_HOLLYWOOD_PREPROCESSOR); + } else if (IsOperator(sc.ch)) { + sc.SetState(SCE_HOLLYWOOD_OPERATOR); + } else if (IsIdentifier(sc.ch)) { + sc.SetState(SCE_HOLLYWOOD_IDENTIFIER); + } + } + + if (!sc.More()) + break; + } + sc.Complete(); +} + +void SCI_METHOD LexerHollywood::Fold(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, IDocument *pAccess) { + + if (!options.fold) + return; + + LexAccessor styler(pAccess); + + Sci_PositionU lengthDoc = startPos + length; + int visibleChars = 0; + Sci_Position lineCurrent = styler.GetLine(startPos); + int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; + int levelCurrent = levelPrev; + char chNext = styler[startPos]; + int styleNext = styler.StyleAt(startPos); + int done = 0; + char word[256]; + int wordlen = 0; + + for (Sci_PositionU 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 (!done) { + if (wordlen) { // are we scanning a token already? + word[wordlen] = static_cast<char>(LowerCase(ch)); + if (!IsIdentifier(ch)) { // done with token + word[wordlen] = '\0'; + levelCurrent += CheckFoldPoint(word); + done = 1; + } else if (wordlen < 255) { + wordlen++; + } + } else { // start scanning at first non-whitespace character + if (!IsSpace(ch)) { + if (style != SCE_HOLLYWOOD_COMMENTBLOCK && IsIdentifier(ch)) { + word[0] = static_cast<char>(LowerCase(ch)); + wordlen = 1; + } else // done with this line + done = 1; + } + } + } + + if (atEOL) { + int lev = levelPrev; + if (visibleChars == 0 && options.foldCompact) { + 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; + done = 0; + wordlen = 0; + } + if (!IsSpace(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 lmHollywood(SCLEX_HOLLYWOOD, LexerHollywood::LexerFactoryHollywood, "hollywood", hollywoodWordListDesc); |