public override State PushChar (char c, IParseContext context, ref string rollback) { if (context.CurrentStateLength == 0) context.StateTag = 0; if (c == '<') { if (context.StateTag == 0) { context.StateTag++; return null; } } if (context.StateTag > 0) { if (CLOSE[context.StateTag] == c) { context.StateTag++; if (context.StateTag == CLOSE.Length) { var el = (XElement) context.Nodes.Pop (); var closing = new XClosingTag (new XName ("script"), context.LocationMinus (CLOSE.Length)); closing.End (context.Location); el.Close (closing); return Parent; } } else { context.StateTag = 0; } } return null; }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 0) { context.StateTag = 0; } if (c == '<') { if (context.StateTag == 0) { context.StateTag++; return(null); } } if (context.StateTag > 0) { if (CLOSE[context.StateTag] == c) { context.StateTag++; if (context.StateTag == CLOSE.Length) { var el = (XElement)context.Nodes.Pop(); var closing = new XClosingTag(new XName("script"), context.LocationMinus(CLOSE.Length)); closing.End(context.Location); el.Close(closing); rollback = string.Empty; return(Parent); } } else { context.StateTag = 0; } } return(null); }
public override State PushChar(char c, IParseContext context, ref string rollback) { //NOTE: This is (mostly) duplicated in HtmlTagState //handle inline tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { XClosingTag ct = (XClosingTag)context.Nodes.Peek(); if (!ct.Name.HasPrefix && ct.Name.IsValid) { //Note: the node stack will always be at least 1 deep due to the XDocument var parent = context.Nodes.Peek(1) as XElement; //if it's not a matching closing tag if (parent != null && !string.Equals(ct.Name.Name, parent.Name.Name, StringComparison.OrdinalIgnoreCase)) { //attempt to implicitly close the parents while (parent != null && parent.ValidAndNoPrefix() && parent.IsImplicitlyClosedBy(ct)) { context.Nodes.Pop(); context.Nodes.Pop(); if (warnAutoClose) { context.LogWarning(string.Format("Tag '{0}' implicitly closed by closing tag '{1}'.", parent.Name.Name, ct.Name.Name), parent.Region); } //parent.Region.End = element.Region.Start; //parent.Region.EndColumn = Math.Max (parent.Region.EndColumn - 1, 1); parent.Close(parent); context.Nodes.Push(ct); parent = context.Nodes.Peek(1) as XElement; } } } } return(base.PushChar(c, context, ref rollback)); }
public override State PushChar(char c, MonoDevelop.Xml.StateEngine.IParseContext context, ref string rollback) { //NOTE: This is (mostly) duplicated in HtmlTagState //handle "paragraph" tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { XClosingTag ct = (XClosingTag)context.Nodes.Peek(); //Note: the node stack will always be at least 1 deep due to the XDocument XElement parent = context.Nodes.Peek(1) as XElement; while (parent != null && parent.Name.IsValid && !parent.Name.HasPrefix && !ct.Name.HasPrefix && ct.Name.IsValid && string.Compare(ct.Name.Name, parent.Name.Name, StringComparison.OrdinalIgnoreCase) != 0 && !ElementTypes.IsInline(ct.Name.Name) && (ElementTypes.IsInline(parent.Name.Name) || ElementTypes.IsParagraph(parent.Name.Name)) ) { context.Nodes.Pop(); context.Nodes.Pop(); if (warnAutoClose) { context.LogWarning(string.Format("Tag '{0}' implicitly closed by closing tag '{1}'.", parent.Name.Name, ct.Name.Name), parent.Region); } //parent.Region.End = element.Region.Start; //parent.Region.End.Column = Math.Max (parent.Region.End.Column - 1, 1); parent.Close(parent); context.Nodes.Push(ct); parent = context.Nodes.Peek(1) as XElement; } } return(base.PushChar(c, context, ref rollback)); }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { var ct = context.Nodes.Peek() as XClosingTag; if (ct == null) { Debug.Assert(context.CurrentStateLength == 1, "IncompleteNode must not be an XClosingTag when CurrentStateLength is 1"); ct = new XClosingTag(context.LocationMinus(3)); //3 = </ and the current char context.Nodes.Push(ct); } //if tag closed if (c == '>') { context.Nodes.Pop(); if (ct.IsNamed) { ct.End(context.Location); // walk up tree of parents looking for matching tag int popCount = 0; bool found = false; foreach (XObject node in context.Nodes) { popCount++; XElement element = node as XElement; if (element != null && element.Name == ct.Name) { found = true; break; } } if (!found) { popCount = 0; } //clear the stack of intermediate unclosed tags while (popCount > 1) { XElement el = context.Nodes.Pop() as XElement; if (el != null) { context.LogError(string.Format( "Unclosed tag '{0}' at line {1}, column {2}.", el.Name.FullName, el.Region.BeginLine, el.Region.BeginColumn), ct.Region); } popCount--; } //close the start tag, if we found it if (popCount > 0) { if (context.BuildTree) { ((XElement)context.Nodes.Pop()).Close(ct); } else { context.Nodes.Pop(); } } else { context.LogError( "Closing tag '" + ct.Name.FullName + "' does not match any currently open tag.", ct.Region ); } } else { context.LogError("Closing tag ended prematurely."); } return(Parent); } if (c == '<') { context.LogError("Unexpected '<' in tag."); rollback = string.Empty; return(Parent); } if (!ct.IsNamed && (char.IsLetter(c) || c == '_')) { rollback = string.Empty; return(NameState); } rollback = string.Empty; context.LogError("Unexpected character '" + c + "' in closing tag."); return(Parent); }
public override State PushChar (char c, IParseContext context, ref string rollback) { XClosingTag ct = context.Nodes.Peek () as XClosingTag; if (ct == null) { Debug.Assert (context.CurrentStateLength == 1, "IncompleteNode must not be an XClosingTag when CurrentStateLength is 1"); Debug.Assert (context.Nodes.Peek () is XElement); ct = new XClosingTag (context.LocationMinus (3)); //3 = </ and the current char context.Nodes.Push (ct); } //if tag closed if (c == '>') { context.Nodes.Pop (); if (ct.IsNamed) { ct.End (context.Location); // walk up tree of parents looking for matching tag int popCount = 0; bool found = false; foreach (XObject node in context.Nodes) { popCount++; XElement element = node as XElement; if (element != null && element.Name == ct.Name) { found = true; break; } } if (!found) popCount = 0; //clear the stack of intermediate unclosed tags while (popCount > 1) { XElement el = context.Nodes.Pop () as XElement; if (el != null) context.LogError (string.Format ( "Unclosed tag '{0}' at line {1}, column {2}.", el.Name.FullName, el.Region.Start.Line, el.Region.Start.Column), ct.Region); popCount--; } //close the start tag, if we found it if (popCount > 0) { if (context.BuildTree) ((XElement) context.Nodes.Pop ()).Close (ct); else context.Nodes.Pop (); } else { context.LogError ( "Closing tag '" + ct.Name.FullName + "' does not match any currently open tag."); } } else { context.LogError ("Closing tag ended prematurely."); } return Parent; } if (c == '<') { context.LogError ("Unexpected '<' in tag."); rollback = string.Empty; return Parent; } if (!ct.IsNamed && (char.IsLetter (c) || c == '_')) { rollback = string.Empty; return NameState; } rollback = string.Empty; //note: MalformedTagState logs an error, so skip this //context.LogError ("Unexpected character '" + c + "' in closing tag."); return MalformedTagState; }
public override XmlParserState PushChar(char c, XmlParserContext context, ref string rollback) { var ct = context.Nodes.Peek() as XClosingTag; if (ct == null) { Debug.Assert(context.CurrentStateLength == 0, "IncompleteNode must not be an XClosingTag when CurrentStateLength is 0"); ct = new XClosingTag(context.Position - STARTOFFSET); context.Nodes.Push(ct); } //if tag closed if (c == '>') { context.Nodes.Pop(); if (ct.IsNamed) { ct.End(context.Position + 1); // walk up tree of parents looking for matching tag int popCount = 0; bool found = false; foreach (XObject node in context.Nodes) { popCount++; if (node is XElement element && element.Name == ct.Name) { found = true; break; } } if (!found) { popCount = 0; } //clear the stack of intermediate unclosed tags while (popCount > 1) { if (context.Nodes.Pop() is XElement el) { context.Diagnostics?.LogError(string.Format("Unclosed tag '{0}'", el.Name.FullName), el.Span); } popCount--; } //close the start tag, if we found it if (popCount > 0) { // close it even if not in tree mode, as some spines may want to know whether an element was closed after advancing the parser ((XElement)context.Nodes.Pop()).Close(ct); } else { if (context.BuildTree) { context.Diagnostics?.LogError( $"Closing tag '{ct.Name.FullName}' does not match any currently open tag.", ct.Span ); // add it into the tree anyway so it's accessible var parent = context.Nodes.Peek() as XContainer; if (parent != null) { if (!parent.IsEnded) { parent = context.Nodes.Count > 1? context.Nodes.Peek(1) as XContainer : null; } if (parent != null) { parent.AddChildNode(ct); } } } } } else { context.Diagnostics?.LogError("Closing tag ended prematurely.", context.Position); } return(Parent); } if (c == '<') { context.Diagnostics?.LogError("Unexpected '<' in tag.", context.Position - 1); context.Nodes.Pop(); rollback = string.Empty; return(Parent); } if (XmlChar.IsWhitespace(c)) { return(null); } if (!ct.IsNamed && (char.IsLetter(c) || c == '_')) { rollback = string.Empty; return(NameState); } rollback = string.Empty; context.Diagnostics?.LogError("Unexpected character '" + c + "' in closing tag.", context.Position - 1); context.Nodes.Pop(); return(Parent); }