public override State PushChar(char c, IParseContext context, ref string rollback) { System.Diagnostics.Debug.Assert(((XAttribute)context.Nodes.Peek()).Value == null); if (c == '\n' || c == '\r') { XAttribute att = (XAttribute)context.Nodes.Peek(); context.LogWarning("Unexpected newline in value for attribute '" + att.Name.FullName + "'.", att.Region.Start); } if (c == '<') { //the parent state should report the error rollback = string.Empty; return(Parent); } else if (c == '"') { //ending the value XAttribute att = (XAttribute)context.Nodes.Peek(); att.Value = context.KeywordBuilder.ToString(); return(Parent); } else { context.KeywordBuilder.Append(c); 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, IParseContext context, ref string rollback) { //NOTE: This is (mostly) duplicated in HtmlClosingTagState //handle "paragraph" tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { XElement element = (XElement) 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 && !element.Name.HasPrefix && element.Name.IsValid && !ElementTypes.IsInline (element.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 tag '{1}'.", parent.Name.Name, element.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 (element); parent = context.Nodes.Peek (1) as XElement; } } State ret = base.PushChar (c, context, ref rollback); //handle implicitly empty tags if (c == '>') { XElement element = context.Nodes.Peek () as XElement; if (element != null && !element.Name.HasPrefix && element.Name.IsValid && ElementTypes.IsEmpty (element.Name.Name)) { element.Close (element); context.Nodes.Pop (); if (warnAutoClose) { context.LogWarning (string.Format ("Implicitly closed empty tag '{0}'", element.Name.Name), element.Region); } } } return ret; }
public override State PushChar (char c, IParseContext context, ref string rollback) { if (context.CurrentStateLength == 1 && context.PreviousState is HtmlScriptBodyState) return Parent; //NOTE: This is (mostly) duplicated in HtmlClosingTagState //handle "paragraph" tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { XElement element = (XElement) context.Nodes.Peek (); if (!element.Name.HasPrefix && element.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; while (parent.ValidAndNoPrefix () && parent.IsImplicitlyClosedBy (element)) { context.Nodes.Pop (); context.Nodes.Pop (); if (warnAutoClose) { context.LogWarning (string.Format ("Tag '{0}' implicitly closed by tag '{1}'.", parent.Name.Name, element.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 (element); parent = context.Nodes.Peek (1) as XElement; } } } State ret = base.PushChar (c, context, ref rollback); if (ret == Parent && c == '>') { var element = context.Nodes.Peek () as XElement; if (element != null && !element.Name.HasPrefix && element.Name.IsValid) { if (element.Name.Name.Equals ("script", StringComparison.OrdinalIgnoreCase)) { return ScriptState; } else if (ElementTypes.IsEmpty (element.Name.Name)) { element.Close (element); context.Nodes.Pop (); if (warnAutoClose) { context.LogWarning (string.Format ("Implicitly closed empty tag '{0}'", element.Name.Name), element.Region); } } } } return ret; }
public override State PushChar(char c, IParseContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push(new XComment(context.LocationMinus("<!--".Length + 1))); } if (c == '-') { //make sure we know when there are two '-' chars together if (context.StateTag == NOMATCH) { context.StateTag = SINGLE_DASH; } else { context.StateTag = DOUBLE_DASH; } } else if (context.StateTag == DOUBLE_DASH) { if (c == '>') { // if the '--' is followed by a '>', the state has ended // so attach a node to the DOM and end the state XComment comment = (XComment)context.Nodes.Pop(); if (context.BuildTree) { comment.End(context.Location); ((XContainer)context.Nodes.Peek()).AddChildNode(comment); } rollback = string.Empty; return(Parent); } else { context.LogWarning("The string '--' should not appear within comments."); } } else { // not any part of a '-->', so make sure matching is reset context.StateTag = NOMATCH; } 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, IParseContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push (new XComment (context.LocationMinus ("<!--".Length + 1))); } if (c == '-') { //make sure we know when there are two '-' chars together if (context.StateTag == NOMATCH) context.StateTag = SINGLE_DASH; else context.StateTag = DOUBLE_DASH; } else if (context.StateTag == DOUBLE_DASH) { if (c == '>') { // if the '--' is followed by a '>', the state has ended // so attach a node to the DOM and end the state XComment comment = (XComment) context.Nodes.Pop (); if (context.BuildTree) { comment.End (context.Location); ((XContainer) context.Nodes.Peek ()).AddChildNode (comment); } rollback = string.Empty; return Parent; } else { context.LogWarning ("The string '--' should not appear within comments."); } } else { // not any part of a '-->', so make sure matching is reset context.StateTag = NOMATCH; } return null; }
public override State PushChar(char c, IParseContext context, ref string rollback) { if (context.CurrentStateLength == 0 && context.PreviousState is HtmlScriptBodyState) { return(Parent); } //NOTE: This is (mostly) duplicated in HtmlClosingTagState //handle "paragraph" tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { XElement element = (XElement)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 && !element.Name.HasPrefix && element.Name.IsValid && !ElementTypes.IsInline(element.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 tag '{1}'.", parent.Name.Name, element.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(element); parent = context.Nodes.Peek(1) as XElement; } } State ret = base.PushChar(c, context, ref rollback); if (ret == Parent && c == '>') { var element = context.Nodes.Peek() as XElement; if (element != null && !element.Name.HasPrefix && element.Name.IsValid) { if (element.Name.Name.Equals("script", StringComparison.OrdinalIgnoreCase)) { return(ScriptState); } else if (ElementTypes.IsEmpty(element.Name.Name)) { element.Close(element); context.Nodes.Pop(); if (warnAutoClose) { context.LogWarning(string.Format("Implicitly closed empty tag '{0}'", element.Name.Name), element.Region); } } } } return(ret); }
public override State PushChar(char c, IParseContext context, ref string rollback) { XAttribute att = context.Nodes.Peek() as XAttribute; if (c == '<') { //parent handles message if (att != null) { context.Nodes.Pop(); } rollback = string.Empty; return(Parent); } //state has just been entered if (context.CurrentStateLength == 1) { if (context.PreviousState is XmlNameState) { Debug.Assert(att.IsNamed); context.StateTag = GETTINGEQ; } else if (context.PreviousState is XmlAttributeValueState) { //Got value, so end attribute context.Nodes.Pop(); att.End(context.LocationMinus(1)); IAttributedXObject element = (IAttributedXObject)context.Nodes.Peek(); element.Attributes.AddAttribute(att); rollback = string.Empty; return(Parent); } else { //starting a new attribute Debug.Assert(att == null); Debug.Assert(context.StateTag == NAMING); att = new XAttribute(context.LocationMinus(1)); context.Nodes.Push(att); rollback = string.Empty; return(XmlNameState); } } if (c == '>') { context.LogWarning("Attribute ended unexpectedly with '>' character."); if (att != null) { context.Nodes.Pop(); } rollback = string.Empty; return(Parent); } if (context.StateTag == GETTINGEQ) { if (char.IsWhiteSpace(c)) { return(null); } else if (c == '=') { context.StateTag = GETTINGVAL; return(null); } } else if (context.StateTag == GETTINGVAL) { if (char.IsWhiteSpace(c)) { return(null); } else if (c == '"') { return(DoubleQuotedAttributeValueState); } else if (c == '\'') { return(SingleQuotedAttributeValueState); } else if (char.IsLetterOrDigit(c)) { rollback = string.Empty; return(UnquotedAttributeValueState); } } if (char.IsLetterOrDigit(c) || char.IsPunctuation(c) || char.IsWhiteSpace(c)) { if (context.StateTag == GETTINGEQ) { context.LogError("Expecting = in attribute, got " + c + "."); } else if (context.StateTag == GETTINGVAL) { context.LogError("Expecting attribute value, got " + c + "."); } else { context.LogError("Unexpected character '" + c + "' in attribute."); } if (att != null) { context.Nodes.Pop(); } rollback = string.Empty; return(Parent); } rollback = string.Empty; return(Parent); }
public override State PushChar(char c, IParseContext context, ref string rollback) { XElement element = context.Nodes.Peek() as XElement; if (element == null || element.IsComplete) { element = new XElement(context.LocationMinus(2)); // 2 == < + current char context.Nodes.Push(element); } if (c == '<') { if (element.IsNamed) { context.LogError("Unexpected '<' in tag '" + element.Name.FullName + "'."); Close(element, context, context.LocationMinus(1)); } else { context.LogError("Unexpected '<' in unnamed tag."); } rollback = string.Empty; return(Parent); } Debug.Assert(!element.IsComplete); if (element.IsClosed && c != '>') { if (char.IsWhiteSpace(c)) { context.LogWarning("Unexpected whitespace after '/' in self-closing tag."); return(null); } context.LogError("Unexpected character '" + c + "' after '/' in self-closing tag."); context.Nodes.Pop(); return(Parent); } //if tag closed if (c == '>') { if (context.StateTag == MAYBE_SELF_CLOSING) { element.Close(element); } if (!element.IsNamed) { context.LogError("Tag closed prematurely."); } else { Close(element, context, context.Location); } return(Parent); } if (c == '/') { context.StateTag = MAYBE_SELF_CLOSING; return(null); } if (context.StateTag == ATTEMPT_RECOVERY) { if (XmlChar.IsWhitespace(c)) { context.StateTag = RECOVERY_FOUND_WHITESPACE; } return(null); } if (context.StateTag == RECOVERY_FOUND_WHITESPACE) { if (!XmlChar.IsFirstNameChar(c)) { return(null); } } context.StateTag = OK; if (!element.IsNamed && XmlChar.IsFirstNameChar(c)) { rollback = string.Empty; return(NameState); } if (context.CurrentStateLength > 1 && XmlChar.IsFirstNameChar(c)) { rollback = string.Empty; return(AttributeState); } if (XmlChar.IsWhitespace(c)) { return(null); } context.LogError("Unexpected character '" + c + "' in tag.", context.LocationMinus(1)); context.StateTag = ATTEMPT_RECOVERY; return(null); }
public override State PushChar (char c, IParseContext context, ref string rollback) { XElement element = context.Nodes.Peek () as XElement; if (element == null || element.IsComplete) { element = new XElement (context.LocationMinus (2)); // 2 == < + current char context.Nodes.Push (element); } if (c == '<') { if (element.IsNamed) { context.LogError ("Unexpected '<' in tag '" + element.Name.FullName + "'."); Close (element, context, context.LocationMinus (1)); } else { context.LogError ("Unexpected '<' in unnamed tag."); } rollback = string.Empty; return Parent; } Debug.Assert (!element.IsComplete); if (element.IsClosed && c != '>') { if (char.IsWhiteSpace (c)) { context.LogWarning ("Unexpected whitespace after '/' in self-closing tag."); return null; } context.LogError ("Unexpected character '" + c + "' after '/' in self-closing tag."); context.Nodes.Pop (); return Parent; } //if tag closed if (c == '>') { if (context.StateTag == MAYBE_SELF_CLOSING) { element.Close (element); } if (!element.IsNamed) { context.LogError ("Tag closed prematurely."); } else { Close (element, context, context.Location); } return Parent; } if (c == '/') { context.StateTag = MAYBE_SELF_CLOSING; return null; } if (context.StateTag == ATTEMPT_RECOVERY) { if (XmlChar.IsWhitespace (c)) { context.StateTag = RECOVERY_FOUND_WHITESPACE; } return null; } if (context.StateTag == RECOVERY_FOUND_WHITESPACE) { if (!XmlChar.IsFirstNameChar (c)) return null; } context.StateTag = OK; if (!element.IsNamed && XmlChar.IsFirstNameChar (c)) { rollback = string.Empty; return NameState; } if (context.CurrentStateLength > 1 && XmlChar.IsFirstNameChar (c)) { rollback = string.Empty; return AttributeState; } if (XmlChar.IsWhitespace (c)) return null; context.LogError ("Unexpected character '" + c + "' in tag.", context.LocationMinus (1)); context.StateTag = ATTEMPT_RECOVERY; return null; }
public override State PushChar (char c, IParseContext context, ref string rollback) { XAttribute att = context.Nodes.Peek () as XAttribute; if (c == '<') { //parent handles message if (att != null) context.Nodes.Pop (); rollback = string.Empty; return Parent; } //state has just been entered if (context.CurrentStateLength == 1) { if (context.PreviousState is XmlNameState) { Debug.Assert (att.IsNamed); context.StateTag = GETTINGEQ; } else if (context.PreviousState is XmlAttributeValueState) { //Got value, so end attribute context.Nodes.Pop (); att.End (context.LocationMinus (1)); IAttributedXObject element = (IAttributedXObject) context.Nodes.Peek (); element.Attributes.AddAttribute (att); rollback = string.Empty; return Parent; } else { //starting a new attribute Debug.Assert (att == null); Debug.Assert (context.StateTag == NAMING); att = new XAttribute (context.LocationMinus (1)); context.Nodes.Push (att); rollback = string.Empty; return XmlNameState; } } if (c == '>') { context.LogWarning ("Attribute ended unexpectedly with '>' character."); if (att != null) context.Nodes.Pop (); rollback = string.Empty; return Parent; } if (context.StateTag == GETTINGEQ) { if (char.IsWhiteSpace (c)) { return null; } else if (c == '=') { context.StateTag = GETTINGVAL; return null; } } else if (context.StateTag == GETTINGVAL) { if (char.IsWhiteSpace (c)) { return null; } else if (c== '"') { return DoubleQuotedAttributeValueState; } else if (c == '\'') { return SingleQuotedAttributeValueState; } else if (char.IsLetterOrDigit (c)) { rollback = string.Empty; return UnquotedAttributeValueState; } } if (Char.IsLetterOrDigit (c) || char.IsPunctuation (c) || char.IsWhiteSpace (c)) { string err; if (context.StateTag == GETTINGEQ) context.LogError ("Expecting = in attribute, got " + c + "."); else if (context.StateTag == GETTINGVAL) context.LogError ("Expecting attribute value, got " + c + "."); else context.LogError ("Unexpected character '" + c + "' in attribute."); if (att != null) context.Nodes.Pop (); rollback = string.Empty; return Parent; } rollback = string.Empty; return Parent; }
public override State PushChar (char c, IParseContext context, ref string rollback) { XElement element = context.Nodes.Peek () as XElement; if (element == null || element.IsComplete) { element = new XElement (context.LocationMinus (2)); // 2 == < + current char context.Nodes.Push (element); } if (c == '<') { if (element.IsNamed) { context.LogError ("Unexpected '<' in tag '" + element.Name.FullName + "'."); Close (element, context); } else { context.LogError ("Unexpected '<' in unnamed tag."); } rollback = string.Empty; return Parent; } Debug.Assert (!element.IsComplete); if (element.IsClosed && c != '>') { if (char.IsWhiteSpace (c)) { context.LogWarning ("Unexpected whitespace after '/' in self-closing tag."); return null; } else { context.LogError ("Unexpected character '" + c + "' after '/' in self-closing tag."); context.Nodes.Pop (); return Parent; } } //if tag closed if (c == '>') { if (!element.IsNamed) { context.LogError ("Tag closed prematurely."); } else { Close (element, context); } return Parent; } if (XmlChar.IsFirstNameChar (c)) { rollback = string.Empty; if (!element.IsNamed) { return NameState; } else { return AttributeState; } } if (c == '/') { element.Close (element); return null; } if (XmlChar.IsWhitespace (c)) return null; if (element.IsNamed) Close (element, context); context.LogError ("Unexpected character '" + c + "' in tag."); rollback = string.Empty; return Parent; }
public override State PushChar (char c, IParseContext context, ref string rollback) { System.Diagnostics.Debug.Assert (((XAttribute) context.Nodes.Peek ()).Value == null); if (c == '\n' || c == '\r') { XAttribute att = (XAttribute) context.Nodes.Peek (); context.LogWarning ("Unexpected newline in value for attribute '" + att.Name.FullName +"'.", att.Region.Start); } if (c == '<') { //the parent state should report the error rollback = string.Empty; return Parent; } else if (c == '\'') { //ending the value XAttribute att = (XAttribute) context.Nodes.Peek (); att.Value = context.KeywordBuilder.ToString (); return Parent; } else { context.KeywordBuilder.Append (c); return null; } }