Example #1
0
        /// <summary>
        /// Creates an eval expression given template replacement info
        /// </summary>
        /// <param name="context">The context that contains information about the document being rendered</param>
        /// <returns></returns>
        public IDocumentExpression CreateExpression(DocumentExpressionContext context)
        {
            if (context.Body.Count > 0)
            {
                throw new DocumentRenderException("eval tags can't have a body", context.ReplacementKeyToken);
            }

            TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(context.Parameters);

            DocumentToken fgToken, bgToken;

            var ret = new EvalExpression(context.ReplacementKeyToken);

            if (reader.TryAdvance(out fgToken, skipWhitespace: true) == false)
            {
                return(ret);
            }
            else
            {
                ret.ForegroundColorToken = fgToken;
            }

            if (reader.TryAdvance(out bgToken, skipWhitespace: true) == false)
            {
                return(ret);
            }
            else
            {
                ret.BackgroundColorToken = bgToken;
            }

            return(ret);
        }
Example #2
0
        /// <summary>
        /// Creates a template expression given a replacement token and parameters.
        /// </summary>
        /// <param name="replacementKeyToken">The token whose value should be 'template'</param>
        /// <param name="parameters">There should be 2 parameters.  One representing the name of the template to render and one representing the data to bind to the template.</param>
        /// <param name="body">Should be empty.  Template expressions do not support a body.</param>
        /// <returns>a template expression</returns>
        public IDocumentExpression CreateExpression(DocumentToken replacementKeyToken, List <DocumentToken> parameters, List <DocumentToken> body)
        {
            if (body.Count > 0)
            {
                throw new DocumentRenderException("template tags can't have a body", replacementKeyToken);
            }

            TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(parameters);

            DocumentToken idToken;

            if (reader.TryAdvance(out idToken, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("missing template Id", replacementKeyToken);
            }

            DocumentToken evalToken;

            if (reader.TryAdvance(out evalToken, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("missing eval token", idToken);
            }

            var ret = new TemplateExpression(idToken, evalToken);

            return(ret);
        }
Example #3
0
        /// <summary>
        /// Creates a variable expression given replacement info
        /// </summary>
        /// <param name="replacementKeyToken">The replacement key token that should have a value of 'var'</param>
        /// <param name="parameters">There should be 2 parameters.  The name of the variable and the initial value.</param>
        /// <param name="body">There should be no body</param>
        /// <returns>A variable expression</returns>
        public IDocumentExpression CreateExpression(DocumentToken replacementKeyToken, List <DocumentToken> parameters, List <DocumentToken> body)
        {
            if (body.Count > 0)
            {
                throw new DocumentRenderException("var tags can't have a body", body.First());
            }

            TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(parameters);

            DocumentToken variableName;

            if (reader.TryAdvance(out variableName, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("Expected variable name after var tag", replacementKeyToken);
            }

            DocumentToken variableValue;

            if (reader.TryAdvance(out variableValue, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("Expected variable value expression", variableName);
            }

            return(new VarExpression(variableName, variableValue));
        }
        /// <summary>
        /// Takes in document replacement info and converts it into a document expression that represents an each loop.
        /// </summary>
        /// <param name="replacementKeyToken">The token that is expected to have a value of 'each'</param>
        /// <param name="parameters">The parameters which should follow the format ITERATION_VARIABLE_NAME in COLLECTION_EXPRESSION</param>
        /// <param name="body">The body of the each loop</param>
        /// <returns>The parsed each expression</returns>
        public IDocumentExpression CreateExpression(DocumentToken replacementKeyToken, List <DocumentToken> parameters, List <DocumentToken> body)
        {
            if (body.Count == 0)
            {
                throw new DocumentRenderException("Each tag has no body", replacementKeyToken);
            }

            TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(parameters);

            DocumentToken variableName;

            if (reader.TryAdvance(out variableName, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("missing variable name in each tag", replacementKeyToken);
            }

            DocumentToken inToken;

            if (reader.TryAdvance(out inToken, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("Expected 'in' after iteration variable", variableName);
            }

            if (inToken.Value != "in")
            {
                throw new DocumentRenderException("Expected 'in', got '" + inToken.Value + "'", inToken);
            }

            DocumentToken collectionExpressionToken;

            if (reader.TryAdvance(out collectionExpressionToken, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("Expected collection expression after 'in' ", inToken);
            }

            DocumentToken unexpected;

            if (reader.TryAdvance(out unexpected, skipWhitespace: true))
            {
                throw new DocumentRenderException("Unexpected parameter '" + unexpected.Value + "' after collection", unexpected);
            }

            return(new EachExpression(variableName, collectionExpressionToken, body));
        }
        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>
        /// Creates a table expression from the given document info.
        /// </summary>
        /// <param name="context">The context that contains information about the document being rendered</param>
        /// <returns>The created document expression</returns>
        public IDocumentExpression CreateExpression(DocumentExpressionContext context)
        {
            if (context.Body.Count > 0)
            {
                throw new DocumentRenderException("table tags can't have a body", context.ReplacementKeyToken);
            }

            TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(context.Parameters);

            DocumentToken variableExpressionToken;

            if (reader.TryAdvance(out variableExpressionToken, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("missing collection expression after table tag", context.ReplacementKeyToken);
            }

            List <DocumentToken> columns = new List <DocumentToken>();

            bool showDefaults      = true;
            bool showPossibilities = true;

            while (reader.CanAdvance(skipWhitespace: true))
            {
                var nextToken = reader.Advance(skipWhitespace: true);

                if (nextToken.Value == "-HideDefaults")
                {
                    showDefaults = false;
                }
                else if (nextToken.Value == "-HideEnumValues")
                {
                    showPossibilities = false;
                }
                else
                {
                    columns.Add(nextToken);
                }
            }

            if (columns.Count == 0)
            {
                throw new DocumentRenderException("table elements need to have at least one column parameter", context.ReplacementKeyToken);
            }

            return(new TableExpression(variableExpressionToken, columns, context)
            {
                ShowDefaultValuesForArguments = showDefaults, ShowPossibleValuesForArguments = showPossibilities
            });
        }
        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);
        }
        private DocumentToken AdvanceAndExpect(TokenReader <DocumentToken> reader, DocumentTokenType expectedType, string expectedText, bool skipWhitespace = false)
        {
            DocumentToken read;

            if (reader.TryAdvance(out read, skipWhitespace: skipWhitespace) == false)
            {
                throw Unexpected(expectedText);
            }

            if (read.TokenType != expectedType)
            {
                throw Unexpected(expectedText, read);
            }

            return(read);
        }
        /// <summary>
        /// Creates either an if or an ifnot expression, based on its configuration, using the given document info.
        /// </summary>
        /// <param name="replacementKeyToken">The replacement key token whose value is either 'if' or 'ifnot'</param>
        /// <param name="parameters">There should be no parameters to an if or ifnot expression</param>
        /// <param name="body">The body which will be conditionally rendered.</param>
        /// <returns>The expression, either an if or an ifnot expression</returns>
        public IDocumentExpression CreateExpression(DocumentToken replacementKeyToken, List <DocumentToken> parameters, List <DocumentToken> body)
        {
            TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(parameters);

            DocumentToken ifExpressionToken;

            if (reader.TryAdvance(out ifExpressionToken, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("missing if expression", replacementKeyToken);
            }

            if (reader.CanAdvance(skipWhitespace: true))
            {
                throw new DocumentRenderException("unexpected parameters after if expression", reader.Advance(skipWhitespace: true));
            }

            return(not ? new IfNotExpression(ifExpressionToken, body) : new IfExpression(ifExpressionToken, body));
        }
        /// <summary>
        /// Creates a clear variable expression given replacement info
        /// </summary>
        /// <param name="context">The context that contains information about the document being rendered</param>
        /// <returns>a clear variable expression</returns>
        public IDocumentExpression CreateExpression(DocumentExpressionContext context)
        {
            if (context.Body.Count > 0)
            {
                throw new DocumentRenderException("clearvar tags can't have a body", context.ReplacementKeyToken);
            }

            TokenReader <DocumentToken> reader = new TokenReader <DocumentToken>(context.Parameters);

            DocumentToken variableName;

            if (reader.TryAdvance(out variableName, skipWhitespace: true) == false)
            {
                throw new DocumentRenderException("Expected variable name after clearvar tag", context.ReplacementKeyToken);
            }

            return(new ClearVarExpression(variableName));
        }
        /// <summary>
        /// Parses an object path expression from a string.
        /// </summary>
        /// <param name="expression">The expression text to parse</param>
        /// <returns>The parsed expression</returns>
        public static ObjectPathExpression Parse(string expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("path cannot be null");
            }
            if (expression.Length == 0)
            {
                throw new FormatException("Cannot parse empty string");
            }

            Tokenizer <ObjectPathToken> tokenizer = new Tokenizer <ObjectPathToken>();

            tokenizer.TokenFactory        = ObjectPathToken.TokenFactoryImpl;
            tokenizer.WhitespaceBehavior  = WhitespaceBehavior.DelimitAndInclude;
            tokenizer.DoubleQuoteBehavior = DoubleQuoteBehavior.IncludeQuotedTokensAsStringLiterals;
            tokenizer.Delimiters.Add("[");
            tokenizer.Delimiters.Add("]");
            tokenizer.Delimiters.Add(".");
            List <ObjectPathToken> tokens = tokenizer.Tokenize(expression);

            TokenReader <ObjectPathToken> reader = new TokenReader <ObjectPathToken>(tokens);

            List <IObjectPathElement> pathElements = new List <IObjectPathElement>();

            bool lastTokenWasNavigation = false;

            while (reader.CanAdvance(skipWhitespace: true))
            {
                var currentToken = reader.Advance(skipWhitespace: true);

                if (lastTokenWasNavigation == true && currentToken.TokenType == ObjectPathTokenType.IndexerOpen)
                {
                    throw new FormatException("Expected property, got '['" + " at " + currentToken.Position);
                }

                lastTokenWasNavigation = false;

                if (pathElements.Count == 0 && currentToken.TokenType == ObjectPathTokenType.NavigationElement)
                {
                    throw new FormatException("Expected property or index, got '" + currentToken.Value + "'" + " at " + currentToken.Position);
                }

                if (currentToken.TokenType == ObjectPathTokenType.IndexerClose ||
                    currentToken.TokenType == ObjectPathTokenType.StringLiteral)
                {
                    throw new FormatException("Expected property or index, got '" + currentToken.Value + "'" + " at " + currentToken.Position);
                }

                if (currentToken.TokenType == ObjectPathTokenType.IndexerOpen)
                {
                    // read index value
                    if (reader.TryAdvance(out currentToken, skipWhitespace: true) == false)
                    {
                        throw new FormatException("Expected index value, got end of string");
                    }

                    if (currentToken.TokenType == ObjectPathTokenType.Identifier || currentToken.TokenType == ObjectPathTokenType.StringLiteral)
                    {
                        string indexValueText = currentToken.Value;

                        if (currentToken.TokenType == ObjectPathTokenType.StringLiteral)
                        {
                            indexValueText = indexValueText.Substring(1, indexValueText.Length - 2);
                        }

                        object indexValue;
                        int    indexValueInt;
                        if (int.TryParse(indexValueText, out indexValueInt) == false)
                        {
                            indexValue = indexValueText;
                        }
                        else
                        {
                            indexValue = indexValueInt;
                        }

                        // read index close
                        if (reader.TryAdvance(out currentToken, skipWhitespace: true) == false)
                        {
                            throw new FormatException("Expected ']', got end of string");
                        }
                        if (currentToken.TokenType != ObjectPathTokenType.IndexerClose)
                        {
                            throw new FormatException("Expected ']', got '" + currentToken.Value + "' at " + currentToken.Position);
                        }

                        IndexerPathElement el = new IndexerPathElement(indexValue);
                        pathElements.Add(el);

                        if (reader.TryAdvance(out currentToken, skipWhitespace: true))
                        {
                            if (currentToken.TokenType != ObjectPathTokenType.NavigationElement)
                            {
                                throw new FormatException("Expected '.', got '" + currentToken.Value + "' at " + currentToken.Position);
                            }
                            if (reader.CanAdvance(skipWhitespace: true) == false)
                            {
                                throw new FormatException("Expected property, got end of string");
                            }
                            lastTokenWasNavigation = true;
                        }
                    }
                    else
                    {
                        throw new ArgumentException("Unexpected token '" + currentToken.Value + "' at " + currentToken.Position);
                    }
                }
                else if (currentToken.TokenType == ObjectPathTokenType.Identifier)
                {
                    PropertyPathElement el = new PropertyPathElement(currentToken.Value);
                    pathElements.Add(el);
                }
                else if (currentToken.TokenType == ObjectPathTokenType.NavigationElement)
                {
                    // do nothing
                }
                else
                {
                    throw new ArgumentException("Unexpected token '" + currentToken.Value + "' at " + currentToken.Position);
                }
            }

            return(new ObjectPathExpression(pathElements));
        }