private bool TryResolveOdataExpression(MethodCallNode node, out Expression expression) { expression = null; switch (node.Name) { case "isof": case "cast": if (node.Children.Count > 2 || node.Children.Count < 1) { throw CreateParseException(node, "Only one or two arguments to cast operator is allowed."); } TypeNameNode castTypeArg; Expression operand; if (node.Children.Count == 1) { castTypeArg = node.Children[0] as TypeNameNode; operand = this.thisParam; } else { operand = ParseExpression(node.Children[0]); castTypeArg = node.Children[1] as TypeNameNode; } if (castTypeArg == null) { throw CreateParseException(node, "Argument to cast is required to be a type literal."); } var type = ResolveType(castTypeArg); if (node.Name == "cast") { expression = Expression.Convert(operand, type); } else if (node.Name == "isof") { expression = Expression.TypeIs(operand, type); } return(true); case "iif": ParseConditionalOperator(node, ref expression); return(true); } var memberCandidates = QueryFunctionMapping.GetMemberCandidates(node.Name, node.Children.Count); foreach (var memberMapping in memberCandidates) { if (TryResolveMemberMapping(memberMapping, node, out expression)) { return(true); } } return(false); }
private void ParseConditionalOperator(MethodCallNode node, ref Expression expression) { if (node.Children.Count != 3) { throw CreateParseException(node, "Conditional requires three arguments: iif(test, iftrue, iffalse)."); } var testExpr = ParseExpression(node.Children[0]); var ifTrue = ParseExpression(node.Children[1]); var ifFalse = ParseExpression(node.Children[2]); if (ifTrue.Type != ifFalse.Type) { PeformImplicitConversionForNodePair(ref ifTrue, ref ifFalse); } expression = Expression.Condition(testExpr, ifTrue, ifFalse); }
private Expression ParseMethodCallNode(MethodCallNode node, Expression memberExpression) { if (memberExpression == null) { throw new ArgumentNullException(nameof(memberExpression)); } if (memberExpression == this.thisParam) { if (node.HasArguments) { Expression expression; if (TryResolveOdataExpression(node, out expression)) { return(expression); } } } throw CreateParseException(node, "Could not recognize method " + node.Name); }
private bool TryResolveMemberMapping(QueryFunctionMapping.MemberMapping memberMapping, MethodCallNode node, out Expression expression) { expression = null; var reorderedArgs = memberMapping.ReorderArguments(node.Children); var method = memberMapping.Member as MethodInfo; var property = memberMapping.Member as PropertyInfo; if (method != null) { Expression instance = null; if (!method.IsStatic) { instance = ParseExpression(reorderedArgs[0], this.thisParam, null); if (!TryResolveGenericInstanceMethod(instance, ref method)) { return(false); } } // Convert each node and check whether argument matches.. var argArrayOffset = method.IsStatic ? 0 : 1; var methodParameters = method.GetParameters(); if (methodParameters.Length != reorderedArgs.Count - argArrayOffset) { var message = $"Number parameters count ({methodParameters.Length}) for method {method.DeclaringType?.FullName}.{method.Name} does not match provided argument count ({reorderedArgs.Count - argArrayOffset})"; throw CreateParseException(node, message); } var argExprArray = new Expression[methodParameters.Length]; if (!method.IsGenericMethodDefinition) { for (var i = 0; i < methodParameters.Length; i++) { var param = methodParameters[i]; var argNode = reorderedArgs[i + argArrayOffset]; var argExpr = ParseExpression(argNode, this.thisParam, param.ParameterType); if (!param.ParameterType.IsAssignableFrom(argExpr.Type)) { return(false); } argExprArray[i] = argExpr; } } else { var methodDefinition = method; var methodTypeArgs = method.GetGenericArguments(); for (var i = 0; i < methodParameters.Length; i++) { var param = methodParameters[i]; var argNode = reorderedArgs[i + argArrayOffset]; var argExpr = ParseExpression(argNode, this.thisParam, param.ParameterType); bool typeArgsWasResolved; if ( !TypeExtensions.TryFillGenericTypeParameters(param.ParameterType, argExpr.Type, methodTypeArgs, out typeArgsWasResolved)) { return(false); } if (typeArgsWasResolved) { // Upgrade to real method when all type args are resolved!! method = methodDefinition.MakeGenericMethod(methodTypeArgs); methodParameters = method.GetParameters(); } argExprArray[i] = argExpr; } } expression = Expression.Call(instance, method, argExprArray); expression = memberMapping.PostResolveHook(expression); return(true); } if (property != null) { var instance = ParseExpression(reorderedArgs[0], this.thisParam, null); if (!TryResolveGenericInstanceMethod(instance, ref property)) { return(false); } expression = Expression.MakeMemberAccess(instance, property); expression = memberMapping.PostResolveHook(expression); return(true); } return(false); }
private Expression ParseBinaryOperator(BinaryOperatorNode binaryOperatorNode) { var rightNode = binaryOperatorNode.Right; var leftNode = binaryOperatorNode.Left; if (binaryOperatorNode.NodeType == NodeType.Dot) { if (rightNode.NodeType == NodeType.MethodCall) { var origCallNode = (MethodCallNode)rightNode; // Rewrite extension method call to static method call of tree: // We do this by taking inserting the first node before arg nodes of extension method call. var staticMethodArgs = leftNode.WrapAsEnumerable().Concat(rightNode.Children); var staticMethodCall = new MethodCallNode(origCallNode.Name, staticMethodArgs); return(ParseExpression(staticMethodCall)); } var left = ParseExpression(leftNode); return(ParseExpression(rightNode, left, null)); } if (binaryOperatorNode.NodeType == NodeType.As) { if (rightNode.NodeType != NodeType.TypeNameLiteral) { throw CreateParseException(binaryOperatorNode, "Right side of as operator is required to be a type literal."); } return(Expression.TypeAs(ParseExpression(leftNode), ResolveType((TypeNameNode)rightNode))); } if (binaryOperatorNode.NodeType == NodeType.In) { return(ParseInOperator(binaryOperatorNode)); } var leftChild = ParseExpression(leftNode); var rightChild = ParseExpression(rightNode); PeformImplicitConversionForNodePair(ref leftChild, ref rightChild); switch (binaryOperatorNode.NodeType) { case NodeType.AndAlso: return(Expression.AndAlso(leftChild, rightChild)); case NodeType.OrElse: return(Expression.OrElse(leftChild, rightChild)); case NodeType.Add: return(Expression.Add(leftChild, rightChild)); case NodeType.Subtract: return(Expression.Subtract(leftChild, rightChild)); case NodeType.Multiply: return(Expression.Multiply(leftChild, rightChild)); case NodeType.Modulo: return(Expression.Modulo(leftChild, rightChild)); case NodeType.Divide: return(Expression.Divide(leftChild, rightChild)); case NodeType.Equal: return(ParseBinaryOperator(leftChild, rightChild, ExpressionType.Equal)); case NodeType.LessThan: return(Expression.LessThan(leftChild, rightChild)); case NodeType.GreaterThan: return(Expression.GreaterThan(leftChild, rightChild)); case NodeType.GreaterThanOrEqual: return(Expression.GreaterThanOrEqual(leftChild, rightChild)); case NodeType.LessThanOrEqual: return(Expression.LessThanOrEqual(leftChild, rightChild)); case NodeType.NotEqual: return(ParseBinaryOperator(leftChild, rightChild, ExpressionType.NotEqual)); case NodeType.CaseInsensitiveEqual: return(ParseCaseInsensitiveEqualOperator(leftChild, rightChild)); default: throw new NotImplementedException($"Don't know how to handle node type {binaryOperatorNode.NodeType}."); } }