private void ProcessField()
        {
            if (!_parseRuleStack.Any())
            {
                _parseRuleStack.Push(new DefaultExpressionTokens());
            }

            var fieldName = _context.GetToken(new[] { Delimiters.DOLLAR }, new[] { Delimiters.WHITE_SPACE }).Item1;

            if (_supportedFields != null && _supportedFields.All(s => s != fieldName))
            {
                var errorMessage = $"Unsupported Fields, Value : {fieldName}, SupportedFields : {string.Join(",", _supportedFields)}, ParserState : {_context.GetProcessedString()}";
                SetState(new ErrorParserState {
                    ErrorMessage = errorMessage
                });
                return;
            }

            _availableFields.Add(fieldName);

            _currentExpressionToken = new ConditionExpressionToken
            {
                FieldName = fieldName
            };

            SetState(new LogicalOperatorParserState());
        }
        private void PushToExpressionStack()
        {
            var token = _parseRuleStack.Peek();

            _currentExpressionToken.PreviousToken = token.Tokens.LastOrDefault();
            token.Tokens.Add(_currentExpressionToken);
            _currentExpressionToken = null;
            SetState(new BinaryOperatorParserState());
        }
        private ExpressionBuilder <K> BuildExpression(ConditionExpressionToken token, ExpressionBuilder <K> builder)
        {
            if (token.PreviousToken == null)
            {
                return(BuildLogicalExpression(builder, BinaryOperator.NONE, token));
            }

            var prevBinaryToken = token.PreviousToken as BinaryExpressionToken;

            if (prevBinaryToken == null)
            {
                throw new Exception();
            }

            switch (prevBinaryToken.Operator)
            {
            case BinaryOperatorType.AND: return(BuildLogicalExpression(builder, BinaryOperator.AND, token));

            case BinaryOperatorType.OR: return(BuildLogicalExpression(builder, BinaryOperator.OR, token));

            default: throw new ArgumentException($"Binary operator '{prevBinaryToken.Operator}' not supported");
            }
        }
        private void ProcessOperandArray()
        {
            if (new[] { LogicalOperatorType.IN, LogicalOperatorType.NI }.All(s => s != _currentExpressionToken.Operator))
            {
                var errorMessage = $"Invalid Field Value for Logical Operator, Operator : {_currentExpressionToken.Operator}, " +
                                   $"ParserState : {_context.GetProcessedString()}";
                SetState(new ErrorParserState {
                    ErrorMessage = errorMessage
                });
                return;
            }

            var token     = _context.GetToken(new[] { Delimiters.OPEN_BRACE }, new[] { Delimiters.CLOSE_BRACE }).Item1;
            var subTokens = token.Split(new[] { ",", " " }, StringSplitOptions.RemoveEmptyEntries);

            if (!subTokens.Any())
            {
                var errorMessage = $"Set cannot be Empty. It should contain atleast one Field Value, ParserState : {_context.GetProcessedString()}";
                SetState(new ErrorParserState {
                    ErrorMessage = errorMessage
                });
                return;
            }

            if (!_parseRuleStack.Any())
            {
                _parseRuleStack.Push(new DefaultExpressionTokens());
            }

            var tExpressionTokens = new DefaultExpressionTokens();

            for (int i = 0; i < subTokens.Length; i++)
            {
                var subToken = subTokens[i];
                var tToken   = new ConditionExpressionToken
                {
                    FieldName     = _currentExpressionToken.FieldName,
                    Operator      = _currentExpressionToken.Operator == LogicalOperatorType.IN ? LogicalOperatorType.EQ : LogicalOperatorType.NE,
                    PreviousToken = tExpressionTokens.Tokens.LastOrDefault()
                };

                if (subToken.StartsWith("'"))
                {
                    tToken.Operand = subToken.Trim('\'');
                }
                else if (subToken.Equals("null", StringComparison.CurrentCultureIgnoreCase))
                {
                    tToken.Operand = null;
                }
                else
                {
                    var errorMessage = $"Invalid Field Value, Value : {subToken}, ParserState : {_context.GetProcessedString()}";
                    SetState(new ErrorParserState {
                        ErrorMessage = errorMessage
                    });
                    return;
                }

                tExpressionTokens.Tokens.Add(tToken);
                if (i < subTokens.Length - 1)
                {
                    tExpressionTokens.Tokens.Add(new BinaryExpressionToken
                    {
                        Operator      = _currentExpressionToken.Operator == LogicalOperatorType.IN ? BinaryOperatorType.OR : BinaryOperatorType.AND,
                        PreviousToken = tToken
                    });
                }
            }

            _currentExpressionToken = null;

            var previousToken = _parseRuleStack.Peek();

            tExpressionTokens.PreviousToken = previousToken.Tokens.LastOrDefault();
            previousToken.Tokens.Add(tExpressionTokens);
            SetState(new BinaryOperatorParserState());
        }
        private ExpressionBuilder <K> BuildLogicalExpression(ExpressionBuilder <K> builder, BinaryOperator binaryOperator, ConditionExpressionToken token)
        {
            if (_supportedFields != null && _supportedFields.All(s => s != token.FieldName))
            {
                throw new ArgumentException($"Field not supported, FieldName : {token.FieldName}, SupportedFields : {string.Join(",", _supportedFields)}");
            }

            var transformedFieldName  = TransformFieldName(token.FieldName);
            var transformedFieldValue = token.Operand;

            if (transformedFieldValue != null)
            {
                transformedFieldValue = TransformFieldValue(token.FieldName, transformedFieldValue);
            }

            Func <string, string, Tuple <ExpressionBuilder <K>, string> > buildExpression = (fieldName, fieldValue) =>
            {
                try
                {
                    switch (token.Operator)
                    {
                    case LogicalOperatorType.EQ: return(builder.BuildEqualToExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.GE: return(builder.BuildGreaterThanOrEqualToExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.LE: return(builder.BuildLessThanOrEqualToExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.GT: return(builder.BuildGreaterThanExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.LT: return(builder.BuildLesserThanExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.NE: return(builder.BuildNotEqualToExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.CN: return(builder.BuildContainsExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.SW: return(builder.BuildStartsWithExpression(binaryOperator, fieldName, fieldValue));

                    case LogicalOperatorType.EW: return(builder.BuildEndsWithExpression(binaryOperator, fieldName, fieldValue));
                    }
                }
                catch (Exception)
                {
                    throw new ArgumentException($"Invalid field value, Operator : {token.Operator}, " +
                                                $"FieldName : {fieldName}, " +
                                                $"FieldValue : {fieldValue ?? string.Empty}");
                }

                throw new ArgumentException($"Operator not supported, Operator : {token.Operator}");
            };

            var expression = buildExpression(transformedFieldName, transformedFieldValue);

            if (!string.IsNullOrEmpty(expression.Item2))
            {
                throw new ArgumentException(expression.Item2);
            }

            return(expression.Item1);
        }