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>(); }
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) }); } }
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); } }
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); }
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); }
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); }
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"); } } }
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); } } } }
protected abstract void Visit(SpecialNode specialNode);
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(); } }
public SpecialNodeInspector(SpecialNode node) { _node = node; Attributes = new List<AttributeNode>(node.Element.Attributes); }
private void VisitIgnore(SpecialNode specialNode, SpecialNodeInspector inspector) { Accept(specialNode.Body); }
private void PushSpecial(ElementNode element) { SpecialNode special = new SpecialNode(element) { OriginalNode = element }; Nodes.Add(special); _stack.Push(Nodes); _nodes = special.Body; }
protected override void Visit(SpecialNode specialNode) { throw new System.NotImplementedException(); }
protected override void Visit(SpecialNode specialNode) { Add(specialNode); }
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(); }
private void VisitMarkdown(SpecialNode specialNode, SpecialNodeInspector inspector) { var markdownChunk = new MarkdownChunk(); Chunks.Add(markdownChunk); using (new Frame(this, markdownChunk.Body)) { Accept(inspector.Body); } }
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)); }
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); } }
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)); }
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(); }
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); }