diff --git a/DD.Persistence.Test/TreeBuilderShould.cs b/DD.Persistence.Test/TreeBuilderShould.cs
new file mode 100644
index 0000000..f96f85b
--- /dev/null
+++ b/DD.Persistence.Test/TreeBuilderShould.cs
@@ -0,0 +1,107 @@
+using DD.Persistence.Filter.Interpreter;
+using DD.Persistence.Filter.Models;
+using DD.Persistence.Filter.Models.Enumerations;
+using Newtonsoft.Json;
+
+namespace DD.Persistence.Test;
+public class TreeBuilderShould
+{
+ [Fact]
+ public void TestTreeBuilding()
+ {
+ //arrange
+ var treeString = "(\"A\"==1)||(\"B\"==2)&&(\"C\"==3)||((\"D\"==4)||(\"E\"==5))&&(\"F\"==6)";
+
+ //act
+ var root = treeString.BuildTree();
+
+ //assert
+ Assert.NotNull(root);
+
+ var expectedRoot = JsonConvert.SerializeObject(new TVertex(
+ OperationEnum.And,
+ new TVertex(
+ OperationEnum.And,
+ new TVertex(
+ OperationEnum.Or,
+ new TLeaf(OperationEnum.Equal, "A", 1),
+ new TLeaf(OperationEnum.Equal, "B", 2)
+ ),
+ new TVertex(
+ OperationEnum.Or,
+ new TLeaf(OperationEnum.Equal, "C", 3),
+ new TVertex(
+ OperationEnum.Or,
+ new TLeaf(OperationEnum.Equal, "D", 4),
+ new TLeaf(OperationEnum.Equal, "E", 5)
+ )
+ )
+ ),
+ new TLeaf(OperationEnum.Equal, "F", 6)
+ ));
+ var actualRoot = JsonConvert.SerializeObject(root);
+ Assert.Equal(expectedRoot, actualRoot);
+ }
+
+ [Fact]
+ public void TestTreeOperations()
+ {
+ //arrange
+ var treeString = "(\"A\"==1)||(\"B\"!=1)||(\"C\">1)||(\"D\">=1)||(\"E\"<1)||(\"F\"<=1)";
+
+ //act
+ var root = treeString.BuildTree();
+
+ //assert
+ Assert.NotNull(root);
+
+ var expectedRoot = JsonConvert.SerializeObject(new TVertex(
+ OperationEnum.Or,
+ new TVertex(
+ OperationEnum.Or,
+ new TVertex(
+ OperationEnum.Or,
+ new TLeaf(OperationEnum.Equal, "A", 1),
+ new TLeaf(OperationEnum.NotEqual, "B", 1)
+ ),
+ new TVertex(
+ OperationEnum.Or,
+ new TLeaf(OperationEnum.Greate, "C", 1),
+ new TLeaf(OperationEnum.GreateOrEqual, "D", 1)
+ )
+ ),
+ new TVertex(
+ OperationEnum.Or,
+ new TLeaf(OperationEnum.Less, "E", 1),
+ new TLeaf(OperationEnum.LessOrEqual, "F", 1)
+ )
+ ));
+ var actualRoot = JsonConvert.SerializeObject(root);
+ Assert.Equal(expectedRoot, actualRoot);
+ }
+
+ [Fact]
+ public void TestLeafValues()
+ {
+ //arrange
+ var treeString = "(\"A\"==1.2345)||(\"B\"==12345)||(\"C\"==\"12345\")";
+
+ //act
+ var root = treeString.BuildTree();
+
+ //assert
+ Assert.NotNull(root);
+
+ var expectedRoot = JsonConvert.SerializeObject(new TVertex(
+ OperationEnum.Or,
+ new TVertex(
+ OperationEnum.Or,
+ new TLeaf(OperationEnum.Equal, "A", 1.2345),
+ new TLeaf(OperationEnum.Equal, "B", 12345)
+ ),
+ new TLeaf(OperationEnum.Equal, "C", "12345")
+ ));
+ var actualRoot = JsonConvert.SerializeObject(root);
+ Assert.Equal(expectedRoot, actualRoot);
+ }
+}
diff --git a/DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs b/DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs
new file mode 100644
index 0000000..f039ee1
--- /dev/null
+++ b/DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs
@@ -0,0 +1,22 @@
+namespace DD.Persistence.Filter.Models.Abstractions;
+
+///
+/// Посетитель бинарного дерева
+///
+///
+public interface INodeVisitor
+{
+ ///
+ /// Посетить узел
+ ///
+ ///
+ ///
+ TVisitResult Visit(TVertex vertex);
+
+ ///
+ /// Посетить лист
+ ///
+ ///
+ ///
+ TVisitResult Visit(TLeaf leaf);
+}
diff --git a/DD.Persistence/Filter/Models/Abstractions/TNode.cs b/DD.Persistence/Filter/Models/Abstractions/TNode.cs
new file mode 100644
index 0000000..226a3ef
--- /dev/null
+++ b/DD.Persistence/Filter/Models/Abstractions/TNode.cs
@@ -0,0 +1,28 @@
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.Models.Abstractions;
+
+///
+/// Абстрактная модель вершины
+///
+public abstract class TNode
+{
+ ///
+ public TNode(OperationEnum operation)
+ {
+ Operation = operation;
+ }
+
+ ///
+ /// Логическая операция
+ ///
+ public OperationEnum Operation { get; }
+
+ ///
+ /// Принять посетителя
+ ///
+ ///
+ ///
+ ///
+ public abstract TVisitResult AcceptVisitor(INodeVisitor visitor);
+}
diff --git a/DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs b/DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs
new file mode 100644
index 0000000..8f22b86
--- /dev/null
+++ b/DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs
@@ -0,0 +1,47 @@
+namespace DD.Persistence.Filter.Models.Enumerations;
+
+///
+/// Логические операции
+///
+public enum OperationEnum
+{
+ ///
+ /// И
+ ///
+ And = 1,
+
+ ///
+ /// ИЛИ
+ ///
+ Or = 2,
+
+ ///
+ /// РАВНО
+ ///
+ Equal = 3,
+
+ ///
+ /// НЕ РАВНО
+ ///
+ NotEqual = 4,
+
+ ///
+ /// БОЛЬШЕ
+ ///
+ Greate = 5,
+
+ ///
+ /// БОЛЬШЕ ЛИБО РАВНО
+ ///
+ GreateOrEqual = 6,
+
+ ///
+ /// МЕНЬШЕ
+ ///
+ Less = 7,
+
+ ///
+ /// МЕНЬШЕ ЛИБО РАВНО
+ ///
+ LessOrEqual = 8
+}
diff --git a/DD.Persistence/Filter/Models/TLeaf.cs b/DD.Persistence/Filter/Models/TLeaf.cs
new file mode 100644
index 0000000..d974ced
--- /dev/null
+++ b/DD.Persistence/Filter/Models/TLeaf.cs
@@ -0,0 +1,33 @@
+using DD.Persistence.Filter.Models.Abstractions;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.Models;
+
+///
+/// Модель листа
+///
+public class TLeaf : TNode
+{
+ ///
+ /// Наименование поля
+ ///
+ public string PropName { get; }
+
+ ///
+ /// Значение для фильтрации
+ ///
+ public object? Value { get; }
+
+ ///
+ public TLeaf(OperationEnum operation, string fieldName, object? value) : base(operation)
+ {
+ PropName = fieldName;
+ Value = value;
+ }
+
+ ///
+ public override TVisitResult AcceptVisitor(INodeVisitor visitor)
+ {
+ return visitor.Visit(this);
+ }
+}
diff --git a/DD.Persistence/Filter/Models/TVertex.cs b/DD.Persistence/Filter/Models/TVertex.cs
new file mode 100644
index 0000000..3f6c200
--- /dev/null
+++ b/DD.Persistence/Filter/Models/TVertex.cs
@@ -0,0 +1,33 @@
+using DD.Persistence.Filter.Models.Abstractions;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.Models;
+
+///
+/// Модель узла
+///
+public class TVertex : TNode
+{
+ ///
+ /// Левый потомок
+ ///
+ public TNode Left { get; }
+
+ ///
+ /// Правый потомок
+ ///
+ public TNode Rigth { get; }
+
+ ///
+ public TVertex(OperationEnum operation, TNode left, TNode rigth) : base(operation)
+ {
+ Left = left;
+ Rigth = rigth;
+ }
+
+ ///
+ public override TVisitResult AcceptVisitor(INodeVisitor visitor)
+ {
+ return visitor.Visit(this);
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs b/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs
new file mode 100644
index 0000000..b512a53
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs
@@ -0,0 +1,16 @@
+using DD.Persistence.Filter.Models.Abstractions;
+
+namespace DD.Persistence.Filter.Interpreter.Abstractions;
+
+///
+/// Интерпретатор для построения дерева
+///
+public interface ITreeBuilder
+{
+ ///
+ /// Построить дерево
+ ///
+ /// Дерево в виде строки
+ /// Корень дерева в виде вершины
+ TNode? Build(string treeString);
+}
\ No newline at end of file
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs
new file mode 100644
index 0000000..b28bde8
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs
@@ -0,0 +1,27 @@
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.Interpreter.Expressions.Abstract;
+
+///
+/// Интерфейс для выражений
+///
+public interface IExpression
+{
+ ///
+ /// Получить логическую операцию
+ ///
+ ///
+ public OperationEnum GetOperation();
+
+ ///
+ /// Получить логическую операцию в виде строки (для регулярных выражений)
+ ///
+ ///
+ public string GetOperationString();
+
+ ///
+ /// Реализация правила
+ ///
+ ///
+ public void Interpret(InterpreterContext context);
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs
new file mode 100644
index 0000000..137ec4b
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs
@@ -0,0 +1,83 @@
+using DD.Persistence.Extensions;
+using DD.Persistence.Filter.Interpreter.Expressions.Abstract;
+using DD.Persistence.Filter.Models;
+using DD.Persistence.Filter.Models.Enumerations;
+using System.Text.RegularExpressions;
+
+namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base;
+
+///
+/// Абстрактный класс для нетерминальных выражений
+///
+public abstract class NonTerminalExpression : IExpression
+{
+ ///
+ /// Реализация правила для нетерминальных выражений
+ ///
+ ///
+ public void Interpret(InterpreterContext context)
+ {
+ var operation = GetOperation();
+ var operationString = GetOperationString();
+
+ var matches = GetMatches(context, operation, operationString);
+ while (matches.Any())
+ {
+ matches.ForEach(m =>
+ {
+ var matchString = m.ToString();
+
+ var separator = operationString.Replace("\\", string.Empty);
+ var pair = matchString
+ .Trim(['(', ')'])
+ .Split(separator)
+ .Select(e => int.Parse(e));
+
+ var leftNode = context.treeNodes
+ .FirstOrDefault(e => e.Key == pair.First())
+ .Value;
+ var rigthNode = context.treeNodes
+ .FirstOrDefault(e => e.Key == pair.Last())
+ .Value;
+ var node = new TVertex(operation, leftNode, rigthNode);
+
+ var key = context.treeNodes.Count();
+ context.treeNodes.Add(key, node);
+
+ var keyString = key.ToString();
+ context.treeString = context.treeString.Replace(matchString, keyString);
+ });
+
+ matches = GetMatches(context, operation, operationString);
+ }
+
+ var isRoot = int.TryParse(context.treeString, out _);
+ if (isRoot)
+ {
+ context.treeString = string.Empty;
+ context.root = context.treeNodes.Last().Value;
+ }
+ }
+
+ ///
+ public abstract OperationEnum GetOperation();
+
+ ///
+ public abstract string GetOperationString();
+
+
+ ///
+ /// Получить из акткуального состояния строки все совпадения для текущего выражения
+ ///
+ private IEnumerable GetMatches(InterpreterContext context, OperationEnum operation, string operationString)
+ {
+ string pattern = context.treeString.Contains('(') && context.treeString.Contains(')')
+ ? $@"\(\d+{operationString}\d+\)" : $@"\d+{operationString}\d+";
+ Regex regex = new Regex(pattern);
+ var matches = regex
+ .Matches(context.treeString)
+ .ToArray();
+
+ return matches;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs
new file mode 100644
index 0000000..4a3d363
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal;
+
+///
+/// Выражение для "И"
+///
+public class AndExpression : NonTerminalExpression
+{
+ private const string AndString = "&&";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.And;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return AndString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs
new file mode 100644
index 0000000..e47b935
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal;
+
+///
+/// Выражение для "ИЛИ"
+///
+public class OrExpression : NonTerminalExpression
+{
+ private const string OrString = @"\|\|";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.Or;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return OrString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs
new file mode 100644
index 0000000..ada1f56
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs
@@ -0,0 +1,79 @@
+using DD.Persistence.Extensions;
+using DD.Persistence.Filter.Interpreter.Expressions.Abstract;
+using DD.Persistence.Filter.Models;
+using DD.Persistence.Filter.Models.Enumerations;
+using System.Text.RegularExpressions;
+
+namespace DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base;
+
+///
+/// Абстрактный класс для терминальных выражений
+///
+public abstract class TerminalExpression : IExpression
+{
+ ///
+ /// Реализация правила для терминальных выражений
+ ///
+ ///
+ public void Interpret(InterpreterContext context)
+ {
+ var operation = GetOperation();
+ var operationString = GetOperationString();
+
+ var matches = GetMatches(context, operation, operationString);
+ matches.ForEach(m =>
+ {
+ var matchString = m.ToString();
+
+ var pair = matchString
+ .Trim(['(', ')'])
+ .Split(operationString);
+ var fieldName = pair
+ .First()
+ .Trim('\"');
+ var value = ParseValue(pair.Last());
+ var node = new TLeaf(operation, fieldName, value);
+
+ var key = context.treeNodes.Count();
+ context.treeNodes.Add(key, node);
+
+ var keyString = key.ToString();
+ context.treeString = context.treeString.Replace(matchString, keyString);
+ });
+ }
+
+ ///
+ public abstract OperationEnum GetOperation();
+
+ ///
+ public abstract string GetOperationString();
+
+ ///
+ /// Получить из акткуального состояния строки все совпадения для текущего выражения
+ ///
+ private IEnumerable GetMatches(InterpreterContext context, OperationEnum operation, string operationString)
+ {
+ string pattern = $@"\([^()]*{operationString}.*?\)";
+ Regex regex = new Regex(pattern);
+ var matches = regex.Matches(context.treeString);
+
+ return matches;
+ }
+
+ private object? ParseValue(string value)
+ {
+ value = value.Replace('.', ',');
+ if (value.Contains(',') && double.TryParse(value, out _))
+ {
+ return double.Parse(value);
+ }
+
+ if (int.TryParse(value, out _))
+ {
+ return int.Parse(value);
+ }
+
+ value = value.Trim('\"');
+ return value;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs
new file mode 100644
index 0000000..4c78e36
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal;
+
+///
+/// Выражение для "РАВНО"
+///
+public class EqualExpression : TerminalExpression
+{
+ private const string EqualString = "==";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.Equal;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return EqualString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs
new file mode 100644
index 0000000..a7e6902
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal;
+
+///
+/// Выражение для "МЕНЬШЕ"
+///
+public class LessExpression : TerminalExpression
+{
+ private const string EqualString = "<";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.Less;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return EqualString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs
new file mode 100644
index 0000000..9a5c6be
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal;
+
+///
+/// Выражение для "МЕНЬШЕ ЛИБО РАВНО"
+///
+public class LessOrEqualExpression : TerminalExpression
+{
+ private const string EqualString = "<=";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.LessOrEqual;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return EqualString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs
new file mode 100644
index 0000000..0d6c8b0
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal;
+
+///
+/// Выражение для "БОЛЬШЕ"
+///
+public class MoreExpression : TerminalExpression
+{
+ private const string EqualString = ">";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.Greate;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return EqualString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs
new file mode 100644
index 0000000..1dd2db4
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal;
+
+///
+/// Выражение для "БОЛЬШЕ ЛИБО РАВНО"
+///
+public class MoreOrEqualExpression : TerminalExpression
+{
+ private const string EqualString = ">=";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.GreateOrEqual;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return EqualString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs
new file mode 100644
index 0000000..b51817a
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base;
+using DD.Persistence.Filter.Models.Enumerations;
+
+namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal;
+
+///
+/// Выражение для "НЕРАВНО"
+///
+public class NotEqualExpression : TerminalExpression
+{
+ private const string NotEqulString = "!=";
+
+ ///
+ public override OperationEnum GetOperation()
+ {
+ return OperationEnum.NotEqual;
+ }
+
+ ///
+ public override string GetOperationString()
+ {
+ return NotEqulString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs
new file mode 100644
index 0000000..72e0384
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs
@@ -0,0 +1,30 @@
+using DD.Persistence.Filter.Models.Abstractions;
+
+namespace DD.Persistence.Filter.Interpreter;
+
+///
+/// Контекст интерпретатора
+///
+public class InterpreterContext
+{
+ ///
+ /// Корень дерева (результат интерпретации)
+ ///
+ public TNode? root { get; set; }
+
+ ///
+ /// Дерево в виде строки (входной параметр)
+ ///
+ public string treeString { get; set; }
+
+ ///
+ /// Проиндексированные вершины дерева
+ ///
+ public Dictionary treeNodes { get; set; } = [];
+
+ ///
+ public InterpreterContext(string theeString)
+ {
+ this.treeString = theeString;
+ }
+}
diff --git a/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs b/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs
new file mode 100644
index 0000000..224c74c
--- /dev/null
+++ b/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs
@@ -0,0 +1,52 @@
+using DD.Persistence.Filter.Interpreter.Expressions.Abstract;
+using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal;
+using DD.Persistence.Filter.Models.Abstractions;
+using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal;
+
+namespace DD.Persistence.Filter.Interpreter;
+
+///
+/// Строитель бинарных деревьев
+///
+public static class TreeBuilder
+{
+
+ ///
+ /// Построить бинарное дерево логических операций сравнения из строки
+ ///
+ ///
+ ///
+ public static TNode? BuildTree(this string treeString)
+ {
+ InterpreterContext context = new InterpreterContext(treeString);
+
+ // Порядок важен
+ List terminalExpressions = new List
+ {
+ new EqualExpression(),
+ new NotEqualExpression(),
+ new MoreOrEqualExpression(),
+ new LessOrEqualExpression(),
+ new MoreExpression(),
+ new LessExpression()
+ };
+ terminalExpressions.ForEach(e => {
+ e.Interpret(context);
+ });
+
+ // Порядок важен
+ List nonTerminalExpressions = new List
+ {
+ new OrExpression(),
+ new AndExpression()
+ };
+ while (!string.IsNullOrEmpty(context.treeString))
+ {
+ nonTerminalExpressions.ForEach(e => {
+ e.Interpret(context);
+ });
+ }
+
+ return context.root;
+ }
+}
diff --git a/DD.Persistence/Filter/Visitors/NodeVisitor.cs b/DD.Persistence/Filter/Visitors/NodeVisitor.cs
new file mode 100644
index 0000000..07c7792
--- /dev/null
+++ b/DD.Persistence/Filter/Visitors/NodeVisitor.cs
@@ -0,0 +1,24 @@
+using DD.Persistence.Filter.Models;
+using DD.Persistence.Filter.Models.Abstractions;
+
+namespace DD.Persistence.Filter.Visitors;
+
+///
+public class NodeVisitor : INodeVisitor
+{
+ private readonly Func _ifVertex;
+ private readonly Func _ifLeaf;
+
+ ///
+ public NodeVisitor(Func ifVertex, Func ifLeaf)
+ {
+ _ifVertex = ifVertex;
+ _ifLeaf = ifLeaf;
+ }
+
+ ///
+ public TVisitResult Visit(TVertex vertex) => _ifVertex(vertex);
+
+ ///
+ public TVisitResult Visit(TLeaf leaf) => _ifLeaf(leaf);
+}