123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- // Scintilla source code edit control
- /** @file LexVisualProlog.cxx
- ** Lexer for Visual Prolog.
- **/
- // Author Thomas Linder Puls, Prolog Development Denter A/S, http://www.visual-prolog.com
- // Based on Lexer for C++, C, Java, and JavaScript.
- // 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 <stdio.h>
- #include <stdarg.h>
- #include <assert.h>
- #include <ctype.h>
- #ifdef _MSC_VER
- #pragma warning(disable: 4786)
- #endif
- #include <string>
- #include <vector>
- #include <map>
- #include <algorithm>
- #include "ILexer.h"
- #include "Scintilla.h"
- #include "SciLexer.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"
- #ifdef SCI_NAMESPACE
- using namespace Scintilla;
- #endif
- // Options used for LexerVisualProlog
- struct OptionsVisualProlog {
- OptionsVisualProlog() {
- }
- };
- static const char *const visualPrologWordLists[] = {
- "Major keywords (class, predicates, ...)",
- "Minor keywords (if, then, try, ...)",
- "Directive keywords without the '#' (include, requires, ...)",
- "Documentation keywords without the '@' (short, detail, ...)",
- 0,
- };
- struct OptionSetVisualProlog : public OptionSet<OptionsVisualProlog> {
- OptionSetVisualProlog() {
- DefineWordListSets(visualPrologWordLists);
- }
- };
- class LexerVisualProlog : public ILexer {
- WordList majorKeywords;
- WordList minorKeywords;
- WordList directiveKeywords;
- WordList docKeywords;
- OptionsVisualProlog options;
- OptionSetVisualProlog osVisualProlog;
- public:
- LexerVisualProlog() {
- }
- virtual ~LexerVisualProlog() {
- }
- void SCI_METHOD Release() {
- delete this;
- }
- int SCI_METHOD Version() const {
- return lvOriginal;
- }
- const char * SCI_METHOD PropertyNames() {
- return osVisualProlog.PropertyNames();
- }
- int SCI_METHOD PropertyType(const char *name) {
- return osVisualProlog.PropertyType(name);
- }
- const char * SCI_METHOD DescribeProperty(const char *name) {
- return osVisualProlog.DescribeProperty(name);
- }
- Sci_Position SCI_METHOD PropertySet(const char *key, const char *val);
- const char * SCI_METHOD DescribeWordListSets() {
- return osVisualProlog.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 ILexer *LexerFactoryVisualProlog() {
- return new LexerVisualProlog();
- }
- };
- Sci_Position SCI_METHOD LexerVisualProlog::PropertySet(const char *key, const char *val) {
- if (osVisualProlog.PropertySet(&options, key, val)) {
- return 0;
- }
- return -1;
- }
- Sci_Position SCI_METHOD LexerVisualProlog::WordListSet(int n, const char *wl) {
- WordList *wordListN = 0;
- switch (n) {
- case 0:
- wordListN = &majorKeywords;
- break;
- case 1:
- wordListN = &minorKeywords;
- break;
- case 2:
- wordListN = &directiveKeywords;
- break;
- case 3:
- wordListN = &docKeywords;
- break;
- }
- Sci_Position firstModification = -1;
- if (wordListN) {
- WordList wlNew;
- wlNew.Set(wl);
- if (*wordListN != wlNew) {
- wordListN->Set(wl);
- firstModification = 0;
- }
- }
- return firstModification;
- }
- // Functor used to truncate history
- struct After {
- Sci_Position line;
- After(Sci_Position 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 isStringVerbatimOpenClose(int ch){
- CharacterCategory cc = CategoriseCharacter(ch);
- return (ccPc <= cc && cc <= ccSo);
- }
- 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 (isStringVerbatimOpenClose(next)) {
- closingQuote = next;
- return true;
- } else {
- return false;
- }
- }
- }
- // Look ahead to see which colour "end" should have (takes colour after the following keyword)
- static void endLookAhead(char s[], LexAccessor &styler, Sci_Position start) {
- char ch = styler.SafeGetCharAt(start, '\n');
- while (' ' == ch) {
- start++;
- ch = styler.SafeGetCharAt(start, '\n');
- }
- Sci_Position i = 0;
- while (i < 100 && isLowerLetter(ch)){
- s[i] = ch;
- i++;
- ch = styler.SafeGetCharAt(start + i, '\n');
- }
- s[i] = '\0';
- }
- static void forwardEscapeLiteral(StyleContext &sc, int EscapeState) {
- sc.Forward();
- 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.Match('u')) {
- if (IsADigit(sc.chNext, 16)) {
- sc.Forward();
- if (IsADigit(sc.chNext, 16)) {
- sc.Forward();
- if (IsADigit(sc.chNext, 16)) {
- sc.Forward();
- if (IsADigit(sc.chNext, 16)) {
- sc.Forward();
- sc.ChangeState(EscapeState);
- }
- }
- }
- }
- }
- }
- void SCI_METHOD LexerVisualProlog::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
- LexAccessor styler(pAccess);
- CharacterSet setDoxygen(CharacterSet::setAlpha, "");
- CharacterSet setNumber(CharacterSet::setNone, "0123456789abcdefABCDEFxoXO");
- StyleContext sc(startPos, length, initStyle, styler, 0x7f);
- int styleBeforeDocKeyword = SCE_VISUALPROLOG_DEFAULT;
- Sci_Position currentLine = styler.GetLine(startPos);
- int closingQuote = '"';
- int nestLevel = 0;
- if (currentLine >= 1)
- {
- nestLevel = styler.GetLineState(currentLine - 1);
- closingQuote = nestLevel;
- }
- // Truncate ppDefineHistory before current line
- for (; sc.More(); sc.Forward()) {
- // Determine if the current state should terminate.
- switch (sc.state) {
- case SCE_VISUALPROLOG_OPERATOR:
- sc.SetState(SCE_VISUALPROLOG_DEFAULT);
- break;
- case SCE_VISUALPROLOG_NUMBER:
- // We accept almost anything because of hex. and number suffixes
- if (!(setNumber.Contains(sc.ch)) || (sc.Match('.') && IsADigit(sc.chNext))) {
- sc.SetState(SCE_VISUALPROLOG_DEFAULT);
- }
- break;
- case SCE_VISUALPROLOG_IDENTIFIER:
- if (!isIdChar(sc.ch)) {
- char s[1000];
- sc.GetCurrent(s, sizeof(s));
- if (0 == strcmp(s, "end")) {
- endLookAhead(s, styler, sc.currentPos);
- }
- if (majorKeywords.InList(s)) {
- sc.ChangeState(SCE_VISUALPROLOG_KEY_MAJOR);
- } else if (minorKeywords.InList(s)) {
- sc.ChangeState(SCE_VISUALPROLOG_KEY_MINOR);
- }
- sc.SetState(SCE_VISUALPROLOG_DEFAULT);
- }
- break;
- case SCE_VISUALPROLOG_VARIABLE:
- case SCE_VISUALPROLOG_ANONYMOUS:
- if (!isIdChar(sc.ch)) {
- sc.SetState(SCE_VISUALPROLOG_DEFAULT);
- }
- break;
- case SCE_VISUALPROLOG_KEY_DIRECTIVE:
- if (!isLowerLetter(sc.ch)) {
- char s[1000];
- sc.GetCurrent(s, sizeof(s));
- if (!directiveKeywords.InList(s+1)) {
- sc.ChangeState(SCE_VISUALPROLOG_IDENTIFIER);
- }
- sc.SetState(SCE_VISUALPROLOG_DEFAULT);
- }
- break;
- case SCE_VISUALPROLOG_COMMENT_BLOCK:
- if (sc.Match('*', '/')) {
- sc.Forward();
- nestLevel--;
- int nextState = (nestLevel == 0) ? SCE_VISUALPROLOG_DEFAULT : SCE_VISUALPROLOG_COMMENT_BLOCK;
- sc.ForwardSetState(nextState);
- } else if (sc.Match('/', '*')) {
- sc.Forward();
- nestLevel++;
- } else if (sc.Match('@')) {
- styleBeforeDocKeyword = sc.state;
- sc.SetState(SCE_VISUALPROLOG_COMMENT_KEY_ERROR);
- }
- break;
- case SCE_VISUALPROLOG_COMMENT_LINE:
- if (sc.atLineEnd) {
- int nextState = (nestLevel == 0) ? SCE_VISUALPROLOG_DEFAULT : SCE_VISUALPROLOG_COMMENT_BLOCK;
- sc.SetState(nextState);
- } 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) || sc.atLineEnd) {
- char s[1000];
- sc.GetCurrent(s, sizeof(s));
- if (docKeywords.InList(s+1)) {
- sc.ChangeState(SCE_VISUALPROLOG_COMMENT_KEY);
- }
- 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:
- case SCE_VISUALPROLOG_STRING_ESCAPE_ERROR:
- // return to SCE_VISUALPROLOG_STRING and treat as such (fall-through)
- sc.SetState(SCE_VISUALPROLOG_STRING);
- case SCE_VISUALPROLOG_STRING:
- if (sc.atLineEnd) {
- sc.SetState(SCE_VISUALPROLOG_STRING_EOL_OPEN);
- } else if (sc.Match(closingQuote)) {
- sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT);
- } else if (sc.Match('\\')) {
- sc.SetState(SCE_VISUALPROLOG_STRING_ESCAPE_ERROR);
- forwardEscapeLiteral(sc, SCE_VISUALPROLOG_STRING_ESCAPE);
- }
- break;
- case SCE_VISUALPROLOG_STRING_EOL_OPEN:
- if (sc.atLineStart) {
- sc.SetState(SCE_VISUALPROLOG_DEFAULT);
- }
- break;
- case SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL:
- case SCE_VISUALPROLOG_STRING_VERBATIM_EOL:
- // return to SCE_VISUALPROLOG_STRING_VERBATIM and treat as such (fall-through)
- sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM);
- case SCE_VISUALPROLOG_STRING_VERBATIM:
- if (sc.atLineEnd) {
- sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM_EOL);
- } else if (sc.Match(closingQuote)) {
- if (closingQuote == sc.chNext) {
- sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL);
- sc.Forward();
- } else {
- sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT);
- }
- }
- break;
- }
- 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('@') && isOpenStringVerbatim(sc.chNext, closingQuote)) {
- sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM);
- sc.Forward();
- } else if (IsADigit(sc.ch) || (sc.Match('.') && IsADigit(sc.chNext))) {
- sc.SetState(SCE_VISUALPROLOG_NUMBER);
- } else if (isLowerLetter(sc.ch)) {
- sc.SetState(SCE_VISUALPROLOG_IDENTIFIER);
- } else if (isUpperLetter(sc.ch)) {
- sc.SetState(SCE_VISUALPROLOG_VARIABLE);
- } 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.Match('%')) {
- sc.SetState(SCE_VISUALPROLOG_COMMENT_LINE);
- } else if (sc.Match('\'')) {
- closingQuote = '\'';
- sc.SetState(SCE_VISUALPROLOG_STRING);
- } else if (sc.Match('"')) {
- closingQuote = '"';
- sc.SetState(SCE_VISUALPROLOG_STRING);
- } else if (sc.Match('#')) {
- sc.SetState(SCE_VISUALPROLOG_KEY_DIRECTIVE);
- } else if (isoperator(static_cast<char>(sc.ch)) || sc.Match('\\')) {
- sc.SetState(SCE_VISUALPROLOG_OPERATOR);
- }
- }
- }
- sc.Complete();
- styler.Flush();
- }
- // Store both the current line's fold level and the next lines in the
- // level store to make it easy to pick up with each increment
- // and to make it possible to fiddle the current level for "} else {".
- void SCI_METHOD LexerVisualProlog::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
- LexAccessor styler(pAccess);
- Sci_PositionU endPos = startPos + length;
- int visibleChars = 0;
- Sci_Position currentLine = styler.GetLine(startPos);
- int levelCurrent = SC_FOLDLEVELBASE;
- if (currentLine > 0)
- levelCurrent = styler.LevelAt(currentLine-1) >> 16;
- int levelMinCurrent = levelCurrent;
- int levelNext = levelCurrent;
- char chNext = styler[startPos];
- int styleNext = styler.StyleAt(startPos);
- int style = initStyle;
- for (Sci_PositionU i = startPos; i < endPos; i++) {
- char ch = chNext;
- chNext = styler.SafeGetCharAt(i + 1);
- style = styleNext;
- styleNext = styler.StyleAt(i + 1);
- bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
- if (style == SCE_VISUALPROLOG_OPERATOR) {
- if (ch == '{') {
- // Measure the minimum before a '{' to allow
- // folding on "} else {"
- if (levelMinCurrent > levelNext) {
- levelMinCurrent = levelNext;
- }
- levelNext++;
- } else if (ch == '}') {
- levelNext--;
- }
- }
- if (!IsASpace(ch))
- visibleChars++;
- if (atEOL || (i == endPos-1)) {
- int levelUse = levelCurrent;
- int lev = levelUse | levelNext << 16;
- if (levelUse < levelNext)
- lev |= SC_FOLDLEVELHEADERFLAG;
- if (lev != styler.LevelAt(currentLine)) {
- styler.SetLevel(currentLine, lev);
- }
- currentLine++;
- levelCurrent = levelNext;
- levelMinCurrent = levelCurrent;
- if (atEOL && (i == static_cast<Sci_PositionU>(styler.Length()-1))) {
- // There is an empty line at end of file so give it same level and empty
- styler.SetLevel(currentLine, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
- }
- visibleChars = 0;
- }
- }
- }
- LexerModule lmVisualProlog(SCLEX_VISUALPROLOG, LexerVisualProlog::LexerFactoryVisualProlog, "visualprolog", visualPrologWordLists);
|