// Algorithm's description here: // https://www.haskell.org/onlinereport/haskell2010/haskellch10.html // https://en.wikibooks.org/wiki/Haskell/Indentation public override IToken NextToken() { if (tokenQueue.Any()) { return(tokenQueue.DequeueBottom()); } IToken next = base.NextToken(); var type = next.Type; if (type == HaskellLexer.OpenPragmaBracket) { inPragmas = true; } if (startIndent == -1 && type != HaskellLexer.NEWLINE && type != HaskellLexer.WS && type != HaskellLexer.TAB && type != HaskellLexer.OCURLY) { if (type == HaskellLexer.MODULE) { moduleStartIndent = true; wasModuleExport = true; } if (type != HaskellLexer.MODULE && !moduleStartIndent && !inPragmas) { startIndent = next.Column; } else if (lastKeyWord.Equals("where") && moduleStartIndent) { lastKeyWord = ""; prevWasKeyWord = false; nestedLevel = 0; moduleStartIndent = false; prevWasEndl = false; startIndent = next.Column; tokenQueue.Push(createToken(HaskellLexer.VOCURLY, "VOCURLY", next)); tokenQueue.Push(createToken(type, next.Text, next)); return(tokenQueue.DequeueBottom()); } } if (type == HaskellLexer.ClosePragmaBracket) { inPragmas = false; } if (type == HaskellLexer.OCURLY) { if (prevWasKeyWord) { nestedLevel--; prevWasKeyWord = false; } if (moduleStartIndent) { moduleStartIndent = false; // because will be HaskellLexer.CCURLY in the end of file wasModuleExport = false; } ignoreIndent = true; prevWasEndl = false; } if (prevWasKeyWord && !prevWasEndl && !moduleStartIndent && type != HaskellLexer.WS && type != HaskellLexer.NEWLINE && type != HaskellLexer.TAB && type != HaskellLexer.OCURLY) { prevWasKeyWord = false; indentStack.Push(new Pair <string, int>(lastKeyWord, next.Column)); tokenQueue.Push(createToken(HaskellLexer.VOCURLY, "VOCURLY", next)); } if (ignoreIndent && (type == HaskellLexer.WHERE || type == HaskellLexer.DO || type == HaskellLexer.MDO || type == HaskellLexer.LET || type == HaskellLexer.OF || type == HaskellLexer.LCASE || type == HaskellLexer.REC || type == HaskellLexer.CCURLY) ) { ignoreIndent = false; } if (pendingDent && prevWasKeyWord && !ignoreIndent && indentCount <= getSavedIndent() && type != HaskellLexer.NEWLINE && type != HaskellLexer.WS) { tokenQueue.Push(createToken(HaskellLexer.VOCURLY, "VOCURLY", next)); prevWasKeyWord = false; prevWasEndl = true; } if (pendingDent && prevWasEndl && !ignoreIndent && indentCount <= getSavedIndent() && type != HaskellLexer.NEWLINE && type != HaskellLexer.WS && type != HaskellLexer.WHERE && type != HaskellLexer.IN && type != HaskellLexer.DO && type != HaskellLexer.MDO && type != HaskellLexer.OF && type != HaskellLexer.LCASE && type != HaskellLexer.REC && type != HaskellLexer.CCURLY && type != Antlr4.Runtime.TokenConstants.EOF) { while (nestedLevel > indentStack.Count()) { if (nestedLevel > 0) { nestedLevel--; } tokenQueue.Push(createToken(HaskellLexer.SEMI, "SEMI", next)); tokenQueue.Push(createToken(HaskellLexer.VCCURLY, "VCCURLY", next)); } while (indentCount < getSavedIndent()) { if (indentStack.Any() && nestedLevel > 0) { indentStack.Pop(); nestedLevel--; } tokenQueue.Push(createToken(HaskellLexer.SEMI, "SEMI", next)); tokenQueue.Push(createToken(HaskellLexer.VCCURLY, "VCCURLY", next)); } if (indentCount == getSavedIndent()) { tokenQueue.Push(createToken(HaskellLexer.SEMI, "SEMI", next)); } prevWasEndl = false; if (indentCount == startIndent) { pendingDent = false; } } if (pendingDent && prevWasKeyWord && !moduleStartIndent && !ignoreIndent && indentCount > getSavedIndent() && type != HaskellLexer.NEWLINE && type != HaskellLexer.WS && type != Antlr4.Runtime.TokenConstants.EOF) { prevWasKeyWord = false; if (prevWasEndl) { indentStack.Push(new Pair <string, int>(lastKeyWord, indentCount)); prevWasEndl = false; } tokenQueue.Push(createToken(HaskellLexer.VOCURLY, "VOCURLY", next)); } if (pendingDent && initialIndentToken == null && HaskellLexer.NEWLINE != type) { initialIndentToken = next; } if (next != null && type == HaskellLexer.NEWLINE) { prevWasEndl = true; } if (type == HaskellLexer.WHERE || type == HaskellLexer.LET || type == HaskellLexer.DO || type == HaskellLexer.MDO || type == HaskellLexer.OF || type == HaskellLexer.LCASE || type == HaskellLexer.REC) { // if next will be HaskellLexer.OCURLY need to decrement nestedLevel nestedLevel++; prevWasKeyWord = true; prevWasEndl = false; lastKeyWord = next.Text; if (type == HaskellLexer.WHERE) { if (indentStack.Any() && (indentStack.Peek().first().Equals("do") || indentStack.Peek().first().Equals("mdo"))) { tokenQueue.Push(createToken(HaskellLexer.SEMI, "SEMI", next)); tokenQueue.Push(createToken(HaskellLexer.VCCURLY, "VCCURLY", next)); indentStack.Pop(); nestedLevel--; } } } if (next != null && type == HaskellLexer.OCURLY) { prevWasKeyWord = false; } if (next == null || Antlr4.Runtime.TokenConstants.HiddenChannel == next.Channel || HaskellLexer.NEWLINE == type) { return(next); } if (type == HaskellLexer.IN) { processINToken(next); } if (type == Antlr4.Runtime.TokenConstants.EOF) { processEOFToken(next); } pendingDent = true; tokenQueue.Push(next); return(tokenQueue.DequeueBottom()); }