From 4298eb8ade4bea77c836f65eb23fbc603bdc4ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD?= Date: Thu, 4 Aug 2022 17:06:14 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B1=D0=B0=D0=B3=D0=B0=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D1=80=D0=B0=D0=B7=D1=80=D0=B5=D1=88=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8E=20=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA=20(#8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Скелет исправления бага через паттерн "Посетитель" * Реализация некоторых посещений, удаление неактуального функционала, доработка тестов * Доработка функционала: - если мы определяем посещение компонента виртуальным методом, то переопределять его надо только в том наследнике компонента, для которого существует специальная логика посещения - доработка тестов --- Interpreter.Lib/Semantic/Types/ArrayType.cs | 25 ++----- .../Semantic/Types/FunctionType.cs | 41 ++--------- .../Semantic/Types/NullableType.cs | 23 ++---- Interpreter.Lib/Semantic/Types/ObjectType.cs | 43 +++++------- Interpreter.Lib/Semantic/Types/Type.cs | 10 +-- .../Types/Visitors/ReferenceResolver.cs | 70 +++++++++++++++++++ Interpreter.Tests/Unit/TypeTests.cs | 32 +++++++-- 7 files changed, 138 insertions(+), 106 deletions(-) create mode 100644 Interpreter.Lib/Semantic/Types/Visitors/ReferenceResolver.cs diff --git a/Interpreter.Lib/Semantic/Types/ArrayType.cs b/Interpreter.Lib/Semantic/Types/ArrayType.cs index 57001d3f..87663e9e 100644 --- a/Interpreter.Lib/Semantic/Types/ArrayType.cs +++ b/Interpreter.Lib/Semantic/Types/ArrayType.cs @@ -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) { diff --git a/Interpreter.Lib/Semantic/Types/FunctionType.cs b/Interpreter.Lib/Semantic/Types/FunctionType.cs index 5db298c2..0fd9b3e8 100644 --- a/Interpreter.Lib/Semantic/Types/FunctionType.cs +++ b/Interpreter.Lib/Semantic/Types/FunctionType.cs @@ -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 Arguments { get; } @@ -17,40 +19,9 @@ public FunctionType(Type returnType, IEnumerable arguments) Arguments = new List(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; diff --git a/Interpreter.Lib/Semantic/Types/NullableType.cs b/Interpreter.Lib/Semantic/Types/NullableType.cs index 8d66e1e2..ac73bb23 100644 --- a/Interpreter.Lib/Semantic/Types/NullableType.cs +++ b/Interpreter.Lib/Semantic/Types/NullableType.cs @@ -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}?") { @@ -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) { diff --git a/Interpreter.Lib/Semantic/Types/ObjectType.cs b/Interpreter.Lib/Semantic/Types/ObjectType.cs index aa11ddea..8d8cff01 100644 --- a/Interpreter.Lib/Semantic/Types/ObjectType.cs +++ b/Interpreter.Lib/Semantic/Types/ObjectType.cs @@ -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 { @@ -21,36 +23,23 @@ public ObjectType(IEnumerable 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 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) diff --git a/Interpreter.Lib/Semantic/Types/Type.cs b/Interpreter.Lib/Semantic/Types/Type.cs index d186590e..31d65ce4 100644 --- a/Interpreter.Lib/Semantic/Types/Type.cs +++ b/Interpreter.Lib/Semantic/Types/Type.cs @@ -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 { private readonly string _name; @@ -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) { diff --git a/Interpreter.Lib/Semantic/Types/Visitors/ReferenceResolver.cs b/Interpreter.Lib/Semantic/Types/Visitors/ReferenceResolver.cs new file mode 100644 index 00000000..6c21650e --- /dev/null +++ b/Interpreter.Lib/Semantic/Types/Visitors/ReferenceResolver.cs @@ -0,0 +1,70 @@ +using Visitor.NET.Lib.Core; + +namespace Interpreter.Lib.Semantic.Types.Visitors +{ + public class ReferenceResolver : + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor + { + 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; + } + } +} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/TypeTests.cs b/Interpreter.Tests/Unit/TypeTests.cs index feb89c9e..fdf11fa5 100644 --- a/Interpreter.Tests/Unit/TypeTests.cs +++ b/Interpreter.Tests/Unit/TypeTests.cs @@ -93,6 +93,8 @@ 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 { new("self") }); var linkedListType = new ObjectType( new List { @@ -100,14 +102,34 @@ public void RecursiveTypeTest() new("wrapped", new ObjectType(new List { new("next", new Type("self")) - })) + })), + new("children", array), + new("compare", method) } ); + linkedListType.ResolveSelfReferences("self"); - var wrapper = new ObjectType(new List {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 + { + 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); } } } \ No newline at end of file