private CodeExpression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            var mr = GetMethodRef(methodCallExpression.Method);

            if (methodCallExpression.Object == null)
            {
                if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.VarRef" ||
                    mr.MethodName == "LinqToCodedom.Generator.CodeDom.ParamRef")
                {
                    return(new LinqToCodedom.Generator.CodeDom.CodeVarExpression(
                               CodeDom.Eval <string>(methodCallExpression.Arguments[0])));
                }

                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.TypeRef")
                {
                    var c = new CodeTypeReferenceExpression(
                        CodeDom.Eval <string>(methodCallExpression.Arguments[0]));

                    if (methodCallExpression.Arguments.Count == 2)
                    {
                        NewArrayExpression arr = methodCallExpression.Arguments[1] as NewArrayExpression;
                        foreach (Expression ee in arr.Expressions)
                        {
                            object t = CodeDom.Eval(ee);
                            c.Type.TypeArguments.Add(CodeDom.GetTypeReference(t));
                        }
                    }
                    return(c);
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.TypeOf")
                {
                    var c = new CodeTypeOfExpression(
                        CodeDom.Eval <string>(methodCallExpression.Arguments[0]));

                    if (methodCallExpression.Arguments.Count == 2)
                    {
                        NewArrayExpression arr = methodCallExpression.Arguments[1] as NewArrayExpression;
                        foreach (Expression ee in arr.Expressions)
                        {
                            object t = CodeDom.Eval(ee);
                            c.Type.TypeArguments.Add(CodeDom.GetTypeReference(t));
                        }
                    }

                    return(c);
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.get_nil")
                {
                    return(null);
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.Property")
                {
                    CodeExpression targetExp = _Visit(methodCallExpression.Arguments[0]);
                    if (targetExp is CodePrimitiveExpression && ((CodePrimitiveExpression)targetExp).Value == null)
                    {
                        targetExp = null;
                    }

                    return(new CodePropertyReferenceExpression(
                               targetExp,
                               CodeDom.Eval <string>(methodCallExpression.Arguments[1])));
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.Field")
                {
                    object val = null;
                    try
                    {
                        val = CodeDom.Eval(methodCallExpression.Arguments[0]);
                    }
                    catch (Exception)
                    {
                    }

                    if (val != null && val is CodeTypeReference)
                    {
                        return(new CodeFieldReferenceExpression(
                                   new CodeTypeReferenceExpression((CodeTypeReference)val),
                                   CodeDom.Eval <string>(methodCallExpression.Arguments[1])));
                    }
                    else
                    {
                        CodeExpression targetExp = _Visit(methodCallExpression.Arguments[0]);
                        if (targetExp is CodePrimitiveExpression && ((CodePrimitiveExpression)targetExp).Value == null)
                        {
                            targetExp = null;
                        }

                        return(new CodeFieldReferenceExpression(
                                   targetExp,
                                   CodeDom.Eval <string>(methodCallExpression.Arguments[1])));
                    }
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.Call")
                {
                    if (methodCallExpression.Arguments.Count == 1)
                    {
                        return(new CodeMethodInvokeExpression(
                                   null,
                                   CodeDom.Eval <string>(methodCallExpression.Arguments[0])));
                    }
                    else
                    {
                        CodeExpression targetExp = _Visit(methodCallExpression.Arguments[0]);
                        if (targetExp is CodePrimitiveExpression && ((CodePrimitiveExpression)targetExp).Value == null)
                        {
                            targetExp = null;
                        }

                        var m = new CodeMethodReferenceExpression(
                            targetExp,
                            CodeDom.Eval <string>(methodCallExpression.Arguments[1]));

                        if (methodCallExpression.Arguments.Count == 3)
                        {
                            foreach (Expression e in (methodCallExpression.Arguments[2] as NewArrayExpression).Expressions)
                            {
                                m.TypeArguments.Add(CodeDom.GetTypeReference(CodeDom.Eval(e)));
                            }
                        }

                        return(new CodeMethodInvokeExpression(m));
                    }
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.new")
                {
                    object            t    = CodeDom.Eval(methodCallExpression.Arguments[0]);
                    CodeTypeReference type = CodeDom.GetTypeReference(t);

                    if (methodCallExpression.Arguments.Count == 2)
                    {
                        NewArrayExpression arr = methodCallExpression.Arguments[1] as NewArrayExpression;
                        var exp = new CodeObjectCreateExpression(type);
                        foreach (Expression par in arr.Expressions)
                        {
                            AddParam(exp.Parameters, par);
                        }
                        return(exp);
                    }
                    else
                    {
                        return(new CodeObjectCreateExpression(type));
                    }
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.cast")
                {
                    object            t    = CodeDom.Eval(methodCallExpression.Arguments[0]);
                    CodeTypeReference type = CodeDom.GetTypeReference(t);

                    if (methodCallExpression.Method.IsGenericMethod && methodCallExpression.Method.GetGenericArguments()[0] == typeof(Var))
                    {
                        return(new CodeDom.CodeWrapExpression(new CodeCastExpression(type, _Visit(methodCallExpression.Arguments[1]))));
                    }
                    else
                    {
                        return(new CodeCastExpression(type, _Visit(methodCallExpression.Arguments[1])));
                    }
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.default")
                {
                    object            t    = CodeDom.Eval(methodCallExpression.Arguments[0]);
                    CodeTypeReference type = CodeDom.GetTypeReference(t);
                    return(new CodeDefaultValueExpression(type));
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.InjectExp")
                {
                    int num = CodeDom.Eval <int>(methodCallExpression.Arguments[0]);
                    return(_ctx.Injections[num]);
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.Is")
                {
                    return(new CodeIdentityEqualityExpression(
                               true,
                               _Visit(methodCallExpression.Arguments[0]),
                               _Visit(methodCallExpression.Arguments[1])
                               ));
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.IsNot")
                {
                    return(new CodeIdentityEqualityExpression(
                               false,
                               _Visit(methodCallExpression.Arguments[0]),
                               _Visit(methodCallExpression.Arguments[1])
                               ));
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.Lambda")
                {
                    if (methodCallExpression.Arguments[0].Type.IsArray)
                    {
                        List <LambdaParam> pars = new List <LambdaParam>();
                        foreach (LambdaParam lambdaParam in CodeDom.Eval <IEnumerable>(methodCallExpression.Arguments[0]))
                        {
                            pars.Add(lambdaParam);
                        }
                        List <CodeStatement> stmts = new List <CodeStatement>();
                        foreach (CodeStatement stmt in CodeDom.Eval <IEnumerable>(methodCallExpression.Arguments[1]))
                        {
                            stmts.Add(stmt);
                        }
                        return(new CodeLambdaStatements(stmts, pars));
                    }
                    else
                    {
                        CodeExpression     exp  = _Visit(methodCallExpression.Arguments[0]);
                        List <LambdaParam> pars = new List <LambdaParam>();
                        if (methodCallExpression.Arguments.Count == 2)
                        {
                            NewArrayExpression arr = methodCallExpression.Arguments[1] as NewArrayExpression;
                            foreach (Expression par in arr.Expressions)
                            {
                                pars.Add(CodeDom.Eval <LambdaParam>(par));
                            }
                        }
                        return(new CodeLambdaExpression(exp, pars));
                    }
                }
                else if (mr.MethodName == "LinqToCodedom.Generator.CodeDom.CallDelegate")
                {
                    CodeExpression target = null;
                    if (methodCallExpression.Arguments[0].Type == typeof(string))
                    {
                        target = new CodeVariableReferenceExpression(CodeDom.Eval <string>(methodCallExpression.Arguments[0]));
                    }
                    else
                    {
                        target = _Visit(methodCallExpression.Arguments[0]);
                    }

                    var d = new CodeDelegateInvokeExpression(target);

                    return(d);
                }
            }

            var to = _Visit(methodCallExpression.Object);

            if (to is CodeDom.CodeThisExpression || to is CodeDom.CodeBaseExpression || to is CodeDom.CodeVarExpression || to is CodeDom.CodeWrapExpression)
            {
                CodeExpression rto = to is CodeDom.CodeThisExpression ?
                                     new CodeThisReferenceExpression() :
                                     to is CodeDom.CodeBaseExpression ?
                                     new CodeBaseReferenceExpression() :
                                     to is CodeVariableReferenceExpression ?
                                     to as CodeVariableReferenceExpression :
                                     to;

                switch (mr.MethodName)
                {
                case "Call":
                    //case "CallFunction":
                    if (methodCallExpression.Arguments.Count > 0)
                    {
                        var m = new CodeMethodReferenceExpression(
                            rto,
                            CodeDom.Eval <string>(methodCallExpression.Arguments[0]));

                        if (methodCallExpression.Arguments.Count == 2)
                        {
                            foreach (Expression e in (methodCallExpression.Arguments[1] as NewArrayExpression).Expressions)
                            {
                                m.TypeArguments.Add(CodeDom.GetTypeReference(CodeDom.Eval(e)));
                            }
                        }

                        return(new CodeMethodInvokeExpression(m));
                    }
                    else
                    {
                        return(new CodeDelegateInvokeExpression(rto));
                    }

                case "Property":
                    string propertyName = CodeDom.Eval <string>(methodCallExpression.Arguments[0]);
                    if (methodCallExpression.Arguments.Count > 1)
                    {
                        throw new NotImplementedException();
                    }
                    return(new CodeDom.CodeWrapExpression(new CodePropertyReferenceExpression(rto, propertyName)));

                //return new CodePropertyReferenceExpression(rto, propertyName);
                case "Field":
                    string fieldName = CodeDom.Eval <string>(methodCallExpression.Arguments[0]);
                    if (methodCallExpression.Arguments.Count > 1)
                    {
                        throw new NotImplementedException();
                    }
                    return(new CodeFieldReferenceExpression(rto, fieldName));

                case "Raise":
                    string eventName = CodeDom.Eval <string>(methodCallExpression.Arguments[0]);
                    return(new CodeDom.CodeDelegateArgsInvoke(
                               new CodeEventReferenceExpression(rto, eventName)));

                case "ArrayGet":
                    return(new CodeArrayIndexerExpression(rto,
                                                          VisitExpressionList((methodCallExpression.Arguments[0] as NewArrayExpression).Expressions).ToArray()
                                                          ));

                case "JaggedArrayGet":
                    var n = methodCallExpression.Arguments[0] as NewArrayExpression;
                    CodeArrayIndexerExpression prev = null;
                    foreach (CodeExpression e in VisitExpressionList(n.Expressions.Reverse()))
                    {
                        if (prev == null)
                        {
                            prev = new CodeArrayIndexerExpression(rto, e);
                        }
                        else
                        {
                            prev = new CodeArrayIndexerExpression(prev, e);
                        }
                    }
                    return(prev);

                case "cast":
                    return(rto);

                default:
                    throw new NotImplementedException(mr.MethodName);
                }
            }
            //else if (to is CodeDom.CodeArgsInvoke)
            //{
            //    var c = to as CodeMethodInvokeExpression;
            //    c.Parameters.AddRange(VisitArguments(methodCallExpression.Arguments));
            //    //foreach (CodeExpression par in VisitSequence(
            //    //    new QueryVisitor((e) => e is LambdaExpression)
            //    //        .Visit(methodCallExpression.Arguments[0]) as LambdaExpression))
            //    //{
            //    //    c.Parameters.Add(par);
            //    //}
            //    return c;
            //}
            //else if (to is CodeDom.CodeDelegateArgsInvoke)
            //{
            //    var c = to as CodeDelegateInvokeExpression;
            //    c.Parameters.AddRange(VisitArguments(methodCallExpression.Arguments));
            //    //foreach (CodeExpression par in VisitSequence(
            //    //    new QueryVisitor((e) => e is LambdaExpression)
            //    //        .Visit(methodCallExpression.Arguments[0]) as LambdaExpression))
            //    //{
            //    //    c.Parameters.Add(par);
            //    //}
            //    return c;
            //}
            else
            {
                if ((methodCallExpression.Object != null && methodCallExpression.Object.Type.IsArray &&
                     mr.MethodName == "Get") ||
                    (mr.MethodName == "get_Item" && methodCallExpression.Method.IsSpecialName))
                {
                    var c = new CodeArrayIndexerExpression();
                    foreach (var par in methodCallExpression.Arguments)
                    {
                        AddParam(c.Indices, par);
                    }
                    c.TargetObject = to;
                    return(c);
                }
                else
                {
                    var c = new CodeMethodInvokeExpression(mr);
                    foreach (var par in methodCallExpression.Arguments)
                    {
                        AddParam(c.Parameters, par);
                    }
                    c.Method.TargetObject = to;
                    return(c);
                }
            }
        }