Skip to content

Commit

Permalink
Решение бага по разбору типа (#20)
Browse files Browse the repository at this point in the history
* new visitor

* контракт взаимодействия

* исправление бага

* new visitor for ObjectType's hashcode computing

* visitor integration

* tests

* version

* tests adjustment

* coverage
  • Loading branch information
Stepami authored Oct 15, 2022
1 parent 3c04b84 commit 58b7b13
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 61 deletions.
4 changes: 3 additions & 1 deletion Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ private TypeStatement TypeStatement(SymbolTable table)
}
var type = TypeValue(table);

if (type is ObjectType objectType)
type.Recursive = type.ToString().Contains(ident.Value);

if (type is ObjectType objectType && type.Recursive)
{
objectType.ResolveSelfReferences(ident.Value);
}
Expand Down
3 changes: 3 additions & 0 deletions Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public override Unit Accept(ReferenceResolver visitor) =>

public override string Accept(ObjectTypePrinter visitor) =>
visitor.Visit(this);

public override int Accept(ObjectTypeHasher visitor) =>
visitor.Visit(this);

public override bool Equals(object obj)
{
Expand Down
5 changes: 4 additions & 1 deletion Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public override Unit Accept(ReferenceResolver visitor) =>
public override string Accept(ObjectTypePrinter visitor) =>
visitor.Visit(this);

public override int Accept(ObjectTypeHasher visitor) =>
visitor.Visit(this);

public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj)) return true;
Expand All @@ -42,7 +45,7 @@ public override int GetHashCode() =>
ReturnType,
Arguments
.Select(arg => arg.GetHashCode())
.Aggregate(HashCode.Combine)
.Aggregate(36, HashCode.Combine)
);

public override string ToString() =>
Expand Down
3 changes: 3 additions & 0 deletions Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public override Unit Accept(ReferenceResolver visitor) =>

public override string Accept(ObjectTypePrinter visitor) =>
visitor.Visit(this);

public override int Accept(ObjectTypeHasher visitor) =>
visitor.Visit(this);

public override bool Equals(object obj)
{
Expand Down
13 changes: 8 additions & 5 deletions Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Interpreter.Lib.IR.CheckSemantics.Types.Visitors;
Expand All @@ -9,6 +8,7 @@ namespace Interpreter.Lib.IR.CheckSemantics.Types
public class ObjectType : NullableType
{
private readonly Dictionary<string, Type> _properties;
private readonly ObjectTypeHasher _hasher;
private readonly ObjectTypePrinter _serializer;

public ObjectType(IEnumerable<PropertyType> properties)
Expand All @@ -19,6 +19,7 @@ public ObjectType(IEnumerable<PropertyType> properties)
x => x.Id,
x => x.Type
);
_hasher = new ObjectTypeHasher(this);
_serializer = new ObjectTypePrinter(this);
}

Expand All @@ -41,6 +42,9 @@ public override Unit Accept(ReferenceResolver visitor) =>

public override string Accept(ObjectTypePrinter visitor) =>
visitor.Visit(this);

public override int Accept(ObjectTypeHasher visitor) =>
visitor.Visit(this);

public override bool Equals(object obj)
{
Expand All @@ -59,11 +63,10 @@ public override bool Equals(object obj)
}

public override int GetHashCode() =>
_properties
.Select(kvp => HashCode.Combine(kvp.Key, kvp.Value))
.Aggregate(HashCode.Combine);
_hasher.Visit(this);

public override string ToString() => _serializer.Visit(this);
public override string ToString() =>
_serializer.Visit(this);
}

public record PropertyType(string Id, Type Type);
Expand Down
8 changes: 7 additions & 1 deletion Interpreter.Lib/IR/CheckSemantics/Types/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ namespace Interpreter.Lib.IR.CheckSemantics.Types
{
public class Type :
IVisitable<ReferenceResolver, Unit>,
IVisitable<ObjectTypePrinter, string>
IVisitable<ObjectTypePrinter, string>,
IVisitable<ObjectTypeHasher, int>
{
private readonly string _name;

Expand All @@ -15,12 +16,17 @@ protected Type()

public Type(string name) => _name = name;

public bool Recursive { get; set; }

public virtual Unit Accept(ReferenceResolver visitor) =>
visitor.Visit(this);

public virtual string Accept(ObjectTypePrinter visitor) =>
visitor.Visit(this);

public virtual int Accept(ObjectTypeHasher visitor) =>
visitor.Visit(this);

public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj)) return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Linq;
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.IR.CheckSemantics.Types.Visitors
{
public class ObjectTypeHasher :
IVisitor<Type, int>,
IVisitor<ObjectType, int>,
IVisitor<ArrayType, int>,
IVisitor<NullableType, int>,
IVisitor<FunctionType, int>
{
private readonly ObjectType _reference;

public ObjectTypeHasher(ObjectType reference) =>
_reference = reference;

public int Visit(Type visitable) =>
visitable.GetHashCode();

public int Visit(ObjectType visitable) =>
visitable.Keys.Select(key => HashCode.Combine(key,
visitable[key].Equals(_reference)
? "@this".GetHashCode()
: visitable[key].Recursive
? key.GetHashCode()
: visitable[key].Accept(this))
).Aggregate(36, HashCode.Combine);

public int Visit(ArrayType visitable) =>
visitable.Type.Equals(_reference)
? "@this".GetHashCode()
: visitable.Type.Accept(this);

public int Visit(NullableType visitable) =>
visitable.Type.Equals(_reference)
? "@this".GetHashCode()
: visitable.Type.Accept(this);

public int Visit(FunctionType visitable) =>
HashCode.Combine(
visitable.ReturnType.Equals(_reference)
? "@this".GetHashCode()
: visitable.ReturnType.Accept(this),
visitable.Arguments.Select(arg =>
arg.Equals(_reference)
? "@this".GetHashCode()
: arg.Accept(this)
).Aggregate(36, HashCode.Combine));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public string Visit(ObjectType visitable)
var prop = $"{key}: ";
prop += type.Equals(_reference)
? "@this"
: type.Accept(this);
: type.Recursive
? key
: type.Accept(this);
sb.Append(prop).Append(';');
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.IR.CheckSemantics.Types.Visitors
Expand All @@ -11,15 +12,21 @@ public class ReferenceResolver :
{
private readonly ObjectType _reference;
private readonly string _refId;
private readonly HashSet<Type> _visited;

public ReferenceResolver(ObjectType reference, string refId)
{
_reference = reference;
_refId = refId;
_visited = new();
}

public Unit Visit(ObjectType visitable)
{
if (_visited.Contains(visitable))
return default;
_visited.Add(visitable);

foreach (var key in visitable.Keys)
if (_refId == visitable[key])
visitable[key] = _reference;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,13 @@
using System;
using System.Collections.Generic;
using Interpreter.Lib.IR.CheckSemantics.Types;
using Xunit;
using Type = Interpreter.Lib.IR.CheckSemantics.Types.Type;

namespace Interpreter.Tests.Unit.IR
namespace Interpreter.Tests.Unit.IR.Types
{
public class TypeTests
public class ObjectTypeTests
{
[Fact]
public void TypeEqualityTest()
{
var number = new Type("number");
var arrayOfNumbers = new ArrayType(number);
Assert.False(arrayOfNumbers.Equals(number));
Assert.False(number.Equals(arrayOfNumbers));
}

[Fact]
public void TypeStringRepresentationTest()
{
var matrix = new ArrayType(new ArrayType(new Type("number")));

Assert.Equal("number[][]", matrix.ToString());
}

[Fact]
public void ObjectTypeEqualityTest()
{
Expand Down Expand Up @@ -62,38 +47,14 @@ public void ObjectTypeEqualityTest()
Assert.NotEqual(p3d1, p3d2);
Assert.NotEqual(p3d2, p2d1);
}

[Fact]
public void NullTests()
{
var number = new Type("number");
// ReSharper disable once SuspiciousTypeConversion.Global
Assert.True(new NullType().Equals(new NullableType(number)));
}

[Fact]
public void TypeWrappingTest()
{
var str = new Type("string");
str = new NullableType(str);
str = new ArrayType(str);
Assert.Equal("string?[]", str.ToString());
}

[Fact]
public void DefaultValueTest()
{
Assert.Null(TypeUtils.GetDefaultValue(new NullableType(new Any())));
Assert.Null(TypeUtils.GetDefaultValue(new NullType()));
Assert.Null(TypeUtils.GetDefaultValue(new ObjectType(new List<PropertyType>())));
}


[Fact]
public void RecursiveTypeTest()
public void RecursiveTypeReferenceResolvingTest()
{
var number = new Type("number");
var array = new ArrayType(new Type("self"));
var method = new FunctionType(number, new List<Type> { new("self") });
var nullable = new NullableType(new Type("self"));
var linkedListType = new ObjectType(
new List<PropertyType>
{
Expand All @@ -103,14 +64,16 @@ public void RecursiveTypeTest()
new("next", new Type("self"))
})),
new("children", array),
new("parent", nullable),
new("compare", method)
}
);

linkedListType.ResolveSelfReferences("self");

Assert.Equal(linkedListType, ((ObjectType)linkedListType["wrapped"])["next"]);
Assert.Equal(linkedListType, array.Type);
Assert.Equal(linkedListType, nullable.Type);
Assert.Equal(linkedListType, method.Arguments[0]);
}

Expand All @@ -137,6 +100,7 @@ public void ObjectTypeToStringTest()
var number = new Type("number");
var array = new ArrayType(new Type("self"));
var method = new FunctionType(number, new List<Type> { new("self") });
var nullable = new NullableType(new Type("self"));
var linkedListType = new ObjectType(
new List<PropertyType>
{
Expand All @@ -146,12 +110,42 @@ public void ObjectTypeToStringTest()
new("next", new Type("self"))
})),
new("children", array),
new("parent", nullable),
new("compare", method)
}
);

linkedListType.ResolveSelfReferences("self");
Assert.Contains("@this", linkedListType.ToString());
}

[Fact]
public void SerializationOfTypeWithRecursivePropertyTest()
{
var nodeType = new ObjectType(
new List<PropertyType>
{
new("data", new Type("number")),
new("next", new Type("self"))
}
) { Recursive = true };
nodeType.ResolveSelfReferences("self");

var linkedListType = new ObjectType(
new List<PropertyType>
{
new("head", nodeType),
new("append", new FunctionType(
new Type("void"),
new List<Type> { nodeType }
)
),
new("copy", new FunctionType(new Type("self"), Array.Empty<Type>()))
}
) { Recursive = true };
linkedListType.ResolveSelfReferences("self");

Assert.Contains("head: head;", linkedListType.ToString());
}
}
}
Loading

0 comments on commit 58b7b13

Please sign in to comment.