private void ParseReplacement(TokenReader <DocumentToken> reader, List <IDocumentExpression> ret)
        {
            var openToken           = AdvanceAndExpectConstantType(reader, DocumentTokenType.BeginReplacementSegment);
            var replacementKeyToken = AdvanceAndExpect(reader, DocumentTokenType.ReplacementKey, "replacement key", skipWhitespace: true);

            List <DocumentToken> parameters = new List <DocumentToken>();
            List <DocumentToken> body       = new List <DocumentToken>();

            while (reader.CanAdvance(skipWhitespace: true) && reader.Peek(skipWhitespace: true).TokenType == DocumentTokenType.ReplacementParameter)
            {
                var paramToken = reader.Advance(skipWhitespace: true);
                parameters.Add(paramToken);
            }


            DocumentToken closeReplacementToken;

            if (reader.TryAdvance(out closeReplacementToken, skipWhitespace: true) == false)
            {
                throw Unexpected(string.Format("'{0}' or '{1}'", DocumentToken.GetTokenTypeValue(DocumentTokenType.EndReplacementSegment), DocumentToken.GetTokenTypeValue(DocumentTokenType.QuickTerminateReplacementSegment)));
            }

            if (closeReplacementToken.TokenType == DocumentTokenType.EndReplacementSegment)
            {
                body.AddRange(ReadReplacementBody(reader, replacementKeyToken));
            }
            else if (closeReplacementToken.TokenType == DocumentTokenType.QuickTerminateReplacementSegment)
            {
                // do nothing, there is no body when the quick termination replacement segment is used
            }
            else
            {
                throw Unexpected(string.Format("'{0}' or '{1}'", DocumentToken.GetTokenTypeValue(DocumentTokenType.EndReplacementSegment), DocumentToken.GetTokenTypeValue(DocumentTokenType.QuickTerminateReplacementSegment)), closeReplacementToken);
            }

            IDocumentExpressionProvider provider;

            if (this.expressionProviders.TryGetValue(replacementKeyToken.Value, out provider) == false)
            {
                provider = new EvalExpressionProvider();
            }

            var context = new DocumentExpressionContext
            {
                OpenToken           = openToken,
                CloseToken          = closeReplacementToken,
                Parameters          = parameters.AsReadOnly(),
                Body                = body.AsReadOnly(),
                ReplacementKeyToken = replacementKeyToken,
            };

            var expression = provider.CreateExpression(context);

            ret.Add(expression);
        }
        private DocumentToken AdvanceAndExpectConstantType(TokenReader <DocumentToken> reader, DocumentTokenType expectedType)
        {
            DocumentToken read;

            if (reader.TryAdvance(out read, skipWhitespace: true) == false)
            {
                throw Unexpected(DocumentToken.GetTokenTypeValue(expectedType));
            }

            if (read.TokenType != expectedType)
            {
                throw Unexpected(DocumentToken.GetTokenTypeValue(expectedType), read);
            }
            return(read);
        }