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()); }
public PropertyFilterSubExpression(PropertyExpressionToken token) { PropertyChain = token?.PropertyChain?.Select(x => x.StringValue)?.ToArray() ?? throw new ArgumentNullException(nameof(token)); IsWhildcard = token.ChildProperties; IsRecursive = token.RecursiveProperties; }