Beispiel #1
0
        /// <summary>
        ///		Parses the Tokens into a Document.
        /// </summary>
        /// <param name="tokens">The tokens.</param>
        /// <param name="options">The options.</param>
        /// <returns></returns>
        internal static IDocumentItem Parse(Queue <TokenPair> tokens, ParserOptions options)
        {
            var buildStack = new Stack <FormattingScope>();

            //instead of recursive calling the parse function we stack the current document
            buildStack.Push(new FormattingScope(new MorestachioDocument(), false));

            while (tokens.Any())
            {
                var currentToken        = tokens.Dequeue();
                var currentDocumentItem = buildStack.Peek();                 //get the latest document

                if (currentToken.Type == TokenType.Comment)
                {
                    //just ignore this part and print nothing
                }
                else if (currentToken.Type == TokenType.Content)
                {
                    currentDocumentItem.Item1.Add(new ContentDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
                else if (currentToken.Type == TokenType.CollectionOpen)
                {
                    var nestedDocument = new CollectionDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new FormattingScope(nestedDocument, false));
                    currentDocumentItem.Item1.Add(nestedDocument);
                }
                else if (currentToken.Type == TokenType.ElementOpen)
                {
                    var nestedDocument = new ExpressionScopeDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new FormattingScope(nestedDocument, false));
                    currentDocumentItem.Item1.Add(nestedDocument);
                }
                else if (currentToken.Type == TokenType.InvertedElementOpen)
                {
                    var invertedScope = new InvertedExpressionScopeDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new FormattingScope(invertedScope, false));
                    currentDocumentItem.Item1.Add(invertedScope);
                }
                else if (currentToken.Type == TokenType.CollectionClose || currentToken.Type == TokenType.ElementClose)
                {
                    // remove the last document from the stack and go back to the parents
                    buildStack.Pop();
                    if (buildStack.Peek().Item2)                     //is the remaining scope a formatting one. If it is pop it and return to its parent
                    {
                        buildStack.Pop();
                    }
                }
                else if (currentToken.Type == TokenType.PrintFormatted)
                {
                    currentDocumentItem.Item1.Add(new PrintFormattedItem());
                    buildStack.Pop();                     //Print formatted can only be followed by a Format and if not the parser should have not emited it
                }
                else if (currentToken.Type == TokenType.Format)
                {
                    if (buildStack.Peek().Item2)
                    {
                        buildStack.Pop();
                    }
                    var formatterItem = new IsolatedContextDocumentItem()
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new FormattingScope(formatterItem, true));
                    formatterItem.Add(new CallFormatterDocumentItem(currentToken.FormatString, currentToken.Value));
                    currentDocumentItem.Item1.Add(formatterItem);
                }
                else if (currentToken.Type == TokenType.EscapedSingleValue ||
                         currentToken.Type == TokenType.UnescapedSingleValue)
                {
                    currentDocumentItem.Item1.Add(new PathDocumentItem(currentToken.Value,
                                                                       currentToken.Type == TokenType.EscapedSingleValue)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
                else if (currentToken.Type == TokenType.PartialDeclarationOpen)
                {
                    // currently same named partials will override each other
                    // to allow recursive calls of partials we first have to declare the partial and then load it as we would parse
                    // -the partial as a whole and then add it to the list would lead to unknown calls of partials inside the partial
                    var nestedDocument = new MorestachioDocument();
                    buildStack.Push(new FormattingScope(nestedDocument, false));
                    currentDocumentItem.Item1.Add(new PartialDocumentItem(currentToken.Value, nestedDocument)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
                else if (currentToken.Type == TokenType.PartialDeclarationClose)
                {
                    currentDocumentItem.Item1.Add(new RenderPartialDoneDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                    buildStack.Pop();
                }
                else if (currentToken.Type == TokenType.RenderPartial)
                {
                    currentDocumentItem.Item1.Add(new RenderPartialDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
            }

            if (buildStack.Count != 1)
            {
                //var invalidScopedElements = buildStack
                //throw new MorestachioSyntaxError(new Tokenizer.CharacterLocation(){Character = }, );
                throw new InvalidOperationException("There is an Error with the Parser. The Parser still contains unscoped builds: " + buildStack.Select(e => e.Item1.Kind).Aggregate((e, f) => e + ", " + f));
            }

            return(buildStack.Pop().Item1);
        }
Beispiel #2
0
        /// <summary>
        ///     Parses the Tokens into a Document.
        /// </summary>
        /// <param name="tokens">The tokens.</param>
        /// <returns></returns>
        internal static IDocumentItem Parse(Queue <TokenPair> tokens, ParserOptions options)
        {
            var buildStack = new Stack <DocumentScope>();

            //instead of recursive calling the parse function we stack the current document
            buildStack.Push(new DocumentScope(new MorestachioDocument()));

            while (tokens.Any())
            {
                var currentToken        = tokens.Dequeue();
                var currentDocumentItem = buildStack.Peek();                 //get the latest document

                if (currentToken.Type == TokenType.Comment)
                {
                    //just ignore this part and print nothing
                }
                else if (currentToken.Type == TokenType.Content)
                {
                    currentDocumentItem.Document.Add(new ContentDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
                else if (currentToken.Type == TokenType.If)
                {
                    var nestedDocument = new IfExpressionScopeDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new DocumentScope(nestedDocument));
                    currentDocumentItem.Document.Add(nestedDocument);
                }
                else if (currentToken.Type == TokenType.IfNot)
                {
                    var nestedDocument = new IfNotExpressionScopeDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new DocumentScope(nestedDocument));
                    currentDocumentItem.Document.Add(nestedDocument);
                }
                else if (currentToken.Type == TokenType.Else)
                {
                    var nestedDocument = new ElseExpressionScopeDocumentItem()
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new DocumentScope(nestedDocument));
                    currentDocumentItem.Document.Add(nestedDocument);
                }
                else if (currentToken.Type == TokenType.CollectionOpen)
                {
                    var nestedDocument = new EachDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new DocumentScope(nestedDocument));
                    currentDocumentItem.Document.Add(nestedDocument);
                }
                else if (currentToken.Type == TokenType.ElementOpen)
                {
                    var nestedDocument = new ExpressionScopeDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new DocumentScope(nestedDocument));
                    currentDocumentItem.Document.Add(nestedDocument);
                }
                else if (currentToken.Type == TokenType.InvertedElementOpen)
                {
                    var invertedScope = new InvertedExpressionScopeDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new DocumentScope(invertedScope));
                    currentDocumentItem.Document.Add(invertedScope);
                }
                else if (currentToken.Type == TokenType.CollectionClose ||
                         currentToken.Type == TokenType.ElementClose ||
                         currentToken.Type == TokenType.IfClose ||
                         currentToken.Type == TokenType.ElseClose)
                {
                    if (buildStack.Peek().HasAlias)                     //are we in a alias then remove it
                    {
                        currentDocumentItem.Document.Add(new RemoveAliasDocumentItem(buildStack.Peek().AliasName));
                        buildStack.Pop();
                    }
                    // remove the last document from the stack and go back to the parents
                    buildStack.Pop();

                    if (buildStack.Peek().IsFormattingScope
                        )                 //is the remaining scope a formatting one. If it is pop it and return to its parent
                    {
                        buildStack.Pop();
                    }
                }
                else if (currentToken.Type == TokenType.Print)
                {
                    currentDocumentItem.Document.Add(new PrintContextValue());
                    buildStack.Pop();                     //Print formatted can only be followed by a Format and if not the parser should have not emited it
                }
                else if (currentToken.Type == TokenType.Format)
                {
                    if (buildStack.Peek().IsFormattingScope)
                    {
                        buildStack.Pop();
                    }

                    var formatterItem = new IsolatedContextDocumentItem
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    buildStack.Push(new DocumentScope(formatterItem, true));
                    formatterItem.Add(new CallFormatterDocumentItem(ParseArgumentHeader(currentToken),
                                                                    currentToken.Value,
                                                                    string.IsNullOrWhiteSpace(currentToken.Format?.FormatterName) ? null : currentToken.Format.FormatterName));

                    currentDocumentItem.Document.Add(formatterItem);
                }
                else if (currentToken.Type == TokenType.EscapedSingleValue ||
                         currentToken.Type == TokenType.UnescapedSingleValue)
                {
                    currentDocumentItem.Document.Add(new PathDocumentItem(currentToken.Value,
                                                                          currentToken.Type == TokenType.EscapedSingleValue)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
                else if (currentToken.Type == TokenType.PartialDeclarationOpen)
                {
                    // currently same named partials will override each other
                    // to allow recursive calls of partials we first have to declare the partial and then load it as we would parse
                    // -the partial as a whole and then add it to the list would lead to unknown calls of partials inside the partial
                    var nestedDocument = new MorestachioDocument();
                    buildStack.Push(new DocumentScope(nestedDocument));
                    currentDocumentItem.Document.Add(new PartialDocumentItem(currentToken.Value, nestedDocument)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
                else if (currentToken.Type == TokenType.PartialDeclarationClose)
                {
                    currentDocumentItem.Document.Add(new RenderPartialDoneDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                    buildStack.Pop();
                }
                else if (currentToken.Type == TokenType.RenderPartial)
                {
                    currentDocumentItem.Document.Add(new RenderPartialDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    });
                }
                else if (currentToken.Type == TokenType.Alias)
                {
                    var aliasDocumentItem = new AliasDocumentItem(currentToken.Value)
                    {
                        ExpressionStart = currentToken.TokenLocation
                    };
                    currentDocumentItem.Document.Add(aliasDocumentItem);
                    buildStack.Push(new DocumentScope(aliasDocumentItem, currentToken.Value));
                }
                else if (currentToken.Type == TokenType.VariableDeclaration)
                {
                    var evaluateVariableDocumentItem = new EvaluateVariableDocumentItem(currentToken.Value);
                    currentDocumentItem.Document.Add(evaluateVariableDocumentItem);
                    buildStack.Push(new DocumentScope(evaluateVariableDocumentItem));
                }
                else if (currentToken.Type == TokenType.VariableSet)
                {
                    if (buildStack.Peek().IsFormattingScope)                     //is the remaining scope a formatting one. If it is pop it and return to its parent
                    {
                        buildStack.Pop();
                    }
                    // remove the last document from the stack and go back to the parents
                    buildStack.Pop();
                }
                else
                {
                    var customDocumentItemProvider =
                        options.CustomDocumentItemProviders.FirstOrDefault(e => e.ShouldParse(currentToken, options));
                    if (customDocumentItemProvider != null)
                    {
                        var documentItem = customDocumentItemProvider.Parse(currentToken, options, buildStack);
                        currentDocumentItem.Document.Add(documentItem);
                    }
                }
            }

            if (buildStack.Count != 1)
            {
                //var invalidScopedElements = buildStack
                //throw new MorestachioSyntaxError(new Tokenizer.CharacterLocation(){Character = }, );
                throw new InvalidOperationException(
                          "There is an Error with the Parser. The Parser still contains unscoped builds: " +
                          buildStack.Select(e => e.Document.Kind).Aggregate((e, f) => e + ", " + f));
            }

            return(buildStack.Pop().Document);
        }