private Expression CreateExpression(Expression parameterExpression, ExpressionData exp)
        {
            Expression ex;

            switch (exp.Type)
            {
            case ExpressionType.Condition:
                ex = BoolExpression(exp.Filter, null, parameterExpression);
                break;

            case ExpressionType.Expression:

                Expression ep;

                switch (exp.Expression.PropertyType)
                {
                case PropertyType.Value:
                case PropertyType.Collection:
                case PropertyType.Key:
                case PropertyType.BasicCollection:
                case PropertyType.StringContains:
                    ep = BuilderUtility.GetProperty(parameterExpression, exp.Expression.PropertyId);
                    break;

                case PropertyType.Method:
                    ep = BuilderUtility.CallMethod(parameterExpression, exp, _methods);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                ex = BuildExpression(ep, exp);

                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(ex);
        }
        private Expression BuildExpression(Expression ep, ExpressionData exp)
        {
            Expression ex;

            var dataType   = exp.Expression.Type;
            var ce         = BuilderUtility.BuildConstantExpression(_tokens, ep, exp, dataType);
            var memberType = BuilderUtility.GetDataType(exp.Expression.Type, ep);

            switch (exp.Expression.PropertyType)
            {
            case PropertyType.Value:
                break;

            case PropertyType.Collection:
            case PropertyType.BasicCollection:

                ep =
                    BuilderUtility.CallAction(
                        exp.Expression.Action, ep, BuildListCall(exp, ep, $"f{_peCounter}"));

                _peCounter++;

                break;

            case PropertyType.Key:

                if (exp.Expression.Action == Action.Compare)
                {
                    break;
                }

                if (exp.Expression.Action != Action.Contains)
                {
                    throw new NotSupportedException();
                }

                ep = BuilderUtility.CallContains(exp, ep);

                break;

            case PropertyType.Method:
                break;

            case PropertyType.StringContains:

                ep = BuilderUtility.CallStringContains(exp, ep);

                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            switch (exp.Expression.Operator)
            {
            case Operator.Eq:
                ex = Expression.Equal(ep, Expression.Convert(ce, memberType));
                break;

            case Operator.Neq:
                ex = Expression.NotEqual(ep, Expression.Convert(ce, memberType));
                break;

            case Operator.Gt:
                ex = Expression.GreaterThan(ep, Expression.Convert(ce, memberType));
                break;

            case Operator.Gte:
                ex = Expression.GreaterThanOrEqual(ep, Expression.Convert(ce, memberType));
                break;

            case Operator.Lt:
                ex = Expression.LessThan(ep, Expression.Convert(ce, memberType));
                break;

            case Operator.Lte:
                ex = Expression.LessThanOrEqual(ep, Expression.Convert(ce, memberType));
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(ex);
        }