bool MatchStartTag(string bbCode, ref int pos, Stack<SyntaxTreeNode> stack)
{
// Before we do *anything* - if the topmost node on the stack is marked as StopProcessing then
// don't match anything
var topmost = stack.Peek() as TagNode;
if (topmost != null && topmost.Tag.StopProcessing)
{
return false;
}
int end = pos;
var tag = ParseTagStart(bbCode, ref end);
if (tag != null)
{
if (tag.Tag.EnableIterationElementBehavior)
{
//this element behaves like a list item: it allows tags as content, it auto-closes and it does not nest.
//the last property is ensured by closing all currently open tags up to the opening list element
var isThisTagAlreadyOnStack = stack.OfType<TagNode>().Any(n => n.Tag == tag.Tag);
//if this condition is false, no nesting would occur anyway
if (isThisTagAlreadyOnStack)
{
var openingNode = stack.Peek() as TagNode; //could also be a SequenceNode
Debug.Assert(openingNode != null); //isThisTagAlreadyOnStack would have been false
if (openingNode.Tag != tag.Tag && ErrorMode == ErrorMode.Strict && ErrorOrReturn("TagNotMatching", tag.Tag.Name, openingNode.Tag.Name)) return false;
while (true)
{
var poppedOpeningNode = (TagNode)stack.Pop();
if (poppedOpeningNode.Tag != tag.Tag)
{
//a nesting imbalance was detected
if (openingNode.Tag.RequiresClosingTag && ErrorMode == ErrorMode.Strict && ErrorOrReturn("TagNotMatching", tag.Tag.Name, openingNode.Tag.Name))
return false;
//close the (wrongly) open tag. we have already popped so do nothing.
}
else
{
//the opening node matches the closing node
//close the already open li-item. we have already popped. we have already popped so do nothing.
break;
}
}
}
}
stack.Peek().SubNodes.Add(tag);
if (tag.Tag.TagClosingStyle != BBTagClosingStyle.LeafElementWithoutContent)
stack.Push(tag); //leaf elements have no content - they are closed immediately
pos = end;
return true;
}
return false;
}
bool MatchTextNode(string bbCode, ref int pos, Stack<SyntaxTreeNode> stack)