TagNode ParseTagStart(string input, ref int pos)
{
var end = pos;
if (!ParseChar(input, ref end, '[')) return null;
var tagName = ParseName(input, ref end);
if (tagName == null) return null;
var tag = Tags.SingleOrDefault(t => t.Name.Equals(tagName, StringComparison.OrdinalIgnoreCase));
if (tag == null && ErrorOrReturn("UnknownTag", tagName)) return null;
var result = new TagNode(tag);
var defaultAttrValue = ParseAttributeValue(input, ref end, tag.GreedyAttributeProcessing);
if (defaultAttrValue != null)
{
var attr = tag.FindAttribute("");
if (attr == null && ErrorOrReturn("UnknownAttribute", tag.Name, "\"Default Attribute\"")) return null;
result.AttributeValues.Add(attr, defaultAttrValue);
}
while (true)
{
ParseWhitespace(input, ref end);
var attrName = ParseName(input, ref end);
if (attrName == null) break;
var attrVal = ParseAttributeValue(input, ref end);
if (attrVal == null && ErrorOrReturn("")) return null;
if (tag.Attributes == null && ErrorOrReturn("UnknownTag", tag.Name)) return null;
var attr = tag.FindAttribute(attrName);
if (attr == null && ErrorOrReturn("UnknownTag", tag.Name, attrName)) return null;
if (result.AttributeValues.ContainsKey(attr) && ErrorOrReturn("DuplicateAttribute", tagName, attrName)) return null;
result.AttributeValues.Add(attr, attrVal);
}
if (!ParseChar(input, ref end, ']') && ErrorOrReturn("TagNotClosed", tagName)) return null;
ParseWhitespace(input, ref end);
pos = end;
return result;
}
string ParseTagEnd(string input, ref int pos)