Skip to content

Commit 58b7b13

Browse files
authored
Решение бага по разбору типа (#20)
* new visitor * контракт взаимодействия * исправление бага * new visitor for ObjectType's hashcode computing * visitor integration * tests * version * tests adjustment * coverage
1 parent 3c04b84 commit 58b7b13

File tree

13 files changed

+187
-61
lines changed

13 files changed

+187
-61
lines changed

Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,9 @@ private TypeStatement TypeStatement(SymbolTable table)
234234
}
235235
var type = TypeValue(table);
236236

237-
if (type is ObjectType objectType)
237+
type.Recursive = type.ToString().Contains(ident.Value);
238+
239+
if (type is ObjectType objectType && type.Recursive)
238240
{
239241
objectType.ResolveSelfReferences(ident.Value);
240242
}

Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public override Unit Accept(ReferenceResolver visitor) =>
1717

1818
public override string Accept(ObjectTypePrinter visitor) =>
1919
visitor.Visit(this);
20+
21+
public override int Accept(ObjectTypeHasher visitor) =>
22+
visitor.Visit(this);
2023

2124
public override bool Equals(object obj)
2225
{

Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public override Unit Accept(ReferenceResolver visitor) =>
2525
public override string Accept(ObjectTypePrinter visitor) =>
2626
visitor.Visit(this);
2727

28+
public override int Accept(ObjectTypeHasher visitor) =>
29+
visitor.Visit(this);
30+
2831
public override bool Equals(object obj)
2932
{
3033
if (ReferenceEquals(this, obj)) return true;
@@ -42,7 +45,7 @@ public override int GetHashCode() =>
4245
ReturnType,
4346
Arguments
4447
.Select(arg => arg.GetHashCode())
45-
.Aggregate(HashCode.Combine)
48+
.Aggregate(36, HashCode.Combine)
4649
);
4750

4851
public override string ToString() =>

Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ public override Unit Accept(ReferenceResolver visitor) =>
2121

2222
public override string Accept(ObjectTypePrinter visitor) =>
2323
visitor.Visit(this);
24+
25+
public override int Accept(ObjectTypeHasher visitor) =>
26+
visitor.Visit(this);
2427

2528
public override bool Equals(object obj)
2629
{

Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using System.Collections.Generic;
32
using System.Linq;
43
using Interpreter.Lib.IR.CheckSemantics.Types.Visitors;
@@ -9,6 +8,7 @@ namespace Interpreter.Lib.IR.CheckSemantics.Types
98
public class ObjectType : NullableType
109
{
1110
private readonly Dictionary<string, Type> _properties;
11+
private readonly ObjectTypeHasher _hasher;
1212
private readonly ObjectTypePrinter _serializer;
1313

1414
public ObjectType(IEnumerable<PropertyType> properties)
@@ -19,6 +19,7 @@ public ObjectType(IEnumerable<PropertyType> properties)
1919
x => x.Id,
2020
x => x.Type
2121
);
22+
_hasher = new ObjectTypeHasher(this);
2223
_serializer = new ObjectTypePrinter(this);
2324
}
2425

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

4243
public override string Accept(ObjectTypePrinter visitor) =>
4344
visitor.Visit(this);
45+
46+
public override int Accept(ObjectTypeHasher visitor) =>
47+
visitor.Visit(this);
4448

4549
public override bool Equals(object obj)
4650
{
@@ -59,11 +63,10 @@ public override bool Equals(object obj)
5963
}
6064

6165
public override int GetHashCode() =>
62-
_properties
63-
.Select(kvp => HashCode.Combine(kvp.Key, kvp.Value))
64-
.Aggregate(HashCode.Combine);
66+
_hasher.Visit(this);
6567

66-
public override string ToString() => _serializer.Visit(this);
68+
public override string ToString() =>
69+
_serializer.Visit(this);
6770
}
6871

6972
public record PropertyType(string Id, Type Type);

Interpreter.Lib/IR/CheckSemantics/Types/Type.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ namespace Interpreter.Lib.IR.CheckSemantics.Types
55
{
66
public class Type :
77
IVisitable<ReferenceResolver, Unit>,
8-
IVisitable<ObjectTypePrinter, string>
8+
IVisitable<ObjectTypePrinter, string>,
9+
IVisitable<ObjectTypeHasher, int>
910
{
1011
private readonly string _name;
1112

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

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

19+
public bool Recursive { get; set; }
20+
1821
public virtual Unit Accept(ReferenceResolver visitor) =>
1922
visitor.Visit(this);
2023

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

27+
public virtual int Accept(ObjectTypeHasher visitor) =>
28+
visitor.Visit(this);
29+
2430
public override bool Equals(object obj)
2531
{
2632
if (ReferenceEquals(this, obj)) return true;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Linq;
3+
using Visitor.NET.Lib.Core;
4+
5+
namespace Interpreter.Lib.IR.CheckSemantics.Types.Visitors
6+
{
7+
public class ObjectTypeHasher :
8+
IVisitor<Type, int>,
9+
IVisitor<ObjectType, int>,
10+
IVisitor<ArrayType, int>,
11+
IVisitor<NullableType, int>,
12+
IVisitor<FunctionType, int>
13+
{
14+
private readonly ObjectType _reference;
15+
16+
public ObjectTypeHasher(ObjectType reference) =>
17+
_reference = reference;
18+
19+
public int Visit(Type visitable) =>
20+
visitable.GetHashCode();
21+
22+
public int Visit(ObjectType visitable) =>
23+
visitable.Keys.Select(key => HashCode.Combine(key,
24+
visitable[key].Equals(_reference)
25+
? "@this".GetHashCode()
26+
: visitable[key].Recursive
27+
? key.GetHashCode()
28+
: visitable[key].Accept(this))
29+
).Aggregate(36, HashCode.Combine);
30+
31+
public int Visit(ArrayType visitable) =>
32+
visitable.Type.Equals(_reference)
33+
? "@this".GetHashCode()
34+
: visitable.Type.Accept(this);
35+
36+
public int Visit(NullableType visitable) =>
37+
visitable.Type.Equals(_reference)
38+
? "@this".GetHashCode()
39+
: visitable.Type.Accept(this);
40+
41+
public int Visit(FunctionType visitable) =>
42+
HashCode.Combine(
43+
visitable.ReturnType.Equals(_reference)
44+
? "@this".GetHashCode()
45+
: visitable.ReturnType.Accept(this),
46+
visitable.Arguments.Select(arg =>
47+
arg.Equals(_reference)
48+
? "@this".GetHashCode()
49+
: arg.Accept(this)
50+
).Aggregate(36, HashCode.Combine));
51+
}
52+
}

Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypePrinter.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ public string Visit(ObjectType visitable)
2828
var prop = $"{key}: ";
2929
prop += type.Equals(_reference)
3030
? "@this"
31-
: type.Accept(this);
31+
: type.Recursive
32+
? key
33+
: type.Accept(this);
3234
sb.Append(prop).Append(';');
3335
}
3436

Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ReferenceResolver.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Generic;
12
using Visitor.NET.Lib.Core;
23

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

1517
public ReferenceResolver(ObjectType reference, string refId)
1618
{
1719
_reference = reference;
1820
_refId = refId;
21+
_visited = new();
1922
}
2023

2124
public Unit Visit(ObjectType visitable)
2225
{
26+
if (_visited.Contains(visitable))
27+
return default;
28+
_visited.Add(visitable);
29+
2330
foreach (var key in visitable.Keys)
2431
if (_refId == visitable[key])
2532
visitable[key] = _reference;

Interpreter.Tests/Unit/IR/TypeTests.cs renamed to Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,13 @@
1+
using System;
12
using System.Collections.Generic;
23
using Interpreter.Lib.IR.CheckSemantics.Types;
34
using Xunit;
5+
using Type = Interpreter.Lib.IR.CheckSemantics.Types.Type;
46

5-
namespace Interpreter.Tests.Unit.IR
7+
namespace Interpreter.Tests.Unit.IR.Types
68
{
7-
public class TypeTests
9+
public class ObjectTypeTests
810
{
9-
[Fact]
10-
public void TypeEqualityTest()
11-
{
12-
var number = new Type("number");
13-
var arrayOfNumbers = new ArrayType(number);
14-
Assert.False(arrayOfNumbers.Equals(number));
15-
Assert.False(number.Equals(arrayOfNumbers));
16-
}
17-
18-
[Fact]
19-
public void TypeStringRepresentationTest()
20-
{
21-
var matrix = new ArrayType(new ArrayType(new Type("number")));
22-
23-
Assert.Equal("number[][]", matrix.ToString());
24-
}
25-
2611
[Fact]
2712
public void ObjectTypeEqualityTest()
2813
{
@@ -62,38 +47,14 @@ public void ObjectTypeEqualityTest()
6247
Assert.NotEqual(p3d1, p3d2);
6348
Assert.NotEqual(p3d2, p2d1);
6449
}
65-
66-
[Fact]
67-
public void NullTests()
68-
{
69-
var number = new Type("number");
70-
// ReSharper disable once SuspiciousTypeConversion.Global
71-
Assert.True(new NullType().Equals(new NullableType(number)));
72-
}
73-
74-
[Fact]
75-
public void TypeWrappingTest()
76-
{
77-
var str = new Type("string");
78-
str = new NullableType(str);
79-
str = new ArrayType(str);
80-
Assert.Equal("string?[]", str.ToString());
81-
}
82-
83-
[Fact]
84-
public void DefaultValueTest()
85-
{
86-
Assert.Null(TypeUtils.GetDefaultValue(new NullableType(new Any())));
87-
Assert.Null(TypeUtils.GetDefaultValue(new NullType()));
88-
Assert.Null(TypeUtils.GetDefaultValue(new ObjectType(new List<PropertyType>())));
89-
}
90-
50+
9151
[Fact]
92-
public void RecursiveTypeTest()
52+
public void RecursiveTypeReferenceResolvingTest()
9353
{
9454
var number = new Type("number");
9555
var array = new ArrayType(new Type("self"));
9656
var method = new FunctionType(number, new List<Type> { new("self") });
57+
var nullable = new NullableType(new Type("self"));
9758
var linkedListType = new ObjectType(
9859
new List<PropertyType>
9960
{
@@ -103,14 +64,16 @@ public void RecursiveTypeTest()
10364
new("next", new Type("self"))
10465
})),
10566
new("children", array),
67+
new("parent", nullable),
10668
new("compare", method)
10769
}
10870
);
109-
71+
11072
linkedListType.ResolveSelfReferences("self");
11173

11274
Assert.Equal(linkedListType, ((ObjectType)linkedListType["wrapped"])["next"]);
11375
Assert.Equal(linkedListType, array.Type);
76+
Assert.Equal(linkedListType, nullable.Type);
11477
Assert.Equal(linkedListType, method.Arguments[0]);
11578
}
11679

@@ -137,6 +100,7 @@ public void ObjectTypeToStringTest()
137100
var number = new Type("number");
138101
var array = new ArrayType(new Type("self"));
139102
var method = new FunctionType(number, new List<Type> { new("self") });
103+
var nullable = new NullableType(new Type("self"));
140104
var linkedListType = new ObjectType(
141105
new List<PropertyType>
142106
{
@@ -146,12 +110,42 @@ public void ObjectTypeToStringTest()
146110
new("next", new Type("self"))
147111
})),
148112
new("children", array),
113+
new("parent", nullable),
149114
new("compare", method)
150115
}
151116
);
152117

153118
linkedListType.ResolveSelfReferences("self");
154119
Assert.Contains("@this", linkedListType.ToString());
155120
}
121+
122+
[Fact]
123+
public void SerializationOfTypeWithRecursivePropertyTest()
124+
{
125+
var nodeType = new ObjectType(
126+
new List<PropertyType>
127+
{
128+
new("data", new Type("number")),
129+
new("next", new Type("self"))
130+
}
131+
) { Recursive = true };
132+
nodeType.ResolveSelfReferences("self");
133+
134+
var linkedListType = new ObjectType(
135+
new List<PropertyType>
136+
{
137+
new("head", nodeType),
138+
new("append", new FunctionType(
139+
new Type("void"),
140+
new List<Type> { nodeType }
141+
)
142+
),
143+
new("copy", new FunctionType(new Type("self"), Array.Empty<Type>()))
144+
}
145+
) { Recursive = true };
146+
linkedListType.ResolveSelfReferences("self");
147+
148+
Assert.Contains("head: head;", linkedListType.ToString());
149+
}
156150
}
157151
}

0 commit comments

Comments
 (0)