private static List <FilterExpressionToken> ReplaceMethodCallsOnProps(List <FilterExpressionToken> tokens)
        {
            List <PropertyExpressionToken> propTokens = tokens.Where(x => x is PropertyExpressionToken).Cast <PropertyExpressionToken>().ToList();
            List <FilterExpressionToken>   ret        = tokens.ToList();

            foreach (PropertyExpressionToken pt in propTokens)
            {
                int nextIndex = ret.IndexOf(pt) + 1;
                if (nextIndex < ret.Count && ret[nextIndex] is OpenGroupToken)
                {
                    OpenGroupToken  open  = ret[nextIndex] as OpenGroupToken;
                    CloseGroupToken close = ret.First(x => x is CloseGroupToken cgt && cgt.GroupId == open.GroupId) as CloseGroupToken;

                    int openIndex  = ret.IndexOf(open);
                    int closeIndex = ret.IndexOf(close);

                    List <FilterExpressionToken> args = new List <FilterExpressionToken>();
                    for (int i = openIndex + 1; i < closeIndex; i++)
                    {
                        args.Add(ret[i]);
                    }
                    args = FormatAndValidateMethodArgumentTokens(args);

                    string methodName;
                    PropertyExpressionToken allButLast = pt.AllButLast(out methodName);
                    int ptIndex = ret.IndexOf(pt);

                    ret[ptIndex] = new MethodCallExpressionToken(allButLast, methodName, args.ToArray());

                    List <FilterExpressionToken> toRemove = new List <FilterExpressionToken>();

                    for (int i = ptIndex + 1; i <= closeIndex; i++)
                    {
                        ret[i] = null;
                    }
                }
            }

            return(ret.Where(x => x != null).ToList());
        }
        /// <summary>
        /// Replaces chained property tokens with expression property tokens
        /// </summary>
        /// <param name="tokens">tokens input</param>
        /// <returns>tokens</returns>
        private static List <FilterExpressionToken> ReplacePropertyTokens(List <FilterExpressionToken> tokens)
        {
            List <PrimitiveExpressionToken> @symbols = tokens
                                                       .Where(x => x is PrimitiveExpressionToken pet && pet.Token.IsSymbolToken('@'))
                                                       .Cast <PrimitiveExpressionToken>()
                                                       .ToList();

            if (!symbols.Any())
            {
                return(tokens);
            }

            List <(PropertyExpressionToken prop, List <FilterExpressionToken> primitives)> replacements = new List <(PropertyExpressionToken, List <FilterExpressionToken>)>();

            foreach (PrimitiveExpressionToken st in @symbols)
            {
                List <PrimitiveExpressionToken> tokensForReplacement = new List <PrimitiveExpressionToken>();
                tokensForReplacement.Add(st);

                int index = tokens.IndexOf(st);
                index++;

                bool isPreviousDot = false;

                while (index < tokens.Count)
                {
                    FilterExpressionToken t = tokens[index];

                    isPreviousDot = index > 0 && (tokens[index - 1] is PrimitiveExpressionToken pet3 && pet3.Token.IsSymbolToken('.'));

                    bool isDot = t is PrimitiveExpressionToken pet && pet.Token.IsSymbolToken('.');
                    if (isDot)
                    {
                        if (isPreviousDot)
                        {
                            throw new UnexpectedTokenException((t as PrimitiveExpressionToken).Token);
                        }

                        index++;
                        continue;
                    }

                    if (t is PrimitiveExpressionToken pet2 && pet2.Token.IsPropertyToken())
                    {
                        PropertyToken prop = pet2.Token.CastToPropertyToken();

                        if (prop.Escaped && isPreviousDot)
                        {
                            throw new UnexpectedTokenException(prop, "Unexpected token after \".\" symbol");
                        }

                        tokensForReplacement.Add(t as PrimitiveExpressionToken);
                        index++;
                        continue;
                    }

                    if (t is PrimitiveExpressionToken pet4 && (pet4.Token.IsChildPropertiesToken() || pet4.Token.IsRecursivePropertiesToken()))
                    {
                        tokensForReplacement.Add(t as PrimitiveExpressionToken);
                        index++;
                        continue;
                    }

                    break;
                }

                List <PrimitiveExpressionToken> tokensToRemove = tokensForReplacement.ToList();
                if (tokensForReplacement.First().Token.IsSymbolToken('@'))
                {
                    tokensForReplacement = tokensForReplacement.Skip(1).ToList();
                }

                for (int i = 0; i < tokensForReplacement.Count - 1; i++)
                {
                    if (tokensForReplacement[i].Token.IsChildPropertiesToken() || tokensForReplacement[i].Token.IsRecursivePropertiesToken())
                    {
                        // only last property can be wildcard * or recursive ..
                        string accessor = tokensForReplacement[i].Token.IsChildPropertiesToken() ? "\"*\"" : "\"..\"";
                        throw new ParsingException($"Unexpected token accessor {accessor} at {tokensForReplacement[i].Token.StartIndex}" +
                                                   ", this kind of token is expected to be last in property chain");
                    }
                }

                PropertyExpressionToken propEx;
                Token last = tokensForReplacement.Last().Token;

                if (last.IsRecursivePropertiesToken())
                {
                    List <PrimitiveExpressionToken> props = tokensForReplacement.Where(x => !x.Token.IsSymbolToken('@')).ToList();
                    props = tokensForReplacement.Take(props.Count - 1).ToList();

                    propEx = new PropertyExpressionToken(
                        props.Select(x => x.Token.CastToPropertyToken()).ToArray(),
                        tokensForReplacement.Last().Token.CastToRecursivePropertiesToken(),
                        tokensForReplacement.First().StartIndex
                        );
                }
                else if (last.IsChildPropertiesToken())
                {
                    List <PrimitiveExpressionToken> props = tokensForReplacement.Where(x => !x.Token.IsSymbolToken('@')).ToList();
                    props = tokensForReplacement.Take(props.Count - 1).ToList();

                    propEx = new PropertyExpressionToken(
                        props.Select(x => x.Token.CastToPropertyToken()).ToArray(),
                        tokensForReplacement.Last().Token.CastToChildPropertiesToken(),
                        tokensForReplacement.First().StartIndex
                        );
                }
                else
                {
                    propEx = new PropertyExpressionToken(
                        tokensForReplacement.Where(x => !x.Token.IsSymbolToken('@')).Select(x => x.Token.CastToPropertyToken()).ToArray(),
                        tokensForReplacement.First().StartIndex
                        );
                }

                replacements.Add((propEx, tokensToRemove.Cast <FilterExpressionToken>().ToList()));
            }

            List <FilterExpressionToken> ret = tokens.ToList();

            foreach ((PropertyExpressionToken prop, List <FilterExpressionToken> primitives)r in replacements)
            {
                List <int> indexes = r.primitives.Select(x => ret.IndexOf(x)).ToList();

                for (int i = indexes.First(); i <= indexes.Last(); i++)
                {
                    ret[i] = null;
                }

                ret[indexes[0]] = r.prop;
            }

            return(ret.Where(x => x != null).ToList());
        }
Exemplo n.º 3
0
 public PropertyFilterSubExpression(PropertyExpressionToken token)
 {
     PropertyChain = token?.PropertyChain?.Select(x => x.StringValue)?.ToArray() ?? throw new ArgumentNullException(nameof(token));
     IsWhildcard   = token.ChildProperties;
     IsRecursive   = token.RecursiveProperties;
 }