コード例 #1
0
        private List<string> GetKnownAttributesForSpecialNode(SpecialNode node)
        {
            var allKnown = new Dictionary<string, List<string>>
            {
                {"var", new List<string>{"type"}},
                {"def", new List<string>{"type"}},
                {"default", new List<string>{"type"}},
                {"global", new List<string>{"type"}},
                {"viewdata", new List<string>{"default","model"}},
                {"set", new List<string>()},
                {"for", new List<string>{"each"}},
                {"test", new List<string>{"condition", "if", "once"}},
                {"if", new List<string>{"condition", "once"}},
                {"else", new List<string>{"if"}},
                {"elseif", new List<string>{"condition"}},
                {"content", new List<string>{"add","def", "name", "set", "var"}},
                {"use", new List<string>{"assembly", "content", "file", "import", "master", "namespace", "pageBaseType" }},
                {"macro", new List<string>{"name"}},
                {"render", new List<string>{"partial", "section"}},
                {"section", new List<string>{"name"}},
                {"cache", new List<string>{"expires", "key", "signal"}}
            };

            List<string> knownAttributes;

            return allKnown.TryGetValue(node.Element.Name, out knownAttributes)
                ? knownAttributes
                : new List<string>();
        }
コード例 #2
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitGlobal(SpecialNode specialNode)
        {
            var typeAttr = specialNode.Element.Attributes.FirstOrDefault(attr => attr.Name == "type");
            var type = typeAttr != null ? AsCode(typeAttr) : (Snippets)"object";

            foreach (var attr in specialNode.Element.Attributes.Where(a => a != typeAttr))
            {
                AddUnordered(new GlobalVariableChunk { Type = type, Name = attr.Name, Value = AsCode(attr) });
            }
        }
コード例 #3
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitFor(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            var eachAttr = inspector.TakeAttribute("each");

            var forEachChunk = new ForEachChunk { Code = AsCode(eachAttr), Position = Locate(specialNode.Element) };
            Chunks.Add(forEachChunk);
            using (new Frame(this, forEachChunk.Body))
            {
                foreach (var attr in inspector.Attributes)
                {
                    Chunks.Add(new AssignVariableChunk { Name = attr.Name, Value = AsCode(attr), Position = Locate(attr) });
                }

                Accept(specialNode.Body);
            }
        }
コード例 #4
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitElseIf(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            if (!SatisfyElsePrecondition())
                throw new CompilerException("An 'elseif' may only follow an 'if' or 'elseif'.");

            var conditionAttr = inspector.TakeAttribute("condition");
            var elseIfChunk = new ConditionalChunk { Type = ConditionalType.ElseIf, Condition = AsCode(conditionAttr), Position = Locate(inspector.OriginalNode) };
            Chunks.Add(elseIfChunk);
            using (new Frame(this, elseIfChunk.Body))
                Accept(specialNode.Body);
        }
コード例 #5
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitCache(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            var keyAttr = inspector.TakeAttribute("key");
            var expiresAttr = inspector.TakeAttribute("expires");
            var signalAttr = inspector.TakeAttribute("signal");

            var chunk = new CacheChunk { Position = Locate(specialNode.Element) };

            if (keyAttr != null)
                chunk.Key = AsCode(keyAttr);
            else
                chunk.Key = "\"\"";

            if (expiresAttr != null)
                chunk.Expires = AsCode(expiresAttr);
            else
                chunk.Expires = "";

            if (signalAttr != null)
                chunk.Signal = AsCode(signalAttr);
            else
                chunk.Signal = "";

            Chunks.Add(chunk);
            using (new Frame(this, chunk.Body))
                Accept(inspector.Body);
        }
コード例 #6
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: pr0nin/spark
        private void VisitUnless(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            var conditionAttr = inspector.TakeAttribute("condition") ?? inspector.TakeAttribute("unless");

            var unlessChunk = new ConditionalChunk { Type = ConditionalType.Unless, Condition = AsCode(conditionAttr), Position = Locate(inspector.OriginalNode) };
            Chunks.Add(unlessChunk);
            using (new Frame(this, unlessChunk.Body))
                Accept(specialNode.Body);
        }
コード例 #7
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitUse(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            var file = inspector.TakeAttribute("file");
            if (file != null)
            {
                var scope = new ScopeChunk { Position = Locate(inspector.OriginalNode) };
                Chunks.Add(scope);
                using (new Frame(this, scope.Body))
                {
                    foreach (var attr in inspector.Attributes)
                    {
                        Chunks.Add(new LocalVariableChunk { Name = attr.Name, Value = AsCode(attr), Position = Locate(attr) });
                    }

                    var useFileChunk = new RenderPartialChunk { Name = file.Value, Position = Locate(inspector.OriginalNode) };
                    Chunks.Add(useFileChunk);
                    using (new Frame(this, useFileChunk.Body, useFileChunk.Sections))
                    {
                        Accept(inspector.Body);
                    }
                }
            }
            else
            {
                var contentAttr = inspector.TakeAttribute("content");
                var namespaceAttr = inspector.TakeAttribute("namespace");
                var assemblyAttr = inspector.TakeAttribute("assembly");
                var importAttr = inspector.TakeAttribute("import");
                var masterAttr = inspector.TakeAttribute("master");
                var pageBaseTypeAttr = inspector.TakeAttribute("pageBaseType");

                if (contentAttr != null)
                {
                    var useContentChunk = new UseContentChunk { Name = contentAttr.Value, Position = Locate(inspector.OriginalNode) };
                    Chunks.Add(useContentChunk);
                    using (new Frame(this, useContentChunk.Default))
                    {
                        Accept(specialNode.Body);
                    }
                }
                else if (namespaceAttr != null || assemblyAttr != null)
                {
                    if (namespaceAttr != null)
                    {
                        var useNamespaceChunk = new UseNamespaceChunk { Namespace = AsCode(namespaceAttr) };
                        AddUnordered(useNamespaceChunk);
                    }

                    if (assemblyAttr != null)
                    {
                        var useAssemblyChunk = new UseAssemblyChunk { Assembly = assemblyAttr.Value };
                        AddUnordered(useAssemblyChunk);
                    }
                }
                else if (importAttr != null)
                {
                    var useImportChunk = new UseImportChunk { Name = importAttr.Value };
                    AddUnordered(useImportChunk);
                }
                else if (masterAttr != null)
                {
                    var useMasterChunk = new UseMasterChunk { Name = masterAttr.Value };
                    AddUnordered(useMasterChunk);
                }
                else if (pageBaseTypeAttr != null)
                {
                    var usePageBaseTypeChunk = new PageBaseTypeChunk { BaseClass = AsCode(pageBaseTypeAttr) };
                    AddUnordered(usePageBaseTypeChunk);
                }
                else
                {
                    throw new CompilerException("Special node use had no understandable attributes");
                }
            }
        }
コード例 #8
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitRender(SpecialNode node, SpecialNodeInspector inspector)
        {
            var partial = inspector.TakeAttribute("partial");

            if (partial != null)
            {
                var scope = new ScopeChunk { Position = Locate(inspector.OriginalNode) };
                Chunks.Add(scope);
                using (new Frame(this, scope.Body))
                {
                    foreach (var attr in inspector.Attributes)
                    {
                        Chunks.Add(new LocalVariableChunk { Name = attr.Name, Value = AsCode(attr), Position = Locate(attr) });
                    }

                    var renderPartial = new RenderPartialChunk { Name = partial.Value, Position = Locate(inspector.OriginalNode) };
                    Chunks.Add(renderPartial);

                    using (new Frame(this, renderPartial.Body, renderPartial.Sections))
                    {
                        Accept(inspector.Body);
                    }
                }
            }
            else
            {
                var sectionAttr = inspector.TakeAttribute("section");

                string sectionName = null;
                if (sectionAttr != null)
                    sectionName = sectionAttr.Value;

                var scope = new ScopeChunk { Position = Locate(inspector.OriginalNode) };
                Chunks.Add(scope);
                using (new Frame(this, scope.Body))
                {
                    foreach (var attr in inspector.Attributes)
                    {
                        Chunks.Add(new LocalVariableChunk { Name = attr.Name, Value = AsCode(attr), Position = Locate(attr) });
                    }

                    var render = new RenderSectionChunk { Name = sectionName };
                    Chunks.Add(render);
                    using (new Frame(this, render.Default))
                    {
                        Accept(inspector.Body);
                    }
                }
            }
        }
コード例 #9
0
ファイル: AbstractNodeVisitor.cs プロジェクト: Eilon/spark
 protected abstract void Visit(SpecialNode specialNode);
コード例 #10
0
ファイル: TestElseElementVisitor.cs プロジェクト: Eilon/spark
        protected override void Visit(SpecialNode node)
        {
            bool detachFromParent = false;
            if (NameUtility.IsMatch("else", Context.Namespaces, node.Element.Name, node.Element.Namespace) &&
                node.Element.IsEmptyElement &&
                _frame.TestParentNodes != null)
            {
                detachFromParent = true;
            }

            if (detachFromParent)
            {
                var reconstructed = new SpecialNode(node.Element);
                _frame.TestParentNodes.Add(reconstructed);
                _frame.Nodes = reconstructed.Body;
            }
            else
            {
                var reconstructed = new SpecialNode(node.Element);
                Nodes.Add(reconstructed);

                var parentNodes = _frame.Nodes;

                PushFrame();

                _frame.Nodes = reconstructed.Body;
                if (NameUtility.IsMatch("if", Context.Namespaces, node.Element.Name, node.Element.Namespace) ||
                    NameUtility.IsMatch("test", Context.Namespaces, node.Element.Name, node.Element.Namespace))
                {
                    _frame.TestParentNodes = parentNodes;
                }

                Accept(node.Body);

                PopFrame();
            }
        }
コード例 #11
0
 public SpecialNodeInspector(SpecialNode node)
 {
     _node = node;
     Attributes = new List<AttributeNode>(node.Element.Attributes);
 }
コード例 #12
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: emiaj/spark
 private void VisitIgnore(SpecialNode specialNode, SpecialNodeInspector inspector)
 {
     Accept(specialNode.Body);
 }
コード例 #13
0
ファイル: SpecialNodeVisitor.cs プロジェクト: otac0n/spark
 private void PushSpecial(ElementNode element)
 {
     SpecialNode special = new SpecialNode(element) { OriginalNode = element };
     Nodes.Add(special);
     _stack.Push(Nodes);
     _nodes = special.Body;
 }
コード例 #14
0
ファイル: SpecialNodeVisitor.cs プロジェクト: otac0n/spark
 protected override void Visit(SpecialNode specialNode)
 {
     throw new System.NotImplementedException();
 }
コード例 #15
0
ファイル: SpecialNodeVisitor.cs プロジェクト: emiaj/spark
 protected override void Visit(SpecialNode specialNode)
 {
     Add(specialNode);
 }
コード例 #16
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitIf(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            var conditionAttr = inspector.TakeAttribute("condition") ?? inspector.TakeAttribute("if");

            var onceAttr = inspector.TakeAttribute("once");

            if (conditionAttr == null && onceAttr == null)
            {
                throw new CompilerException("Element must contain an if, condition, or once attribute");
            }

            Frame ifFrame = null;
            if (conditionAttr != null)
            {
                var ifChunk = new ConditionalChunk { Type = ConditionalType.If, Condition = AsCode(conditionAttr), Position = Locate(inspector.OriginalNode) };
                Chunks.Add(ifChunk);
                ifFrame = new Frame(this, ifChunk.Body);
            }

            Frame onceFrame = null;
            if (onceAttr != null)
            {
                var onceChunk = new ConditionalChunk { Type = ConditionalType.Once, Condition = onceAttr.AsCodeInverted(), Position = Locate(inspector.OriginalNode) };
                Chunks.Add(onceChunk);
                onceFrame = new Frame(this, onceChunk.Body);
            }

            Accept(specialNode.Body);

            if (onceFrame != null)
                onceFrame.Dispose();

            if (ifFrame != null)
                ifFrame.Dispose();
        }
コード例 #17
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitMarkdown(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            var markdownChunk = new MarkdownChunk();

            Chunks.Add(markdownChunk);
            using (new Frame(this, markdownChunk.Body))
            {
                Accept(inspector.Body);
            }
        }
コード例 #18
0
ファイル: TargetExtension.cs プロジェクト: Eilon/sake
        public void VisitNode(INodeVisitor visitor, IList<Node> body, IList<Chunk> chunks)
        {
            var registerTarget = string.Format(
                @"RegisterTarget(""{0}"", ""{1}"", ""{2}"", __target_{3});",
                _idAttribute.Value,
                _classAttribute != null ? _classAttribute.Value : "",
                _descriptionAttribute != null ? _descriptionAttribute.Value : "",
                _targetExtensionCount);

            if (_targetAttribute != null)
            {
                registerTarget +=
                    Environment.NewLine +
                    string.Format(
                        @"RegisterTarget(""{0}"", ""{1}"", null, null);",
                        _targetAttribute.Value,
                        _idAttribute.Value);
            }

            var beginLambda = string.Format(
                @"__target_{0} = () => {{",
                _targetExtensionCount);
            const string endLambda = "};";

            var startingTarget = string.Format(
                @"StartingTarget(""{0}"");",
                _idAttribute.Value);

            var nameAttribute = new AttributeNode("name", _idAttribute.QuotChar, _idAttribute.Nodes) { OriginalNode = _idAttribute };

            var macroAttributes = _targetElement.Attributes
                .Where(x => x != _idAttribute && x != _classAttribute && x != _descriptionAttribute)
                .Concat(new[] { nameAttribute })
                .ToList();
            var macroElement = new SpecialNode(new ElementNode("macro", macroAttributes, false));

            var onceAttribute = new AttributeNode("once", _idAttribute.QuotChar, _idAttribute.Nodes);
            var testElement = new SpecialNode(new ElementNode("test", new[] { onceAttribute }, false));

            macroElement.Body.Add(testElement);
            testElement.Body = body;
            testElement.Body.Insert(0, new StatementNode(startingTarget));

            visitor.Accept(new StatementNode(beginLambda));
            visitor.Accept(testElement);
            visitor.Accept(new StatementNode(endLambda));
            visitor.Accept(new StatementNode(registerTarget));
        }
コード例 #19
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitSection(SpecialNode node, SpecialNodeInspector inspector)
        {
            if (SectionChunks == null)
                throw new CompilerException("Section cannot be used at this location", Locate(node.Element));

            var name = inspector.TakeAttribute("name");
            if (name == null)
                throw new CompilerException("Section element must have a name attribute", Locate(node.Element));

            IList<Chunk> sectionChunks;
            if (!SectionChunks.TryGetValue(name.Value, out sectionChunks))
            {
                sectionChunks = new List<Chunk>();
                SectionChunks.Add(name.Value, sectionChunks);
            }

            var scope = new ScopeChunk { Position = Locate(inspector.OriginalNode) };
            sectionChunks.Add(scope);
            using (new Frame(this, scope.Body))
            {
                foreach (var attr in inspector.Attributes)
                {
                    Chunks.Add(new LocalVariableChunk { Name = attr.Name, Value = AsCode(attr), Position = Locate(attr) });
                }

                Accept(inspector.Body);
            }
        }
コード例 #20
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        protected override void Visit(SpecialNode specialNode)
        {
            string nqName = NameUtility.GetName(specialNode.Element.Name);
            if (!SpecialNodeMap.ContainsKey(nqName))
            {
                throw new CompilerException(string.Format("Unknown special node {0}", specialNode.Element.Name));
            }

            var action = SpecialNodeMap[nqName];
            action(specialNode, new SpecialNodeInspector(specialNode));
        }
コード例 #21
0
ファイル: ChunkBuilderVisitor.cs プロジェクト: otac0n/spark
        private void VisitVar(SpecialNode specialNode, SpecialNodeInspector inspector)
        {
            Frame frame = null;
            if (!specialNode.Element.IsEmptyElement)
            {
                var scope = new ScopeChunk { Position = Locate(specialNode.Element) };
                Chunks.Add(scope);
                frame = new Frame(this, scope.Body);
            }

            var typeAttr = inspector.TakeAttribute("type");
            var type = typeAttr != null ? AsCode(typeAttr) : (Snippets)"var";

            foreach (var attr in inspector.Attributes)
            {
                Chunks.Add(new LocalVariableChunk { Type = type, Name = attr.Name, Value = AsCode(attr), Position = Locate(attr) });
            }

            Accept(specialNode.Body);

            if (frame != null)
                frame.Dispose();
        }
コード例 #22
0
        public MarkupGrammar(IParserSettings settings)
        {
            var Apos  = Ch('\'');
            var Quot  = Ch('\"');
            var Lt    = Ch('<');
            var Gt    = Ch('>');
            var NotLt = ChNot('<');


            //var CombiningChar = Ch('*');
            //var Extener = Ch('*');

            //[4]       NameChar	   ::=       Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender
            var NameChar = Ch(char.IsLetterOrDigit).Or(Ch('.', '-', '_', ':')) /*.Or(CombiningChar).Or(Extener)*/;

            //[5]       Name	   ::=      (Letter | '_' | ':') (NameChar)*
            var Name =
                Ch(char.IsLetter).Or(Ch('_', ':')).And(Rep(NameChar))
                .Build(hit => hit.Left + new string(hit.Down.ToArray()));

            //[7]       Nmtoken	   ::=      (NameChar)+
            var NmToken =
                Rep1(NameChar)
                .Build(hit => new string(hit.ToArray()));

            //[3]       S	   ::=      (#x20 | #x9 | #xD | #xA)+
            Whitespace = Rep1(Ch(char.IsWhiteSpace));

            //[25]      Eq	   ::=       S? '=' S?
            var Eq = Opt(Whitespace).And(Ch('=')).And(Opt(Whitespace));



            var paintedStatement1 = Statement1.Build(hit => new StatementNode(hit)).Paint <StatementNode, Node>();

            var statementMarker = string.IsNullOrEmpty(settings.StatementMarker) ? "#" : settings.StatementMarker;

            // Syntax 1: '\r'? ('\n' | '\u0002') S? '#' (statement ^('\r' | '\n' | '\u0003') )
            var StatementNode1 = Opt(Ch('\r')).And(Ch('\n').Or(ChSTX())).And(Rep(Ch(' ', '\t'))).And(TkCode(Ch(statementMarker))).And(paintedStatement1).IfNext(Ch('\r', '\n').Or(ChETX()))
                                 .Build(hit => hit.Down);


            var paintedStatement2 = Statement2.Build(hit => new StatementNode(hit)).Paint <StatementNode, Node>();

            // Syntax 2: '<%' (statement ^'%>')  '%>'
            var StatementNode2 = TkAspxCode(Ch("<%")).NotNext(Ch('=')).And(paintedStatement2).And(TkAspxCode(Ch("%>")))
                                 .Build(hit => hit.Left.Down);

            Statement = StatementNode1.Or(StatementNode2);

            var EscapedCode1 = TkCode(Ch("\\${").Or(Ch("$${")).Or(Ch("`${"))).And(Expression).And(TkCode(Ch('}')))
                               .Build(hit => new TextNode("${" + hit.Left.Down + "}"));

            var EscapedCode2 = TkCode(Ch("\\!{").Or(Ch("!!{")).Or(Ch("`!{"))).And(Expression).And(TkCode(Ch('}')))
                               .Build(hit => new TextNode("!{" + hit.Left.Down + "}"));

            var EscapedCode3 = TkCode(Ch("\\$!{").Or(Ch("$$!{")).Or(Ch("`$!{"))).And(Expression).And(TkCode(Ch('}')))
                               .Build(hit => new TextNode("$!{" + hit.Left.Down + "}"));

            EscapedCode = EscapedCode1.Or(EscapedCode2).Or(EscapedCode3);

            // Syntax 1: ${csharp_expression}
            var Code1 = TkCode(Ch("${")).And(Expression).And(TkCode(Ch('}')))
                        .Build(hit => new ExpressionNode(hit.Left.Down)
            {
                AutomaticEncoding = settings.AutomaticEncoding
            });

            // Syntax 3: <%=csharp_expression%>;
            var Code3 = TkAspxCode(Ch("<%")).And(TkAttDelim(Ch('='))).And(Expression).And(TkAspxCode(Ch("%>")))
                        .Build(hit => new ExpressionNode(hit.Left.Down));

            // Syntax 4: $!{csharp_expression}
            var Code4 = TkCode(Ch("$!{")).And(Expression).And(TkCode(Ch('}')))
                        .Build(hit => new ExpressionNode(hit.Left.Down)
            {
                SilentNulls = true, AutomaticEncoding = settings.AutomaticEncoding
            });

            // Syntax 5: !{sharp_expression}
            var Code5 = TkCode(Ch("!{")).And(Expression).And(TkCode(Ch('}')))
                        .Build(hit => new ExpressionNode(hit.Left.Down));

            Code = Code1.Or(Code3).Or(Code4).Or(Code5);

            var Condition = TkCode(Ch("?{")).And(Expression).And(TkCode(Ch('}')))
                            .Build(hit => new ConditionNode(hit.Left.Down));

            var LessThanTextNode = Ch('<')
                                   .Build(hit => (Node) new TextNode("<"));

            //[68]      EntityRef	   ::=      '&' Name ';'
            EntityRef =
                TkEntity(Ch('&').And(Name).And(Ch(';')))
                .Build(hit => new EntityNode(hit.Left.Down));

            var EntityRefOrAmpersand = AsNode(EntityRef).Or(Ch('&').Build(hit => (Node) new TextNode("&")));

            //[10]      AttValue	   ::=      '"' ([^<&"] | Reference)* '"' |  "'" ([^<&'] | Reference)* "'"
            var AttValueSingleText = TkAttVal(Rep1(ChNot('<', '&', '\'').Unless(Code).Unless(Condition))).Build(hit => new TextNode(hit));
            var AttValueSingle     = TkAttQuo(Apos).And(Rep(AsNode(AttValueSingleText).Or(EntityRefOrAmpersand).Or(AsNode(Code)).Or(AsNode(Condition)).Or(LessThanTextNode).Paint())).And(TkAttQuo(Apos));
            var AttValueDoubleText = TkAttVal(Rep1(ChNot('<', '&', '\"').Unless(Code).Unless(Condition))).Build(hit => new TextNode(hit));
            var AttValueDouble     = TkAttQuo(Quot).And(Rep(AsNode(AttValueDoubleText).Or(EntityRefOrAmpersand).Or(AsNode(Code)).Or(AsNode(Condition)).Or(LessThanTextNode).Paint())).And(TkAttQuo(Quot));
            var AttValueQuoted     = AttValueSingle.Or(AttValueDouble);

            //[41]      Attribute	   ::=       Name  Eq  AttValue
            Attribute =
                TkAttNam(Name).And(TkAttDelim(Eq)).And(AttValueQuoted)
                .Build(hit => new AttributeNode(hit.Left.Left, hit.Down.Down, hit.Down.Left.Down)).Paint <AttributeNode, Node>();

            Ignore =
                Opt(Ch("\r\n").Or(Ch("\n")).And(StringOf(Ch(char.IsWhiteSpace).Unless(Ch('\r', '\n'))))).And(TkTagDelim(Lt)).And(TkEleNam(Ch("ignore"))).And(TkTagDelim(Gt)).And(Rep(ChNot('<').Or(Lt.IfNext(ChNot("/ignore>"))))).And(Ch("</ignore>"))
                .Build(hit =>
            {
                var node = new SpecialNode(new ElementNode(
                                               hit.Left.Left.Left.Down,
                                               new List <AttributeNode>(),
                                               false,
                                               hit.Left.Left.Left.Left.Left == null ? string.Empty : hit.Left.Left.Left.Left.Left.Left + hit.Left.Left.Left.Left.Left.Down));
                node.Body = new List <Node> {
                    new TextNode(hit.Left.Down)
                };
                return(node);
            });

            //[40]      STag	   ::=      '<' Name (S  Attribute)* S? '>'
            //[44]      EmptyElemTag	   ::=      '<' Name (S  Attribute)* S? '/>'
            Element =
                Opt(Ch("\r\n").Or(Ch("\n")).And(StringOf(Ch(char.IsWhiteSpace).Unless(Ch('\r', '\n'))))).And(TkTagDelim(Lt)).And(TkEleNam(Name)).And(Rep(Whitespace.And(Attribute).Down())).And(Opt(Whitespace)).And(Opt(TkTagDelim(Ch('/')))).And(TkTagDelim(Gt))
                .Build(hit => new ElementNode(
                           hit.Left.Left.Left.Left.Down,
                           hit.Left.Left.Left.Down,
                           hit.Left.Down != default(char),
                           hit.Left.Left.Left.Left.Left.Left == null ? string.Empty : hit.Left.Left.Left.Left.Left.Left.Left + hit.Left.Left.Left.Left.Left.Left.Down));

            //[42]      ETag	   ::=      '</' Name  S? '>'
            EndElement =
                Opt(Ch("\r\n").Or(Ch("\n")).And(StringOf(Ch(char.IsWhiteSpace).Unless(Ch('\r', '\n'))))).And(TkTagDelim(Lt.And(Ch('/')))).And(TkEleNam(Name)).And(Opt(Whitespace)).And(TkTagDelim(Gt))
                .Build(hit => new EndElementNode(hit.Left.Left.Down, hit.Left.Left.Left.Left == null ? string.Empty : hit.Left.Left.Left.Left.Left + hit.Left.Left.Left.Left.Down));

            Text =
                Rep1(ChNot('&', '<').Unless(Statement).Unless(Code).Unless(EscapedCode).Unless(Ignore).Unless(Element).Unless(EndElement))
                .Build(hit => new TextNode(hit));

            //[15]      Comment	   ::=      '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
            Comment =
                TkComm(Ch("<!--").And(Rep(ChNot('-').Or(Ch('-').IfNext(ChNot('-'))))).And(Ch("-->")))
                .Build(hit => new CommentNode(hit.Left.Down));

            //[11]      SystemLiteral	   ::=      ('"' [^"]* '"') | ("'" [^']* "'")
            var SystemLiteral =
                Quot.And(Rep(ChNot('\"'))).And(Quot).Or(Apos.And(Rep(ChNot('\''))).And(Apos))
                .Build(hit => new string(hit.Left.Down.ToArray()));

            //[13]      PubidChar	   ::=      #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
            var PubidChar1 = Ch(char.IsLetterOrDigit).Or(Ch(" \r\n-()+,./:=?;!*#@$_%".ToArray()));
            var PubidChar2 = PubidChar1.Or(Apos);

            //[12]      PubidLiteral	   ::=      '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
            var PubidLiteral =
                Quot.And(Rep(PubidChar2)).And(Quot).Or(Apos.And(Rep(PubidChar1)).And(Apos))
                .Build(hit => new string(hit.Left.Down.ToArray()));

            //[75]      ExternalID	   ::=      'SYSTEM' S  SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral
            var ExternalIDSystem =
                Ch("SYSTEM").And(Whitespace).And(SystemLiteral)
                .Build(hit => new ExternalIdInfo
            {
                ExternalIdType = hit.Left.Left,
                SystemId       = hit.Down
            });
            var ExternalIDPublic =
                Ch("PUBLIC").And(Whitespace).And(PubidLiteral).And(Whitespace).And(SystemLiteral)
                .Build(hit => new ExternalIdInfo
            {
                ExternalIdType = hit.Left.Left.Left.Left,
                PublicId       = hit.Left.Left.Down,
                SystemId       = hit.Down
            });
            var ExternalID = ExternalIDSystem.Or(ExternalIDPublic);

            //[28]      doctypedecl	   ::=      '<!DOCTYPE' S  Name (S  ExternalID)? S? ('[' intSubset ']' S?)? '>'
            DoctypeDecl = Ch("<!DOCTYPE").And(Whitespace).And(Name).And(Opt(Whitespace.And(ExternalID).Down())).And(Opt(Whitespace)).And(Ch('>'))
                          .Build(hit => new DoctypeNode {
                Name = hit.Left.Left.Left.Down, ExternalId = hit.Left.Left.Down
            });

            //[26]      VersionNum	   ::=      '1.0'
            var VersionNum = Ch("1.0");

            //[24]      VersionInfo	   ::=       S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
            var VersionInfo = Whitespace.And(Ch("version")).And(Eq).And(
                Apos.And(VersionNum).And(Apos).Or(Quot.And(VersionNum).And(Quot)));

            //[81]      EncName	   ::=      [A-Za-z] ([A-Za-z0-9._] | '-')*
            var EncName = Ch(char.IsLetter).And(Rep(Ch(char.IsLetterOrDigit).Or(Ch('.', '_', '-'))))
                          .Build(hit => hit.Left + new string(hit.Down.ToArray()));

            //[80]      EncodingDecl	   ::=       S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
            var EncodingDecl = Whitespace.And(Ch("encoding")).And(Eq).And(
                Apos.And(EncName).And(Apos).Or(Quot.And(EncName).And(Quot)))
                               .Build(hit => hit.Down.Left.Down);

            //[32]      SDDecl	   ::=       S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
            var SSDecl = Whitespace.And(Ch("standalone")).And(Eq).And(
                Apos.And(Ch("yes").Or(Ch("no"))).And(Apos).Or(Quot.And(Ch("yes").Or(Ch("no"))).And(Quot)))
                         .Build(hit => hit.Down.Left.Down);

            //[23]      XMLDecl	   ::=      '<?xml' VersionInfo  EncodingDecl? SDDecl? S? '?>'
            XMLDecl =
                Ch("<?xml").And(VersionInfo).And(Opt(EncodingDecl)).And(Opt(SSDecl)).And(Opt(Whitespace)).And(Ch("?>"))
                .Build(hit => new XMLDeclNode {
                Encoding = hit.Left.Left.Left.Down, Standalone = hit.Left.Left.Down
            });

            //[17]      PITarget	   ::=      Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
            var PITarget = Name.Unless(Ch('X', 'x').And(Ch('M', 'm')).And(Ch('L', 'l')));

            //[16]      PI	   ::=      '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
            ProcessingInstruction = Ch("<?").And(PITarget).And(Opt(Whitespace)).And(Rep(Ch(ch => true).Unless(Ch("?>")))).And(Ch("?>"))
                                    .Build(hit => new ProcessingInstructionNode {
                Name = hit.Left.Left.Left.Down, Body = new string(hit.Left.Down.ToArray())
            });


            AnyNode = AsNode(Ignore).Paint()
                      .Or(AsNode(EscapedCode).Paint())
                      .Or(AsNode(Element).Paint())
                      .Or(AsNode(EndElement).Paint())
                      .Or(AsNode(Text).Paint())
                      .Or(EntityRefOrAmpersand.Paint())
                      .Or(AsNode(Statement))
                      .Or(AsNode(Code).Paint())
                      .Or(AsNode(DoctypeDecl).Paint())
                      .Or(AsNode(Comment).Paint())
                      .Or(AsNode(XMLDecl).Paint())
                      .Or(AsNode(ProcessingInstruction).Paint())
                      .Or(AsNode(LessThanTextNode).Paint());

            Nodes = Rep(AnyNode);
        }