/// <summary> /// Finds and replaces constants (bool, number, string constants) /// </summary> /// <param name="tokens">tokens input</param> /// <returns>tokens</returns> private static List <FilterExpressionToken> ReplaceConstantExpressionTokens(List <FilterExpressionToken> tokens) { List <FilterExpressionToken> ret = new List <FilterExpressionToken>(tokens.Count); for (int i = 0; i < tokens.Count; i++) { FilterExpressionToken t = tokens[i]; if (t is PrimitiveExpressionToken pet) { if (pet.Token.IsStringToken()) { ret.Add(new ConstantStringExpressionToken(pet.Token.CastToStringToken())); } else if (pet.Token.IsBoolToken()) { ret.Add(new ConstantBoolExpressionToken(pet.Token.CastToBoolToken())); } else if (pet.Token.IsNumberToken()) { ret.Add(new ConstantNumberExpressionToken(pet.Token.CastToNumberToken())); } else { ret.Add(pet); } } else { ret.Add(t); } } return(ret); }
private static void EnsureMethodArgumentsAreValid(MethodCallExpressionToken mct, ref int callCount) { callCount++; if (callCount > 10 * 1000) { throw new InternalJsonPathwayException( "Number of calls to EnsureTokensAreValidInner exceeded max expected number of 10000, possible stack overflow or infinite loop."); } if (mct.CalledOnExpression is MethodCallExpressionToken inner1) { EnsureMethodArgumentsAreValid(inner1, ref callCount); } foreach (FilterExpressionToken arg in mct.Arguments) { if (arg is MethodCallExpressionToken inner2) { EnsureMethodArgumentsAreValid(inner2, ref callCount); } } FilterExpressionToken prim = mct.Arguments.FirstOrDefault(x => x is PrimitiveExpressionToken); if (prim != null) { throw new UnexpectedTokenException((prim as PrimitiveExpressionToken).Token); } }
private static List <FilterExpressionToken> ReplaceMethodCallsOnArrayAccess(List <FilterExpressionToken> tokens) { List <ArrayAccessExpressionToken> arrayTokens = tokens.Where(x => x is ArrayAccessExpressionToken).Cast <ArrayAccessExpressionToken>().ToList(); List <FilterExpressionToken> ret = tokens.ToList(); foreach (ArrayAccessExpressionToken at in arrayTokens) { int arrayIndex = ret.IndexOf(at); int dotIndex = arrayIndex + 1; if (dotIndex < ret.Count - 4 && ret[dotIndex] is PrimitiveExpressionToken petDot && petDot.Token.IsSymbolToken('.')) { int methodNameIndex = dotIndex + 1; if (ret[methodNameIndex] is PrimitiveExpressionToken petMethodName && petMethodName.Token.IsPropertyToken()) { PropertyToken propToken = petMethodName.Token.CastToPropertyToken(); if (propToken.Escaped) { throw new UnexpectedTokenException(propToken, "Expected method call on array element"); } string methodName = propToken.StringValue; int openGroupIndex = methodNameIndex + 1; if (openGroupIndex < ret.Count && ret[openGroupIndex] is OpenGroupToken ogt) { FilterExpressionToken closed = ret.FirstOrDefault(x => x is CloseGroupToken cgt && cgt.GroupId == ogt.GroupId); if (closed == null) { throw new ParsingException("Failed to find ) for ( at " + ogt.StartIndex); } List <FilterExpressionToken> args = new List <FilterExpressionToken>(); int startIndex = ret.IndexOf(ogt); int endIndex = ret.IndexOf(closed); for (int i = startIndex + 1; i < endIndex; i++) { args.Add(ret[i]); } args = FormatAndValidateMethodArgumentTokens(args); ret[arrayIndex] = new MethodCallExpressionToken(at, methodName, args.ToArray()); for (int i = arrayIndex + 1; i <= endIndex; i++) { ret[i] = null; } } } } } return(ret.Where(x => x != null).ToList()); }
public ArrayAccessExpressionToken(FilterExpressionToken executedOn, AllArrayElementsToken token) : this(executedOn, token as MultiCharToken) { if (token is null) { throw new ArgumentNullException(nameof(token)); } IsAllArrayElements = true; StartIndex = token.StartIndex; }
public MethodCallExpressionToken(FilterExpressionToken calledOnExpression, string methodName, FilterExpressionToken[] arguments) { if (string.IsNullOrWhiteSpace(methodName)) { throw new ArgumentException("Value not provided", nameof(methodName)); } CalledOnExpression = calledOnExpression ?? throw new ArgumentNullException(nameof(calledOnExpression)); MethodName = methodName; Arguments = arguments ?? throw new ArgumentNullException(nameof(arguments)); }
public ArrayAccessExpressionToken(FilterExpressionToken executedOn, ArrayElementsToken token) : this(executedOn, token as MultiCharToken) { if (token == null) { throw new ArgumentNullException(nameof(token)); } SliceStart = token.SliceStart; SliceEnd = token.SliceEnd; SliceStep = token.SliceStep; ExactElementsAccess = token.ExactElementsAccess; StartIndex = token.StartIndex; }
private ArrayAccessExpressionToken(FilterExpressionToken executedOn, MultiCharToken arrayToken) { if (arrayToken == null) { throw new ArgumentNullException(nameof(arrayToken)); } ExecutedOn = executedOn ?? throw new ArgumentNullException(nameof(executedOn)); if (!(executedOn is PropertyExpressionToken) && !(executedOn is FilterExpressionToken)) { throw new UnexpectedTokenException(arrayToken, "Array access can be applied to property or filter"); } }
private static List <FilterExpressionToken> ReplaceMethodCallsOnMethodsInner(List <FilterExpressionToken> tokens, ref int callCount, out int replacedCount) { callCount++; replacedCount = 0; if (callCount > 10 * 1000) { throw new InternalJsonPathwayException( "Number of calls to ReplaceMethodCallsOnMethodsInner exceeded max expected number of 10000, possible stack overflow or infinite loop."); } List <FilterExpressionToken> ret = tokens.ToList(); foreach (MethodCallExpressionToken mc in tokens.Where(x => x is MethodCallExpressionToken)) { int index = ret.IndexOf(mc); if (index < ret.Count - 4 && ret[index + 1] is PrimitiveExpressionToken pet1 && pet1.Token.IsSymbolToken('.') && ret[index + 2] is PrimitiveExpressionToken pet2 && pet2.Token.IsPropertyToken() && ret[index + 3] is OpenGroupToken) { OpenGroupToken open = ret[index + 3] as OpenGroupToken; FilterExpressionToken close = ret.Single(x => x is CloseGroupToken cgt && cgt.GroupId == open.GroupId); string methodName = (ret[index + 2] as PrimitiveExpressionToken).Token.CastToPropertyToken().StringValue; List <FilterExpressionToken> args = new List <FilterExpressionToken>(); int closeIndex = ret.IndexOf(close); for (int i = index + 4; i < closeIndex; i++) { args.Add(ret[i]); } args = FormatAndValidateMethodArgumentTokens(args); ret[index] = new MethodCallExpressionToken(mc, methodName, args.ToArray()); for (int i = index + 1; i <= closeIndex; i++) { ret[i] = null; } replacedCount++; } } return(ret.Where(x => x != null).ToList()); }
private static List <FilterExpressionToken> ReplaceMethodCallsOnConstants(List <FilterExpressionToken> tokens) { List <FilterExpressionToken> ret = tokens.ToList(); foreach (ConstantBaseExpressionToken ct in tokens.Where(x => x is ConstantBaseExpressionToken)) { int index = ret.IndexOf(ct); if (index < ret.Count - 4 && ret[index + 1] is PrimitiveExpressionToken pet1 && pet1.Token.IsSymbolToken('.') && ret[index + 2] is PrimitiveExpressionToken pet2 && pet2.Token.IsPropertyToken() && ret[index + 3] is OpenGroupToken) { OpenGroupToken open = ret[index + 3] as OpenGroupToken; FilterExpressionToken close = ret.Single(x => x is CloseGroupToken cgt && cgt.GroupId == open.GroupId); string methodName = (ret[index + 2] as PrimitiveExpressionToken).Token.CastToPropertyToken().StringValue; List <FilterExpressionToken> args = new List <FilterExpressionToken>(); int closeIndex = ret.IndexOf(close); for (int i = index + 4; i < closeIndex; i++) { args.Add(ret[i]); } args = FormatAndValidateMethodArgumentTokens(args); ret[index] = new MethodCallExpressionToken(ct, methodName, args.ToArray()); for (int i = index + 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 PrimitiveFilterSubExpression(FilterExpressionToken token) { Token = token ?? throw new ArgumentNullException(nameof(token)); }