/// <summary> Add object to cache, optionally adding extra memory tracking </summary> public void AddParsedObject(AXmlObject obj, int?maxTouchedLocation) { if (!(obj.Length > 0 || obj is AXmlDocument)) { AXmlParser.Assert(false, string.Format(CultureInfo.InvariantCulture, "Invalid object {0}. It has zero length.", obj)); } // // Expensive check // if (obj is AXmlContainer) { // int objStartOffset = obj.StartOffset; // int objEndOffset = obj.EndOffset; // foreach(AXmlObject child in ((AXmlContainer)obj).Children) { // AXmlParser.Assert(objStartOffset <= child.StartOffset && child.EndOffset <= objEndOffset, "Wrong nesting"); // } // } segments.Add(obj); AddSyntaxErrorsOf(obj); obj.IsCached = 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) TouchedRange range = new TouchedRange() { StartOffset = obj.StartOffset, EndOffset = maxTouchedLocation.Value + 1, TouchedByObject = obj }; segments.Add(range); AXmlParser.Log("{0} touched range ({1}-{2})", obj, range.StartOffset, range.EndOffset); } }
protected string GetText(int start, int end) { AXmlParser.Assert(end <= currentLocation, "Reading ahead of current location"); if (start == inputLength && end == inputLength) { return(string.Empty); } else { return(GetCachedString(input.Substring(start, end - start))); } }
bool TryReadFromCacheOrNew <T>(out T res, Predicate <T> condition) where T : AXmlObject, new() { T cached = trackedSegments.GetCachedObject <T>(this.CurrentLocation, 0, condition); if (cached != null) { Skip(cached.Length); AXmlParser.Assert(cached.Length > 0, "cached elements must not have zero length"); res = cached; return(true); } else { res = new T(); return(false); } }
protected void GoBack(int oldLocation) { AXmlParser.Assert(oldLocation <= currentLocation, "Trying to move forward"); maxTouchedLocation = Math.Max(maxTouchedLocation, currentLocation); currentLocation = oldLocation; }
protected void Skip(int count) { AXmlParser.Assert(currentLocation + count <= inputLength, "Skipping after the end of file"); currentLocation += count; }
protected void AssertHasMoreData() { AXmlParser.Assert(HasMoreData(), "Unexpected end of file"); }
/// <summary> Get posible configurations after considering fiven object </summary> Configurations ProcessObject(Configurations oldConfigs, AXmlObject obj) { AXmlParser.Log("Processing {0}", obj); AXmlTag tag = obj as AXmlTag; AXmlParser.Assert(obj is AXmlTag || obj is AXmlText || obj is AXmlElement, obj.GetType().Name + " not expected"); if (obj is AXmlElement) { AXmlParser.Assert(((AXmlElement)obj).IsProperlyNested, "Element not proprly nested"); } Configurations newConfigs = new Configurations(); foreach (var kvp in oldConfigs) { Configuration oldConfig = kvp.Value; var oldStartTags = oldConfig.StartTags; var oldDocument = oldConfig.Document; int oldCost = oldConfig.Cost; if (tag != null && tag.IsStartTag) { newConfigs.Add(new Configuration { // Push start-tag (cost 0) StartTags = oldStartTags.Push(tag), Document = oldDocument.Push(tag), Cost = oldCost, }); } else if (tag != null && tag.IsEndTag) { newConfigs.Add(new Configuration { // Ignore (cost 1) StartTags = oldStartTags, Document = oldDocument.Push(StartTagPlaceholder).Push(tag), Cost = oldCost + 1, }); if (!oldStartTags.IsEmpty && oldStartTags.Peek().Name != tag.Name) { newConfigs.Add(new Configuration { // Pop 1 item (cost 1) - not mathcing StartTags = oldStartTags.Pop(), Document = oldDocument.Push(tag), Cost = oldCost + 1, }); } int popedCount = 0; var startTags = oldStartTags; var doc = oldDocument; foreach (AXmlTag poped in oldStartTags) { popedCount++; if (poped.Name == tag.Name) { newConfigs.Add(new Configuration { // Pop 'x' items (cost x-1) - last one is matching StartTags = startTags.Pop(), Document = doc.Push(tag), Cost = oldCost + popedCount - 1, }); } startTags = startTags.Pop(); doc = doc.Push(EndTagPlaceholder); } } else { // Empty tag or other tag type or text or properly nested element newConfigs.Add(new Configuration { // Ignore (cost 0) StartTags = oldStartTags, Document = oldDocument.Push(obj), Cost = oldCost, }); } } // Log("New configurations:" + newConfigs.ToString()); Configurations bestNewConfigurations = new Configurations( newConfigs.Values.OrderBy(v => v.Cost).Take(maxConfigurationCount) ); // AXmlParser.Log("Best new configurations:" + bestNewConfigurations.ToString()); return(bestNewConfigurations); }
AXmlElement ReadElement(IEnumerator <AXmlObject> objStream) { AXmlElement element = new AXmlElement(); element.IsProperlyNested = true; // Read start tag AXmlTag startTag = ReadSingleObject(objStream) as AXmlTag; AXmlParser.DebugAssert(startTag != null, "Start tag expected"); AXmlParser.DebugAssert(startTag.IsStartOrEmptyTag || startTag == StartTagPlaceholder, "Start tag expected"); if (startTag == StartTagPlaceholder) { element.HasStartOrEmptyTag = false; element.IsProperlyNested = false; TagReader.OnSyntaxError(element, objStream.Current.StartOffset, objStream.Current.EndOffset, "Matching openning tag was not found"); } else { element.HasStartOrEmptyTag = true; element.AddChild(startTag); } // Read content and end tag if (startTag == StartTagPlaceholder || // Check first in case the start tag is null element.StartTag.IsStartTag) { while (true) { AXmlTag currTag = objStream.Current as AXmlTag; // Peek if (currTag == EndTagPlaceholder) { TagReader.OnSyntaxError(element, element.LastChild.EndOffset, element.LastChild.EndOffset, "Expected '</{0}>'", element.StartTag.Name); ReadSingleObject(objStream); element.HasEndTag = false; element.IsProperlyNested = false; break; } else if (currTag != null && currTag.IsEndTag) { if (element.HasStartOrEmptyTag && currTag.Name != element.StartTag.Name) { TagReader.OnSyntaxError(element, currTag.StartOffset + 2, currTag.StartOffset + 2 + currTag.Name.Length, "Expected '{0}'. End tag must have same name as start tag.", element.StartTag.Name); } element.AddChild(ReadSingleObject(objStream)); element.HasEndTag = true; break; } AXmlObject nested = ReadTextOrElement(objStream); if (nested is AXmlElement) { if (!((AXmlElement)nested).IsProperlyNested) { element.IsProperlyNested = false; } element.AddChildren(Split((AXmlElement)nested).ToList()); } else { element.AddChild(nested); } } } else { element.HasEndTag = false; } element.StartOffset = element.FirstChild.StartOffset; element.EndOffset = element.LastChild.EndOffset; AXmlParser.Assert(element.HasStartOrEmptyTag || element.HasEndTag, "Must have at least start or end tag"); AXmlParser.Log("Constructed {0}", element); trackedSegments.AddParsedObject(element, null); // Need all elements in cache for offset tracking return(element); }