Ejemplo n.º 1
0
        /// <summary>
        /// Initializes FilterExpressionWrapper with given filterString and options.
        /// </summary>
        public FilterExpressionWrapper(string filterString, FilterOptions options)
        {
            ValidateArg.NotNullOrEmpty(filterString, "filterString");

            this.FilterString  = filterString;
            this.FilterOptions = options;

            try
            {
                // We prefer fast filter when it's available.
                this.filterExpression = FilterExpression.Parse(filterString, out this.fastFilter);

                if (UseFastFilter)
                {
                    this.filterExpression = null;

                    // Property value regex is only supported for fast filter,
                    // so we ignore it if no fast filter is constructed.

                    // TODO: surface an error message to suer.
                    var regexString = options?.FilterRegEx;
                    if (!string.IsNullOrEmpty(regexString))
                    {
                        Debug.Assert(options.FilterRegExReplacement != null ? options.FilterRegEx != null : true);
                        this.fastFilter.PropertyValueRegex            = new Regex(regexString, RegexOptions.Compiled);
                        this.fastFilter.PropertyValueRegexReplacement = options.FilterRegExReplacement;
                    }
                }
            }
            catch (FormatException ex)
            {
                this.ParseError = ex.Message;
            }
            catch (ArgumentException ex)
            {
                this.fastFilter = null;
                this.ParseError = ex.Message;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Return FilterExpression after parsing the given filter expression, and a FastFilter when possible.
        /// </summary>
        internal static FilterExpression Parse(string filterString, out FastFilter fastFilter)
        {
            ValidateArg.NotNull(filterString, nameof(filterString));

            // Below parsing doesn't error out on pattern (), so explicitly search for that (empty parethesis).
            var invalidInput = Regex.Match(filterString, @"\(\s*\)");

            if (invalidInput.Success)
            {
                throw new FormatException(string.Format(CultureInfo.CurrentCulture, CommonResources.TestCaseFilterFormatException, CommonResources.EmptyParenthesis));
            }

            var tokens        = TokenizeFilterExpressionString(filterString);
            var operatorStack = new Stack <Operator>();
            var filterStack   = new Stack <FilterExpression>();

            var fastFilterBuilder = FastFilter.CreateBuilder();

            // This is based on standard parsing of in order expression using two stacks (operand stack and operator stack)
            // Precedence(And) > Precedence(Or)
            foreach (var inputToken in tokens)
            {
                var token = inputToken.Trim();
                if (string.IsNullOrEmpty(token))
                {
                    // ignore empty tokens
                    continue;
                }

                switch (token)
                {
                case "&":
                case "|":

                    Operator currentOperator = Operator.And;
                    if (string.Equals("|", token))
                    {
                        currentOperator = Operator.Or;
                    }

                    fastFilterBuilder.AddOperator(currentOperator);

                    // Always put only higher priority operator on stack.
                    //  if lesser priority -- pop up the stack and process the operator to maintain operator precedence.
                    //  if equal priority -- pop up the stack and process the operator to maintain operator associativity.
                    //  OpenBrace is special condition. & or | can come on top of OpenBrace for case like ((a=b)&c=d)
                    while (true)
                    {
                        bool     isEmpty          = operatorStack.Count == 0;
                        Operator stackTopOperator = isEmpty ? Operator.None : operatorStack.Peek();
                        if (isEmpty || stackTopOperator == Operator.OpenBrace || stackTopOperator < currentOperator)
                        {
                            operatorStack.Push(currentOperator);
                            break;
                        }
                        stackTopOperator = operatorStack.Pop();
                        ProcessOperator(filterStack, stackTopOperator);
                    }
                    break;

                case "(":
                    operatorStack.Push(Operator.OpenBrace);
                    break;

                case ")":
                    // process operators from the stack till OpenBrace is found.
                    // If stack is empty at any time, than matching OpenBrace is missing from the expression.
                    if (operatorStack.Count == 0)
                    {
                        throw new FormatException(string.Format(CultureInfo.CurrentCulture, CommonResources.TestCaseFilterFormatException, CommonResources.MissingOpenParenthesis));
                    }

                    Operator temp = operatorStack.Pop();
                    while (temp != Operator.OpenBrace)
                    {
                        ProcessOperator(filterStack, temp);
                        if (operatorStack.Count == 0)
                        {
                            throw new FormatException(string.Format(CultureInfo.CurrentCulture, CommonResources.TestCaseFilterFormatException, CommonResources.MissingOpenParenthesis));
                        }
                        temp = operatorStack.Pop();
                    }

                    break;

                default:
                    // push the operand to the operand stack.
                    Condition        condition = Condition.Parse(token);
                    FilterExpression filter    = new FilterExpression(condition);
                    filterStack.Push(filter);

                    fastFilterBuilder.AddCondition(condition);
                    break;
                }
            }
            while (operatorStack.Count != 0)
            {
                Operator temp = operatorStack.Pop();
                ProcessOperator(filterStack, temp);
            }

            if (filterStack.Count != 1)
            {
                throw new FormatException(string.Format(CultureInfo.CurrentCulture, CommonResources.TestCaseFilterFormatException, CommonResources.MissingOperator));
            }

            fastFilter = fastFilterBuilder.ToFastFilter();

            return(filterStack.Pop());
        }