Browse Source

Add ICSharpCode.NRefactory.Xml.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
2faf35e6fc
  1. 3
      ICSharpCode.NRefactory.Xml/.gitignore
  2. 61
      ICSharpCode.NRefactory.Xml/AXmlAttribute.cs
  3. 163
      ICSharpCode.NRefactory.Xml/AXmlObject.cs
  4. 91
      ICSharpCode.NRefactory.Xml/AXmlTag.cs
  5. 51
      ICSharpCode.NRefactory.Xml/AXmlText.cs
  6. 37
      ICSharpCode.NRefactory.Xml/IAXmlVisitor.cs
  7. 79
      ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj
  8. 32
      ICSharpCode.NRefactory.Xml/IncrementalParserState.cs
  9. 107
      ICSharpCode.NRefactory.Xml/InternalDocument.cs
  10. 88
      ICSharpCode.NRefactory.Xml/Log.cs
  11. 15
      ICSharpCode.NRefactory.Xml/Properties/AssemblyInfo.cs
  12. 63
      ICSharpCode.NRefactory.Xml/SyntaxError.cs
  13. 755
      ICSharpCode.NRefactory.Xml/TagReader.cs
  14. 70
      ICSharpCode.NRefactory.Xml/TagSoupParser.cs
  15. 47
      ICSharpCode.NRefactory.Xml/TextType.cs
  16. 348
      ICSharpCode.NRefactory.Xml/TokenReader.cs
  17. 48
      ICSharpCode.NRefactory.Xml/XmlSegment.cs
  18. 20
      ICSharpCode.NRefactory/Editor/ITextSource.cs
  19. 12
      ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs
  20. 12
      ICSharpCode.NRefactory/Editor/StringTextSource.cs
  21. 1
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  22. 19
      ICSharpCode.NRefactory/Properties/AssemblyInfo.cs
  23. 26
      ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs
  24. 14
      NRefactory.sln
  25. 2
      doc/XML Documentation.html

3
ICSharpCode.NRefactory.Xml/.gitignore vendored

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
bin/
obj/

61
ICSharpCode.NRefactory.Xml/AXmlAttribute.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// Name-value pair in a tag
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
public class AXmlAttribute : AXmlObject
{
internal AXmlAttribute(AXmlObject parent, int startOffset, InternalAttribute internalObject)
: base(parent, startOffset, internalObject)
{
}
internal InternalAttribute InternalAttribute {
get { return (InternalAttribute)internalObject; }
}
/// <summary> Name with namespace prefix - exactly as in source file </summary>
public string Name { get { return InternalAttribute.Name; } }
/// <summary> Unquoted and dereferenced value of the attribute </summary>
public string Value { get { return InternalAttribute.Value; } }
/// <summary>Gets the segment for the attribute name</summary>
public ISegment NameSegment {
get { return new XmlSegment(startOffset, startOffset + Name.Length); }
}
/// <summary>Gets the segment for the attribute value, including the quotes</summary>
public ISegment ValueSegment {
get { return new XmlSegment(startOffset + Name.Length + InternalAttribute.EqualsSignLength, this.EndOffset); }
}
/// <inheritdoc/>
public override void AcceptVisitor(IAXmlVisitor visitor)
{
visitor.VisitAttribute(this);
}
}
}

163
ICSharpCode.NRefactory.Xml/AXmlObject.cs

@ -0,0 +1,163 @@ @@ -0,0 +1,163 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// XML object.
/// </summary>
public abstract class AXmlObject : ISegment
{
readonly AXmlObject parent;
internal readonly int startOffset;
internal readonly InternalObject internalObject;
IList<AXmlObject> children;
internal AXmlObject(AXmlObject parent, int startOffset, InternalObject internalObject)
{
this.parent = parent;
this.startOffset = startOffset;
this.internalObject = internalObject;
}
/// <summary>
/// Gets the parent node.
/// </summary>
public AXmlObject Parent {
get { return parent; }
}
/// <summary>
/// Gets the list of child objects.
/// </summary>
public IList<AXmlObject> Children {
get {
var result = this.children;
if (result != null) {
LazyInit.ReadBarrier();
return result;
} else {
if (internalObject.NestedObjects != null) {
var array = new AXmlObject[internalObject.NestedObjects.Length];
for (int i = 0; i < array.Length; i++) {
array[i] = internalObject.NestedObjects[i].CreatePublicObject(this, startOffset);
}
result = Array.AsReadOnly(array);
} else {
result = EmptyList<AXmlObject>.Instance;
}
return LazyInit.GetOrSet(ref this.children, result);
}
}
}
/// <summary>
/// The error that occured in the context of this node (excluding nested nodes)
/// </summary>
public IEnumerable<SyntaxError> MySyntaxErrors {
get {
if (internalObject.SyntaxErrors != null) {
return internalObject.SyntaxErrors.Select(e => new SyntaxError(startOffset + e.RelativeStart, startOffset + e.RelativeEnd, e.Description));
} else {
return EmptyList<SyntaxError>.Instance;
}
}
}
/// <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 TreeTraversal.PreOrder(this, n => n.Children).SelectMany(obj => obj.MySyntaxErrors);
}
}
/// <summary> Get all ancestors of this node </summary>
public IEnumerable<AXmlObject> Ancestors {
get {
AXmlObject curr = this.Parent;
while(curr != null) {
yield return curr;
curr = curr.Parent;
}
}
}
#region Helper methods
/// <summary> The part of name before ":" </summary>
/// <returns> Empty string if not found </returns>
protected static string GetNamespacePrefix(string name)
{
if (string.IsNullOrEmpty(name)) return string.Empty;
int colonIndex = name.IndexOf(':');
if (colonIndex != -1) {
return name.Substring(0, colonIndex);
} else {
return string.Empty;
}
}
/// <summary> The part of name after ":" </summary>
/// <returns> Whole name if ":" not found </returns>
protected static string GetLocalName(string name)
{
if (string.IsNullOrEmpty(name)) return string.Empty;
int colonIndex = name.IndexOf(':');
if (colonIndex != -1) {
return name.Remove(0, colonIndex + 1);
} else {
return name ?? string.Empty;
}
}
#endregion
/// <summary> Call appropriate visit method on the given visitor </summary>
public abstract void AcceptVisitor(IAXmlVisitor visitor);
/// <summary>
/// Gets the start offset of the segment.
/// </summary>
public int StartOffset {
get { return startOffset; }
}
int ISegment.Offset {
get { return startOffset; }
}
/// <inheritdoc/>
public int Length {
get { return internalObject.Length; }
}
/// <inheritdoc/>
public int EndOffset {
get { return startOffset + internalObject.Length; }
}
}
}

91
ICSharpCode.NRefactory.Xml/AXmlTag.cs

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.ObjectModel;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// Represents any markup starting with "&lt;" and (hopefully) ending with ">"
/// </summary>
public class AXmlTag : AXmlObject
{
/// <summary> These identify the start of DTD elements </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification="ReadOnlyCollection is immutable")]
public static readonly ReadOnlyCollection<string> DtdNames = new ReadOnlyCollection<string>(
new string[] {"<!DOCTYPE", "<!NOTATION", "<!ELEMENT", "<!ATTLIST", "<!ENTITY" } );
new readonly InternalTag internalObject;
internal AXmlTag(AXmlObject parent, int startOffset, InternalTag internalObject)
: base(parent, startOffset, internalObject)
{
this.internalObject = internalObject;
}
/// <summary> Opening bracket - usually "&lt;" </summary>
public string OpeningBracket {
get { return internalObject.OpeningBracket; }
}
/// <summary> Name following the opening bracket </summary>
public string Name {
get { return internalObject.Name; }
}
/// <summary> Gets the segment containing the tag name </summary>
public ISegment NameSegment {
get {
int start = startOffset + internalObject.RelativeNameStart;
return new XmlSegment(start, start + internalObject.Name.Length);
}
}
/// <summary> Closing bracket - usually "&gt;" </summary>
public string ClosingBracket {
get { return internalObject.ClosingBracket; }
}
/// <summary> True if tag starts with "&lt;" </summary>
public bool IsStartOrEmptyTag { get { return internalObject.IsStartOrEmptyTag; } }
/// <summary> True if tag starts with "&lt;" and ends with "&gt;" </summary>
public bool IsStartTag { get { return internalObject.IsStartOrEmptyTag && ClosingBracket == ">"; } }
/// <summary> True if tag starts with "&lt;" and does not end with "&gt;" </summary>
public bool IsEmptyTag { get { return internalObject.IsStartOrEmptyTag && ClosingBracket != ">" ; } }
/// <summary> True if tag starts with "&lt;/" </summary>
public bool IsEndTag { get { return internalObject.IsEndTag; } }
/// <summary> True if tag starts with "&lt;?" </summary>
public bool IsProcessingInstruction { get { return internalObject.IsProcessingInstruction; } }
/// <summary> True if tag starts with "&lt;!--" </summary>
public bool IsComment { get { return internalObject.IsComment; } }
/// <summary> True if tag starts with "&lt;![CDATA[" </summary>
public bool IsCData { get { return internalObject.IsCData; } }
/// <summary> True if tag starts with one of the DTD starts </summary>
public bool IsDocumentType { get { return internalObject.IsDocumentType; } }
/// <summary> True if tag starts with "&lt;!" </summary>
public bool IsUnknownBang { get { return internalObject.IsUnknownBang; } }
/// <inheritdoc/>
public override void AcceptVisitor(IAXmlVisitor visitor)
{
visitor.VisitTag(this);
}
}
}

51
ICSharpCode.NRefactory.Xml/AXmlText.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// Whitespace or character data
/// </summary>
public class AXmlText : AXmlObject
{
internal AXmlText(AXmlObject parent, int startOffset, InternalText internalObject)
: base(parent, startOffset, internalObject)
{
}
/// <summary> The text with all entity references resloved </summary>
public string Value {
get { return ((InternalText)internalObject).Value; }
}
/// <summary> True if the text contains only whitespace characters </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Whitespace",
Justification = "System.Xml also uses 'Whitespace'")]
public bool ContainsOnlyWhitespace {
get { return ((InternalText)internalObject).ContainsOnlyWhitespace; }
}
/// <inheritdoc/>
public override void AcceptVisitor(IAXmlVisitor visitor)
{
visitor.VisitText(this);
}
}
}

37
ICSharpCode.NRefactory.Xml/IAXmlVisitor.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// Visitor for the XML tree
/// </summary>
public interface IAXmlVisitor
{
/// <summary> Visit tag </summary>
void VisitTag(AXmlTag tag);
/// <summary> Visit attribute </summary>
void VisitAttribute(AXmlAttribute attribute);
/// <summary> Visit text </summary>
void VisitText(AXmlText text);
}
}

79
ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj

@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.NRefactory.Xml</RootNamespace>
<AssemblyName>ICSharpCode.NRefactory.Xml</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<DocumentationFile>..\ICSharpCode.NRefactory\bin\$(Configuration)\ICSharpCode.NRefactory.Xml.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\ICSharpCode.NRefactory\bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>..\ICSharpCode.NRefactory\bin\Release\</OutputPath>
<DebugSymbols>false</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\ICSharpCode.NRefactory\Properties\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AXmlAttribute.cs" />
<Compile Include="AXmlObject.cs" />
<Compile Include="AXmlTag.cs" />
<Compile Include="AXmlText.cs" />
<Compile Include="IAXmlVisitor.cs" />
<Compile Include="IncrementalParserState.cs" />
<Compile Include="InternalDocument.cs" />
<Compile Include="SyntaxError.cs" />
<Compile Include="TextType.cs" />
<Compile Include="Log.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TagReader.cs" />
<Compile Include="TagSoupParser.cs" />
<Compile Include="TokenReader.cs" />
<Compile Include="XmlSegment.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

32
ICSharpCode.NRefactory.Xml/IncrementalParserState.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// Encapsulates the state of the incremental tag soup parser.
/// </summary>
public class IncrementalParserState
{
internal IncrementalParserState()
{
}
}
}

107
ICSharpCode.NRefactory.Xml/InternalDocument.cs

@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.NRefactory.Xml
{
abstract class InternalObject
{
internal int StartRelativeToParent;
internal int Length;
internal InternalSyntaxError[] SyntaxErrors;
internal InternalObject[] NestedObjects;
internal InternalObject SetStartRelativeToParent(int newStartRelativeToParent)
{
if (newStartRelativeToParent == StartRelativeToParent)
return this;
InternalObject obj = (InternalObject)MemberwiseClone();
obj.StartRelativeToParent = newStartRelativeToParent;
return obj;
}
public abstract AXmlObject CreatePublicObject(AXmlObject parent, int parentStartOffset);
}
sealed class InternalText : InternalObject
{
internal TextType Type;
internal bool ContainsOnlyWhitespace;
internal string Value;
public override AXmlObject CreatePublicObject(AXmlObject parent, int parentStartOffset)
{
return new AXmlText(parent, parentStartOffset + StartRelativeToParent, this);
}
}
sealed class InternalTag : InternalObject
{
internal string OpeningBracket;
internal int RelativeNameStart;
internal string Name;
internal string ClosingBracket;
/// <summary> True if tag starts with "&lt;" </summary>
public bool IsStartOrEmptyTag { get { return OpeningBracket == "<"; } }
/// <summary> True if tag starts with "&lt;/" </summary>
public bool IsEndTag { get { return OpeningBracket == "</"; } }
/// <summary> True if tag starts with "&lt;?" </summary>
public bool IsProcessingInstruction { get { return OpeningBracket == "<?"; } }
/// <summary> True if tag starts with "&lt;!--" </summary>
public bool IsComment { get { return OpeningBracket == "<!--"; } }
/// <summary> True if tag starts with "&lt;![CDATA[" </summary>
public bool IsCData { get { return OpeningBracket == "<![CDATA["; } }
/// <summary> True if tag starts with one of the DTD starts </summary>
public bool IsDocumentType { get { return AXmlTag.DtdNames.Contains(OpeningBracket); } }
/// <summary> True if tag starts with "&lt;!" </summary>
public bool IsUnknownBang { get { return OpeningBracket == "<!"; } }
public override AXmlObject CreatePublicObject(AXmlObject parent, int parentStartOffset)
{
return new AXmlTag(parent, parentStartOffset + StartRelativeToParent, this);
}
}
struct InternalSyntaxError
{
internal readonly int RelativeStart;
internal readonly int RelativeEnd;
internal readonly string Description;
public InternalSyntaxError(int relativeStart, int relativeEnd, string description)
{
this.RelativeStart = relativeStart;
this.RelativeEnd = relativeEnd;
this.Description = description;
}
}
class InternalAttribute : InternalObject
{
internal string Name;
internal int EqualsSignLength; // length of equals sign including the surrounding whitespace
internal string Value;
public override AXmlObject CreatePublicObject(AXmlObject parent, int parentStartOffset)
{
return new AXmlAttribute(parent, parentStartOffset + StartRelativeToParent, this);
}
}
}

88
ICSharpCode.NRefactory.Xml/Log.cs

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Runtime.Serialization;
namespace ICSharpCode.NRefactory.Xml
{
static class Log
{
/// <summary> Throws exception if condition is false </summary>
internal static void Assert(bool condition, string message)
{
if (!condition) {
throw new InternalException("Assertion failed: " + message);
}
}
/// <summary> Throws exception if condition is false </summary>
[Conditional("DEBUG")]
internal static void DebugAssert(bool condition, string message)
{
if (!condition) {
throw new InternalException("Assertion failed: " + message);
}
}
[Conditional("DEBUG")]
internal static void WriteLine(string text, params object[] pars)
{
//System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "XML: " + text, pars));
}
}
/// <summary>
/// Exception used for internal errors in XML parser.
/// This exception indicates a bug in NRefactory.
/// </summary>
[Serializable]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic", Justification = "This exception is not public because it is not supposed to be caught by user code - it indicates a bug in AvalonEdit.")]
class InternalException : Exception
{
/// <summary>
/// Creates a new InternalException instance.
/// </summary>
public InternalException() : base()
{
}
/// <summary>
/// Creates a new InternalException instance.
/// </summary>
public InternalException(string message) : base(message)
{
}
/// <summary>
/// Creates a new InternalException instance.
/// </summary>
public InternalException(string message, Exception innerException) : base(message, innerException)
{
}
/// <summary>
/// Creates a new InternalException instance.
/// </summary>
protected InternalException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}

15
ICSharpCode.NRefactory.Xml/Properties/AssemblyInfo.cs

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ICSharpCode.NRefactory.Xml")]
[assembly: AssemblyDescription("Error-tolerant XML parser")]
[assembly: CLSCompliant(true)]

63
ICSharpCode.NRefactory.Xml/SyntaxError.cs

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
/*
* Created by SharpDevelop.
* User: Daniel
* Date: 2/20/2012
* Time: 17:46
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// A syntax error.
/// </summary>
public class SyntaxError : ISegment
{
readonly int startOffset;
readonly int endOffset;
readonly string description;
/// <summary>
/// Creates a new syntax error.
/// </summary>
public SyntaxError(int startOffset, int endOffset, string description)
{
if (description == null)
throw new ArgumentNullException("description");
this.startOffset = startOffset;
this.endOffset = endOffset;
this.description = description;
}
/// <summary>
/// Gets a description of the syntax error.
/// </summary>
public string Description {
get { return description; }
}
/// <summary>
/// Gets the start offset of the segment.
/// </summary>
public int StartOffset {
get { return startOffset; }
}
int ISegment.Offset {
get { return startOffset; }
}
/// <inheritdoc/>
public int Length {
get { return endOffset - startOffset; }
}
/// <inheritdoc/>
public int EndOffset {
get { return endOffset; }
}
}
}

755
ICSharpCode.NRefactory.Xml/TagReader.cs

@ -0,0 +1,755 @@ @@ -0,0 +1,755 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
class TagReader : TokenReader
{
readonly TagSoupParser tagSoupParser;
public TagReader(TagSoupParser tagSoupParser, ITextSource input) : base(input)
{
this.tagSoupParser = tagSoupParser;
}
public InternalObject[] ReadAllObjects()
{
while (HasMoreData()) {
ReadObject();
}
var arr = objects.ToArray();
objects.Clear();
return arr;
}
/// <summary>
/// Reads one or more objects.
/// </summary>
void ReadObject()
{
if (TryPeek('<')) {
ReadTag();
} else {
ReadText(TextType.CharacterData);
}
}
#region BeginInternalObject / EndInternalObject
List<InternalObject> objects = new List<InternalObject>();
int internalObjectStartPosition;
int CurrentRelativeLocation {
get { return CurrentLocation - internalObjectStartPosition; }
}
struct InternalObjectFrame
{
public readonly InternalObject InternalObject;
public readonly int ParentStartPosition;
public InternalObjectFrame(InternalObject internalObject, int parentStartPosition)
{
this.InternalObject = internalObject;
this.ParentStartPosition = parentStartPosition;
}
}
InternalObjectFrame BeginInternalObject(InternalObject internalObject)
{
return BeginInternalObject(internalObject, this.CurrentLocation);
}
InternalObjectFrame BeginInternalObject(InternalObject internalObject, int beginLocation)
{
internalObject.StartRelativeToParent = beginLocation - internalObjectStartPosition;
var frame = new InternalObjectFrame(internalObject, internalObjectStartPosition);
internalObjectStartPosition = CurrentLocation;
return frame;
}
void EndInternalObject(InternalObjectFrame frame, bool storeNewObject = true)
{
frame.InternalObject.Length = this.CurrentRelativeLocation;
frame.InternalObject.SyntaxErrors = GetSyntaxErrors();
if (storeNewObject)
objects.Add(frame.InternalObject);
internalObjectStartPosition = frame.ParentStartPosition;
}
#endregion
#region Read Tag
/// <summary>
/// Context: "&lt;"
/// </summary>
void ReadTag()
{
AssertHasMoreData();
int tagStart = this.CurrentLocation;
InternalTag tag = new InternalTag();
var frame = BeginInternalObject(tag);
// Read the opening bracket
// It identifies the type of tag and parsing behavior for the rest of it
tag.OpeningBracket = ReadOpeningBracket();
if (tag.IsUnknownBang && !TryPeekWhiteSpace())
OnSyntaxError(tagStart, this.CurrentLocation, "Unknown tag");
if (tag.IsStartOrEmptyTag || tag.IsEndTag || tag.IsProcessingInstruction) {
// Read the name
TryMoveToNonWhiteSpace();
tag.RelativeNameStart = this.CurrentRelativeLocation;
string name;
if (TryReadName(out name)) {
if (!IsValidName(name)) {
OnSyntaxError(this.CurrentLocation - name.Length, this.CurrentLocation, "The name '{0}' is invalid", name);
}
} else {
OnSyntaxError("Element name expected");
}
tag.Name = name;
} else {
tag.Name = string.Empty;
}
bool isXmlDeclr = tag.Name == "xml" && tag.IsProcessingInstruction;
int oldObjectCount = objects.Count;
if (tag.IsStartOrEmptyTag || tag.IsEndTag || isXmlDeclr) {
// Read attributes for the tag
while (HasMoreData()) {
// Chech for all forbiden 'name' characters first - see ReadName
TryMoveToNonWhiteSpace();
if (TryPeek('<')) break;
string endBr;
int endBrStart = this.CurrentLocation; // Just peek
if (TryReadClosingBracket(out endBr)) { // End tag
GoBack(endBrStart);
break;
}
// We have "=\'\"" or name - read attribute
int attrStartOffset = this.CurrentLocation;
ReadAttribute();
if (tag.IsEndTag)
OnSyntaxError(attrStartOffset, this.CurrentLocation, "Attribute not allowed in end tag.");
}
} else if (tag.IsDocumentType) {
ReadContentOfDTD();
} else {
int start = this.CurrentLocation;
if (tag.IsComment) {
ReadText(TextType.Comment);
} else if (tag.IsCData) {
ReadText(TextType.CData);
} else if (tag.IsProcessingInstruction) {
ReadText(TextType.ProcessingInstruction);
} else if (tag.IsUnknownBang) {
ReadText(TextType.UnknownBang);
} else {
throw new InternalException(string.Format(CultureInfo.InvariantCulture, "Unknown opening bracket '{0}'", tag.OpeningBracket));
}
// Backtrack at complete start
if (IsEndOfFile() || (tag.IsUnknownBang && TryPeek('<'))) {
GoBack(start);
objects.RemoveRange(oldObjectCount, objects.Count - oldObjectCount);
}
}
// Read closing bracket
string bracket;
TryReadClosingBracket(out bracket);
tag.ClosingBracket = bracket;
// Error check
int brStart = this.CurrentLocation - (tag.ClosingBracket ?? string.Empty).Length;
int brEnd = this.CurrentLocation;
if (tag.Name == null) {
// One error was reported already
} else if (tag.IsStartOrEmptyTag) {
if (tag.ClosingBracket != ">" && tag.ClosingBracket != "/>") OnSyntaxError(brStart, brEnd, "'>' or '/>' expected");
} else if (tag.IsEndTag) {
if (tag.ClosingBracket != ">") OnSyntaxError(brStart, brEnd, "'>' expected");
} else if (tag.IsComment) {
if (tag.ClosingBracket != "-->") OnSyntaxError(brStart, brEnd, "'-->' expected");
} else if (tag.IsCData) {
if (tag.ClosingBracket != "]]>") OnSyntaxError(brStart, brEnd, "']]>' expected");
} else if (tag.IsProcessingInstruction) {
if (tag.ClosingBracket != "?>") OnSyntaxError(brStart, brEnd, "'?>' expected");
} else if (tag.IsUnknownBang) {
if (tag.ClosingBracket != ">") OnSyntaxError(brStart, brEnd, "'>' expected");
} else if (tag.IsDocumentType) {
if (tag.ClosingBracket != ">") OnSyntaxError(brStart, brEnd, "'>' expected");
} else {
throw new InternalException(string.Format(CultureInfo.InvariantCulture, "Unknown opening bracket '{0}'", tag.OpeningBracket));
}
// Attribute name may not apper multiple times
if (objects.Count > oldObjectCount) {
// Move nested objects into tag.NestedObjects:
tag.NestedObjects = new InternalObject[objects.Count - oldObjectCount];
objects.CopyTo(oldObjectCount, tag.NestedObjects, 0, tag.NestedObjects.Length);
objects.RemoveRange(oldObjectCount, objects.Count - oldObjectCount);
// Look for duplicate attributes:
HashSet<string> attributeNames = new HashSet<string>();
foreach (var obj in tag.NestedObjects) {
InternalAttribute attr = obj as InternalAttribute;
if (attr != null && attributeNames.Add(attr.Name)) {
int attrStart = tagStart + attr.StartRelativeToParent;
OnSyntaxError(attrStart, attrStart + attr.Name.Length, "Attribute with name '{0}' already exists", attr.Name);
}
}
}
EndInternalObject(frame);
}
#endregion
#region Read DTD
void ReadContentOfDTD()
{
int start = this.CurrentLocation;
while (HasMoreData()) {
TryMoveToNonWhiteSpace(); // Skip whitespace
if (TryRead('\'')) TryMoveTo('\''); // Skip single quoted string TODO: Bug
if (TryRead('\"')) TryMoveTo('\"'); // Skip single quoted string
if (TryRead('[')) { // Start of nested infoset
// Reading infoset
while (HasMoreData()) {
TryMoveToAnyOf('<', ']');
if (TryPeek('<')) {
if (start != this.CurrentLocation) { // Two following tags
MakeText(start, this.CurrentLocation);
}
ReadTag();
start = this.CurrentLocation;
}
if (TryPeek(']')) break;
}
}
TryRead(']'); // End of nested infoset
if (TryPeek('>')) break; // Proper closing
if (TryPeek('<')) break; // Malformed XML
TryMoveNext(); // Skip anything else
}
if (start != this.CurrentLocation) {
MakeText(start, this.CurrentLocation);
}
}
void MakeText(int start, int end)
{
Log.DebugAssert(end > start, "Empty text");
Log.DebugAssert(end == this.CurrentLocation, "end == current location");
InternalText text = new InternalText();
var frame = BeginInternalObject(text, start);
text.Type = TextType.Other;
text.Value = GetText(start, end);
EndInternalObject(frame);
}
#endregion
#region Read Brackets
/// <summary>
/// Reads any of the know opening brackets. (only full bracket)
/// Context: "&lt;"
/// </summary>
string ReadOpeningBracket()
{
// We are using a lot of string literals so that the memory instances are shared
//int start = this.CurrentLocation;
if (TryRead('<')) {
if (TryRead('/')) {
return "</";
} else if (TryRead('?')) {
return "<?";
} else if (TryRead('!')) {
if (TryRead("--")) {
return "<!--";
} else if (TryRead("[CDATA[")) {
return "<![CDATA[";
} else {
foreach (string dtdName in AXmlTag.DtdNames) {
// the dtdName includes "<!"
if (TryRead(dtdName.Remove(0, 2))) return dtdName;
}
return "<!";
}
} else {
return "<";
}
} else {
throw new InternalException("'<' expected");
}
}
/// <summary>
/// Reads any of the know closing brackets. (only full bracket)
/// Context: any
/// </summary>
bool TryReadClosingBracket(out string bracket)
{
// We are using a lot of string literals so that the memory instances are shared
if (TryRead('>')) {
bracket = ">";
} else if (TryRead("/>")) {
bracket = "/>";
} else if (TryRead("?>")) {
bracket = "?>";
} else if (TryRead("-->")) {
bracket = "-->";
} else if (TryRead("]]>")) {
bracket = "]]>";
} else {
bracket = string.Empty;
return false;
}
return true;
}
#endregion
#region Attributes
/// <summary>
/// Context: name or "=\'\""
/// </summary>
void ReadAttribute()
{
AssertHasMoreData();
InternalAttribute attr = new InternalAttribute();
var frame = BeginInternalObject(attr);
// Read name
string name;
if (TryReadName(out name)) {
if (!IsValidName(name)) {
OnSyntaxError(this.CurrentLocation - name.Length, this.CurrentLocation, "The name '{0}' is invalid", name);
}
} else {
OnSyntaxError("Attribute name expected");
}
attr.Name = name;
// Read equals sign and surrounding whitespace
int checkpoint = this.CurrentLocation;
TryMoveToNonWhiteSpace();
if (TryRead('=')) {
int chk2 = this.CurrentLocation;
TryMoveToNonWhiteSpace();
if (!TryPeek('"') && !TryPeek('\'')) {
// Do not read whitespace if quote does not follow
GoBack(chk2);
}
attr.EqualsSignLength = this.CurrentLocation - checkpoint;
} else {
GoBack(checkpoint);
OnSyntaxError("'=' expected");
attr.EqualsSignLength = 0;
}
// Read attribute value
int start = this.CurrentLocation;
char quoteChar = TryPeek('"') ? '"' : '\'';
bool startsWithQuote;
if (TryRead(quoteChar)) {
startsWithQuote = true;
int valueStart = this.CurrentLocation;
TryMoveToAnyOf(quoteChar, '<');
if (TryRead(quoteChar)) {
if (!TryPeekAnyOf(' ', '\t', '\n', '\r', '/', '>', '?')) {
if (TryPeekPrevious('=', 2) || (TryPeekPrevious('=', 3) && TryPeekPrevious(' ', 2))) {
// This actually most likely means that we are in the next attribute value
GoBack(valueStart);
ReadAttributeValue(quoteChar);
if (TryRead(quoteChar)) {
OnSyntaxError("White space or end of tag expected");
} else {
OnSyntaxError("Quote {0} expected (or add whitespace after the following one)", quoteChar);
}
} else {
OnSyntaxError("White space or end of tag expected");
}
}
} else {
// '<' or end of file
GoBack(valueStart);
ReadAttributeValue(quoteChar);
OnSyntaxError("Quote {0} expected", quoteChar);
}
} else {
startsWithQuote = false;
int valueStart = this.CurrentLocation;
ReadAttributeValue(null);
TryRead('\"');
TryRead('\'');
if (valueStart == this.CurrentLocation) {
OnSyntaxError("Attribute value expected");
} else {
OnSyntaxError(valueStart, this.CurrentLocation, "Attribute value must be quoted");
}
}
string val = GetText(start, this.CurrentLocation);
val = Unquote(val);
attr.Value = Dereference(val, startsWithQuote ? start + 1 : start);
EndInternalObject(frame);
}
/// <summary>
/// Read everything up to quote (excluding), opening/closing tag or attribute signature
/// </summary>
void ReadAttributeValue(char? quote)
{
while (HasMoreData()) {
// What is next?
int start = this.CurrentLocation;
TryMoveToNonWhiteSpace(); // Read white space (if any)
if (quote.HasValue) {
if (TryPeek(quote.Value)) return;
} else {
if (TryPeek('"') || TryPeek('\'')) return;
}
// Opening/closing tag
string endBr;
if (TryPeek('<') || TryReadClosingBracket(out endBr)) {
GoBack(start);
return;
}
// Try reading attribute signature
if (TryReadName()) {
int nameEnd = this.CurrentLocation;
if (TryMoveToNonWhiteSpace() && TryRead("=") &&
TryMoveToNonWhiteSpace() && TryPeekAnyOf('"', '\''))
{
// Start of attribute. Great
GoBack(start);
return; // Done
} else {
// Just some gargabe - make it part of the value
GoBack(nameEnd);
continue; // Read more
}
}
TryMoveNext(); // Accept everyting else
}
}
/// <summary> Remove quoting from the given string </summary>
static string Unquote(string quoted)
{
if (string.IsNullOrEmpty(quoted)) return string.Empty;
char first = quoted[0];
if (quoted.Length == 1) return (first == '"' || first == '\'') ? string.Empty : quoted;
char last = quoted[quoted.Length - 1];
if (first == '"' || first == '\'') {
if (first == last) {
// Remove both quotes
return quoted.Substring(1, quoted.Length - 2);
} else {
// Remove first quote
return quoted.Remove(0, 1);
}
} else {
if (last == '"' || last == '\'') {
// Remove last quote
return quoted.Substring(0, quoted.Length - 1);
} else {
// Keep whole string
return quoted;
}
}
}
#endregion
#region Text
/// <summary>
/// Reads text and optionaly separates it into fragments.
/// It can also return empty set for no appropriate text input.
/// Make sure you enumerate it only once
/// </summary>
void ReadText(TextType type)
{
const int maxTextFragmentSize = 128;
bool finished;
do {
var text = new InternalText();
var frame = BeginInternalObject(text);
text.Type = type;
// Limit the reading to just a few characters
// (the first character not to be read)
int fragmentEnd = Math.Min(this.CurrentLocation + maxTextFragmentSize, this.InputLength);
int start = this.CurrentLocation;
// Whitespace would be skipped anyway by any operation
TryMoveToNonWhiteSpace(fragmentEnd);
int wsEnd = this.CurrentLocation;
// Try move to the terminator given by the context
if (type == TextType.WhiteSpace) {
TryMoveToNonWhiteSpace(fragmentEnd);
} else if (type == TextType.CharacterData) {
while(true) {
if (!TryMoveToAnyOf(new char[] {'<', ']'}, fragmentEnd)) break; // End of fragment
if (TryPeek('<')) break;
if (TryPeek(']')) {
if (TryPeek("]]>")) {
OnSyntaxError(this.CurrentLocation, this.CurrentLocation + 3, "']]>' is not allowed in text");
}
TryMoveNext();
continue;
}
throw new InternalException("Infinite loop");
}
} else if (type == TextType.Comment) {
// Do not report too many errors
bool errorReported = false;
while(true) {
if (!TryMoveTo('-', fragmentEnd)) break; // End of fragment
if (TryPeek("-->")) break;
if (TryPeek("--") && !errorReported) {
OnSyntaxError(this.CurrentLocation, this.CurrentLocation + 2, "'--' is not allowed in comment");
errorReported = true;
}
TryMoveNext();
}
} else if (type == TextType.CData) {
while(true) {
// We can not use use TryMoveTo("]]>", fragmentEnd) because it may incorectly accept "]" at the end of fragment
if (!TryMoveTo(']', fragmentEnd)) break; // End of fragment
if (TryPeek("]]>")) break;
TryMoveNext();
}
} else if (type == TextType.ProcessingInstruction) {
while(true) {
if (!TryMoveTo('?', fragmentEnd)) break; // End of fragment
if (TryPeek("?>")) break;
TryMoveNext();
}
} else if (type == TextType.UnknownBang) {
TryMoveToAnyOf(new char[] {'<', '>'}, fragmentEnd);
} else {
throw new InternalException("Uknown type " + type);
}
text.ContainsOnlyWhitespace = (wsEnd == this.CurrentLocation);
// Terminal found or real end was reached;
finished = this.CurrentLocation < fragmentEnd || IsEndOfFile();
if (!finished) {
// We have to continue reading more text fragments
// If there is entity reference, make sure the next segment starts with it to prevent framentation
int entitySearchStart = Math.Max(start + 1 /* data for us */, this.CurrentLocation - maxEntityLength);
int entitySearchLength = this.CurrentLocation - entitySearchStart;
if (entitySearchLength > 0) {
// Note that LastIndexOf works backward
int entityIndex = input.LastIndexOf('&', this.CurrentLocation - entitySearchLength, entitySearchLength);
if (entityIndex != -1) {
GoBack(entityIndex);
}
}
}
string escapedValue = GetText(start, this.CurrentLocation);
if (type == TextType.CharacterData) {
// Normalize end of line first
text.Value = Dereference(NormalizeEndOfLine(escapedValue), start);
} else {
text.Value = escapedValue;
}
text.Value = GetCachedString(text.Value);
EndInternalObject(frame, storeNewObject: this.CurrentLocation > start);
} while (!finished);
}
#endregion
#region Dereference
const int maxEntityLength = 16; // The longest built-in one is 10 ("&#1114111;")
string Dereference(string text, int textLocation)
{
StringBuilder sb = null; // The dereferenced text so far (all up to 'curr')
int curr = 0;
while(true) {
// Reached end of input
if (curr == text.Length) {
if (sb != null) {
return sb.ToString();
} else {
return text;
}
}
// Try to find reference
int start = text.IndexOf('&', curr);
// No more references found
if (start == -1) {
if (sb != null) {
sb.Append(text, curr, text.Length - curr); // Add rest
return sb.ToString();
} else {
return text;
}
}
// Append text before the enitiy reference
if (sb == null) sb = new StringBuilder(text.Length);
sb.Append(text, curr, start - curr);
curr = start;
// Process the entity
int errorLoc = textLocation + sb.Length;
// Find entity name
int end = text.IndexOfAny(new char[] {'&', ';'}, start + 1, Math.Min(maxEntityLength, text.Length - (start + 1)));
if (end == -1 || text[end] == '&') {
// Not found
OnSyntaxError(errorLoc, errorLoc + 1, "Entity reference must be terminated with ';'");
// Keep '&'
sb.Append('&');
curr++;
continue; // Restart and next character location
}
string name = text.Substring(start + 1, end - (start + 1));
// Resolve the name
string replacement;
if (name.Length == 0) {
replacement = null;
OnSyntaxError(errorLoc + 1, errorLoc + 1, "Entity name expected");
} else if (name == "amp") {
replacement = "&";
} else if (name == "lt") {
replacement = "<";
} else if (name == "gt") {
replacement = ">";
} else if (name == "apos") {
replacement = "'";
} else if (name == "quot") {
replacement = "\"";
} else if (name.Length > 0 && name[0] == '#') {
int num;
if (name.Length > 1 && name[1] == 'x') {
if (!int.TryParse(name.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat, out num)) {
num = -1;
OnSyntaxError(errorLoc + 3, errorLoc + 1 + name.Length, "Hexadecimal code of unicode character expected");
}
} else {
if (!int.TryParse(name.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out num)) {
num = -1;
OnSyntaxError(errorLoc + 2, errorLoc + 1 + name.Length, "Numeric code of unicode character expected");
}
}
if (num != -1) {
try {
replacement = char.ConvertFromUtf32(num);
} catch (ArgumentOutOfRangeException) {
replacement = null;
OnSyntaxError(errorLoc + 2, errorLoc + 1 + name.Length, "Invalid unicode character U+{0:X} ({0})", num);
}
} else {
replacement = null;
}
} else if (!IsValidName(name)) {
replacement = null;
OnSyntaxError(errorLoc + 1, errorLoc + 1, "Invalid entity name");
} else {
replacement = null;
if (tagSoupParser.UnknownEntityReferenceIsError) {
OnSyntaxError(errorLoc, errorLoc + 1 + name.Length + 1, "Unknown entity reference '{0}'", name);
}
}
// Append the replacement to output
if (replacement != null) {
sb.Append(replacement);
} else {
sb.Append('&');
sb.Append(name);
sb.Append(';');
}
curr = end + 1;
continue;
}
}
#endregion
#region Syntax Errors
List<InternalSyntaxError> syntaxErrors = new List<InternalSyntaxError>();
InternalSyntaxError[] GetSyntaxErrors()
{
if (syntaxErrors.Count > 0) {
var arr = syntaxErrors.ToArray();
syntaxErrors.Clear();
return arr;
} else {
return null;
}
}
void OnSyntaxError(string message, params object[] args)
{
OnSyntaxError(this.CurrentLocation, this.CurrentLocation + 1, message, args);
}
void OnSyntaxError(int start, int end, string message, params object[] args)
{
if (end <= start) end = start + 1;
string formattedMessage = string.Format(CultureInfo.InvariantCulture, message, args);
Log.WriteLine("Syntax error ({0}-{1}): {2}", start, end, formattedMessage);
syntaxErrors.Add(new InternalSyntaxError(start - internalObjectStartPosition, end - internalObjectStartPosition, formattedMessage));
}
#endregion
#region Helper functions
static bool IsValidName(string name)
{
try {
System.Xml.XmlConvert.VerifyName(name);
return true;
} catch (System.Xml.XmlException) {
return false;
}
}
static string NormalizeEndOfLine(string text)
{
return text.Replace("\r\n", "\n").Replace('\r', '\n');
}
#endregion
}
}

70
ICSharpCode.NRefactory.Xml/TagSoupParser.cs

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// XML tag soup parser that .
/// </summary>
public class TagSoupParser
{
/// <summary>
/// Generate syntax error when seeing entity reference other then the built-in ones
/// </summary>
public bool UnknownEntityReferenceIsError { get; set; }
/// <summary>
/// Parses a document.
/// </summary>
/// <returns>Parsed tag soup.</returns>
public IList<AXmlObject> Parse(ITextSource textSource)
{
if (textSource == null)
throw new ArgumentNullException("textSource");
var reader = new TagReader(this, textSource);
var internalObjects = reader.ReadAllObjects();
var publicObjects = new AXmlObject[internalObjects.Length];
int pos = 0;
for (int i = 0; i < internalObjects.Length; i++) {
publicObjects[i] = internalObjects[i].CreatePublicObject(null, pos);
pos += internalObjects[i].Length;
}
return Array.AsReadOnly(publicObjects);
}
/// <summary>
/// Parses a document incrementally.
/// </summary>
/// <param name="oldParserState">The parser state from a previous call to ParseIncremental(). Use null for the first call.</param>
/// <param name="newTextSource">The text source for the new document version.</param>
/// <param name="newParserState">Out: the new parser state, pass this to the next ParseIncremental() call.</param>
/// <returns>Parsed tag soup.</returns>
public IList<AXmlObject> ParseIncremental(IncrementalParserState oldParserState, ITextSource newTextSource, out IncrementalParserState newParserState)
{
if (newTextSource == null)
throw new ArgumentNullException("newTextSource");
// TODO: incremental parser
newParserState = null;
return Parse(newTextSource);
}
}
}

47
ICSharpCode.NRefactory.Xml/TextType.cs

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary> Identifies the context in which the text occured </summary>
enum TextType
{
/// <summary> Ends with non-whitespace </summary>
WhiteSpace,
/// <summary> Ends with "&lt;"; "]]&gt;" is error </summary>
CharacterData,
/// <summary> Ends with "-->"; "--" is error </summary>
Comment,
/// <summary> Ends with "]]&gt;" </summary>
CData,
/// <summary> Ends with "?>" </summary>
ProcessingInstruction,
/// <summary> Ends with "&lt;" or ">" </summary>
UnknownBang,
/// <summary> Unknown </summary>
Other
}
}

348
ICSharpCode.NRefactory.Xml/TokenReader.cs

@ -0,0 +1,348 @@ @@ -0,0 +1,348 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
class TokenReader
{
protected readonly ITextSource input;
protected readonly int inputLength;
int currentLocation;
// CurrentLocation is assumed to be touched and the fact does not
// have to be recorded in this variable.
// This stores any value bigger than that if applicable.
// Actual value is max(currentLocation, maxTouchedLocation).
int maxTouchedLocation;
public int InputLength {
get { return inputLength; }
}
public int CurrentLocation {
get { return currentLocation; }
}
public int MaxTouchedLocation {
get { return Math.Max(currentLocation, maxTouchedLocation); }
}
public TokenReader(ITextSource input)
{
this.input = input;
this.inputLength = input.TextLength;
}
protected bool IsEndOfFile()
{
return currentLocation == inputLength;
}
protected bool HasMoreData()
{
return currentLocation < inputLength;
}
protected void AssertHasMoreData()
{
Log.Assert(HasMoreData(), "Unexpected end of file");
}
protected bool TryMoveNext()
{
if (currentLocation == inputLength) return false;
currentLocation++;
return true;
}
protected void Skip(int count)
{
Log.Assert(currentLocation + count <= inputLength, "Skipping after the end of file");
currentLocation += count;
}
protected void GoBack(int oldLocation)
{
Log.Assert(oldLocation <= currentLocation, "Trying to move forward");
maxTouchedLocation = Math.Max(maxTouchedLocation, currentLocation);
currentLocation = oldLocation;
}
protected bool TryRead(char c)
{
if (currentLocation == inputLength) return false;
if (input.GetCharAt(currentLocation) == c) {
currentLocation++;
return true;
} else {
return false;
}
}
protected bool TryReadAnyOf(params char[] c)
{
if (currentLocation == inputLength) return false;
if (c.Contains(input.GetCharAt(currentLocation))) {
currentLocation++;
return true;
} else {
return false;
}
}
protected bool TryRead(string text)
{
if (TryPeek(text)) {
currentLocation += text.Length;
return true;
} else {
return false;
}
}
protected bool TryPeekPrevious(char c, int back)
{
if (currentLocation - back == inputLength) return false;
if (currentLocation - back < 0 ) return false;
return input.GetCharAt(currentLocation - back) == c;
}
protected bool TryPeek(char c)
{
if (currentLocation == inputLength) return false;
return input.GetCharAt(currentLocation) == c;
}
protected bool TryPeekAnyOf(params char[] chars)
{
if (currentLocation == inputLength) return false;
return chars.Contains(input.GetCharAt(currentLocation));
}
protected bool TryPeek(string text)
{
if (!TryPeek(text[0])) return false; // Early exit
maxTouchedLocation = Math.Max(maxTouchedLocation, currentLocation + (text.Length - 1));
// The following comparison 'touches' the end of file - it does depend on the end being there
if (currentLocation + text.Length > inputLength) return false;
return input.GetText(currentLocation, text.Length) == text;
}
protected bool TryPeekWhiteSpace()
{
if (currentLocation == inputLength) return false;
char c = input.GetCharAt(currentLocation);
return ((int)c <= 0x20) && (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
// The move functions do not have to move if already at target
// The move functions allow 'overriding' of the document length
protected bool TryMoveTo(char c)
{
return TryMoveTo(c, inputLength);
}
protected bool TryMoveTo(char c, int inputLength)
{
if (currentLocation == inputLength) return false;
int index = input.IndexOf(c, currentLocation, inputLength - currentLocation);
if (index != -1) {
currentLocation = index;
return true;
} else {
currentLocation = inputLength;
return false;
}
}
protected bool TryMoveToAnyOf(params char[] c)
{
return TryMoveToAnyOf(c, inputLength);
}
protected bool TryMoveToAnyOf(char[] c, int inputLength)
{
if (currentLocation == inputLength) return false;
int index = input.IndexOfAny(c, currentLocation, inputLength - currentLocation);
if (index != -1) {
currentLocation = index;
return true;
} else {
currentLocation = inputLength;
return false;
}
}
protected bool TryMoveTo(string text)
{
return TryMoveTo(text, inputLength);
}
protected bool TryMoveTo(string text, int inputLength)
{
if (currentLocation == inputLength) return false;
int index = input.IndexOf(text, currentLocation, inputLength - currentLocation, StringComparison.Ordinal);
if (index != -1) {
maxTouchedLocation = index + text.Length - 1;
currentLocation = index;
return true;
} else {
currentLocation = inputLength;
return false;
}
}
protected bool TryMoveToNonWhiteSpace()
{
return TryMoveToNonWhiteSpace(inputLength);
}
protected bool TryMoveToNonWhiteSpace(int inputLength)
{
while(true) {
if (currentLocation == inputLength) return false; // Reject end of file
char c = input.GetCharAt(currentLocation);
if (((int)c <= 0x20) && (c == ' ' || c == '\t' || c == '\n' || c == '\r')) {
currentLocation++; // Accept white-space
continue;
} else {
return true; // Found non-white-space
}
}
}
/// <summary>
/// Read a name token.
/// The following characters are not allowed:
/// "" End of file
/// " \n\r\t" Whitesapce
/// "=\'\"" Attribute value
/// "&lt;>/?" Tags
/// </summary>
/// <returns>Returns the length of the name</returns>
protected bool TryReadName()
{
int start = currentLocation;
// Keep reading up to invalid character
while (HasMoreData()) {
char c = input.GetCharAt(currentLocation);
if (0x41 <= (int)c) { // Accpet from 'A' onwards
currentLocation++;
continue;
}
if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || // Reject whitesapce
c == '=' || c == '\'' || c == '"' || // Reject attributes
c == '<' || c == '>' || c == '/' || c == '?') { // Reject tags
break;
} else {
currentLocation++;
continue; // Accept other character
}
}
return currentLocation > start;
}
protected bool TryReadName(out string name)
{
int start = currentLocation;
if (TryReadName()) {
name = GetCachedString(GetText(start, currentLocation));
return true;
} else {
name = string.Empty;
return false;
}
}
protected string GetText(int start, int end)
{
Log.Assert(end <= currentLocation, "Reading ahead of current location");
return input.GetText(start, end - start);
}
Dictionary<string, string> stringCache = new Dictionary<string, string>();
#if DEBUG
int stringCacheRequestedCount;
int stringCacheRequestedSize;
int stringCacheStoredCount;
int stringCacheStoredSize;
#endif
internal void PrintStringCacheStats()
{
#if DEBUG
Log.WriteLine("String cache: Requested {0} ({1} bytes); Actaully stored {2} ({3} bytes); {4}% stored", stringCacheRequestedCount, stringCacheRequestedSize, stringCacheStoredCount, stringCacheStoredSize, stringCacheRequestedSize == 0 ? 0 : stringCacheStoredSize * 100 / stringCacheRequestedSize);
#endif
}
[Conditional("DEBUG")]
void AddToRequestedSize(string text)
{
#if DEBUG
stringCacheRequestedCount += 1;
stringCacheRequestedSize += 8 + 2 * text.Length;
#endif
}
[Conditional("DEBUG")]
void AddToStoredSize(string text)
{
#if DEBUG
stringCacheStoredCount += 1;
stringCacheStoredSize += 8 + 2 * text.Length;
#endif
}
protected string GetCachedString(string cached)
{
AddToRequestedSize(cached);
// Do not bother with long strings
if (cached.Length > 32) {
AddToStoredSize(cached);
return cached;
}
string result;
if (stringCache.TryGetValue(cached, out result)) {
// Get the instance from the cache instead
return result;
} else {
// Add to cache
AddToStoredSize(cached);
stringCache.Add(cached, cached);
return cached;
}
}
}
}

48
ICSharpCode.NRefactory.Xml/XmlSegment.cs

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
sealed class XmlSegment : ISegment
{
readonly int startOffset, endOffset;
public XmlSegment(int startOffset, int endOffset)
{
if (endOffset < startOffset)
throw new ArgumentOutOfRangeException();
this.startOffset = startOffset;
this.endOffset = endOffset;
}
int ISegment.Offset {
get { return startOffset; }
}
int ISegment.Length {
get { return endOffset - startOffset; }
}
int ISegment.EndOffset {
get { return endOffset; }
}
}
}

20
ICSharpCode.NRefactory/Editor/ITextSource.cs

@ -93,6 +93,15 @@ namespace ICSharpCode.NRefactory.Editor @@ -93,6 +93,15 @@ namespace ICSharpCode.NRefactory.Editor
/// <exception cref="ArgumentOutOfRangeException">offset or length is outside the valid range.</exception>
string GetText(ISegment segment);
/// <summary>
/// Gets the index of the first occurrence of the character in the specified array.
/// </summary>
/// <param name="c">Character to search for</param>
/// <param name="startIndex">Start index of the area to search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The first index where the character was found; or -1 if no occurrence was found.</returns>
int IndexOf(char c, int startIndex, int count);
/// <summary>
/// Gets the index of the first occurrence of any character in the specified array.
/// </summary>
@ -112,6 +121,17 @@ namespace ICSharpCode.NRefactory.Editor @@ -112,6 +121,17 @@ namespace ICSharpCode.NRefactory.Editor
/// <returns>The first index where the search term was found; or -1 if no occurrence was found.</returns>
int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType);
/// <summary>
/// Gets the index of the last occurrence of the specified character in this text source.
/// </summary>
/// <param name="c">The search character</param>
/// <param name="startIndex">Start index of the area to search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The last index where the search term was found; or -1 if no occurrence was found.</returns>
/// <remarks>The search proceeds backwards from (startIndex+count) to startIndex.
/// This is different than the meaning of the parameters on string.LastIndexOf!</remarks>
int LastIndexOf(char c, int startIndex, int count);
/// <summary>
/// Gets the index of the last occurrence of the specified search text in this text source.
/// </summary>

12
ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs

@ -354,6 +354,12 @@ namespace ICSharpCode.NRefactory.Editor @@ -354,6 +354,12 @@ namespace ICSharpCode.NRefactory.Editor
return textSource.GetText(segment);
}
/// <inheritdoc/>
public int IndexOf(char c, int startIndex, int count)
{
return textSource.IndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
@ -366,6 +372,12 @@ namespace ICSharpCode.NRefactory.Editor @@ -366,6 +372,12 @@ namespace ICSharpCode.NRefactory.Editor
return textSource.IndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public int LastIndexOf(char c, int startIndex, int count)
{
return textSource.LastIndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{

12
ICSharpCode.NRefactory/Editor/StringTextSource.cs

@ -97,6 +97,12 @@ namespace ICSharpCode.NRefactory.Editor @@ -97,6 +97,12 @@ namespace ICSharpCode.NRefactory.Editor
return text.Substring(segment.Offset, segment.Length);
}
/// <inheritdoc/>
public int IndexOf(char c, int startIndex, int count)
{
return text.IndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
@ -109,6 +115,12 @@ namespace ICSharpCode.NRefactory.Editor @@ -109,6 +115,12 @@ namespace ICSharpCode.NRefactory.Editor
return text.IndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public int LastIndexOf(char c, int startIndex, int count)
{
return text.LastIndexOf(c, startIndex + count - 1, count);
}
/// <inheritdoc/>
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{

1
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -79,6 +79,7 @@ @@ -79,6 +79,7 @@
<Compile Include="PatternMatching\Pattern.cs" />
<Compile Include="Documentation\XmlDocumentationProvider.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\GlobalAssemblyInfo.cs" />
<Compile Include="Role.cs" />
<Compile Include="Semantics\AmbiguousResolveResult.cs" />
<Compile Include="Semantics\ArrayAccessResolveResult.cs" />

19
ICSharpCode.NRefactory/Properties/AssemblyInfo.cs

@ -10,23 +10,6 @@ using System.Runtime.InteropServices; @@ -10,23 +10,6 @@ using System.Runtime.InteropServices;
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ICSharpCode.NRefactory")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ICSharpCode")]
[assembly: AssemblyProduct("SharpDevelop/MonoDevelop")]
[assembly: AssemblyCopyright("Copyright 2010-2012 AlphaSierraPapa")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyDescription("Type system and other language-independent parts of NRefactory")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
[assembly: CLSCompliant(true)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("5.0.0.4")]

26
ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyCompany("ICSharpCode")]
[assembly: AssemblyProduct("SharpDevelop/MonoDevelop")]
[assembly: AssemblyCopyright("Copyright 2010-2012 AlphaSierraPapa")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("5.0.0.4")]

14
NRefactory.sln

@ -26,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.GtkD @@ -26,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.GtkD
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.ConsistencyCheck", "ICSharpCode.NRefactory.ConsistencyCheck\ICSharpCode.NRefactory.ConsistencyCheck.csproj", "{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.Xml", "ICSharpCode.NRefactory.Xml\ICSharpCode.NRefactory.Xml.csproj", "{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -91,13 +93,21 @@ Global @@ -91,13 +93,21 @@ Global
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_4_0_Release|Any CPU
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Debug|Any CPU.Build.0 = Debug|x86
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Debug|Any CPU.ActiveCfg = Debug|x86
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Debug|x86.Build.0 = Debug|x86
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Debug|x86.ActiveCfg = Debug|x86
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Release|Any CPU.Build.0 = Release|x86
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Release|Any CPU.ActiveCfg = Release|x86
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Release|x86.Build.0 = Release|x86
{D81206EF-3DCA-4A30-897B-E262A2AD9EE3}.Release|x86.ActiveCfg = Release|x86
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Debug|x86.Build.0 = Debug|Any CPU
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Debug|x86.ActiveCfg = Debug|Any CPU
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Release|Any CPU.Build.0 = Release|Any CPU
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Release|x86.Build.0 = Release|Any CPU
{DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = ICSharpCode.NRefactory.Demo\ICSharpCode.NRefactory.Demo.csproj

2
doc/XML Documentation.html

@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
</p>
<p>
When parsing C# code, the <code>TypeSystemConvertVisitor</code> will load the documentation
from the XML comments by default. (this can be disabled using <code>TODO</code>).
from the XML comments by default. (this can be disabled using the <code>SkipXmlDocumentation</code> property).
</p>
<p>
Internally, the type system does not store XML documentation - instead, the documentation is

Loading…
Cancel
Save