Skip to content

Commit

Permalink
Исправление бага по разрешению ссылок (#8)
Browse files Browse the repository at this point in the history
* Скелет исправления бага через паттерн "Посетитель"

* Реализация некоторых посещений, удаление неактуального функционала, доработка тестов

* Доработка функционала:
- если мы определяем посещение компонента виртуальным методом, то переопределять его надо только в том наследнике компонента, для которого существует специальная логика посещения
- доработка тестов
  • Loading branch information
Stepami authored Aug 4, 2022
1 parent 928c35c commit 4298eb8
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 106 deletions.
25 changes: 7 additions & 18 deletions Interpreter.Lib/Semantic/Types/ArrayType.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
using Interpreter.Lib.Semantic.Types.Visitors;
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.Semantic.Types
{
public class ArrayType : Type
{
public Type Type { get; private set; }
public Type Type { get; set; }

public ArrayType(Type type) : base($"{type}[]")
{
Type = type;
}

public override void ResolveReference(string reference, Type toAssign)
{
if (Type == reference)
{
Type = toAssign;
}
else switch (Type)
{
case ObjectType objectType:
objectType.ResolveSelfReferences(reference);
break;
default:
Type.ResolveReference(reference, toAssign);
break;
}
}

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

public override bool Equals(object obj)
{
Expand Down
41 changes: 6 additions & 35 deletions Interpreter.Lib/Semantic/Types/FunctionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Interpreter.Lib.Semantic.Types.Visitors;
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.Semantic.Types
{
public class FunctionType : Type
{
public Type ReturnType { get; private set; }
public Type ReturnType { get; set; }

public List<Type> Arguments { get; }

Expand All @@ -17,40 +19,9 @@ public FunctionType(Type returnType, IEnumerable<Type> arguments)
Arguments = new List<Type>(arguments);
}

public override void ResolveReference(string reference, Type toAssign)
{
if (ReturnType.ToString() == reference)
{
ReturnType = toAssign;
}
else switch (ReturnType)
{
case ObjectType objectType:
objectType.ResolveSelfReferences(reference);
break;
default:
ReturnType.ResolveReference(reference, toAssign);
break;
}

for (var i = 0; i < Arguments.Count; i++)
{
if (Arguments[i].ToString() == reference)
{
Arguments[i] = toAssign;
}
else switch (Arguments[i])
{
case ObjectType objectType:
objectType.ResolveSelfReferences(reference);
break;
default:
Arguments[i].ResolveReference(reference, toAssign);
break;
}
}
}

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

public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj)) return true;
Expand Down
23 changes: 6 additions & 17 deletions Interpreter.Lib/Semantic/Types/NullableType.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using Interpreter.Lib.Semantic.Types.Visitors;
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.Semantic.Types
{
public class NullableType : Type
{
public Type Type { get; private set; }
public Type Type { get; set; }

public NullableType(Type type) : base($"{type}?")
{
Expand All @@ -13,22 +16,8 @@ protected NullableType()
{
}

public override void ResolveReference(string reference, Type toAssign)
{
if (Type == reference)
{
Type = toAssign;
}
else switch (Type)
{
case ObjectType objectType:
objectType.ResolveSelfReferences(reference);
break;
default:
Type.ResolveReference(reference, toAssign);
break;
}
}
public override Unit Accept(ReferenceResolver visitor) =>
visitor.Visit(this);

public override bool Equals(object obj)
{
Expand Down
43 changes: 16 additions & 27 deletions Interpreter.Lib/Semantic/Types/ObjectType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Interpreter.Lib.Semantic.Types.Visitors;
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.Semantic.Types
{
Expand All @@ -21,36 +23,23 @@ public ObjectType(IEnumerable<PropertyType> properties)
_serializer = new ObjectTypeToStringSerializer(this);
}

public Type this[string id] => _properties.ContainsKey(id)
? _properties[id]
: null;
public Type this[string id]
{
get => _properties.ContainsKey(id)
? _properties[id]
: null;
set => _properties[id] = value;
}

public IEnumerable<string> Keys => _properties.Keys;

public void ResolveSelfReferences(string self)
{
foreach (var (key, property) in _properties)
{
if (property == self)
{
_properties[key] = this;
}
else switch (property)
{
case ObjectType objectType:
if (objectType != this)
{
objectType.ResolveSelfReferences(self);
}

break;
default:
property.ResolveReference(self, this);
break;
}
}
}

public void ResolveSelfReferences(string self) =>
new ReferenceResolver(this, self)
.Visit(this);

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

public override bool Equals(object obj)
{
if (obj is ObjectType that)
Expand Down
10 changes: 6 additions & 4 deletions Interpreter.Lib/Semantic/Types/Type.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using Interpreter.Lib.Semantic.Types.Visitors;
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.Semantic.Types
{
public class Type
public class Type : IVisitable<ReferenceResolver, Unit>
{
private readonly string _name;

Expand All @@ -10,9 +13,8 @@ protected Type()

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

public virtual void ResolveReference(string reference, Type toAssign)
{
}
public virtual Unit Accept(ReferenceResolver visitor)
=> visitor.Visit(this);

public override bool Equals(object obj)
{
Expand Down
70 changes: 70 additions & 0 deletions Interpreter.Lib/Semantic/Types/Visitors/ReferenceResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Visitor.NET.Lib.Core;

namespace Interpreter.Lib.Semantic.Types.Visitors
{
public class ReferenceResolver :
IVisitor<Type, Unit>,
IVisitor<ArrayType, Unit>,
IVisitor<FunctionType, Unit>,
IVisitor<NullableType, Unit>,
IVisitor<ObjectType, Unit>
{
private readonly ObjectType _reference;
private readonly string _refId;

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

public Unit Visit(ObjectType visitable)
{
foreach (var key in visitable.Keys)
if (_refId == visitable[key])
visitable[key] = _reference;
else
visitable[key].Accept(this);
return default;
}

public Unit Visit(Type visitable) => default;

public Unit Visit(ArrayType visitable)
{
if (visitable.Type == _refId)
visitable.Type = _reference;
else
visitable.Type.Accept(this);
return default;
}

public Unit Visit(FunctionType visitable)
{
if (visitable.ReturnType == _refId)
visitable.ReturnType = _reference;
else
visitable.ReturnType.Accept(this);

for (var i = 0; i < visitable.Arguments.Count; i++)
{
var argType = visitable.Arguments[i];
if (argType == _refId)
visitable.Arguments[i] = _reference;
else
argType.Accept(this);
}

return default;
}

public Unit Visit(NullableType visitable)
{
if (visitable.Type == _refId)
visitable.Type = _reference;
else
visitable.Type.Accept(this);
return default;
}
}
}
32 changes: 27 additions & 5 deletions Interpreter.Tests/Unit/TypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,43 @@ public void DefaultValueTest()
public void RecursiveTypeTest()
{
var number = new Type("number");
var array = new ArrayType(new Type("self"));
var method = new FunctionType(number, new List<Type> { new("self") });
var linkedListType = new ObjectType(
new List<PropertyType>
{
new("data", number),
new("wrapped", new ObjectType(new List<PropertyType>
{
new("next", new Type("self"))
}))
})),
new("children", array),
new("compare", method)
}
);

linkedListType.ResolveSelfReferences("self");
var wrapper = new ObjectType(new List<PropertyType> {new("data", number)});
Assert.True(linkedListType.Equals(((ObjectType)linkedListType["wrapped"])["next"]));
Assert.False(linkedListType.Equals(wrapper));
Assert.Contains("@this", linkedListType.ToString());

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

[Fact]
public void NonSpecifiedTypesVisitingTest()
{
var objectType = new ObjectType(
new List<PropertyType>
{
new("any", new Any()),
new("some", new NullType()),
new("next", new Type("self")),
new("prop", new Type("number"))
}
);
var ex = Record.Exception(() => objectType.ResolveSelfReferences("self"));
Assert.Null(ex);
Assert.Equal(objectType["next"], objectType);
}
}
}

0 comments on commit 4298eb8

Please sign in to comment.