private ExpressionSyntax ParseInterpolatedStringToken()
        {
            // We don't want to make the scanner stateful (between tokens) if we can possibly avoid it.
            // The approach implemented here is
            //
            // (1) Scan the whole interpolated string literal as a single token. Now the statefulness of
            // the scanner (to match { }'s) is limited to its behavior while scanning a single token.
            //
            // (2) When the parser gets such a token, here, it spins up another scanner / parser on each of
            // the holes and builds a tree for the whole thing (resulting in an interpolated string nonterminal node).
            //
            // (3) The parser discards the original token and replaces it with this tree. (In other words,
            // it replaces one token with a different set of tokens that have already been parsed)
            //
            // (4) On an incremental change, we widen the invalidated region to include any enclosing interpolated
            // string nonterminal so that we never reuse tokens inside a changed interpolated string.
            //
            // This has the secondary advantage that it can reasonably be specified.
            //
            // The substitution will end up being invisible to external APIs and clients such as the IDE, as
            // they have no way to ask for the stream of tokens before parsing.
            //
            // Take special not of the handling of trivia. With one exception, what happens in a hole stays
            // in the hole. That means that the first token in a hole can have leading trivia, even though
            // it is not the first thing on a line. The single exception occurs when the hole is completely
            // empty of tokens, but contains some trivia. In that case we move the trivia (from the fake EOF
            // token inside the hole) to be leading trivia of the following literal part so that it doesn't
            // get dropped on the floor.
            //

            var originalToken = this.EatToken();

            Debug.Assert(originalToken.Kind == SyntaxKind.InterpolatedStringToken);
            var originalText   = originalToken.ValueText;
            var interpolations = ArrayBuilder <Lexer.Interpolation> .GetInstance();

            SyntaxDiagnosticInfo error = null;

            using (var tempLexer = new Lexer(Text.SourceText.From(originalText), this.Options))
            {
                // compute the positions of the interpolations in the original string literal
                var info = default(Lexer.TokenInfo);
                tempLexer.ScanISLTop(interpolations, ref info, ref error);
            }

            Debug.Assert(interpolations.Count != 0);
            var builder = this.pool.AllocateSeparated <InterpolatedStringInsertSyntax>();

            try
            {
                SyntaxToken stringStart = null;
                SyntaxToken stringEnd   = null;

                for (int i = 0; i < interpolations.Count; i++)
                {
                    var interpolation = interpolations[i];
                    var first         = i == 0;
                    var last          = i == (interpolations.Count - 1);

                    if (first)
                    {
                        // compute stringStart
                        var startText = originalText.Substring(0, interpolation.Start + 1);
                        stringStart = MakeStringToken(startText, SyntaxKind.InterpolatedStringStartToken).WithLeadingTrivia(originalToken.GetLeadingTrivia());
                        Debug.Assert(stringStart.Kind == SyntaxKind.InterpolatedStringStartToken);
                    }

                    CSharpSyntaxNode additionalTrivia;
                    var interpText = originalText.Substring(interpolation.Start + 1, interpolation.End - interpolation.Start - 1);
                    using (var tempLexer = new Lexer(Text.SourceText.From(interpText), this.Options))
                    {
                        using (var tempParser = new LanguageParser(tempLexer, null, null))
                        {
                            var insert = tempParser.ParseInterpolatedStringInsert();
                            insert = tempParser.ConsumeUnexpectedTokens(insert);
                            // In case the insert is empty, move the leading trivia from its EOF token to the following literal part.
                            additionalTrivia = tempParser.CurrentToken.GetLeadingTrivia();
                            builder.Add(insert);
                        }
                    }

                    if (last)
                    {
                        // compute stringEnd
                        var endText = originalText.Substring(interpolation.End);
                        stringEnd = MakeStringToken(endText, SyntaxKind.InterpolatedStringEndToken).WithLeadingTrivia(additionalTrivia).WithTrailingTrivia(originalToken.GetTrailingTrivia());
                        Debug.Assert(stringEnd.Kind == SyntaxKind.InterpolatedStringEndToken);
                    }
                    else
                    {
                        // add an interpolated string mid token for the following }...{ part
                        var midText   = originalText.Substring(interpolation.End, interpolations[i + 1].Start - interpolation.End + 1);
                        var stringMid = MakeStringToken(midText, SyntaxKind.InterpolatedStringMidToken).WithLeadingTrivia(additionalTrivia);
                        Debug.Assert(stringMid.Kind == SyntaxKind.InterpolatedStringMidToken);
                        builder.AddSeparator(stringMid);
                    }
                }

                interpolations.Free();
                var result = SyntaxFactory.InterpolatedString(stringStart, builder.ToList(), stringEnd);
                if (error != null)
                {
                    result = result.WithDiagnosticsGreen(new[] { error });
                }
                return(result);
            }
            finally
            {
                this.pool.Free(builder);
            }
        }