diff options
Diffstat (limited to 'lexers')
| -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);              }          } | 
