void SCI_METHOD LexerHaskell::Lex()

in ext/scintilla/lexers/LexHaskell.cxx [476:962]


void SCI_METHOD LexerHaskell::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle
                                 ,IDocument *pAccess) {
   LexAccessor styler(pAccess);

   Sci_Position lineCurrent = styler.GetLine(startPos);

   HaskellLineInfo hs = HaskellLineInfo(lineCurrent ? styler.GetLineState(lineCurrent-1) : 0);

   // Do not leak onto next line
   if (initStyle == SCE_HA_STRINGEOL)
      initStyle = SCE_HA_DEFAULT;
   else if (initStyle == SCE_HA_LITERATE_CODEDELIM)
      initStyle = hs.nonexternalStyle;

   StyleContext sc(startPos, length, initStyle, styler);

   int base = 10;
   bool dot = false;

   bool inDashes = false;
   bool alreadyInTheMiddleOfOperator = false;

   assert(!(IsCommentBlockStyle(initStyle) && hs.nestLevel == 0));

   while (sc.More()) {
      // Check for state end

      if (!IsExternalStyle(sc.state)) {
         hs.nonexternalStyle = sc.state;
      }

      // For lexer to work, states should unconditionally forward at least one
      // character.
      // If they don't, they should still check if they are at line end and
      // forward if so.
      // If a state forwards more than one character, it should check every time
      // that it is not a line end and cease forwarding otherwise.
      if (sc.atLineEnd) {
         // Remember the line state for future incremental lexing
         styler.SetLineState(lineCurrent, hs.ToLineState());
         lineCurrent++;
      }

      // Handle line continuation generically.
      if (sc.ch == '\\' && (sc.chNext == '\n' || sc.chNext == '\r')
         && (  sc.state == SCE_HA_STRING
            || sc.state == SCE_HA_PREPROCESSOR)) {
         // Remember the line state for future incremental lexing
         styler.SetLineState(lineCurrent, hs.ToLineState());
         lineCurrent++;

         sc.Forward();
         if (sc.ch == '\r' && sc.chNext == '\n') {
            sc.Forward();
         }
         sc.Forward();

         continue;
      }

      if (sc.atLineStart) {

         if (sc.state == SCE_HA_STRING || sc.state == SCE_HA_CHARACTER) {
            // Prevent SCE_HA_STRINGEOL from leaking back to previous line
            sc.SetState(sc.state);
         }

         if (literate && hs.lmode == LITERATE_BIRD) {
            if (!IsExternalStyle(sc.state)) {
               sc.SetState(SCE_HA_LITERATE_COMMENT);
            }
         }
      }

      // External
         // Literate
      if (  literate && hs.lmode == LITERATE_BIRD && sc.atLineStart
         && sc.ch == '>') {
            sc.SetState(SCE_HA_LITERATE_CODEDELIM);
            sc.ForwardSetState(hs.nonexternalStyle);
      }
      else if (literate && hs.lmode == LITERATE_BIRD && sc.atLineStart
            && (  sc.ch == ' ' || sc.ch == '\t'
               || sc.Match("\\begin{code}"))) {
         sc.SetState(sc.state);

         while ((sc.ch == ' ' || sc.ch == '\t') && sc.More())
            sc.Forward();

         if (sc.Match("\\begin{code}")) {
            sc.Forward(static_cast<int>(strlen("\\begin{code}")));

            bool correct = true;

            while (!sc.atLineEnd && sc.More()) {
               if (sc.ch != ' ' && sc.ch != '\t') {
                  correct = false;
               }
               sc.Forward();
            }

            if (correct) {
               sc.ChangeState(SCE_HA_LITERATE_CODEDELIM); // color the line end
               hs.lmode = LITERATE_BLOCK;
            }
         }
      }
      else if (literate && hs.lmode == LITERATE_BLOCK && sc.atLineStart
            && sc.Match("\\end{code}")) {
         sc.SetState(SCE_HA_LITERATE_CODEDELIM);

         sc.Forward(static_cast<int>(strlen("\\end{code}")));

         while (!sc.atLineEnd && sc.More()) {
            sc.Forward();
         }

         sc.SetState(SCE_HA_LITERATE_COMMENT);
         hs.lmode = LITERATE_BIRD;
      }
         // Preprocessor
      else if (sc.atLineStart && sc.ch == '#' && options.cpp
            && (!options.stylingWithinPreprocessor || sc.state == SCE_HA_DEFAULT)) {
         sc.SetState(SCE_HA_PREPROCESSOR);
         sc.Forward();
      }
            // Literate
      else if (sc.state == SCE_HA_LITERATE_COMMENT) {
         sc.Forward();
      }
      else if (sc.state == SCE_HA_LITERATE_CODEDELIM) {
         sc.ForwardSetState(hs.nonexternalStyle);
      }
            // Preprocessor
      else if (sc.state == SCE_HA_PREPROCESSOR) {
         if (sc.atLineEnd) {
            sc.SetState(options.stylingWithinPreprocessor
                        ? SCE_HA_DEFAULT
                        : hs.nonexternalStyle);
            sc.Forward(); // prevent double counting a line
         } else if (options.stylingWithinPreprocessor && !IsHaskellLetter(sc.ch)) {
            sc.SetState(SCE_HA_DEFAULT);
         } else {
            sc.Forward();
         }
      }
      // Haskell
         // Operator
      else if (sc.state == SCE_HA_OPERATOR) {
         int style = SCE_HA_OPERATOR;

         if ( sc.ch == ':'
            && !alreadyInTheMiddleOfOperator
            // except "::"
            && !( sc.chNext == ':'
               && !IsAnHaskellOperatorChar(sc.GetRelative(2)))) {
            style = SCE_HA_CAPITAL;
         }

         alreadyInTheMiddleOfOperator = false;

         while (IsAnHaskellOperatorChar(sc.ch))
               sc.Forward();

         char s[100];
         sc.GetCurrent(s, sizeof(s));

         if (reserved_operators.InList(s))
            style = SCE_HA_RESERVED_OPERATOR;

         sc.ChangeState(style);
         sc.SetState(SCE_HA_DEFAULT);
      }
         // String
      else if (sc.state == SCE_HA_STRING) {
         if (sc.atLineEnd) {
            sc.ChangeState(SCE_HA_STRINGEOL);
            sc.ForwardSetState(SCE_HA_DEFAULT);
         } else if (sc.ch == '\"') {
            sc.Forward();
            skipMagicHash(sc, oneHash);
            sc.SetState(SCE_HA_DEFAULT);
         } else if (sc.ch == '\\') {
            sc.Forward(2);
         } else {
            sc.Forward();
         }
      }
         // Char
      else if (sc.state == SCE_HA_CHARACTER) {
         if (sc.atLineEnd) {
            sc.ChangeState(SCE_HA_STRINGEOL);
            sc.ForwardSetState(SCE_HA_DEFAULT);
         } else if (sc.ch == '\'') {
            sc.Forward();
            skipMagicHash(sc, oneHash);
            sc.SetState(SCE_HA_DEFAULT);
         } else if (sc.ch == '\\') {
            sc.Forward(2);
         } else {
            sc.Forward();
         }
      }
         // Number
      else if (sc.state == SCE_HA_NUMBER) {
         if (sc.atLineEnd) {
            sc.SetState(SCE_HA_DEFAULT);
            sc.Forward(); // prevent double counting a line
         } else if (IsADigit(sc.ch, base)) {
            sc.Forward();
         } else if (sc.ch=='.' && dot && IsADigit(sc.chNext, base)) {
            sc.Forward(2);
            dot = false;
         } else if ((base == 10) &&
                    (sc.ch == 'e' || sc.ch == 'E') &&
                    (IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-')) {
            sc.Forward();
            if (sc.ch == '+' || sc.ch == '-')
                sc.Forward();
         } else {
            skipMagicHash(sc, twoHashes);
            sc.SetState(SCE_HA_DEFAULT);
         }
      }
         // Keyword or Identifier
      else if (sc.state == SCE_HA_IDENTIFIER) {
         int style = IsHaskellUpperCase(sc.ch) ? SCE_HA_CAPITAL : SCE_HA_IDENTIFIER;

         assert(IsAHaskellWordStart(sc.ch));

         sc.Forward();

         while (sc.More()) {
            if (IsAHaskellWordChar(sc.ch)) {
               sc.Forward();
            } else if (sc.ch == '.' && style == SCE_HA_CAPITAL) {
               if (IsHaskellUpperCase(sc.chNext)) {
                  sc.Forward();
                  style = SCE_HA_CAPITAL;
               } else if (IsAHaskellWordStart(sc.chNext)) {
                  sc.Forward();
                  style = SCE_HA_IDENTIFIER;
               } else if (IsAnHaskellOperatorChar(sc.chNext)) {
                  sc.Forward();
                  style = sc.ch == ':' ? SCE_HA_CAPITAL : SCE_HA_OPERATOR;
                  while (IsAnHaskellOperatorChar(sc.ch))
                     sc.Forward();
                  break;
               } else {
                  break;
               }
            } else {
               break;
            }
         }

         skipMagicHash(sc, unlimitedHashes);

         char s[100];
         sc.GetCurrent(s, sizeof(s));

         KeywordMode new_mode = HA_MODE_DEFAULT;

         if (keywords.InList(s)) {
            style = SCE_HA_KEYWORD;
         } else if (style == SCE_HA_CAPITAL) {
            if (hs.mode == HA_MODE_IMPORT1 || hs.mode == HA_MODE_IMPORT3) {
               style    = SCE_HA_MODULE;
               new_mode = HA_MODE_IMPORT2;
            } else if (hs.mode == HA_MODE_MODULE) {
               style = SCE_HA_MODULE;
            }
         } else if (hs.mode == HA_MODE_IMPORT1 &&
                    strcmp(s,"qualified") == 0) {
             style    = SCE_HA_KEYWORD;
             new_mode = HA_MODE_IMPORT1;
         } else if (options.highlightSafe &&
                    hs.mode == HA_MODE_IMPORT1 &&
                    strcmp(s,"safe") == 0) {
             style    = SCE_HA_KEYWORD;
             new_mode = HA_MODE_IMPORT1;
         } else if (hs.mode == HA_MODE_IMPORT2) {
             if (strcmp(s,"as") == 0) {
                style    = SCE_HA_KEYWORD;
                new_mode = HA_MODE_IMPORT3;
            } else if (strcmp(s,"hiding") == 0) {
                style     = SCE_HA_KEYWORD;
            }
         } else if (hs.mode == HA_MODE_TYPE) {
            if (strcmp(s,"family") == 0)
               style    = SCE_HA_KEYWORD;
         }

         if (hs.mode == HA_MODE_FFI) {
            if (ffi.InList(s)) {
               style = SCE_HA_KEYWORD;
               new_mode = HA_MODE_FFI;
            }
         }

         sc.ChangeState(style);
         sc.SetState(SCE_HA_DEFAULT);

         if (strcmp(s,"import") == 0 && hs.mode != HA_MODE_FFI)
            new_mode = HA_MODE_IMPORT1;
         else if (strcmp(s,"module") == 0)
            new_mode = HA_MODE_MODULE;
         else if (strcmp(s,"foreign") == 0)
            new_mode = HA_MODE_FFI;
         else if (strcmp(s,"type") == 0
               || strcmp(s,"data") == 0)
            new_mode = HA_MODE_TYPE;

         hs.mode = new_mode;
      }

         // Comments
            // Oneliner
      else if (sc.state == SCE_HA_COMMENTLINE) {
         if (sc.atLineEnd) {
            sc.SetState(hs.pragma ? SCE_HA_PRAGMA : SCE_HA_DEFAULT);
            sc.Forward(); // prevent double counting a line
         } else if (inDashes && sc.ch != '-' && !hs.pragma) {
            inDashes = false;
            if (IsAnHaskellOperatorChar(sc.ch)) {
               alreadyInTheMiddleOfOperator = true;
               sc.ChangeState(SCE_HA_OPERATOR);
            }
         } else {
            sc.Forward();
         }
      }
            // Nested
      else if (IsCommentBlockStyle(sc.state)) {
         if (sc.Match('{','-')) {
            sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
            sc.Forward(2);
            hs.nestLevel++;
         } else if (sc.Match('-','}')) {
            sc.Forward(2);
            assert(hs.nestLevel > 0);
            if (hs.nestLevel > 0)
               hs.nestLevel--;
            sc.SetState(
               hs.nestLevel == 0
                  ? (hs.pragma ? SCE_HA_PRAGMA : SCE_HA_DEFAULT)
                  : CommentBlockStyleFromNestLevel(hs.nestLevel - 1));
         } else {
            sc.Forward();
         }
      }
            // Pragma
      else if (sc.state == SCE_HA_PRAGMA) {
         if (sc.Match("#-}")) {
            hs.pragma = false;
            sc.Forward(3);
            sc.SetState(SCE_HA_DEFAULT);
         } else if (sc.Match('-','-')) {
            sc.SetState(SCE_HA_COMMENTLINE);
            sc.Forward(2);
            inDashes = false;
         } else if (sc.Match('{','-')) {
            sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
            sc.Forward(2);
            hs.nestLevel = 1;
         } else {
            sc.Forward();
         }
      }
            // New state?
      else if (sc.state == SCE_HA_DEFAULT) {
         // Digit
         if (IsADigit(sc.ch)) {
            hs.mode = HA_MODE_DEFAULT;

            sc.SetState(SCE_HA_NUMBER);
            if (sc.ch == '0' && (sc.chNext == 'X' || sc.chNext == 'x')) {
               // Match anything starting with "0x" or "0X", too
               sc.Forward(2);
               base = 16;
               dot = false;
            } else if (sc.ch == '0' && (sc.chNext == 'O' || sc.chNext == 'o')) {
               // Match anything starting with "0o" or "0O", too
               sc.Forward(2);
               base = 8;
               dot = false;
            } else {
               sc.Forward();
               base = 10;
               dot = true;
            }
         }
         // Pragma
         else if (sc.Match("{-#")) {
            hs.pragma = true;
            sc.SetState(SCE_HA_PRAGMA);
            sc.Forward(3);
         }
         // Comment line
         else if (sc.Match('-','-')) {
            sc.SetState(SCE_HA_COMMENTLINE);
            sc.Forward(2);
            inDashes = true;
         }
         // Comment block
         else if (sc.Match('{','-')) {
            sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
            sc.Forward(2);
            hs.nestLevel = 1;
         }
         // String
         else if (sc.ch == '\"') {
            sc.SetState(SCE_HA_STRING);
            sc.Forward();
         }
         // Character or quoted name or promoted term
         else if (sc.ch == '\'') {
            hs.mode = HA_MODE_DEFAULT;

            sc.SetState(SCE_HA_CHARACTER);
            sc.Forward();

            if (options.allowQuotes) {
               // Quoted type ''T
               if (sc.ch=='\'' && IsAHaskellWordStart(sc.chNext)) {
                  sc.Forward();
                  sc.ChangeState(SCE_HA_IDENTIFIER);
               } else if (sc.chNext != '\'') {
                  // Quoted name 'n or promoted constructor 'N
                  if (IsAHaskellWordStart(sc.ch)) {
                     sc.ChangeState(SCE_HA_IDENTIFIER);
                  // Promoted constructor operator ':~>
                  } else if (sc.ch == ':') {
                     alreadyInTheMiddleOfOperator = false;
                     sc.ChangeState(SCE_HA_OPERATOR);
                  // Promoted list or tuple '[T]
                  } else if (sc.ch == '[' || sc.ch== '(') {
                     sc.ChangeState(SCE_HA_OPERATOR);
                     sc.ForwardSetState(SCE_HA_DEFAULT);
                  }
               }
            }
         }
         // Operator starting with '?' or an implicit parameter
         else if (sc.ch == '?') {
            hs.mode = HA_MODE_DEFAULT;

            alreadyInTheMiddleOfOperator = false;
            sc.SetState(SCE_HA_OPERATOR);

            if (  options.implicitParams
               && IsAHaskellWordStart(sc.chNext)
               && !IsHaskellUpperCase(sc.chNext)) {
               sc.Forward();
               sc.ChangeState(SCE_HA_IDENTIFIER);
            }
         }
         // Operator
         else if (IsAnHaskellOperatorChar(sc.ch)) {
            hs.mode = HA_MODE_DEFAULT;

            sc.SetState(SCE_HA_OPERATOR);
         }
         // Braces and punctuation
         else if (sc.ch == ',' || sc.ch == ';'
               || sc.ch == '(' || sc.ch == ')'
               || sc.ch == '[' || sc.ch == ']'
               || sc.ch == '{' || sc.ch == '}') {
            sc.SetState(SCE_HA_OPERATOR);
            sc.ForwardSetState(SCE_HA_DEFAULT);
         }
         // Keyword or Identifier
         else if (IsAHaskellWordStart(sc.ch)) {
            sc.SetState(SCE_HA_IDENTIFIER);
         // Something we don't care about
         } else {
            sc.Forward();
         }
      }
            // This branch should never be reached.
      else {
         assert(false);
         sc.Forward();
      }
   }
   sc.Complete();
}