Browse Source

XML Parser: Fixed a few small bugs

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4682 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
2faa4b3813
  1. 2
      samples/XmlDOM/Window1.xaml.cs
  2. 12
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlAttribute.cs
  3. 20
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlContainer.cs
  4. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlElement.cs
  5. 35
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlObject.cs
  6. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlParser.cs
  7. 12
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlTag.cs
  8. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlText.cs
  9. 26
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/Cache.cs
  10. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs

2
samples/XmlDOM/Window1.xaml.cs

@ -83,7 +83,7 @@ namespace XmlDOM @@ -83,7 +83,7 @@ namespace XmlDOM
MessageBox.Show("Error - Original and pretty printed version of XML differ");
}
markerService.RemoveAll(m => true);
foreach(var error in doc.GetSelfAndAllChildren().SelectMany(c => c.SyntaxErrors)) {
foreach(var error in doc.SyntaxErrors) {
var marker = markerService.Create(error.StartOffset, error.EndOffset - error.StartOffset);
marker.Tag = error.Message;
marker.BackgroundColor = Color.FromRgb(255, 150, 150);

12
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlAttribute.cs

@ -30,13 +30,13 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -30,13 +30,13 @@ namespace ICSharpCode.AvalonEdit.Xml
/// <summary> Unquoted and dereferenced value of the attribute </summary>
public string Value { get; internal set; }
internal override void DebugCheckConsistency(bool allowNullParent)
internal override void DebugCheckConsistency(bool checkParentPointers)
{
DebugAssert(Name != null, "Null Name");
DebugAssert(EqualsSign != null, "Null EqualsSign");
DebugAssert(QuotedValue != null, "Null QuotedValue");
DebugAssert(Value != null, "Null Value");
base.DebugCheckConsistency(allowNullParent);
base.DebugCheckConsistency(checkParentPointers);
}
#region Helpper methods
@ -101,10 +101,9 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -101,10 +101,9 @@ namespace ICSharpCode.AvalonEdit.Xml
}
/// <inheritdoc/>
internal override void UpdateDataFrom(AXmlObject source)
internal override bool UpdateDataFrom(AXmlObject source)
{
base.UpdateDataFrom(source); // Check asserts
if (this.LastUpdatedFrom == source) return;
if (!base.UpdateDataFrom(source)) return false;
AXmlAttribute src = (AXmlAttribute)source;
if (this.Name != src.Name ||
this.EqualsSign != src.EqualsSign ||
@ -117,6 +116,9 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -117,6 +116,9 @@ namespace ICSharpCode.AvalonEdit.Xml
this.QuotedValue = src.QuotedValue;
this.Value = src.Value;
OnChanged();
return true;
} else {
return false;
}
}

20
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlContainer.cs

@ -114,7 +114,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -114,7 +114,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// </summary>
void InsertChild(int index, AXmlObject item)
{
LogDom("Inserting {0} at index {1}", item, index);
AXmlParser.Log("Inserting {0} at index {1}", item, index);
AXmlDocument document = this.Document;
Assert(document != null, "Can not insert to dangling object");
@ -172,7 +172,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -172,7 +172,7 @@ namespace ICSharpCode.AvalonEdit.Xml
void RemoveChild(int index)
{
AXmlObject removed = this.Children[index];
LogDom("Removing {0} at index {1}", removed, index);
AXmlParser.Log("Removing {0} at index {1}", removed, index);
// Null parent pointer
Assert(removed.Parent == this, "Inconsistent child");
@ -184,30 +184,36 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -184,30 +184,36 @@ namespace ICSharpCode.AvalonEdit.Xml
}
/// <summary> Verify that the subtree is consistent. Only in debug build. </summary>
internal override void DebugCheckConsistency(bool allowNullParent)
/// <remarks> Parent pointers might be null or pointing somewhere else in parse tree </remarks>
internal override void DebugCheckConsistency(bool checkParentPointers)
{
base.DebugCheckConsistency(allowNullParent);
base.DebugCheckConsistency(checkParentPointers);
AXmlObject prevChild = null;
int myStartOffset = this.StartOffset;
int myEndOffset = this.EndOffset;
foreach(AXmlObject child in this.Children) {
Assert(child.Length != 0, "Empty child");
if (!allowNullParent) {
if (checkParentPointers) {
Assert(child.Parent != null, "Null parent reference");
Assert(child.Parent == this, "Inccorect parent reference");
}
Assert(child.Parent == null || child.Parent == this, "Inccorect parent reference");
Assert(myStartOffset <= child.StartOffset && child.EndOffset <= myEndOffset, "Child not within parent text range");
if (this.IsInCache)
Assert(child.IsInCache, "Child not in cache");
if (prevChild != null)
Assert(prevChild.EndOffset <= child.StartOffset, "Overlaping childs");
child.DebugCheckConsistency(allowNullParent);
child.DebugCheckConsistency(checkParentPointers);
prevChild = child;
}
}
/// <remarks>
/// Note the the method is not called recuively.
/// Only the helper methods are recursive.
/// </remarks>
internal void UpdateTreeFrom(AXmlContainer srcContainer)
{
this.UpdateDataFrom(srcContainer);
RemoveChildrenNotIn(srcContainer.Children);
InsertAndUpdateChildrenFrom(srcContainer.Children);
}

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlElement.cs

@ -35,10 +35,10 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -35,10 +35,10 @@ namespace ICSharpCode.AvalonEdit.Xml
}
}
internal override void DebugCheckConsistency(bool allowNullParent)
internal override void DebugCheckConsistency(bool checkParentPointers)
{
DebugAssert(Children.Count > 0, "No children");
base.DebugCheckConsistency(allowNullParent);
base.DebugCheckConsistency(checkParentPointers);
}
#region Helpper methods

35
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlObject.cs

@ -66,7 +66,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -66,7 +66,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// <summary> Raises Changing event </summary>
protected void OnChanging()
{
LogDom("Changing {0}", this);
AXmlParser.Log("Changing {0}", this);
if (Changing != null) {
Changing(this, new AXmlObjectEventArgs() { Object = this } );
}
@ -79,7 +79,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -79,7 +79,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// <summary> Raises Changed event </summary>
protected void OnChanged()
{
LogDom("Changed {0}", this);
AXmlParser.Log("Changed {0}", this);
if (Changed != null) {
Changed(this, new AXmlObjectEventArgs() { Object = this } );
}
@ -94,7 +94,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -94,7 +94,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// <summary>
/// The error that occured in the context of this node (excluding nested nodes)
/// </summary>
public IEnumerable<SyntaxError> SyntaxErrors {
public IEnumerable<SyntaxError> MySyntaxErrors {
get {
if (syntaxErrors == null) {
return new SyntaxError[] {};
@ -104,6 +104,16 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -104,6 +104,16 @@ namespace ICSharpCode.AvalonEdit.Xml
}
}
/// <summary>
/// The error that occured in the context of this node and all nested nodes.
/// It has O(n) cost.
/// </summary>
public IEnumerable<SyntaxError> SyntaxErrors {
get {
return GetSelfAndAllChildren().SelectMany(obj => obj.MySyntaxErrors);
}
}
internal void AddSyntaxError(SyntaxError error)
{
DebugAssert(error.Object == this, "Must own the error");
@ -149,7 +159,8 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -149,7 +159,8 @@ namespace ICSharpCode.AvalonEdit.Xml
public abstract void AcceptVisitor(IAXmlVisitor visitor);
/// <summary> The parser tree object this object was updated from </summary>
internal object LastUpdatedFrom { get; private set; }
/// <remarks> Initialized to 'this' </remarks>
internal AXmlObject LastUpdatedFrom { get; private set; }
internal bool IsInCache { get; set; }
@ -163,14 +174,15 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -163,14 +174,15 @@ namespace ICSharpCode.AvalonEdit.Xml
}
/// <summary> Copy all data from the 'source' to this object </summary>
internal virtual void UpdateDataFrom(AXmlObject source)
/// <remarks> Returns true if any updates were done </remarks>
internal virtual bool UpdateDataFrom(AXmlObject source)
{
Assert(this.GetType() == source.GetType(), "Source has different type");
DebugAssert(this.StartOffset == source.StartOffset, "Source has different StartOffset");
if (this.LastUpdatedFrom == source) {
DebugAssert(this.EndOffset == source.EndOffset, "Source has different EndOffset");
return;
return false;
}
Assert(!this.IsInCache, "Can not update cached item");
@ -190,7 +202,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -190,7 +202,7 @@ namespace ICSharpCode.AvalonEdit.Xml
this.syntaxErrors = null;
} else {
this.syntaxErrors = new List<SyntaxError>();
foreach(var error in source.SyntaxErrors) {
foreach(var error in source.MySyntaxErrors) {
// The object differs, so create our own copy
// The source still might need it in the future and we do not want to break it
this.AddSyntaxError(error.Clone(this));
@ -198,6 +210,8 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -198,6 +210,8 @@ namespace ICSharpCode.AvalonEdit.Xml
}
OnChanged();
}
return true;
}
/// <summary> Verify that the item is consistent. Only in debug build. </summary>
@ -210,12 +224,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -210,12 +224,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// <inheritdoc/>
public override string ToString()
{
return string.Format("{0}({1}-{2})", this.GetType().Name.Remove(0, 3), this.StartOffset, this.EndOffset);
}
internal static void LogDom(string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format("XML DOM: " + format, args));
return string.Format("{0}({1}-{2})", this.GetType().Name.Remove(0, 4), this.StartOffset, this.EndOffset);
}
#region Helpper methods

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlParser.cs

@ -158,11 +158,11 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -158,11 +158,11 @@ namespace ICSharpCode.AvalonEdit.Xml
TagReader tagReader = new TagReader(this, input);
List<AXmlObject> tags = tagReader.ReadAllTags();
AXmlDocument parsedDocument = new TagMatchingHeuristics(this, input, tags).ReadDocument();
parsedDocument.DebugCheckConsistency(true);
parsedDocument.DebugCheckConsistency(false);
tagReader.PrintStringCacheStats();
AXmlObject.LogDom("Updating main DOM tree...");
AXmlParser.Log("Updating main DOM tree...");
userDocument.UpdateTreeFrom(parsedDocument);
userDocument.DebugCheckConsistency(false);
userDocument.DebugCheckConsistency(true);
return userDocument;
}
}

12
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlTag.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -50,7 +50,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// <summary> True if tag starts with "&lt;!" </summary>
public bool IsUnknownBang { get { return OpeningBracket == "<!"; } }
internal override void DebugCheckConsistency(bool allowNullParent)
internal override void DebugCheckConsistency(bool checkParentPointers)
{
Assert(OpeningBracket != null, "Null OpeningBracket");
Assert(Name != null, "Null Name");
@ -58,7 +58,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -58,7 +58,7 @@ namespace ICSharpCode.AvalonEdit.Xml
foreach(AXmlObject child in this.Children) {
Assert(child is AXmlText || child is AXmlAttribute, "Only attribute or text children allowed");
}
base.DebugCheckConsistency(allowNullParent);
base.DebugCheckConsistency(checkParentPointers);
}
/// <inheritdoc/>
@ -68,10 +68,9 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -68,10 +68,9 @@ namespace ICSharpCode.AvalonEdit.Xml
}
/// <inheritdoc/>
internal override void UpdateDataFrom(AXmlObject source)
internal override bool UpdateDataFrom(AXmlObject source)
{
base.UpdateDataFrom(source); // Check asserts
if (this.LastUpdatedFrom == source) return;
if (!base.UpdateDataFrom(source)) return false;
AXmlTag src = (AXmlTag)source;
if (this.OpeningBracket != src.OpeningBracket ||
this.Name != src.Name ||
@ -82,6 +81,9 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -82,6 +81,9 @@ namespace ICSharpCode.AvalonEdit.Xml
this.Name = src.Name;
this.ClosingBracket = src.ClosingBracket;
OnChanged();
return true;
} else {
return false;
}
}

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlText.cs

@ -35,10 +35,9 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -35,10 +35,9 @@ namespace ICSharpCode.AvalonEdit.Xml
}
/// <inheritdoc/>
internal override void UpdateDataFrom(AXmlObject source)
internal override bool UpdateDataFrom(AXmlObject source)
{
base.UpdateDataFrom(source); // Check asserts
if (this.LastUpdatedFrom == source) return;
if (!base.UpdateDataFrom(source)) return false;
AXmlText src = (AXmlText)source;
if (this.EscapedValue != src.EscapedValue ||
this.Value != src.Value)
@ -47,6 +46,9 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -47,6 +46,9 @@ namespace ICSharpCode.AvalonEdit.Xml
this.EscapedValue = src.EscapedValue;
this.Value = src.Value;
OnChanged();
return true;
} else {
return false;
}
}

26
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/Cache.cs

@ -24,7 +24,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -24,7 +24,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// Is used to identify what memory range was touched by object
/// The default is (StartOffset, EndOffset + 1) which is not stored
/// </summary>
TextSegmentCollection<TouchedMemoryRange> touchedMemoryRanges = new TextSegmentCollection<TouchedMemoryRange>();
TextSegmentCollection<TouchedRange> touchedRanges = new TextSegmentCollection<TouchedRange>();
/// <summary>
/// Track offsets of syntax errors as well.
@ -32,7 +32,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -32,7 +32,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// </summary>
TextSegmentCollection<SyntaxError> syntaxErrors = new TextSegmentCollection<SyntaxError>();
class TouchedMemoryRange: TextSegment
class TouchedRange: TextSegment
{
public AXmlObject TouchedByObject { get; set; }
}
@ -42,7 +42,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -42,7 +42,7 @@ namespace ICSharpCode.AvalonEdit.Xml
foreach(DocumentChangeEventArgs change in changes) {
// Update offsets of all items
parsedItems.UpdateOffsets(change);
touchedMemoryRanges.UpdateOffsets(change);
touchedRanges.UpdateOffsets(change);
syntaxErrors.UpdateOffsets(change);
// Remove any items affected by the change
@ -53,10 +53,10 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -53,10 +53,10 @@ namespace ICSharpCode.AvalonEdit.Xml
foreach(AXmlObject obj in parsedItems.FindSegmentsContaining(change.Offset)) {
Remove(obj, false);
}
foreach(TouchedMemoryRange memory in touchedMemoryRanges.FindSegmentsContaining(change.Offset)) {
AXmlParser.Log("Found that {0} dependeds on memory ({1}-{2})", memory.TouchedByObject, memory.StartOffset, memory.EndOffset);
Remove(memory.TouchedByObject, true);
touchedMemoryRanges.Remove(memory);
foreach(TouchedRange range in touchedRanges.FindSegmentsContaining(change.Offset)) {
AXmlParser.Log("Found that {0} dependeds on ({1}-{2})", range.TouchedByObject, range.StartOffset, range.EndOffset);
Remove(range.TouchedByObject, true);
touchedRanges.Remove(range);
}
}
}
@ -73,20 +73,20 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -73,20 +73,20 @@ namespace ICSharpCode.AvalonEdit.Xml
}
}
parsedItems.Add(obj);
foreach(SyntaxError syntaxError in obj.SyntaxErrors) {
foreach(SyntaxError syntaxError in obj.MySyntaxErrors) {
syntaxErrors.Add(syntaxError);
}
obj.IsInCache = true;
if (maxTouchedLocation != null) {
// location is assumed to be read so the range ends at (location + 1)
// For example eg for "a_" it is (0-2)
TouchedMemoryRange memRange = new TouchedMemoryRange() {
TouchedRange range = new TouchedRange() {
StartOffset = obj.StartOffset,
EndOffset = maxTouchedLocation.Value + 1,
TouchedByObject = obj
};
touchedMemoryRanges.Add(memRange);
AXmlParser.Log("{0} touched memory range ({1}-{2})", obj, memRange.StartOffset, memRange.EndOffset);
touchedRanges.Add(range);
AXmlParser.Log("{0} touched range ({1}-{2})", obj, range.StartOffset, range.EndOffset);
}
}
@ -110,7 +110,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -110,7 +110,7 @@ namespace ICSharpCode.AvalonEdit.Xml
foreach(AXmlObject r in parents) {
if (parsedItems.Remove(r)) {
foreach(SyntaxError syntaxError in r.SyntaxErrors) {
foreach(SyntaxError syntaxError in r.MySyntaxErrors) {
syntaxErrors.Remove(syntaxError);
}
r.IsInCache = false;
@ -120,7 +120,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -120,7 +120,7 @@ namespace ICSharpCode.AvalonEdit.Xml
}
if (parsedItems.Remove(obj)) {
foreach(SyntaxError syntaxError in obj.SyntaxErrors) {
foreach(SyntaxError syntaxError in obj.MySyntaxErrors) {
syntaxErrors.Remove(syntaxError);
}
obj.IsInCache = false;

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs

@ -295,7 +295,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -295,7 +295,7 @@ namespace ICSharpCode.AvalonEdit.Xml
conifg.Cost += 1;
}
}
AXmlParser.Log("Configurations after closing all remaining tags:" + configurations.ToString());
// AXmlParser.Log("Configurations after closing all remaining tags:" + configurations.ToString());
Configuration bestConfig = configurations.Values.OrderBy(v => v.Cost).First();
AXmlParser.Log("Best configuration has cost {0}", bestConfig.Cost);
@ -370,7 +370,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -370,7 +370,7 @@ namespace ICSharpCode.AvalonEdit.Xml
newConfigs.Values.OrderBy(v => v.Cost).Take(maxConfigurationCount)
);
AXmlParser.Log("Best new configurations:" + bestNewConfigurations.ToString());
// AXmlParser.Log("Best new configurations:" + bestNewConfigurations.ToString());
return bestNewConfigurations;
}

Loading…
Cancel
Save