Пример #1
0
        /// <summary>
        /// Parses the given template string into a <see cref="TemplateTree"/> using standard technique
        /// of preprocessing then lexical analysis followed by a syntactic analysis
        /// </summary>
        /// <param name="template">The template string to parse</param>
        /// <returns>A <see cref="TemplateTree"/> which is the abstract representation of the given string</returns>
        public static TemplateTree Parse(string template)
        {
            string preprocessedTemplate = Preprocess(template);

            if (preprocessedTemplate == null)
            {
                return(null);
            }

            IEnumerable <string> tokenStream = Tokenize(preprocessedTemplate);
            TemplateTree         result      = ParseTokenStream(tokenStream);

            return(result);
        }
Пример #2
0
        private static TemplateTree ParseTokenStream(IEnumerable <string> tokenStream)
        {
            // Structure expressions (like *if and *foreach) cause the state to be pushed in this stack
            var stack = new Stack <(StructureBase, TemplateTree)>();

            // State
            var currentTemplate = new TemplateTree();
            var currentStruct   = default(StructureBase);

            bool insideCurlies = false;

            foreach (var token in tokenStream)
            {
                if (token == "{{")
                {
                    insideCurlies = true;
                }
                else if (token == "}}")
                {
                    insideCurlies = false;
                }
                else if (insideCurlies)
                {
                    var tokenTrim = token.Trim();
                    if (tokenTrim.StartsWith("*")) // Inside the curlies, starts with an asterisk *: Structure component
                    {
                        // If it's an *end component, pop the state stack
                        if (tokenTrim.ToLower() == StructureBase._end || tokenTrim.ToLower().StartsWith(StructureBase._end + " "))
                        {
                            if (stack.Count == 0)
                            {
                                throw new TemplateException("Unexpected expression {{" + token + "}}");
                            }

                            // Pop the previous state
                            (currentStruct, currentTemplate) = stack.Pop();
                        }
                        else // If it's anything other then *end, push the state in the stack
                        {
                            // Parse the token and add it to the current template
                            var templateStructure = StructureBase.Parse(tokenTrim);
                            currentTemplate.Contents.Add(templateStructure);

                            // Start of a structural block
                            // Push the current state into the stack
                            stack.Push((currentStruct, currentTemplate));

                            // Start a fresh state
                            currentStruct          = templateStructure;
                            currentTemplate        = new TemplateTree();
                            currentStruct.Template = currentTemplate;
                        }
                    }
                    else // Inside the curlies, does not start with an asterisk *: An expression
                    {
                        currentTemplate.Contents.Add(TemplexBase.Parse(token));
                    }
                }
                else // Outside the curlies: Plain markup
                {
                    currentTemplate.Contents.Add(TemplateMarkup.Make(token));
                }
            }

            // All scopes that weren't explicitly closed, do so implicitly at the end of the template
            // Keep popping until you're back at the root
            while (stack.Count > 0)
            {
                (_, currentTemplate) = stack.Pop();
            }

            return(currentTemplate);
        }