mirror of
				https://github.com/notepad-plus-plus/notepad-plus-plus.git
				synced 2025-10-31 03:24:04 +01:00 
			
		
		
		
	Update with https://www.scintilla.org/scintilla521.zip https://www.scintilla.org/lexilla515.zip - fix setting to bring Scintilla::PositionCR from ScintillaStructures.h inline with Sci_Position.h Sci_PositionCR - add workaround to enable lexer for searchResult commented out SCI_SETILEXER call on searchResult to get one result which is correctly handled by the lexer, added comment about the current problem with property @MarkingsStruct which seems to disappear after call to SCI_SETILEXER or CreateLexer - corrected usage of ObjC lexer - removed unnecessary filter stuff - use own sections for scintilla and lexilla build targets and allow parallel builds - as libscilex is no longer existing, changed to libscintilla - adapt makefiles and cmake - use VS2019 - started simple changes for createlexer adaptations, nullpointercheck missing on return of lexer name from deprecated LexerNameFromID -> undefined behaviour - movement from id -> lexer name, mostly done via LexerNameFromID + switching off corresponding compiler warning - changed to SCI_SETILEXER from SCI_SETLEXER, SCI_SETLEXERLANGUAGE needs to be corrected, see Scintilla5Migration.html - just commented out: SCI_LOADLEXERLIBRARY Fix #10504, close #11419
		
			
				
	
	
		
			905 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			905 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Scintilla source code edit control
 | |
| /** @file LexTADS3.cxx
 | |
|  ** Lexer for TADS3.
 | |
|  **/
 | |
| // Copyright 1998-2006 by Neil Hodgson <neilh@scintilla.org>
 | |
| // The License.txt file describes the conditions under which this software may be distributed.
 | |
| 
 | |
| /*
 | |
|  * TADS3 is a language designed by Michael J. Roberts for the writing of text
 | |
|  * based games.  TADS comes from Text Adventure Development System.  It has good
 | |
|  * support for the processing and outputting of formatted text and much of a
 | |
|  * TADS program listing consists of strings.
 | |
|  *
 | |
|  * TADS has two types of strings, those enclosed in single quotes (') and those
 | |
|  * enclosed in double quotes (").  These strings have different symantics and
 | |
|  * can be given different highlighting if desired.
 | |
|  *
 | |
|  * There can be embedded within both types of strings html tags
 | |
|  * ( <tag key=value> ), library directives ( <.directive> ), and message
 | |
|  * parameters ( {The doctor's/his} ).
 | |
|  *
 | |
|  * Double quoted strings can also contain interpolated expressions
 | |
|  * ( << rug.moved ? ' and a hole in the floor. ' : nil >> ).  These expressions
 | |
|  * may themselves contain single or double quoted strings, although the double
 | |
|  * quoted strings may not contain interpolated expressions.
 | |
|  *
 | |
|  * These embedded constructs influence the output and formatting and are an
 | |
|  * important part of a program and require highlighting.
 | |
|  *
 | |
|  * LINKS
 | |
|  * http://www.tads.org/
 | |
|  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| #include <stdarg.h>
 | |
| #include <assert.h>
 | |
| #include <ctype.h>
 | |
| 
 | |
| #include <string>
 | |
| #include <string_view>
 | |
| 
 | |
| #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 "LexerModule.h"
 | |
| 
 | |
| using namespace Lexilla;
 | |
| 
 | |
| static const int T3_SINGLE_QUOTE = 1;
 | |
| static const int T3_INT_EXPRESSION = 2;
 | |
| static const int T3_INT_EXPRESSION_IN_TAG = 4;
 | |
| static const int T3_HTML_SQUOTE = 8;
 | |
| 
 | |
| static inline bool IsEOL(const int ch, const int chNext) {
 | |
|         return (ch == '\r' && chNext != '\n') || (ch == '\n');
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *   Test the current character to see if it's the START of an EOL sequence;
 | |
|  *   if so, skip ahead to the last character of the sequence and return true,
 | |
|  *   and if not just return false.  There are a few places where we want to
 | |
|  *   check to see if a newline sequence occurs at a particular point, but
 | |
|  *   where a caller expects a subroutine to stop only upon reaching the END
 | |
|  *   of a newline sequence (in particular, CR-LF on Windows).  That's why
 | |
|  *   IsEOL() above only returns true on CR if the CR isn't followed by an LF
 | |
|  *   - it doesn't want to admit that there's a newline until reaching the END
 | |
|  *   of the sequence.  We meet both needs by saying that there's a newline
 | |
|  *   when we see the CR in a CR-LF, but skipping the CR before returning so
 | |
|  *   that the caller's caller will see that we've stopped at the LF.
 | |
|  */
 | |
| static inline bool IsEOLSkip(StyleContext &sc)
 | |
| {
 | |
|     /* test for CR-LF */
 | |
|     if (sc.ch == '\r' && sc.chNext == '\n')
 | |
|     {
 | |
|         /* got CR-LF - skip the CR and indicate that we're at a newline */
 | |
|         sc.Forward();
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      *   in other cases, we have at most a 1-character newline, so do the
 | |
|      *   normal IsEOL test
 | |
|      */
 | |
|     return IsEOL(sc.ch, sc.chNext);
 | |
| }
 | |
| 
 | |
| static inline bool IsATADS3Operator(const int ch) {
 | |
|         return ch == '=' || ch == '{' || ch == '}' || ch == '(' || ch == ')'
 | |
|                 || ch == '[' || ch == ']' || ch == ',' || ch == ':' || ch == ';'
 | |
|                 || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%'
 | |
|                 || ch == '?' || ch == '!' || ch == '<' || ch == '>' || ch == '|'
 | |
|                 || ch == '@' || ch == '&' || ch == '~';
 | |
| }
 | |
| 
 | |
| static inline bool IsAWordChar(const int ch) {
 | |
|         return isalnum(ch) || ch == '_';
 | |
| }
 | |
| 
 | |
| static inline bool IsAWordStart(const int ch) {
 | |
|         return isalpha(ch) || ch == '_';
 | |
| }
 | |
| 
 | |
| static inline bool IsAHexDigit(const int ch) {
 | |
|         int lch = tolower(ch);
 | |
|         return isdigit(lch) || lch == 'a' || lch == 'b' || lch == 'c'
 | |
|                 || lch == 'd' || lch == 'e' || lch == 'f';
 | |
| }
 | |
| 
 | |
| static inline bool IsAnHTMLChar(int ch) {
 | |
|         return isalnum(ch) || ch == '-' || ch == '_' || ch == '.';
 | |
| }
 | |
| 
 | |
| static inline bool IsADirectiveChar(int ch) {
 | |
|         return isalnum(ch) || isspace(ch) || ch == '-' || ch == '/';
 | |
| }
 | |
| 
 | |
| static inline bool IsANumberStart(StyleContext &sc) {
 | |
|         return isdigit(sc.ch)
 | |
|                 || (!isdigit(sc.chPrev) && sc.ch == '.' && isdigit(sc.chNext));
 | |
| }
 | |
| 
 | |
| inline static void ColouriseTADS3Operator(StyleContext &sc) {
 | |
|         int initState = sc.state;
 | |
|         int c = sc.ch;
 | |
|         sc.SetState(c == '{' || c == '}' ? SCE_T3_BRACE : SCE_T3_OPERATOR);
 | |
|         sc.ForwardSetState(initState);
 | |
| }
 | |
| 
 | |
| static void ColouriseTADSHTMLString(StyleContext &sc, int &lineState) {
 | |
|         int endState = sc.state;
 | |
|         int chQuote = sc.ch;
 | |
|         int chString = (lineState & T3_SINGLE_QUOTE) ? '\'' : '"';
 | |
|         if (endState == SCE_T3_HTML_STRING) {
 | |
|                 if (lineState&T3_SINGLE_QUOTE) {
 | |
|                         endState = SCE_T3_S_STRING;
 | |
|                         chString = '\'';
 | |
|                 } else if (lineState&T3_INT_EXPRESSION) {
 | |
|                         endState = SCE_T3_X_STRING;
 | |
|                         chString = '"';
 | |
|                 } else {
 | |
|                         endState = SCE_T3_HTML_DEFAULT;
 | |
|                         chString = '"';
 | |
|                 }
 | |
|                 chQuote = (lineState & T3_HTML_SQUOTE) ? '\'' : '"';
 | |
|         } else {
 | |
|                 sc.SetState(SCE_T3_HTML_STRING);
 | |
|                 sc.Forward();
 | |
|         }
 | |
|         if (chQuote == '"')
 | |
|                 lineState &= ~T3_HTML_SQUOTE;
 | |
|         else
 | |
|                 lineState |= T3_HTML_SQUOTE;
 | |
| 
 | |
|         while (sc.More()) {
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.ch == chQuote) {
 | |
|                         sc.ForwardSetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.Match('\\', static_cast<char>(chQuote))) {
 | |
|                         sc.Forward(2);
 | |
|                         sc.SetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.ch == chString) {
 | |
|                         sc.SetState(SCE_T3_DEFAULT);
 | |
|                         return;
 | |
|                 }
 | |
| 
 | |
|                 if (sc.Match('<', '<')) {
 | |
|                         lineState |= T3_INT_EXPRESSION | T3_INT_EXPRESSION_IN_TAG;
 | |
|                         sc.SetState(SCE_T3_X_DEFAULT);
 | |
|                         sc.Forward(2);
 | |
|                         return;
 | |
|                 }
 | |
| 
 | |
|                 if (sc.Match('\\', static_cast<char>(chQuote))
 | |
|                         || sc.Match('\\', static_cast<char>(chString))
 | |
|                         || sc.Match('\\', '\\')) {
 | |
|                         sc.Forward(2);
 | |
|                 } else {
 | |
|                         sc.Forward();
 | |
|                 }
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3HTMLTagStart(StyleContext &sc) {
 | |
|         sc.SetState(SCE_T3_HTML_TAG);
 | |
|         sc.Forward();
 | |
|         if (sc.ch == '/') {
 | |
|                 sc.Forward();
 | |
|         }
 | |
|         while (IsAnHTMLChar(sc.ch)) {
 | |
|                 sc.Forward();
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3HTMLTag(StyleContext &sc, int &lineState) {
 | |
|         int endState = sc.state;
 | |
|         int chQuote = '"';
 | |
|         int chString = '\'';
 | |
|         switch (endState) {
 | |
|                 case SCE_T3_S_STRING:
 | |
|                         ColouriseTADS3HTMLTagStart(sc);
 | |
|                         sc.SetState(SCE_T3_HTML_DEFAULT);
 | |
|                         chQuote = '\'';
 | |
|                         chString = '"';
 | |
|                         break;
 | |
|                 case SCE_T3_D_STRING:
 | |
|                 case SCE_T3_X_STRING:
 | |
|                         ColouriseTADS3HTMLTagStart(sc);
 | |
|                         sc.SetState(SCE_T3_HTML_DEFAULT);
 | |
|                         break;
 | |
|                 case SCE_T3_HTML_DEFAULT:
 | |
|                         if (lineState&T3_SINGLE_QUOTE) {
 | |
|                                 endState = SCE_T3_S_STRING;
 | |
|                                 chQuote = '\'';
 | |
|                                 chString = '"';
 | |
|                         } else if (lineState&T3_INT_EXPRESSION) {
 | |
|                                 endState = SCE_T3_X_STRING;
 | |
|                         } else {
 | |
|                                 endState = SCE_T3_D_STRING;
 | |
|                         }
 | |
|                         break;
 | |
|         }
 | |
| 
 | |
|         while (sc.More()) {
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.Match('/', '>')) {
 | |
|                         sc.SetState(SCE_T3_HTML_TAG);
 | |
|                         sc.Forward(2);
 | |
|                         sc.SetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.ch == '>') {
 | |
|                         sc.SetState(SCE_T3_HTML_TAG);
 | |
|                         sc.ForwardSetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.ch == chQuote) {
 | |
|                         sc.SetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.Match('\\', static_cast<char>(chQuote))) {
 | |
|                         sc.Forward();
 | |
|                         ColouriseTADSHTMLString(sc, lineState);
 | |
|                         if (sc.state == SCE_T3_X_DEFAULT)
 | |
|                             break;
 | |
|                 } else if (sc.ch == chString) {
 | |
|                         ColouriseTADSHTMLString(sc, lineState);
 | |
|                 } else if (sc.ch == '=') {
 | |
|                         ColouriseTADS3Operator(sc);
 | |
|                 } else {
 | |
|                         sc.Forward();
 | |
|                 }
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3Keyword(StyleContext &sc,
 | |
|                                                         WordList *keywordlists[],       Sci_PositionU endPos) {
 | |
|         char s[250];
 | |
|         WordList &keywords = *keywordlists[0];
 | |
|         WordList &userwords1 = *keywordlists[1];
 | |
|         WordList &userwords2 = *keywordlists[2];
 | |
|         WordList &userwords3 = *keywordlists[3];
 | |
|         int initState = sc.state;
 | |
|         sc.SetState(SCE_T3_IDENTIFIER);
 | |
|         while (sc.More() && (IsAWordChar(sc.ch))) {
 | |
|                 sc.Forward();
 | |
|         }
 | |
|         sc.GetCurrent(s, sizeof(s));
 | |
|         if ( strcmp(s, "is") == 0 || strcmp(s, "not") == 0) {
 | |
|                 // have to find if "in" is next
 | |
|                 Sci_Position n = 1;
 | |
|                 while (n + sc.currentPos < endPos && IsASpaceOrTab(sc.GetRelative(n)))
 | |
|                         n++;
 | |
|                 if (sc.GetRelative(n) == 'i' && sc.GetRelative(n+1) == 'n') {
 | |
|                         sc.Forward(n+2);
 | |
|                         sc.ChangeState(SCE_T3_KEYWORD);
 | |
|                 }
 | |
|         } else if (keywords.InList(s)) {
 | |
|                 sc.ChangeState(SCE_T3_KEYWORD);
 | |
|         } else if (userwords3.InList(s)) {
 | |
|                 sc.ChangeState(SCE_T3_USER3);
 | |
|         } else if (userwords2.InList(s)) {
 | |
|                 sc.ChangeState(SCE_T3_USER2);
 | |
|         } else if (userwords1.InList(s)) {
 | |
|                 sc.ChangeState(SCE_T3_USER1);
 | |
|         }
 | |
|         sc.SetState(initState);
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3MsgParam(StyleContext &sc, int &lineState) {
 | |
|         int endState = sc.state;
 | |
|         int chQuote = '"';
 | |
|         switch (endState) {
 | |
|                 case SCE_T3_S_STRING:
 | |
|                         sc.SetState(SCE_T3_MSG_PARAM);
 | |
|                         sc.Forward();
 | |
|                         chQuote = '\'';
 | |
|                         break;
 | |
|                 case SCE_T3_D_STRING:
 | |
|                 case SCE_T3_X_STRING:
 | |
|                         sc.SetState(SCE_T3_MSG_PARAM);
 | |
|                         sc.Forward();
 | |
|                         break;
 | |
|                 case SCE_T3_MSG_PARAM:
 | |
|                         if (lineState&T3_SINGLE_QUOTE) {
 | |
|                                 endState = SCE_T3_S_STRING;
 | |
|                                 chQuote = '\'';
 | |
|                         } else if (lineState&T3_INT_EXPRESSION) {
 | |
|                                 endState = SCE_T3_X_STRING;
 | |
|                         } else {
 | |
|                                 endState = SCE_T3_D_STRING;
 | |
|                         }
 | |
|                         break;
 | |
|         }
 | |
|         while (sc.More() && sc.ch != '}' && sc.ch != chQuote) {
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.ch == '\\') {
 | |
|                         sc.Forward();
 | |
|                 }
 | |
|                 sc.Forward();
 | |
|         }
 | |
|         if (sc.ch == chQuote) {
 | |
|                 sc.SetState(endState);
 | |
|         } else {
 | |
|                 sc.ForwardSetState(endState);
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3LibDirective(StyleContext &sc, int &lineState) {
 | |
|         int initState = sc.state;
 | |
|         int chQuote = '"';
 | |
|         switch (initState) {
 | |
|                 case SCE_T3_S_STRING:
 | |
|                         sc.SetState(SCE_T3_LIB_DIRECTIVE);
 | |
|                         sc.Forward(2);
 | |
|                         chQuote = '\'';
 | |
|                         break;
 | |
|                 case SCE_T3_D_STRING:
 | |
|                         sc.SetState(SCE_T3_LIB_DIRECTIVE);
 | |
|                         sc.Forward(2);
 | |
|                         break;
 | |
|                 case SCE_T3_LIB_DIRECTIVE:
 | |
|                         if (lineState&T3_SINGLE_QUOTE) {
 | |
|                                 initState = SCE_T3_S_STRING;
 | |
|                                 chQuote = '\'';
 | |
|                         } else {
 | |
|                                 initState = SCE_T3_D_STRING;
 | |
|                         }
 | |
|                         break;
 | |
|         }
 | |
|         while (sc.More() && IsADirectiveChar(sc.ch)) {
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         return;
 | |
|                 }
 | |
|                 sc.Forward();
 | |
|         };
 | |
|         if (sc.ch == '>' || !sc.More()) {
 | |
|                 sc.ForwardSetState(initState);
 | |
|         } else if (sc.ch == chQuote) {
 | |
|                 sc.SetState(initState);
 | |
|         } else {
 | |
|                 sc.ChangeState(initState);
 | |
|                 sc.Forward();
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3String(StyleContext &sc, int &lineState) {
 | |
|         int chQuote = sc.ch;
 | |
|         int endState = sc.state;
 | |
|         switch (sc.state) {
 | |
|                 case SCE_T3_DEFAULT:
 | |
|                 case SCE_T3_X_DEFAULT:
 | |
|                         if (chQuote == '"') {
 | |
|                                 if (sc.state == SCE_T3_DEFAULT) {
 | |
|                                         sc.SetState(SCE_T3_D_STRING);
 | |
|                                 } else {
 | |
|                                         sc.SetState(SCE_T3_X_STRING);
 | |
|                                 }
 | |
|                                 lineState &= ~T3_SINGLE_QUOTE;
 | |
|                         } else {
 | |
|                                 sc.SetState(SCE_T3_S_STRING);
 | |
|                                 lineState |= T3_SINGLE_QUOTE;
 | |
|                         }
 | |
|                         sc.Forward();
 | |
|                         break;
 | |
|                 case SCE_T3_S_STRING:
 | |
|                         chQuote = '\'';
 | |
|                         endState = lineState&T3_INT_EXPRESSION ?
 | |
|                                 SCE_T3_X_DEFAULT : SCE_T3_DEFAULT;
 | |
|                         break;
 | |
|                 case SCE_T3_D_STRING:
 | |
|                         chQuote = '"';
 | |
|                         endState = SCE_T3_DEFAULT;
 | |
|                         break;
 | |
|                 case SCE_T3_X_STRING:
 | |
|                         chQuote = '"';
 | |
|                         endState = SCE_T3_X_DEFAULT;
 | |
|                         break;
 | |
|         }
 | |
|         while (sc.More()) {
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.ch == chQuote) {
 | |
|                         sc.ForwardSetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.state == SCE_T3_D_STRING && sc.Match('<', '<')) {
 | |
|                         lineState |= T3_INT_EXPRESSION;
 | |
|                         sc.SetState(SCE_T3_X_DEFAULT);
 | |
|                         sc.Forward(2);
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.Match('\\', static_cast<char>(chQuote))
 | |
|                     || sc.Match('\\', '\\')) {
 | |
|                         sc.Forward(2);
 | |
|                 } else if (sc.ch == '{') {
 | |
|                         ColouriseTADS3MsgParam(sc, lineState);
 | |
|                 } else if (sc.Match('<', '.')) {
 | |
|                         ColouriseTADS3LibDirective(sc, lineState);
 | |
|                 } else if (sc.ch == '<') {
 | |
|                         ColouriseTADS3HTMLTag(sc, lineState);
 | |
|                         if (sc.state == SCE_T3_X_DEFAULT)
 | |
|                                 return;
 | |
|                 } else {
 | |
|                         sc.Forward();
 | |
|                 }
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3Comment(StyleContext &sc, int endState) {
 | |
|         sc.SetState(SCE_T3_BLOCK_COMMENT);
 | |
|         while (sc.More()) {
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         return;
 | |
|                 }
 | |
|                 if (sc.Match('*', '/')) {
 | |
|                         sc.Forward(2);
 | |
|                         sc.SetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 sc.Forward();
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseToEndOfLine(StyleContext &sc, int initState, int endState) {
 | |
|         sc.SetState(initState);
 | |
|         while (sc.More()) {
 | |
|                 if (sc.ch == '\\') {
 | |
|                         sc.Forward();
 | |
|                         if (IsEOLSkip(sc)) {
 | |
|                                         return;
 | |
|                         }
 | |
|                 }
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         sc.SetState(endState);
 | |
|                         return;
 | |
|                 }
 | |
|                 sc.Forward();
 | |
|         }
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3Number(StyleContext &sc) {
 | |
|         int endState = sc.state;
 | |
|         bool inHexNumber = false;
 | |
|         bool seenE = false;
 | |
|         bool seenDot = sc.ch == '.';
 | |
|         sc.SetState(SCE_T3_NUMBER);
 | |
|         if (sc.More()) {
 | |
|                 sc.Forward();
 | |
|         }
 | |
|         if (sc.chPrev == '0' && tolower(sc.ch) == 'x') {
 | |
|                 inHexNumber = true;
 | |
|                 sc.Forward();
 | |
|         }
 | |
|         while (sc.More()) {
 | |
|                 if (inHexNumber) {
 | |
|                         if (!IsAHexDigit(sc.ch)) {
 | |
|                                 break;
 | |
|                         }
 | |
|                 } else if (!isdigit(sc.ch)) {
 | |
|                         if (!seenE && tolower(sc.ch) == 'e') {
 | |
|                                 seenE = true;
 | |
|                                 seenDot = true;
 | |
|                                 if (sc.chNext == '+' || sc.chNext == '-') {
 | |
|                                         sc.Forward();
 | |
|                                 }
 | |
|                         } else if (!seenDot && sc.ch == '.') {
 | |
|                                 seenDot = true;
 | |
|                         } else {
 | |
|                                 break;
 | |
|                         }
 | |
|                 }
 | |
|                 sc.Forward();
 | |
|         }
 | |
|         sc.SetState(endState);
 | |
| }
 | |
| 
 | |
| static void ColouriseTADS3Doc(Sci_PositionU startPos, Sci_Position length, int initStyle,
 | |
|                                                            WordList *keywordlists[], Accessor &styler) {
 | |
|         int visibleChars = 0;
 | |
|         int bracketLevel = 0;
 | |
|         int lineState = 0;
 | |
|         Sci_PositionU endPos = startPos + length;
 | |
|         Sci_Position lineCurrent = styler.GetLine(startPos);
 | |
|         if (lineCurrent > 0) {
 | |
|                 lineState = styler.GetLineState(lineCurrent-1);
 | |
|         }
 | |
|         StyleContext sc(startPos, length, initStyle, styler);
 | |
| 
 | |
|         while (sc.More()) {
 | |
| 
 | |
|                 if (IsEOL(sc.ch, sc.chNext)) {
 | |
|                         styler.SetLineState(lineCurrent, lineState);
 | |
|                         lineCurrent++;
 | |
|                         visibleChars = 0;
 | |
|                         sc.Forward();
 | |
|                         if (sc.ch == '\n') {
 | |
|                                 sc.Forward();
 | |
|                         }
 | |
|                 }
 | |
| 
 | |
|                 switch(sc.state) {
 | |
|                         case SCE_T3_PREPROCESSOR:
 | |
|                         case SCE_T3_LINE_COMMENT:
 | |
|                                 ColouriseToEndOfLine(sc, sc.state, lineState&T3_INT_EXPRESSION ?
 | |
|                                         SCE_T3_X_DEFAULT : SCE_T3_DEFAULT);
 | |
|                                 break;
 | |
|                         case SCE_T3_S_STRING:
 | |
|                         case SCE_T3_D_STRING:
 | |
|                         case SCE_T3_X_STRING:
 | |
|                                 ColouriseTADS3String(sc, lineState);
 | |
|                                 visibleChars++;
 | |
|                                 break;
 | |
|                         case SCE_T3_MSG_PARAM:
 | |
|                                 ColouriseTADS3MsgParam(sc, lineState);
 | |
|                                 break;
 | |
|                         case SCE_T3_LIB_DIRECTIVE:
 | |
|                                 ColouriseTADS3LibDirective(sc, lineState);
 | |
|                                 break;
 | |
|                         case SCE_T3_HTML_DEFAULT:
 | |
|                                 ColouriseTADS3HTMLTag(sc, lineState);
 | |
|                                 break;
 | |
|                         case SCE_T3_HTML_STRING:
 | |
|                                 ColouriseTADSHTMLString(sc, lineState);
 | |
|                                 break;
 | |
|                         case SCE_T3_BLOCK_COMMENT:
 | |
|                                 ColouriseTADS3Comment(sc, lineState&T3_INT_EXPRESSION ?
 | |
|                                         SCE_T3_X_DEFAULT : SCE_T3_DEFAULT);
 | |
|                                 break;
 | |
|                         case SCE_T3_DEFAULT:
 | |
|                         case SCE_T3_X_DEFAULT:
 | |
|                                 if (IsASpaceOrTab(sc.ch)) {
 | |
|                                         sc.Forward();
 | |
|                                 } else if (sc.ch == '#' && visibleChars == 0) {
 | |
|                                         ColouriseToEndOfLine(sc, SCE_T3_PREPROCESSOR, sc.state);
 | |
|                                 } else if (sc.Match('/', '*')) {
 | |
|                                         ColouriseTADS3Comment(sc, sc.state);
 | |
|                                         visibleChars++;
 | |
|                                 } else if (sc.Match('/', '/')) {
 | |
|                                         ColouriseToEndOfLine(sc, SCE_T3_LINE_COMMENT, sc.state);
 | |
|                                 } else if (sc.ch == '"') {
 | |
|                                         bracketLevel = 0;
 | |
|                                         ColouriseTADS3String(sc, lineState);
 | |
|                                         visibleChars++;
 | |
|                                 } else if (sc.ch == '\'') {
 | |
|                                         ColouriseTADS3String(sc, lineState);
 | |
|                                         visibleChars++;
 | |
|                                 } else if (sc.state == SCE_T3_X_DEFAULT && bracketLevel == 0
 | |
|                                                    && sc.Match('>', '>')) {
 | |
|                                         sc.Forward(2);
 | |
|                                         sc.SetState(SCE_T3_D_STRING);
 | |
|                                         if (lineState & T3_INT_EXPRESSION_IN_TAG)
 | |
|                                                 sc.SetState(SCE_T3_HTML_STRING);
 | |
|                                         lineState &= ~(T3_SINGLE_QUOTE|T3_INT_EXPRESSION
 | |
|                                                        |T3_INT_EXPRESSION_IN_TAG);
 | |
|                                 } else if (IsATADS3Operator(sc.ch)) {
 | |
|                                         if (sc.state == SCE_T3_X_DEFAULT) {
 | |
|                                                 if (sc.ch == '(') {
 | |
|                                                         bracketLevel++;
 | |
|                                                 } else if (sc.ch == ')' && bracketLevel > 0) {
 | |
|                                                         bracketLevel--;
 | |
|                                                 }
 | |
|                                         }
 | |
|                                         ColouriseTADS3Operator(sc);
 | |
|                                         visibleChars++;
 | |
|                                 } else if (IsANumberStart(sc)) {
 | |
|                                         ColouriseTADS3Number(sc);
 | |
|                                         visibleChars++;
 | |
|                                 } else if (IsAWordStart(sc.ch)) {
 | |
|                                         ColouriseTADS3Keyword(sc, keywordlists, endPos);
 | |
|                                         visibleChars++;
 | |
|                                 } else if (sc.Match("...")) {
 | |
|                                         sc.SetState(SCE_T3_IDENTIFIER);
 | |
|                                         sc.Forward(3);
 | |
|                                         sc.SetState(SCE_T3_DEFAULT);
 | |
|                                 } else {
 | |
|                                         sc.Forward();
 | |
|                                         visibleChars++;
 | |
|                                 }
 | |
|                                 break;
 | |
|                         default:
 | |
|                                 sc.SetState(SCE_T3_DEFAULT);
 | |
|                                 sc.Forward();
 | |
|                 }
 | |
|         }
 | |
|         sc.Complete();
 | |
| }
 | |
| 
 | |
| /*
 | |
|  TADS3 has two styles of top level block (TLB). Eg
 | |
| 
 | |
|  // default style
 | |
|  silverKey : Key 'small silver key' 'small silver key'
 | |
|         "A small key glints in the sunlight. "
 | |
|  ;
 | |
| 
 | |
|  and
 | |
| 
 | |
|  silverKey : Key {
 | |
|         'small silver key'
 | |
|         'small silver key'
 | |
|         "A small key glints in the sunlight. "
 | |
|  }
 | |
| 
 | |
|  Some constructs mandate one or the other, but usually the author has may choose
 | |
|  either.
 | |
| 
 | |
|  T3_SEENSTART is used to indicate that a braceless TLB has been (potentially)
 | |
|  seen and is also used to match the closing ';' of the default style.
 | |
| 
 | |
|  T3_EXPECTINGIDENTIFIER and T3_EXPECTINGPUNCTUATION are used to keep track of
 | |
|  what characters may be seen without incrementing the block level.  The general
 | |
|  pattern is identifier <punc> identifier, acceptable punctuation characters
 | |
|  are ':', ',', '(' and ')'.  No attempt is made to ensure that punctuation
 | |
|  characters are syntactically correct, eg parentheses match. A ')' always
 | |
|  signifies the start of a block.  We just need to check if it is followed by a
 | |
|  '{', in which case we let the brace handling code handle the folding level.
 | |
| 
 | |
|  expectingIdentifier == false && expectingIdentifier == false
 | |
|  Before the start of a TLB.
 | |
| 
 | |
|  expectingIdentifier == true && expectingIdentifier == true
 | |
|  Currently in an identifier.  Will accept identifier or punctuation.
 | |
| 
 | |
|  expectingIdentifier == true && expectingIdentifier == false
 | |
|  Just seen a punctuation character & now waiting for an identifier to start.
 | |
| 
 | |
|  expectingIdentifier == false && expectingIdentifier == truee
 | |
|  We were in an identifier and have seen space.  Now waiting to see a punctuation
 | |
|  character
 | |
| 
 | |
|  Space, comments & preprocessor directives are always acceptable and are
 | |
|  equivalent.
 | |
| */
 | |
| 
 | |
| static const int T3_SEENSTART = 1 << 12;
 | |
| static const int T3_EXPECTINGIDENTIFIER = 1 << 13;
 | |
| static const int T3_EXPECTINGPUNCTUATION = 1 << 14;
 | |
| 
 | |
| static inline bool IsStringTransition(int s1, int s2) {
 | |
|         return s1 != s2
 | |
|                 && (s1 == SCE_T3_S_STRING || s1 == SCE_T3_X_STRING
 | |
|                         || (s1 == SCE_T3_D_STRING && s2 != SCE_T3_X_DEFAULT))
 | |
|                 && s2 != SCE_T3_LIB_DIRECTIVE
 | |
|                 && s2 != SCE_T3_MSG_PARAM
 | |
|                 && s2 != SCE_T3_HTML_TAG
 | |
|                 && s2 != SCE_T3_HTML_STRING;
 | |
| }
 | |
| 
 | |
| static inline bool IsATADS3Punctuation(const int ch) {
 | |
|         return ch == ':' || ch == ',' || ch == '(' || ch == ')';
 | |
| }
 | |
| 
 | |
| static inline bool IsAnIdentifier(const int style) {
 | |
|         return style == SCE_T3_IDENTIFIER
 | |
|                 || style == SCE_T3_USER1
 | |
|                 || style == SCE_T3_USER2
 | |
|                 || style == SCE_T3_USER3;
 | |
| }
 | |
| 
 | |
| static inline bool IsAnOperator(const int style) {
 | |
|     return style == SCE_T3_OPERATOR || style == SCE_T3_BRACE;
 | |
| }
 | |
| 
 | |
| static inline bool IsSpaceEquivalent(const int ch, const int style) {
 | |
|         return isspace(ch)
 | |
|                 || style == SCE_T3_BLOCK_COMMENT
 | |
|                 || style == SCE_T3_LINE_COMMENT
 | |
|                 || style == SCE_T3_PREPROCESSOR;
 | |
| }
 | |
| 
 | |
| static char peekAhead(Sci_PositionU startPos, Sci_PositionU endPos,
 | |
|                                           Accessor &styler) {
 | |
|         for (Sci_PositionU i = startPos; i < endPos; i++) {
 | |
|                 int style = styler.StyleAt(i);
 | |
|                 char ch = styler[i];
 | |
|                 if (!IsSpaceEquivalent(ch, style)) {
 | |
|                         if (IsAnIdentifier(style)) {
 | |
|                                 return 'a';
 | |
|                         }
 | |
|                         if (IsATADS3Punctuation(ch)) {
 | |
|                                 return ':';
 | |
|                         }
 | |
|                         if (ch == '{') {
 | |
|                                 return '{';
 | |
|                         }
 | |
|                         return '*';
 | |
|                 }
 | |
|         }
 | |
|         return ' ';
 | |
| }
 | |
| 
 | |
| static void FoldTADS3Doc(Sci_PositionU startPos, Sci_Position length, int initStyle,
 | |
|                             WordList *[], Accessor &styler) {
 | |
|         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 seenStart = levelCurrent & T3_SEENSTART;
 | |
|         int expectingIdentifier = levelCurrent & T3_EXPECTINGIDENTIFIER;
 | |
|         int expectingPunctuation = levelCurrent & T3_EXPECTINGPUNCTUATION;
 | |
|         levelCurrent &= SC_FOLDLEVELNUMBERMASK;
 | |
|         int levelMinCurrent = levelCurrent;
 | |
|         int levelNext = levelCurrent;
 | |
|         char chNext = styler[startPos];
 | |
|         int styleNext = styler.StyleAt(startPos);
 | |
|         int style = initStyle;
 | |
|         char ch = chNext;
 | |
|         int stylePrev = style;
 | |
|         bool redo = false;
 | |
|         for (Sci_PositionU i = startPos; i < endPos; i++) {
 | |
|                 if (redo) {
 | |
|                         redo = false;
 | |
|                         i--;
 | |
|                 } else {
 | |
|                         ch = chNext;
 | |
|                         chNext = styler.SafeGetCharAt(i + 1);
 | |
|                         stylePrev = style;
 | |
|                         style = styleNext;
 | |
|                         styleNext = styler.StyleAt(i + 1);
 | |
|                 }
 | |
|                 bool atEOL = IsEOL(ch, chNext);
 | |
| 
 | |
|                 if (levelNext == SC_FOLDLEVELBASE) {
 | |
|                         if (IsSpaceEquivalent(ch, style)) {
 | |
|                                 if (expectingPunctuation) {
 | |
|                                         expectingIdentifier = 0;
 | |
|                                 }
 | |
|                                 if (style == SCE_T3_BLOCK_COMMENT) {
 | |
|                                         levelNext++;
 | |
|                                 }
 | |
|                         } else if (ch == '{') {
 | |
|                                 levelNext++;
 | |
|                                 seenStart = 0;
 | |
|                         } else if (ch == '\'' || ch == '"' || ch == '[') {
 | |
|                                 levelNext++;
 | |
|                                 if (seenStart) {
 | |
|                                         redo = true;
 | |
|                                 }
 | |
|                         } else if (ch == ';') {
 | |
|                                 seenStart = 0;
 | |
|                                 expectingIdentifier = 0;
 | |
|                                 expectingPunctuation = 0;
 | |
|                         } else if (expectingIdentifier && expectingPunctuation) {
 | |
|                                 if (IsATADS3Punctuation(ch)) {
 | |
|                                         if (ch == ')' && peekAhead(i+1, endPos, styler) != '{') {
 | |
|                                                 levelNext++;
 | |
|                                         } else {
 | |
|                                                 expectingPunctuation = 0;
 | |
|                                         }
 | |
|                                 } else if (!IsAnIdentifier(style)) {
 | |
|                                         levelNext++;
 | |
|                                 }
 | |
|                         } else if (expectingIdentifier && !expectingPunctuation) {
 | |
|                                 if (!IsAnIdentifier(style)) {
 | |
|                                         levelNext++;
 | |
|                                 } else {
 | |
|                                         expectingPunctuation = T3_EXPECTINGPUNCTUATION;
 | |
|                                 }
 | |
|                         } else if (!expectingIdentifier && expectingPunctuation) {
 | |
|                                 if (!IsATADS3Punctuation(ch)) {
 | |
|                                         levelNext++;
 | |
|                                 } else {
 | |
|                                         if (ch == ')' && peekAhead(i+1, endPos, styler) != '{') {
 | |
|                                                 levelNext++;
 | |
|                                         } else {
 | |
|                                                 expectingIdentifier = T3_EXPECTINGIDENTIFIER;
 | |
|                                                 expectingPunctuation = 0;
 | |
|                                         }
 | |
|                                 }
 | |
|                         } else if (!expectingIdentifier && !expectingPunctuation) {
 | |
|                                 if (IsAnIdentifier(style)) {
 | |
|                                         seenStart = T3_SEENSTART;
 | |
|                                         expectingIdentifier = T3_EXPECTINGIDENTIFIER;
 | |
|                                         expectingPunctuation = T3_EXPECTINGPUNCTUATION;
 | |
|                                 }
 | |
|                         }
 | |
| 
 | |
|                         if (levelNext != SC_FOLDLEVELBASE && style != SCE_T3_BLOCK_COMMENT) {
 | |
|                                 expectingIdentifier = 0;
 | |
|                                 expectingPunctuation = 0;
 | |
|                         }
 | |
| 
 | |
|                 } else if (levelNext == SC_FOLDLEVELBASE+1 && seenStart
 | |
|                                    && ch == ';' && IsAnOperator(style)) {
 | |
|                         levelNext--;
 | |
|                         seenStart = 0;
 | |
|                 } else if (style == SCE_T3_BLOCK_COMMENT) {
 | |
|                         if (stylePrev != SCE_T3_BLOCK_COMMENT) {
 | |
|                                 levelNext++;
 | |
|                         } else if (styleNext != SCE_T3_BLOCK_COMMENT && !atEOL) {
 | |
|                                 // Comments don't end at end of line and the next character may be unstyled.
 | |
|                                 levelNext--;
 | |
|                         }
 | |
|                 } else if (ch == '\'' || ch == '"') {
 | |
|                         if (IsStringTransition(style, stylePrev)) {
 | |
|                                 if (levelMinCurrent > levelNext) {
 | |
|                                         levelMinCurrent = levelNext;
 | |
|                                 }
 | |
|                                 levelNext++;
 | |
|                         } else if (IsStringTransition(style, styleNext)) {
 | |
|                                 levelNext--;
 | |
|                         }
 | |
|                 } else if (IsAnOperator(style)) {
 | |
|                         if (ch == '{' || ch == '[') {
 | |
|                                 // Measure the minimum before a '{' to allow
 | |
|                                 // folding on "} else {"
 | |
|                                 if (levelMinCurrent > levelNext) {
 | |
|                                         levelMinCurrent = levelNext;
 | |
|                                 }
 | |
|                                 levelNext++;
 | |
|                         } else if (ch == '}' || ch == ']') {
 | |
|                                 levelNext--;
 | |
|                         }
 | |
|                 }
 | |
| 
 | |
|                 if (atEOL) {
 | |
|                         if (seenStart && levelNext == SC_FOLDLEVELBASE) {
 | |
|                                 switch (peekAhead(i+1, endPos, styler)) {
 | |
|                                         case ' ':
 | |
|                                         case '{':
 | |
|                                                 break;
 | |
|                                         case '*':
 | |
|                                                 levelNext++;
 | |
|                                                 break;
 | |
|                                         case 'a':
 | |
|                                                 if (expectingPunctuation) {
 | |
|                                                         levelNext++;
 | |
|                                                 }
 | |
|                                                 break;
 | |
|                                         case ':':
 | |
|                                                 if (expectingIdentifier) {
 | |
|                                                         levelNext++;
 | |
|                                                 }
 | |
|                                                 break;
 | |
|                                 }
 | |
|                                 if (levelNext != SC_FOLDLEVELBASE) {
 | |
|                                         expectingIdentifier = 0;
 | |
|                                         expectingPunctuation = 0;
 | |
|                                 }
 | |
|                         }
 | |
|                         int lev = levelMinCurrent | (levelNext | expectingIdentifier
 | |
|                                 | expectingPunctuation | seenStart) << 16;
 | |
|                         if (levelMinCurrent < levelNext)
 | |
|                                 lev |= SC_FOLDLEVELHEADERFLAG;
 | |
|                         if (lev != styler.LevelAt(lineCurrent)) {
 | |
|                                 styler.SetLevel(lineCurrent, lev);
 | |
|                         }
 | |
|                         lineCurrent++;
 | |
|                         levelCurrent = levelNext;
 | |
|                         levelMinCurrent = levelCurrent;
 | |
|                 }
 | |
|         }
 | |
| }
 | |
| 
 | |
| static const char * const tads3WordList[] = {
 | |
|         "TADS3 Keywords",
 | |
|         "User defined 1",
 | |
|         "User defined 2",
 | |
|         "User defined 3",
 | |
|         0
 | |
| };
 | |
| 
 | |
| LexerModule lmTADS3(SCLEX_TADS3, ColouriseTADS3Doc, "tads3", FoldTADS3Doc, tads3WordList);
 |