static SyntaxTokenList PostprocessTokens(List<SyntaxToken> tokens, NavCommonTokenStream cts, SyntaxNode syntax, CancellationToken cancellationToken) {

            var result = new List<SyntaxToken>(cts.AllTokens.Count);
            tokens.Sort((x, y) => x.Start - y.Start);

            // Wir haben bereits die signifikanten Token (T) im GrammarVisitor erstellt.
            // Wir können nicht alle Tokens hier ermitteln, da der Visitor viel mehr Kontextinformationen
            // hat. Somit wird aus einem "Identifier" z.B. je nach Kontext ein Keyword, oder Symbol (=> Classification).
            // Was uns hier jedoch noch fehlt sind vor allem die Whitespaces (w) und "unbekannten" (u),
            // die der Parser nie zu Gesicht bekommt. Der TokenStream liefert uns alle Token
            // (candidates = c):
            // -T---TTT---T----T-- <= bereits im Visitor erfasste Token
            // ccccccccccccccccccc <= alle Tokens (candidates)
            // wTwwwTTTwwwTwwwwTuu <= die Tokens, wie wir sie hier haben wollen
            var index = 0;
            foreach (var candidate in cts.AllTokens) {

                cancellationToken.ThrowIfCancellationRequested();

                if (index < tokens.Count) {
                    var existing = tokens[index];
                    // Das Token wurde bereits im Visitor erfasst (T)
                    if (existing.Start == candidate.StartIndex) {
                        result.Add(existing);
                        index++;
                        continue;
                    }
                }
                // Das Token existiert noch nicht, da es der Parser/Visitor offensichtlich nicht "erwischt hat" (t, u)
                SyntaxTokenClassification tokenClassification;
                switch (candidate.Channel) {
                    case NavGrammarLexer.TriviaChannel:
                        switch (candidate.Type) {
                            case NavGrammarLexer.NewLine:
                                tokenClassification = SyntaxTokenClassification.Whitespace;
                                break;
                            case NavGrammarLexer.Whitespace:
                                tokenClassification = SyntaxTokenClassification.Whitespace;
                                break;
                            case NavGrammarLexer.SingleLineComment:
                                tokenClassification = SyntaxTokenClassification.Comment;
                                break;
                            case NavGrammarLexer.MultiLineComment:
                                tokenClassification = SyntaxTokenClassification.Comment;
                                break;
                            case NavGrammarLexer.Unknown:
                                tokenClassification = SyntaxTokenClassification.Skiped;
                                break;
                            default:
                                // Wir haben sonst eigentlich nix im Trivia Channel
                                throw new ArgumentException();
                        }
                        break;
                    case Lexer.DefaultTokenChannel:
                        tokenClassification = SyntaxTokenClassification.Skiped;
                        break;
                    default:
                        throw new ArgumentException();
                }
                
                //TODO: hier evtl. den "echten" Parent herausfinden...
                SyntaxNode parent = syntax;
                result.Add(SyntaxTokenFactory.CreateToken(candidate, tokenClassification, parent));
            }

            return new SyntaxTokenList(result);
        }
        internal static SyntaxTree ParseTextCore(string sourceText, 
                                                 Func<NavGrammarParser, IParseTree> treeCreator, 
                                                 string filePath, 
                                                 Encoding encoding = null, 
                                                 CancellationToken cancellationToken = default(CancellationToken)) {

            var fileInfo = String.IsNullOrEmpty(filePath) ? null : new FileInfo(filePath);

            sourceText = sourceText ?? String.Empty;

            var stream        = new AntlrInputStream(sourceText);
            var lexer         = new NavGrammarLexer(stream);
            var cts           = new NavCommonTokenStream(lexer);
            var parser        = new NavGrammarParser(cts);
            var errorListener = new NavErrorListener(filePath);

            parser.RemoveErrorListeners();
            parser.AddErrorListener(errorListener);

            var tree = treeCreator(parser);

            var visitor     = new NavGrammarVisitor(expectedTokenCount: cts.AllTokens.Count);
            var syntax      = visitor.Visit(tree);
            var tokens      = PostprocessTokens(visitor.Tokens, cts, syntax, cancellationToken);
            var textLines   = GetTextLines(sourceText);
            var diagnostics = errorListener.Diagnostics;

            var syntaxTree = new SyntaxTree(sourceText : sourceText, 
                                            root       : syntax, 
                                            tokens     : tokens, 
                                            textLines  : textLines,
                                            diagnostics: diagnostics,
                                            fileInfo   : fileInfo, 
                                            encoding   : encoding);

            syntax.FinalConstruct(syntaxTree, null);
            
            return syntaxTree;
        }