diff options
Diffstat (limited to 'lexers/LexCIL.cxx')
| -rw-r--r-- | lexers/LexCIL.cxx | 404 | 
1 files changed, 404 insertions, 0 deletions
| diff --git a/lexers/LexCIL.cxx b/lexers/LexCIL.cxx new file mode 100644 index 000000000..6d5307666 --- /dev/null +++ b/lexers/LexCIL.cxx @@ -0,0 +1,404 @@ +// Scintilla source code edit control +/** @file LexCIL.cxx + ** Lexer for Common Intermediate Language + ** Written by Jad Altahan (github.com/xv) + ** CIL manual: https://www.ecma-international.org/publications/standards/Ecma-335.htm + **/ +// 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 <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include <ctype.h> + +#include <string> +#include <map> +#include <algorithm> + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "StringCopy.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "CharacterCategory.h" +#include "LexerModule.h" +#include "OptionSet.h" +#include "DefaultLexer.h" + +using namespace Scintilla; + +namespace { +    // Use an unnamed namespace to protect the functions and classes from name conflicts + +bool IsAWordChar(const int ch) { +    return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'); +} + +bool IsOperator(const int ch) { +    if ((ch < 0x80) && (isalnum(ch))) +        return false; + +    if (strchr("!%&*+-/<=>@^|~()[]{}", ch)) { +        return true; +    } + +    return false; +} + +constexpr bool IsStreamCommentStyle(const int style) noexcept { +    return style == SCE_CIL_COMMENT; +} + +struct OptionsCIL { +    bool fold; +    bool foldComment; +    bool foldCommentMultiline; +    bool foldCompact; + +    OptionsCIL() { +        fold = true; +        foldComment = false; +        foldCommentMultiline = true; +        foldCompact = true; +    } +}; + +static const char *const cilWordListDesc[] = { +    "Primary CIL keywords", +    "Metadata", +    "Opcode instructions", +    0 +}; + +struct OptionSetCIL : public OptionSet<OptionsCIL> { +    OptionSetCIL() { +        DefineProperty("fold", &OptionsCIL::fold); +        DefineProperty("fold.comment", &OptionsCIL::foldComment); + +        DefineProperty("fold.cil.comment.multiline", &OptionsCIL::foldCommentMultiline, +            "Set this property to 0 to disable folding multi-line comments when fold.comment=1."); + +        DefineProperty("fold.compact", &OptionsCIL::foldCompact); + +        DefineWordListSets(cilWordListDesc); +    } +}; + +LexicalClass lexicalClasses[] = { +    // Lexer CIL SCLEX_CIL SCE_CIL_: +    0,  "SCE_CIL_DEFAULT",     "default",              "White space", +    1,  "SCE_CIL_COMMENT",     "comment",              "Multi-line comment", +    2,  "SCE_CIL_COMMENTLINE", "comment line",         "Line comment", +    3,  "SCE_CIL_WORD",        "keyword",              "Keyword 1", +    4,  "SCE_CIL_WORD2",       "keyword",              "Keyword 2", +    5,  "SCE_CIL_WORD3",       "keyword",              "Keyword 3", +    6,  "SCE_CIL_STRING",      "literal string",       "Double quoted string", +    7,  "SCE_CIL_LABEL",       "label",                "Code label", +    8,  "SCE_CIL_OPERATOR",    "operator",             "Operators", +    9,  "SCE_CIL_STRINGEOL",   "error literal string", "String is not closed", +    10, "SCE_CIL_IDENTIFIER",  "identifier",           "Identifiers", +}; + +} + +class LexerCIL : public DefaultLexer { +    WordList keywords, keywords2, keywords3; +    OptionsCIL options; +    OptionSetCIL osCIL; + +public: +    LexerCIL() : DefaultLexer(lexicalClasses, ELEMENTS(lexicalClasses)) { } + +    virtual ~LexerCIL() { } + +    void SCI_METHOD Release() override { +        delete this; +    } + +    int SCI_METHOD Version() const override { +        return lvRelease4; +    } + +    const char * SCI_METHOD PropertyNames() override { +        return osCIL.PropertyNames(); +    } + +    int SCI_METHOD PropertyType(const char *name) override { +        return osCIL.PropertyType(name); +    } + +    const char * SCI_METHOD DescribeProperty(const char *name) override { +        return osCIL.DescribeProperty(name); +    } + +    Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override; + +    const char * SCI_METHOD DescribeWordListSets() override { +        return osCIL.DescribeWordListSets(); +    } + +    Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override; + +    void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; +    void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; + +    void * SCI_METHOD PrivateCall(int, void *) override { +        return 0; +    } + +    int SCI_METHOD LineEndTypesSupported() override { +        return SC_LINE_END_TYPE_UNICODE; +    } + +    int SCI_METHOD PrimaryStyleFromStyle(int style) override { +        return style; +    } + +    static ILexer4 *LexerFactoryCIL() { +        return new LexerCIL(); +    } +}; + +Sci_Position SCI_METHOD LexerCIL::PropertySet(const char *key, const char *val) { +    if (osCIL.PropertySet(&options, key, val)) { +        return 0; +    } + +    return -1; +} + +Sci_Position SCI_METHOD LexerCIL::WordListSet(int n, const char *wl) { +    WordList *wordListN = 0; + +    switch (n) { +        case 0: +            wordListN = &keywords; +            break; +        case 1: +            wordListN = &keywords2; +            break; +        case 2: +            wordListN = &keywords3; +            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 LexerCIL::Lex(Sci_PositionU startPos, Sci_Position length, +                              int initStyle, IDocument *pAccess) { +    if (initStyle == SCE_CIL_STRINGEOL) { +        initStyle = SCE_CIL_DEFAULT; +    } + +    Accessor styler(pAccess, NULL); +    StyleContext sc(startPos, length, initStyle, styler); + +    bool identAtLineStart = false, // Checks if an identifier is at line start (ignoring spaces) +         canStyleLabels = false;   // Checks if conditions are met to style SCE_CIL_LABEL + +    for (; sc.More(); sc.Forward()) { +        if (sc.atLineStart) { +            if (sc.state == SCE_CIL_STRING) { +                sc.SetState(SCE_CIL_STRING); +            } + +            identAtLineStart = true; +        } + +        // Handle string line continuation +        if (sc.ch == '\\' && (sc.chNext == '\n' || sc.chNext == '\r') && +           (sc.state == SCE_CIL_STRING)) { +            sc.Forward(); + +            if (sc.ch == '\r' && sc.chNext == '\n') { +                sc.Forward(); +            } + +            continue; +        } + +        switch (sc.state) { +            case SCE_CIL_OPERATOR: +                sc.SetState(SCE_CIL_DEFAULT); +                break; +            case SCE_CIL_IDENTIFIER: +                if (!IsAWordChar(sc.ch)) { +                    if (canStyleLabels && (sc.ch == ':' && sc.chNext != ':')) { +                        sc.ChangeState(SCE_CIL_LABEL); +                        sc.ForwardSetState(SCE_CIL_DEFAULT); +                    } else { +                        char kwSize[100]; +                        sc.GetCurrent(kwSize, sizeof(kwSize)); +                        int style = SCE_CIL_IDENTIFIER; + +                        if (keywords.InList(kwSize)) { +                            style = SCE_CIL_WORD; +                        } else if (keywords2.InList(kwSize)) { +                            style = SCE_CIL_WORD2; +                        } else if (keywords3.InList(kwSize)) { +                            style = SCE_CIL_WORD3; +                        } + +                        sc.ChangeState(style); +                        sc.SetState(SCE_CIL_DEFAULT); +                    } +                } +                break; +            case SCE_CIL_COMMENT: +                if (sc.Match('*', '/')) { +                    sc.Forward(); +                    sc.ForwardSetState(SCE_CIL_DEFAULT); +                } +                break; +            case SCE_CIL_COMMENTLINE: +                if (sc.atLineStart) { +                    sc.SetState(SCE_CIL_DEFAULT); +                } +                break; +            case SCE_CIL_STRING: +                if (sc.ch == '\\') { +                    if (sc.chNext == '"' || sc.chNext == '\\') { +                        sc.Forward(); +                    } +                } else if (sc.ch == '"') { +                    sc.ForwardSetState(SCE_CIL_DEFAULT); +                } else if (sc.atLineEnd) { +                    sc.ChangeState(SCE_CIL_STRINGEOL); +                    sc.ForwardSetState(SCE_CIL_DEFAULT); +                } +                break; +        } + +        if (sc.state == SCE_CIL_DEFAULT) { +            // String +            if (sc.ch == '"') { +                sc.SetState(SCE_CIL_STRING); +            } +            // Keyword +            else if (IsAWordChar(sc.ch)) { +                // Allow setting SCE_CIL_LABEL style only if the label is the +                // first token in the line and does not start with a dot or a digit +                canStyleLabels = identAtLineStart && !(sc.ch == '.' || IsADigit(sc.ch)); +                sc.SetState(SCE_CIL_IDENTIFIER); +            } +            // Multi-line comment +            else if (sc.Match('/', '*')) { +                sc.SetState(SCE_CIL_COMMENT); +                sc.Forward(); +            } +            // Line comment +            else if (sc.Match('/', '/')) { +                sc.SetState(SCE_CIL_COMMENTLINE); +            } +            // Operators +            else if (IsOperator(sc.ch)) { +                sc.SetState(SCE_CIL_OPERATOR); +            } +        } + +        if (!IsASpace(sc.ch)) { +            identAtLineStart = false; +        } +    } + +    sc.Complete(); +} + +void SCI_METHOD LexerCIL::Fold(Sci_PositionU startPos, Sci_Position length,  +                               int initStyle, IDocument *pAccess) { +    if (!options.fold) { +        return; +    } + +    LexAccessor styler(pAccess); + +    const Sci_PositionU endPos = startPos + length; +    Sci_Position lineCurrent = styler.GetLine(startPos); + +    int levelCurrent = SC_FOLDLEVELBASE; +    if (lineCurrent > 0) +        levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16; +     +    int style = initStyle; +    int styleNext = styler.StyleAt(startPos); +    int levelNext = levelCurrent; +    int visibleChars = 0; + +    char chNext = styler[startPos]; + +    for (Sci_PositionU i = startPos; i < endPos; i++) { +        const char ch = chNext; +        int stylePrev = style; + +        chNext = styler.SafeGetCharAt(i + 1); +        style = styleNext; +        styleNext = styler.StyleAt(i + 1); + +        const bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); + +        if (options.foldComment &&  +            options.foldCommentMultiline && IsStreamCommentStyle(style)) { +            if (!IsStreamCommentStyle(stylePrev)) { +                levelNext++; +            } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { +                levelNext--; +            } +        } + +        if (style == SCE_CIL_OPERATOR) { +            if (ch == '{') { +                levelNext++; +            } else if (ch == '}') { +                levelNext--; +            } +        } + +        if (!IsASpace(ch)) { +            visibleChars++; +        } + +        if (atEOL || (i == endPos - 1)) { +            int lev = levelCurrent | levelNext << 16; +            if (visibleChars == 0 && options.foldCompact) +                lev |= SC_FOLDLEVELWHITEFLAG; +            if (levelCurrent < levelNext) +                lev |= SC_FOLDLEVELHEADERFLAG; +            if (lev != styler.LevelAt(lineCurrent)) { +                styler.SetLevel(lineCurrent, lev); +            } +             +            lineCurrent++; +            levelCurrent = levelNext; +             +            if (options.foldCompact && +                i == static_cast<Sci_PositionU>(styler.Length() - 1)) { +                styler.SetLevel(lineCurrent, lev | SC_FOLDLEVELWHITEFLAG); +            } + +            visibleChars = 0; +        } +    } +} + +LexerModule lmCIL(SCLEX_CIL, LexerCIL::LexerFactoryCIL, "cil", cilWordListDesc);
\ No newline at end of file | 
