diff options
Diffstat (limited to 'lexers/LexVisualProlog.cxx')
-rw-r--r-- | lexers/LexVisualProlog.cxx | 214 |
1 files changed, 124 insertions, 90 deletions
diff --git a/lexers/LexVisualProlog.cxx b/lexers/LexVisualProlog.cxx index 8a7495b9a..0acdb26a1 100644 --- a/lexers/LexVisualProlog.cxx +++ b/lexers/LexVisualProlog.cxx @@ -7,6 +7,10 @@ // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. +// The line state contains: +// In SCE_VISUALPROLOG_STRING_VERBATIM_EOL (i.e. multiline string literal): The closingQuote. +// else (for SCE_VISUALPROLOG_COMMENT_BLOCK): The comment nesting level + #include <stdlib.h> #include <string.h> #include <ctype.h> @@ -32,6 +36,7 @@ #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" +#include "CharacterCategory.h" #include "LexerModule.h" #include "OptionSet.h" @@ -144,15 +149,73 @@ struct After { After(int line_) : line(line_) {} }; +static bool isLowerLetter(int ch){ + return ccLl == CategoriseCharacter(ch); +} + +static bool isUpperLetter(int ch){ + return ccLu == CategoriseCharacter(ch); +} + +static bool isAlphaNum(int ch){ + CharacterCategory cc = CategoriseCharacter(ch); + return (ccLu == cc || ccLl == cc || ccLt == cc || ccLm == cc || ccLo == cc || ccNd == cc || ccNl == cc || ccNo == cc); +} + +static bool isIdChar(int ch){ + return ('_') == ch || isAlphaNum(ch); +} + +static bool isOpenStringVerbatim(int next, int &closingQuote){ + switch (next) { + case L'<': + closingQuote = L'>'; + return true; + case L'>': + closingQuote = L'<'; + return true; + case L'(': + closingQuote = L')'; + return true; + case L')': + closingQuote = L'('; + return true; + case L'[': + closingQuote = L']'; + return true; + case L']': + closingQuote = L'['; + return true; + case L'{': + closingQuote = L'}'; + return true; + case L'}': + closingQuote = L'{'; + return true; + case L'_': + case L'.': + case L',': + case L';': + return false; + default: + if (isAlphaNum(next)) { + return false; + } else { + closingQuote = next; + return true; + } + } +} + // Look ahead to see which colour "end" should have (takes colour after the following keyword) -static void endLookAhead(char s[], LexAccessor &styler, int start, CharacterSet &setIdentifier) { +static void endLookAhead(char s[], LexAccessor &styler, int start) { char ch = styler.SafeGetCharAt(start, '\n'); while (' ' == ch) { start++; ch = styler.SafeGetCharAt(start, '\n'); } int i = 0; - while (i < 100 && setIdentifier.Contains(ch)){ + while (i < 100 && isLowerLetter(ch)){ s[i] = ch; i++; ch = styler.SafeGetCharAt(start + i, '\n'); @@ -160,11 +223,11 @@ static void endLookAhead(char s[], LexAccessor &styler, int start, CharacterSet s[i] = '\0'; } -static void forwardEscapeLiteral(StyleContext &sc, int OwnChar, int EscapeState) { +static void forwardEscapeLiteral(StyleContext &sc, int EscapeState) { sc.Forward(); - if (sc.ch == OwnChar || sc.ch == '\\' || sc.ch == 'n' || sc.ch == 'l' || sc.ch == 'r' || sc.ch == 't') { + if (sc.Match('"') || sc.Match('\'') || sc.Match('\\') || sc.Match('n') || sc.Match('l') || sc.Match('r') || sc.Match('t')) { sc.ChangeState(EscapeState); - } else if (sc.ch == 'u') { + } else if (sc.Match('u')) { if (IsADigit(sc.chNext, 16)) { sc.Forward(); if (IsADigit(sc.chNext, 16)) { @@ -183,45 +246,26 @@ static void forwardEscapeLiteral(StyleContext &sc, int OwnChar, int EscapeState) void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); + CharacterSet setDoxygen(CharacterSet::setAlpha, ""); + CharacterSet setNumber(CharacterSet::setNone, "+-.0123456789abcdefABCDEFxoXO"); - CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); - - CharacterSet setLowerStart(CharacterSet::setLower); - CharacterSet setVariableStart(CharacterSet::setUpper); - CharacterSet setIdentifier(CharacterSet::setAlphaNum, "_", 0x80, true); + StyleContext sc(startPos, length, initStyle, styler, 0x7f); int styleBeforeDocKeyword = SCE_VISUALPROLOG_DEFAULT; - int currentLine = styler.GetLine(startPos); + int closingQuote = '"'; int nestLevel = 0; if (currentLine >= 1) { nestLevel = styler.GetLineState(currentLine - 1); + closingQuote = nestLevel; } - StyleContext sc(startPos, length, initStyle, styler, 0x7f); - // Truncate ppDefineHistory before current line for (; sc.More(); sc.Forward()) { - if (sc.atLineEnd) { - // Update the line state, so it can be seen by next line - styler.SetLineState(currentLine, nestLevel); - currentLine++; - } - - if (sc.atLineStart) { - if ((sc.state == SCE_VISUALPROLOG_STRING) || (sc.state == SCE_VISUALPROLOG_CHARACTER)) { - // Prevent SCE_VISUALPROLOG_STRING_EOL from leaking back to previous line which - // ends with a line continuation by locking in the state upto this position. - sc.SetState(sc.state); - } - } - - const bool atLineEndBeforeSwitch = sc.atLineEnd; - // Determine if the current state should terminate. switch (sc.state) { case SCE_VISUALPROLOG_OPERATOR: @@ -229,16 +273,16 @@ void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int in break; case SCE_VISUALPROLOG_NUMBER: // We accept almost anything because of hex. and number suffixes - if (!(setIdentifier.Contains(sc.ch) || (sc.ch == '.') || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) { + if (!(setNumber.Contains(sc.ch))) { sc.SetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_IDENTIFIER: - if (!setIdentifier.Contains(sc.ch)) { + if (!isIdChar(sc.ch)) { char s[1000]; sc.GetCurrent(s, sizeof(s)); if (0 == strcmp(s, "end")) { - endLookAhead(s, styler, sc.currentPos, setIdentifier); + endLookAhead(s, styler, sc.currentPos); } if (majorKeywords.InList(s)) { sc.ChangeState(SCE_VISUALPROLOG_KEY_MAJOR); @@ -250,12 +294,12 @@ void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int in break; case SCE_VISUALPROLOG_VARIABLE: case SCE_VISUALPROLOG_ANONYMOUS: - if (!setIdentifier.Contains(sc.ch)) { + if (!isIdChar(sc.ch)) { sc.SetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_KEY_DIRECTIVE: - if (!setLowerStart.Contains(sc.ch)) { + if (!isLowerLetter(sc.ch)) { char s[1000]; sc.GetCurrent(s, sizeof(s)); if (!directiveKeywords.InList(s+1)) { @@ -273,9 +317,7 @@ void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int in } else if (sc.Match('/', '*')) { sc.Forward(); nestLevel++; - } else if (sc.ch == '%') { - sc.SetState(SCE_VISUALPROLOG_COMMENT_LINE); - } else if (sc.ch == '@') { + } else if (sc.Match('@')) { styleBeforeDocKeyword = sc.state; sc.SetState(SCE_VISUALPROLOG_COMMENT_KEY_ERROR); } @@ -284,24 +326,34 @@ void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int in if (sc.atLineEnd) { int nextState = (nestLevel == 0) ? SCE_VISUALPROLOG_DEFAULT : SCE_VISUALPROLOG_COMMENT_BLOCK; sc.SetState(nextState); - } else if (sc.ch == '@') { + } else if (sc.Match('@')) { styleBeforeDocKeyword = sc.state; sc.SetState(SCE_VISUALPROLOG_COMMENT_KEY_ERROR); } break; case SCE_VISUALPROLOG_COMMENT_KEY_ERROR: - if (!setDoxygen.Contains(sc.ch)) { + if (!setDoxygen.Contains(sc.ch) || sc.atLineEnd) { char s[1000]; sc.GetCurrent(s, sizeof(s)); if (docKeywords.InList(s+1)) { sc.ChangeState(SCE_VISUALPROLOG_COMMENT_KEY); } - sc.SetState(styleBeforeDocKeyword); - } - if (SCE_VISUALPROLOG_COMMENT_LINE == styleBeforeDocKeyword && sc.atLineStart) { - sc.SetState(SCE_VISUALPROLOG_DEFAULT); - } else if (SCE_VISUALPROLOG_COMMENT_BLOCK == styleBeforeDocKeyword && sc.atLineStart) { - sc.SetState(SCE_VISUALPROLOG_COMMENT_BLOCK); + if (SCE_VISUALPROLOG_COMMENT_LINE == styleBeforeDocKeyword && sc.atLineEnd) { + // end line comment + int nextState = (nestLevel == 0) ? SCE_VISUALPROLOG_DEFAULT : SCE_VISUALPROLOG_COMMENT_BLOCK; + sc.SetState(nextState); + } else { + sc.SetState(styleBeforeDocKeyword); + if (SCE_VISUALPROLOG_COMMENT_BLOCK == styleBeforeDocKeyword && sc.Match('*', '/')) { + // we have consumed the '*' if it comes immediately after the docKeyword + sc.Forward(); + sc.Forward(); + nestLevel--; + if (0 == nestLevel) { + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + } + } + } } break; case SCE_VISUALPROLOG_STRING_ESCAPE: @@ -311,38 +363,11 @@ void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int in case SCE_VISUALPROLOG_STRING: if (sc.atLineEnd) { sc.SetState(SCE_VISUALPROLOG_STRING_EOL_OPEN); - } else if (sc.ch == '"') { + } else if (sc.Match(closingQuote)) { sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); - } else if (sc.ch == '\\') { + } else if (sc.Match('\\')) { sc.SetState(SCE_VISUALPROLOG_STRING_ESCAPE_ERROR); - forwardEscapeLiteral(sc, '"', SCE_VISUALPROLOG_STRING_ESCAPE); - } - break; - case SCE_VISUALPROLOG_CHARACTER_TOO_MANY: - if (sc.atLineStart) { - sc.SetState(SCE_VISUALPROLOG_DEFAULT); - } else if (sc.ch == '\'') { - sc.SetState(SCE_VISUALPROLOG_CHARACTER); - sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); - } - break; - case SCE_VISUALPROLOG_CHARACTER: - if (sc.atLineEnd) { - sc.SetState(SCE_VISUALPROLOG_STRING_EOL_OPEN); // reuse STRING_EOL_OPEN for this - } else if (sc.ch == '\'') { - sc.SetState(SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR); - sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); - } else { - if (sc.ch == '\\') { - sc.SetState(SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR); - forwardEscapeLiteral(sc, '\'', SCE_VISUALPROLOG_CHARACTER); - } - sc.ForwardSetState(SCE_VISUALPROLOG_CHARACTER); - if (sc.ch == '\'') { - sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); - } else { - sc.SetState(SCE_VISUALPROLOG_CHARACTER_TOO_MANY); - } + forwardEscapeLiteral(sc, SCE_VISUALPROLOG_STRING_ESCAPE); } break; case SCE_VISUALPROLOG_STRING_EOL_OPEN: @@ -357,8 +382,8 @@ void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int in case SCE_VISUALPROLOG_STRING_VERBATIM: if (sc.atLineEnd) { sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM_EOL); - } else if (sc.ch == '\"') { - if (sc.chNext == '\"') { + } else if (sc.Match(closingQuote)) { + if (closingQuote == sc.chNext) { sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL); sc.Forward(); } else { @@ -368,37 +393,46 @@ void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int in break; } - if (sc.atLineEnd && !atLineEndBeforeSwitch) { - // State exit processing consumed characters up to end of line. + if (sc.atLineEnd) { + // Update the line state, so it can be seen by next line + int lineState = 0; + if (SCE_VISUALPROLOG_STRING_VERBATIM_EOL == sc.state) { + lineState = closingQuote; + } else if (SCE_VISUALPROLOG_COMMENT_BLOCK == sc.state) { + lineState = nestLevel; + } + styler.SetLineState(currentLine, lineState); currentLine++; } // Determine if a new state should be entered. if (sc.state == SCE_VISUALPROLOG_DEFAULT) { - if (sc.Match('@', '\"')) { + if (sc.Match('@') && isOpenStringVerbatim(sc.chNext, closingQuote)) { sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM); sc.Forward(); - } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { + } else if (IsADigit(sc.ch) || (sc.Match('.') && IsADigit(sc.chNext))) { sc.SetState(SCE_VISUALPROLOG_NUMBER); - } else if (setLowerStart.Contains(sc.ch)) { + } else if (isLowerLetter(sc.ch)) { sc.SetState(SCE_VISUALPROLOG_IDENTIFIER); - } else if (setVariableStart.Contains(sc.ch)) { + } else if (isUpperLetter(sc.ch)) { sc.SetState(SCE_VISUALPROLOG_VARIABLE); - } else if (sc.ch == '_') { + } else if (sc.Match('_')) { sc.SetState(SCE_VISUALPROLOG_ANONYMOUS); } else if (sc.Match('/', '*')) { sc.SetState(SCE_VISUALPROLOG_COMMENT_BLOCK); nestLevel = 1; sc.Forward(); // Eat the * so it isn't used for the end of the comment - } else if (sc.ch == '%') { + } else if (sc.Match('%')) { sc.SetState(SCE_VISUALPROLOG_COMMENT_LINE); - } else if (sc.ch == '\"') { + } else if (sc.Match('\'')) { + closingQuote = '\''; + sc.SetState(SCE_VISUALPROLOG_STRING); + } else if (sc.Match('"')) { + closingQuote = '"'; sc.SetState(SCE_VISUALPROLOG_STRING); - } else if (sc.ch == '\'') { - sc.SetState(SCE_VISUALPROLOG_CHARACTER); - } else if (sc.ch == '#') { + } else if (sc.Match('#')) { sc.SetState(SCE_VISUALPROLOG_KEY_DIRECTIVE); - } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '\\') { + } else if (isoperator(static_cast<char>(sc.ch)) || sc.Match('\\')) { sc.SetState(SCE_VISUALPROLOG_OPERATOR); } } |