private List <DocumentToken> ReadReplacementBody(TokenReader <DocumentToken> reader, DocumentToken replacementKeyToken) { List <DocumentToken> replacementContents = new List <DocumentToken>(); int numOpenReplacements = 1; while (reader.CanAdvance()) { if (reader.Peek().TokenType == DocumentTokenType.BeginReplacementSegment) { numOpenReplacements++; } else if (reader.Peek().TokenType == DocumentTokenType.QuickTerminateReplacementSegment) { numOpenReplacements--; if (numOpenReplacements == 0) { throw Unexpected(reader.Peek()); } } else if (reader.Peek().TokenType == DocumentTokenType.BeginTerminateReplacementSegment) { numOpenReplacements--; if (numOpenReplacements == 0) { AdvanceAndExpectConstantType(reader, DocumentTokenType.BeginTerminateReplacementSegment); AdvanceAndExpect(reader, DocumentTokenType.ReplacementKey, replacementKeyToken.Value, skipWhitespace: true); AdvanceAndExpectConstantType(reader, DocumentTokenType.EndReplacementSegment); break; } } replacementContents.Add(reader.Advance()); } if (numOpenReplacements != 0) { throw Unexpected("end of '" + replacementKeyToken.Value + "' replacement"); } return(replacementContents); }
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); }
/// <summary> /// Parses the given tokens into document expressions that can then be evaluated against a data context. /// </summary> /// <param name="tokens">The tokens to parse</param> /// <returns>a list of document expressions</returns> public List <IDocumentExpression> Parse(IEnumerable <DocumentToken> tokens) { List <IDocumentExpression> ret = new List <IDocumentExpression>(); TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(tokens); while (reader.CanAdvance()) { if (reader.Peek().TokenType == DocumentTokenType.BeginReplacementSegment) { ParseReplacement(reader, ret); } else { var plain = new PlainTextDocumentExpression(reader.Advance()); ret.Add(plain); } } return(ret); }