Fixed bug in alias resolution.

This commit is contained in:
Antoine Aubry 2011-09-26 13:27:12 +00:00
Родитель 9952b6d2a5
Коммит 453d4461da
11 изменённых файлов: 298 добавлений и 26 удалений

Просмотреть файл

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
namespace YamlDotNet.RepresentationModel
{
@ -10,7 +11,7 @@ namespace YamlDotNet.RepresentationModel
internal class DocumentLoadingState
{
private readonly IDictionary<string, YamlNode> anchors = new Dictionary<string, YamlNode>();
private readonly IDictionary<YamlNode, object> nodesWithUnresolvedAliases = new Dictionary<YamlNode, object>();
private readonly IList<YamlNode> nodesWithUnresolvedAliases = new List<YamlNode>();
/// <summary>
/// Adds the specified node to the anchor list.
@ -62,7 +63,7 @@ namespace YamlDotNet.RepresentationModel
/// </param>
public void AddNodeWithUnresolvedAliases(YamlNode node)
{
nodesWithUnresolvedAliases[node] = null;
nodesWithUnresolvedAliases.Add(node);
}
/// <summary>
@ -70,9 +71,19 @@ namespace YamlDotNet.RepresentationModel
/// </summary>
public void ResolveAliases()
{
foreach(var node in nodesWithUnresolvedAliases.Keys)
foreach(var node in nodesWithUnresolvedAliases)
{
node.ResolveAliases(this);
#if DEBUG
foreach (var child in node.AllNodes)
{
if (child is YamlAliasNode)
{
throw new InvalidOperationException("Error in alias resolution.");
}
}
#endif
}
}
}

Просмотреть файл

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using YamlDotNet.Core;
namespace YamlDotNet.RepresentationModel
@ -51,7 +52,7 @@ namespace YamlDotNet.RepresentationModel
public override bool Equals(object other)
{
var obj = other as YamlAliasNode;
return obj != null && Equals(obj);
return obj != null && Equals(obj) && SafeEquals(Anchor, obj.Anchor);
}
/// <summary>
@ -64,5 +65,24 @@ namespace YamlDotNet.RepresentationModel
{
return base.GetHashCode();
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return "*" + Anchor;
}
/// <summary>
/// Gets all nodes from the document, starting on the current node.
/// </summary>
public override IEnumerable<YamlNode> AllNodes
{
get { yield return this; }
}
}
}

Просмотреть файл

@ -57,6 +57,16 @@ namespace YamlDotNet.RepresentationModel
state.ResolveAliases();
#if DEBUG
foreach (var node in AllNodes)
{
if (node is YamlAliasNode)
{
throw new InvalidOperationException("Error in alias resolution.");
}
}
#endif
events.Expect<DocumentEnd>();
}
@ -156,5 +166,16 @@ namespace YamlDotNet.RepresentationModel
{
visitor.Visit(this);
}
/// <summary>
/// Gets all nodes from the document.
/// </summary>
public IEnumerable<YamlNode> AllNodes
{
get
{
return RootNode.AllNodes;
}
}
}
}

Просмотреть файл

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
@ -49,6 +50,22 @@ namespace YamlDotNet.RepresentationModel
{
state.AddNodeWithUnresolvedAliases(this);
}
#if DEBUG
else
{
foreach (var child in children)
{
if (child.Key is YamlAliasNode)
{
throw new InvalidOperationException("Error in alias resolution.");
}
if (child.Value is YamlAliasNode)
{
throw new InvalidOperationException("Error in alias resolution.");
}
}
}
#endif
events.Expect<MappingEnd>();
}
@ -202,28 +219,30 @@ namespace YamlDotNet.RepresentationModel
internal override void Emit(Emitter emitter, EmitterState state)
{
emitter.Emit(new MappingStart(Anchor, Tag, true, MappingStyle.Any));
foreach (var entry in children) {
foreach (var entry in children)
{
entry.Key.Save(emitter, state);
entry.Value.Save(emitter, state);
}
emitter.Emit(new MappingEnd());
}
/// <summary>
/// Accepts the specified visitor by calling the appropriate Visit method on it.
/// </summary>
/// <param name="visitor">
/// A <see cref="IYamlVisitor"/>.
/// </param>
public override void Accept(IYamlVisitor visitor) {
public override void Accept(IYamlVisitor visitor)
{
visitor.Visit(this);
}
/// <summary />
public override bool Equals(object other)
{
var obj = other as YamlMappingNode;
if(obj == null || !Equals(obj) || children.Count != obj.children.Count)
if (obj == null || !Equals(obj) || children.Count != obj.children.Count)
{
return false;
}
@ -231,15 +250,15 @@ namespace YamlDotNet.RepresentationModel
foreach (var entry in children)
{
YamlNode otherNode;
if(!obj.children.TryGetValue(entry.Key, out otherNode) || !SafeEquals(entry.Value, otherNode))
if (!obj.children.TryGetValue(entry.Key, out otherNode) || !SafeEquals(entry.Value, otherNode))
{
return false;
}
}
return true;
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
@ -249,7 +268,7 @@ namespace YamlDotNet.RepresentationModel
public override int GetHashCode()
{
var hashCode = base.GetHashCode();
foreach (var entry in children)
{
hashCode = CombineHashCodes(hashCode, GetHashCode(entry.Key));
@ -258,6 +277,51 @@ namespace YamlDotNet.RepresentationModel
return hashCode;
}
/// <summary>
/// Gets all nodes from the document, starting on the current node.
/// </summary>
public override IEnumerable<YamlNode> AllNodes
{
get
{
yield return this;
foreach (var child in children)
{
foreach (var node in child.Key.AllNodes)
{
yield return node;
}
foreach (var node in child.Value.AllNodes)
{
yield return node;
}
}
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
var text = new StringBuilder("{ ");
foreach (var child in children)
{
if (text.Length > 2)
{
text.Append(", ");
}
text.Append("{ ").Append(child.Key).Append(", ").Append(child.Value).Append(" }");
}
text.Append(" }");
return text.ToString();
}
#region IEnumerable<KeyValuePair<YamlNode,YamlNode>> Members

Просмотреть файл

@ -1,6 +1,7 @@
using System;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using System.Collections.Generic;
namespace YamlDotNet.RepresentationModel
{
@ -161,5 +162,13 @@ namespace YamlDotNet.RepresentationModel
{
return unchecked(((h1 << 5) + h1) ^ h2);
}
/// <summary>
/// Gets all nodes from the document, starting on the current node.
/// </summary>
public abstract IEnumerable<YamlNode> AllNodes
{
get;
}
}
}

Просмотреть файл

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
@ -121,5 +122,24 @@ namespace YamlDotNet.RepresentationModel
{
return value.Value;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return Value;
}
/// <summary>
/// Gets all nodes from the document, starting on the current node.
/// </summary>
public override IEnumerable<YamlNode> AllNodes
{
get { yield return this; }
}
}
}

Просмотреть файл

@ -1,7 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using System.Text;
namespace YamlDotNet.RepresentationModel
{
@ -47,6 +49,18 @@ namespace YamlDotNet.RepresentationModel
{
state.AddNodeWithUnresolvedAliases(this);
}
#if DEBUG
else
{
foreach (var child in children)
{
if (child is YamlAliasNode)
{
throw new InvalidOperationException("Error in alias resolution.");
}
}
}
#endif
events.Expect<SequenceEnd>();
}
@ -118,42 +132,44 @@ namespace YamlDotNet.RepresentationModel
internal override void Emit(Emitter emitter, EmitterState state)
{
emitter.Emit(new SequenceStart(Anchor, Tag, true, SequenceStyle.Any));
foreach (var node in children) {
foreach (var node in children)
{
node.Save(emitter, state);
}
emitter.Emit(new SequenceEnd());
}
/// <summary>
/// Accepts the specified visitor by calling the appropriate Visit method on it.
/// </summary>
/// <param name="visitor">
/// A <see cref="IYamlVisitor"/>.
/// </param>
public override void Accept(IYamlVisitor visitor) {
public override void Accept(IYamlVisitor visitor)
{
visitor.Visit(this);
}
/// <summary />
public override bool Equals(object other)
{
var obj = other as YamlSequenceNode;
if(obj == null || !Equals(obj) || children.Count != obj.children.Count)
if (obj == null || !Equals(obj) || children.Count != obj.children.Count)
{
return false;
}
for(int i = 0; i < children.Count; ++i)
for (int i = 0; i < children.Count; ++i)
{
if(!SafeEquals(children[i], obj.children[i]))
if (!SafeEquals(children[i], obj.children[i]))
{
return false;
}
}
return true;
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
@ -163,7 +179,7 @@ namespace YamlDotNet.RepresentationModel
public override int GetHashCode()
{
var hashCode = base.GetHashCode();
foreach (var item in children)
{
hashCode = CombineHashCodes(hashCode, GetHashCode(item));
@ -171,6 +187,47 @@ namespace YamlDotNet.RepresentationModel
return hashCode;
}
/// <summary>
/// Gets all nodes from the document, starting on the current node.
/// </summary>
public override IEnumerable<YamlNode> AllNodes
{
get
{
yield return this;
foreach (var child in children)
{
foreach (var node in child.AllNodes)
{
yield return node;
}
}
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
var text = new StringBuilder("[ ");
foreach (var child in children)
{
if(text.Length > 2)
{
text.Append(", ");
}
text.Append(child);
}
text.Append(" ]");
return text.ToString();
}
#region IEnumerable<YamlNode> Members

Просмотреть файл

@ -283,5 +283,62 @@ namespace YamlDotNet.UnitTests.RepresentationModel
RoundtripTest("fail-backreference.yaml");
}
[TestMethod]
[ExpectedException(typeof(AnchorNotFoundException))]
public void AllAliasesMustBeResolved()
{
YamlStream original = new YamlStream();
original.Load(YamlFile("invalid-reference.yaml"));
var visitor = new AliasFindingVisitor();
try
{
original.Accept(visitor);
}
catch (NotSupportedException err)
{
foreach (var node in visitor.CurrentPath)
{
TestContext.WriteLine(node.ToString());
}
Assert.Fail();
}
}
private class AliasFindingVisitor : YamlVisitor
{
private readonly Stack<string> _currentPath = new Stack<string>();
protected override void Visit(YamlMappingNode mapping)
{
base.Visit(mapping);
}
protected override void VisitChildren(YamlSequenceNode sequence)
{
int index = 0;
foreach (var child in sequence.Children)
{
_currentPath.Push(string.Format("seq[{0}]", index.ToString()));
child.Accept(this);
_currentPath.Pop();
}
}
protected override void VisitChildren(YamlMappingNode mapping)
{
foreach (var child in mapping.Children)
{
_currentPath.Push(string.Format("map[{0}]", child.Key.ToString()));
child.Value.Accept(this);
_currentPath.Pop();
}
}
public IEnumerable<string> CurrentPath { get { return _currentPath; } }
}
}
}

Просмотреть файл

@ -158,6 +158,9 @@
<ItemGroup>
<EmbeddedResource Include="fail-backreference.yaml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="invalid-reference.yaml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

Просмотреть файл

@ -0,0 +1,10 @@
- [*municipality-0701, *municipality-0711, *municipality-0707, *municipality-0708, *municipality-0709]
- [*municipality-1501, *municipality-1505, *municipality-1509, *municipality-1513, *municipality-0211]
-
- &municipality-0211 0211
- &municipality-0701 0701
- &municipality-0707 0707
- &municipality-0708 0708
- &municipality-0709 0709
- &municipality-0711 0711
- &municipality-1513 1513

Просмотреть файл

@ -4,7 +4,7 @@
<!-- This build file requires .NET 4.0 and nant 0.91 alpha 2 or higher -->
<property name="nant.settings.currentframework" value="net-4.0"/>
<property name="version" value="1.1.6" />
<property name="version" value="1.1.7" />
<fileset id="binaries">
<include name="YamlDotNet.Core/bin/Release/YamlDotNet.Core.dll" />