Browse Source

XML Parser: Keep track of memory touched during parsing of an item

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4608 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
7b1985525a
  1. 18
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs
  2. 70
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs

18
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs

@ -160,6 +160,24 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -160,6 +160,24 @@ namespace ICSharpCode.AvalonEdit.XmlParser
);
}
/// <summary>
/// Gets a child at the given document offset.
/// Goes recursively down the tree.
/// </summary>
public RawObject GetChildAtOffset(int offset)
{
foreach(RawObject child in this.Children) {
if (child.StartOffset <= offset && offset <= child.EndOffset) {
if (child is RawContainer) {
return ((RawContainer)child).GetChildAtOffset(offset);
} else {
return child;
}
}
}
return this; // No childs at offset
}
// Only these four methods should be used to modify the collection
internal void AddChild(RawObject item)

70
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs

@ -89,7 +89,6 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -89,7 +89,6 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public class XmlParser
{
// TODO: Error reporting
// TODO: Trace touched memory
// TODO: Simple tag matching heuristic
// TODO: Simple attribute value closing heurisitc
// TODO: Backtracking for unclosed long Text sections
@ -97,9 +96,21 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -97,9 +96,21 @@ namespace ICSharpCode.AvalonEdit.XmlParser
RawDocument userDocument;
XDocument userLinqDocument;
TextDocument textDocument;
TextSegmentCollection<RawObject> parsedItems = new TextSegmentCollection<RawObject>();
List<DocumentChangeEventArgs> changesSinceLastParse = new List<DocumentChangeEventArgs>();
// Stored parsed items as long as they are valid
TextSegmentCollection<RawObject> parsedItems = new TextSegmentCollection<RawObject>();
// Is used to identify what memory range was touched by object
// The default is (StartOffset, EndOffset + 1) which is not stored
TextSegmentCollection<TouchedMemoryRange> touchedMemoryRanges = new TextSegmentCollection<TouchedMemoryRange>();
class TouchedMemoryRange: TextSegment
{
public RawObject TouchedByObject { get; set; }
}
/// <summary>
/// Create new parser, but do not parse the text yet.
/// </summary>
@ -135,17 +146,27 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -135,17 +146,27 @@ namespace ICSharpCode.AvalonEdit.XmlParser
foreach(DocumentChangeEventArgs change in changesSinceLastParse) {
// Update offsets of all items
parsedItems.UpdateOffsets(change);
touchedMemoryRanges.UpdateOffsets(change);
// Remove any items affected by the change
int start = Math.Max(change.Offset - 2, 0);
int end = Math.Max(change.Offset + change.InsertionLength + 2, 0);
foreach(RawObject obj in parsedItems.FindOverlappingSegments(start, end - start)) {
Log("Changed offset {0}", change.Offset);
// Removing will cause one of the end to be set to change.Offset
// FindOverlappingSegments apparently removes any segment intersecting of touching
// so that conviniently takes care of the +1 byte
foreach(RawObject obj in parsedItems.FindOverlappingSegments(change.Offset, 0)) {
parsedItems.Remove(obj);
Log("Removed cached item {0}", obj);
}
foreach(TouchedMemoryRange memory in touchedMemoryRanges.FindOverlappingSegments(change.Offset, 0)) {
parsedItems.Remove(memory.TouchedByObject);
touchedMemoryRanges.Remove(memory);
Log("Removed cached item {0} - depended on memory ({1}-{2})", memory.TouchedByObject, memory.StartOffset, memory.EndOffset);
}
}
changesSinceLastParse.Clear();
currentLocation = 0;
maxTouchedLocation = 0;
readingEnd = input.Length;
RawDocument parsedDocument = ReadDocument();
@ -195,9 +216,19 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -195,9 +216,19 @@ namespace ICSharpCode.AvalonEdit.XmlParser
if (obj.Length == 0 && !(obj is RawDocument)) {
throw new Exception(string.Format("Could not parse {0}. It has zero length.", obj));
}
// TODO: Record touched memory
parsedItems.Add(obj);
System.Diagnostics.Debug.WriteLine("XML Parser: Parsed " + obj.ToString());
Log("Parsed {0}", obj);
if (maxTouchedLocation > currentLocation) {
// 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() {
StartOffset = obj.StartOffset,
Length = (maxTouchedLocation + 1 - obj.StartOffset),
TouchedByObject = obj
};
touchedMemoryRanges.Add(memRange);
Log(" - Touched memory range: ({0}-{1})", memRange.StartOffset, memRange.EndOffset);
}
}
void Log(string text, params object[] pars)
@ -236,8 +267,16 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -236,8 +267,16 @@ namespace ICSharpCode.AvalonEdit.XmlParser
string input;
int readingEnd;
// Do not ever set the value from parsing methods
// most importantly do not backtrack except with GoBack(int)
int currentLocation;
// CurrentLocation is assumed to be touched and that fact does not
// have to be recorded in this variable
// This stores any value bigger then that if applicable
// acutal value is max(currentLocation, maxTouchedLocation)
int maxTouchedLocation;
bool IsEndOfFile()
{
return currentLocation == readingEnd;
@ -263,6 +302,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -263,6 +302,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser
return true;
}
void GoBack(int oldLocation)
{
maxTouchedLocation = Math.Max(maxTouchedLocation, currentLocation);
currentLocation = oldLocation;
}
bool TryRead(char c)
{
if (currentLocation == readingEnd) return false;
@ -307,8 +352,10 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -307,8 +352,10 @@ namespace ICSharpCode.AvalonEdit.XmlParser
bool TryPeek(string text)
{
if (currentLocation + text.Length > readingEnd) return false;
return TryPeek(text[0]) && input.Substring(currentLocation, text.Length) == text;
// Early exit
if (!TryPeek(text[0])) return false;
maxTouchedLocation = Math.Max(maxTouchedLocation, currentLocation + (text.Length - 1));
return input.Substring(currentLocation, text.Length) == text;
}
bool TryMoveTo(char c)
@ -656,8 +703,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -656,8 +703,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
TryMoveToNonWhiteSpace();
attr.EqualsSign = GetText(checkpoint, currentLocation);
} else {
// TODO: Track touched memory
currentLocation = checkpoint;
GoBack(checkpoint);
// TODO: ERROR - Equals expected
}
@ -784,7 +830,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -784,7 +830,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
backtrack = entityIndex;
}
currentLocation = Math.Max(start + 1, backtrack); // Max-just in case
GoBack(Math.Max(start + 1, backtrack)); // Max-just in case
}
text.Value = GetText(start, currentLocation);
text.EndOffset = currentLocation;

Loading…
Cancel
Save