Exemple #1
0
        // Returns a dynamic InvokeMember or Invoke expression, depending on the
        // Function expression.
        //
        public static DynamicExpression AnalyzeFunCallExpr(
            SymplFunCallExpr expr, AnalysisScope scope)
        {
            if (expr.Function is SymplDottedExpr)
            {
                SymplDottedExpr dottedExpr = (SymplDottedExpr)expr.Function;
                Expression      objExpr;
                int             length = dottedExpr.Exprs.Length;
                if (length > 1)
                {
                    objExpr = AnalyzeDottedExpr(
                        // create a new dot expression for the object that doesn't
                        // include the last part
                        new SymplDottedExpr(
                            dottedExpr.ObjectExpr,
                            RuntimeHelpers.RemoveLast(dottedExpr.Exprs)),
                        scope
                        );
                }
                else
                {
                    objExpr = AnalyzeExpr(dottedExpr.ObjectExpr, scope);
                }
                List <Expression> args = new List <Expression>();
                args.Add(objExpr);
                args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));

                // last expr must be an id
                var lastExpr = (SymplIdExpr)(dottedExpr.Exprs.Last());
                return(Expression.Dynamic(
                           scope.GetRuntime().GetInvokeMemberBinder(
                               new InvokeMemberBinderKey(
                                   lastExpr.IdToken.Name,
                                   new CallInfo(expr.Arguments.Length))),
                           typeof(object),
                           args
                           ));
            }
            else
            {
                var fun = AnalyzeExpr(expr.Function, scope);
                List <Expression> args = new List <Expression>();
                args.Add(fun);
                args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));
                // Use DynExpr so that I don't always have to have a delegate to call,
                // such as what happens with IPy interop.
                return(Expression.Dynamic(
                           scope.GetRuntime()
                           .GetInvokeBinder(new CallInfo(expr.Arguments.Length)),
                           typeof(object),
                           args
                           ));
            }
        }
Exemple #2
0
        public static Expression AnalyzeBinaryExpr(SymplBinaryExpr expr,
                                                   AnalysisScope scope)
        {
            // The language has the following special logic to handle And and Or
            // x And y == if x then y
            // x Or y == if x then x else (if y then y)
            if (expr.Operation == ExpressionType.And)
            {
                return(AnalyzeIfExpr(
                           new SymplIfExpr(
                               expr.Left, expr.Right, null),
                           scope));
            }
            else if (expr.Operation == ExpressionType.Or)
            {
                // Use (LetStar (tmp expr) (if tmp tmp)) to represent (if expr expr)
                // to remore duplicate evaluation.
                // So x Or y is translated into
                // (Let* (tmp1 x)
                //    (If tmp1 tmp1
                //       (Let* (tmp2 y) (If tmp2 tmp2))))
                //

                IdOrKeywordToken tmp2 = new IdOrKeywordToken(
                    // Real implementation needs to ensure unique ID in scope chain.
                    "__tmpLetVariable2");
                var tmpExpr2 = new SymplIdExpr(tmp2);
                var binding2 = new LetBinding(tmp2, expr.Right);;
                var ifExpr2  = new SymplIfExpr(
                    tmpExpr2, tmpExpr2, null);
                var letExpr2 = new SymplLetStarExpr(
                    new[] { binding2 },
                    new[] { ifExpr2 });

                IdOrKeywordToken tmp1 = new IdOrKeywordToken(
                    // Real implementation needs to ensure unique ID in scope chain.
                    "__tmpLetVariable1");
                var        tmpExpr1 = new SymplIdExpr(tmp1);
                LetBinding binding1 = new LetBinding(tmp1, expr.Left);;
                SymplExpr  ifExpr1  = new SymplIfExpr(
                    tmpExpr1, tmpExpr1, letExpr2);
                return(AnalyzeLetStarExpr(
                           new SymplLetStarExpr(
                               new[] { binding1 },
                               new[] { ifExpr1 }
                               ),
                           scope
                           ));
            }

            return(Expression.Dynamic(
                       scope.GetRuntime().GetBinaryOperationBinder(expr.Operation),
                       typeof(object),
                       AnalyzeExpr(expr.Left, scope),
                       AnalyzeExpr(expr.Right, scope)
                       ));
        }
Exemple #3
0
        // Returns a chain of GetMember and InvokeMember dynamic expressions for
        // the dotted expr.
        //
        public static Expression AnalyzeDottedExpr(SymplDottedExpr expr,
                                                   AnalysisScope scope)
        {
            var curExpr = AnalyzeExpr(expr.ObjectExpr, scope);

            foreach (var e in expr.Exprs)
            {
                if (e is SymplIdExpr)
                {
                    curExpr = Expression.Dynamic(
                        scope.GetRuntime()
                        .GetGetMemberBinder(((SymplIdExpr)e).IdToken.Name),
                        typeof(object),
                        curExpr
                        );
                }
                else if (e is SymplFunCallExpr)
                {
                    var call = (SymplFunCallExpr)e;
                    List <Expression> args = new List <Expression>();
                    args.Add(curExpr);
                    args.AddRange(call.Arguments.Select(a => AnalyzeExpr(a, scope)));

                    curExpr = Expression.Dynamic(
                        // Dotted exprs must be simple invoke members, a.b.(c ...)
                        scope.GetRuntime().GetInvokeMemberBinder(
                            new InvokeMemberBinderKey(
                                ((SymplIdExpr)call.Function).IdToken.Name,
                                new CallInfo(call.Arguments.Length))),
                        typeof(object),
                        args
                        );
                }
                else
                {
                    throw new InvalidOperationException(
                              "Internal: dotted must be IDs or Funs.");
                }
            }
            return(curExpr);
        }
Exemple #4
0
        // AnalyzeEltExpr returns and Expression for accessing an element of an
        // aggregate structure.  This also works for .NET objs with indexer Item
        // properties.  We handle analyzing Elt for assignment in AnalyzeAssignExpr.
        //
        public static Expression AnalyzeEltExpr(SymplEltExpr expr,
                                                AnalysisScope scope)
        {
            List <Expression> args = new List <Expression>();

            args.Add(AnalyzeExpr(expr.ObjectExpr, scope));
            args.AddRange(expr.Indexes.Select(e => AnalyzeExpr(e, scope)));

            return(Expression.Dynamic(
                       scope.GetRuntime().GetGetIndexBinder(
                           new CallInfo(expr.Indexes.Length)),
                       typeof(object),
                       args
                       ));
        }
Exemple #5
0
 public static DynamicExpression AnalyzeDefunExpr(SymplDefunExpr expr,
                                                  AnalysisScope scope)
 {
     if (!scope.IsModule)
     {
         throw new InvalidOperationException(
                   "Use Defmethod or Lambda when not defining top-level function.");
     }
     return(Expression.Dynamic(
                scope.GetRuntime().GetSetMemberBinder(expr.Name),
                typeof(object),
                scope.ModuleExpr,
                AnalyzeLambdaDef(expr.Params, expr.Body, scope,
                                 "defun " + expr.Name)));
 }
Exemple #6
0
 public static Expression AnalyzeUnaryExpr(SymplUnaryExpr expr,
                                           AnalysisScope scope)
 {
     if (expr.Operation == ExpressionType.Not)
     {
         return(Expression.Not(WrapBooleanTest(AnalyzeExpr(expr.Operand,
                                                           scope))));
     }
     // Example purposes only, we should never get here since we only have Not.
     return(Expression.Dynamic(
                scope.GetRuntime().GetUnaryOperationBinder(expr.Operation),
                typeof(object),
                AnalyzeExpr(expr.Operand, scope)
                ));
 }
Exemple #7
0
        public static Expression AnalyzeNewExpr(SymplNewExpr expr,
                                                AnalysisScope scope)
        {
            List <Expression> args = new List <Expression>();

            args.Add(AnalyzeExpr(expr.Type, scope));
            args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));

            return(Expression.Dynamic(
                       scope.GetRuntime().GetCreateInstanceBinder(
                           new CallInfo(expr.Arguments.Length)),
                       typeof(object),
                       args
                       ));
        }
Exemple #8
0
 // Return an Expression for referencing the ID.  If we find the name in the
 // scope chain, then we just return the stored ParamExpr.  Otherwise, the
 // reference is a dynamic member lookup on the root scope, a module object.
 //
 public static Expression AnalyzeIdExpr(SymplIdExpr expr,
                                        AnalysisScope scope)
 {
     if (expr.IdToken.IsKeywordToken)
     {
         if (expr.IdToken == KeywordToken.Nil)
         {
             return(Expression.Constant(null, typeof(object)));
         }
         else if (expr.IdToken == KeywordToken.True)
         {
             return(Expression.Constant(true));
         }
         else if (expr.IdToken == KeywordToken.False)
         {
             return(Expression.Constant(false));
         }
         else
         {
             throw new InvalidOperationException(
                       "Internal: unrecognized keyword literal constant.");
         }
     }
     else
     {
         var param = FindIdDef(expr.IdToken.Name, scope);
         if (param != null)
         {
             return(param);
         }
         else
         {
             return(Expression.Dynamic(
                        scope.GetRuntime().GetGetMemberBinder(expr.IdToken.Name),
                        typeof(object),
                        scope.GetModuleExpr()
                        ));
         }
     }
 }
Exemple #9
0
 public static Expression AnalyzeUnaryExpr(SymplUnaryExpr expr,
                                           AnalysisScope scope) {
     
     if (expr.Operation == ExpressionType.Not) {
         return Expression.Not(WrapBooleanTest(AnalyzeExpr(expr.Operand,
                                                            scope)));
     }
     // Example purposes only, we should never get here since we only have Not.
     return Expression.Dynamic(
         scope.GetRuntime().GetUnaryOperationBinder(expr.Operation),
         typeof(object),
         AnalyzeExpr(expr.Operand, scope)
     );
 }
Exemple #10
0
        public static Expression AnalyzeBinaryExpr(SymplBinaryExpr expr,
                                                   AnalysisScope scope) {

            // The language has the following special logic to handle And and Or
            // x And y == if x then y
            // x Or y == if x then x else (if y then y)
            if (expr.Operation == ExpressionType.And) {
                return AnalyzeIfExpr(
                    new SymplIfExpr(
                        expr.Left, expr.Right, null),
                    scope); 
            } else if (expr.Operation == ExpressionType.Or) {
                // Use (LetStar (tmp expr) (if tmp tmp)) to represent (if expr expr)
                // to remore duplicate evaluation.
                // So x Or y is translated into
                // (Let* (tmp1 x) 
                //    (If tmp1 tmp1  
                //       (Let* (tmp2 y) (If tmp2 tmp2))))
                //           

                IdOrKeywordToken tmp2 = new IdOrKeywordToken(
                    // Real implementation needs to ensure unique ID in scope chain.
                    "__tmpLetVariable2");
                var tmpExpr2 = new SymplIdExpr(tmp2);
                var binding2 = new LetBinding(tmp2, expr.Right); ;
                var ifExpr2 = new SymplIfExpr(
                    tmpExpr2, tmpExpr2, null);
                var letExpr2 = new SymplLetStarExpr(
                        new[] { binding2 },
                        new[] { ifExpr2 });

                IdOrKeywordToken tmp1 = new IdOrKeywordToken(
                    // Real implementation needs to ensure unique ID in scope chain.
                    "__tmpLetVariable1");
                var tmpExpr1 = new SymplIdExpr(tmp1);
                LetBinding binding1 = new LetBinding(tmp1, expr.Left); ;
                SymplExpr ifExpr1 = new SymplIfExpr(
                    tmpExpr1, tmpExpr1, letExpr2);
                return AnalyzeLetStarExpr(
                    new SymplLetStarExpr(
                        new[] { binding1 },
                        new[] { ifExpr1 }
                    ),
                    scope
                );
            }

            return Expression.Dynamic(
                scope.GetRuntime().GetBinaryOperationBinder(expr.Operation),
                typeof(object),
                AnalyzeExpr(expr.Left, scope),
                AnalyzeExpr(expr.Right, scope)
            );
        }
Exemple #11
0
        public static Expression AnalyzeNewExpr(SymplNewExpr expr,
                                                AnalysisScope scope) {

            List<Expression> args = new List<Expression>();
            args.Add(AnalyzeExpr(expr.Type, scope));
            args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));

            return Expression.Dynamic(
                scope.GetRuntime().GetCreateInstanceBinder(
                                     new CallInfo(expr.Arguments.Length)),
                typeof(object),
                args
            );
        }
Exemple #12
0
 // AnalyzeQuoteExpr converts a list, literal, or id expr to a runtime quoted
 // literal and returns the Constant expression for it.
 //
 public static Expression AnalyzeQuoteExpr(SymplQuoteExpr expr,
                                             AnalysisScope scope) {
     return Expression.Constant(MakeQuoteConstant(
                                    expr.Expr, scope.GetRuntime()));
 }
Exemple #13
0
		// Return an Expression for referencing the ID.  If we find the name in the
		// scope chain, then we just return the stored ParamExpr.  Otherwise, the
		// reference is a dynamic member lookup on the root scope, a module object.
		//
        public static Expression AnalyzeIdExpr(SymplIdExpr expr,
                                                AnalysisScope scope) {
            if (expr.IdToken.IsKeywordToken) {
                if (expr.IdToken == KeywordToken.Nil)
                    return Expression.Constant(null, typeof(object));
                else if (expr.IdToken == KeywordToken.True)
                    return Expression.Constant(true);
                else if (expr.IdToken == KeywordToken.False)
                    return Expression.Constant(false);
                else
                    throw new InvalidOperationException(
                        "Internal: unrecognized keyword literal constant.");
            } else {
                var param = FindIdDef(expr.IdToken.Name, scope);
                if (param != null) {
                    return param;
                } else {
                    return Expression.Dynamic(
                       scope.GetRuntime().GetGetMemberBinder(expr.IdToken.Name),
                       typeof(object),
                       scope.GetModuleExpr()
                    );
                }
            }
        }
Exemple #14
0
		// AnalyzeAssignExpr handles IDs, indexing, and member sets.  IDs are either
		// lexical or dynamic exprs on the module scope.  Everything
		// else is dynamic.
		//
        public static Expression AnalyzeAssignExpr(SymplAssignExpr expr,
                                                    AnalysisScope scope) {
            if (expr.Location is SymplIdExpr) {
                var idExpr = (SymplIdExpr)(expr.Location);
                var lhs = AnalyzeExpr(expr.Location, scope);
                var val = AnalyzeExpr(expr.Value, scope);
                var param = FindIdDef(idExpr.IdToken.Name, scope);
                if (param != null) {
                    // Assign returns value stored.
                    return Expression.Assign(
                               lhs,
                               Expression.Convert(val, param.Type));
                } else {
                    var tmp = Expression.Parameter(typeof(object),
                                                   "assignTmpForRes");
                    // Ensure stored value is returned.  Had some erroneous
                    // MOs come through here and left the code for example.
                    return Expression.Block(
                       new[] { tmp },
                       Expression.Assign(
                           tmp,
                           Expression.Convert(val, typeof(object))),
                       Expression.Dynamic(
                           scope.GetRuntime()
                                .GetSetMemberBinder(idExpr.IdToken.Name),
                           typeof(object),
                           scope.GetModuleExpr(),
                           tmp),
                       tmp);
                }
            } else if (expr.Location is SymplEltExpr) {
                var eltExpr = (SymplEltExpr)(expr.Location);
                var args = new List<Expression>();
                args.Add(AnalyzeExpr(eltExpr.ObjectExpr, scope));
                args.AddRange(eltExpr.Indexes.Select(e => AnalyzeExpr(e, scope)));
                args.Add(AnalyzeExpr(expr.Value, scope));
                // Trusting MO convention to return stored values.
                return Expression.Dynamic(
                           scope.GetRuntime().GetSetIndexBinder(
                                   new CallInfo(eltExpr.Indexes.Length)), 
                           typeof(object),
                           args);
            } else if (expr.Location is SymplDottedExpr) {
                // For now, one dot only.  Later, pick oflast dotted member
                // access (like AnalyzeFunctionCall), and use a temp and block.
                var dottedExpr = (SymplDottedExpr)(expr.Location);
                if (dottedExpr.Exprs.Length > 1) {
                    throw new InvalidOperationException(
                        "Don't support assigning with more than simple dotted " +
                        "expression, o.foo.");
                }
                if (!(dottedExpr.Exprs[0] is SymplIdExpr)) {
                    throw new InvalidOperationException(
                        "Only support unindexed field or property when assigning " +
                        "dotted expression location.");
                }
                var id = (SymplIdExpr)(dottedExpr.Exprs[0]);
                // Trusting MOs convention to return stored values.
                return Expression.Dynamic(
                           scope.GetRuntime().GetSetMemberBinder(id.IdToken.Name),
                           typeof(object),
                           AnalyzeExpr(dottedExpr.ObjectExpr, scope),
                           AnalyzeExpr(expr.Value, scope)
                );
            }

            throw new InvalidOperationException("Invalid left hand side type.");
        }
Exemple #15
0
		// Returns a chain of GetMember and InvokeMember dynamic expressions for
		// the dotted expr.
		//
        public static Expression AnalyzeDottedExpr(SymplDottedExpr expr,
                                                    AnalysisScope scope) {
            var curExpr = AnalyzeExpr(expr.ObjectExpr, scope);
            foreach (var e in expr.Exprs) {
                if (e is SymplIdExpr) {
                    curExpr = Expression.Dynamic(
                        scope.GetRuntime()
                             .GetGetMemberBinder(((SymplIdExpr)e).IdToken.Name),
                        typeof(object),
                        curExpr
                    );
                } else if (e is SymplFunCallExpr) {
                    var call = (SymplFunCallExpr)e;
                    List<Expression> args = new List<Expression>();
                    args.Add(curExpr);
                    args.AddRange(call.Arguments.Select(a => AnalyzeExpr(a, scope)));

                    curExpr = Expression.Dynamic(
                        // Dotted exprs must be simple invoke members, a.b.(c ...) 
                        scope.GetRuntime().GetInvokeMemberBinder(
                            new InvokeMemberBinderKey(
                                ((SymplIdExpr)call.Function).IdToken.Name,
                                new CallInfo(call.Arguments.Length))),
                        typeof(object),
                        args
                    );
                } else {
                    throw new InvalidOperationException(
                        "Internal: dotted must be IDs or Funs.");
                }
            }
            return curExpr;
        }
Exemple #16
0
        // AnalyzeAssignExpr handles IDs, indexing, and member sets.  IDs are either
        // lexical or dynamic exprs on the module scope (ExpandoObject).  Everything
        // else is dynamic.
        //
        public static Expression AnalyzeAssignExpr(SymplAssignExpr expr,
                                                   AnalysisScope scope)
        {
            if (expr.Location is SymplIdExpr)
            {
                var idExpr = (SymplIdExpr)(expr.Location);
                var lhs    = AnalyzeExpr(expr.Location, scope);
                var val    = AnalyzeExpr(expr.Value, scope);
                var param  = FindIdDef(idExpr.IdToken.Name, scope);
                if (param != null)
                {
                    // Assign returns value stored.
                    return(Expression.Assign(
                               lhs,
                               Expression.Convert(val, param.Type)));
                }
                else
                {
                    var tmp = Expression.Parameter(typeof(object),
                                                   "assignTmpForRes");
                    // Ensure stored value is returned.  Had some erroneous
                    // MOs come through here and left the code for example.
                    return(Expression.Block(
                               new[] { tmp },
                               Expression.Assign(
                                   tmp,
                                   Expression.Convert(val, typeof(object))),
                               Expression.Dynamic(
                                   scope.GetRuntime()
                                   .GetSetMemberBinder(idExpr.IdToken.Name),
                                   typeof(object),
                                   scope.GetModuleExpr(),
                                   tmp),
                               tmp));
                }
            }
            else if (expr.Location is SymplEltExpr)
            {
                var eltExpr = (SymplEltExpr)(expr.Location);
                var args    = new List <Expression>();
                args.Add(AnalyzeExpr(eltExpr.ObjectExpr, scope));
                args.AddRange(eltExpr.Indexes.Select(e => AnalyzeExpr(e, scope)));
                args.Add(AnalyzeExpr(expr.Value, scope));
                // Trusting MO convention to return stored values.
                return(Expression.Dynamic(
                           scope.GetRuntime().GetSetIndexBinder(
                               new CallInfo(eltExpr.Indexes.Length)),
                           typeof(object),
                           args));
            }
            else if (expr.Location is SymplDottedExpr)
            {
                // For now, one dot only.  Later, pick oflast dotted member
                // access (like AnalyzeFunctionCall), and use a temp and block.
                var dottedExpr = (SymplDottedExpr)(expr.Location);
                if (dottedExpr.Exprs.Length > 1)
                {
                    throw new InvalidOperationException(
                              "Don't support assigning with more than simple dotted " +
                              "expression, o.foo.");
                }
                if (!(dottedExpr.Exprs[0] is SymplIdExpr))
                {
                    throw new InvalidOperationException(
                              "Only support unindexed field or property when assigning " +
                              "dotted expression location.");
                }
                var id = (SymplIdExpr)(dottedExpr.Exprs[0]);
                // Trusting MOs convention to return stored values.
                return(Expression.Dynamic(
                           scope.GetRuntime().GetSetMemberBinder(id.IdToken.Name),
                           typeof(object),
                           AnalyzeExpr(dottedExpr.ObjectExpr, scope),
                           AnalyzeExpr(expr.Value, scope)
                           ));
            }

            throw new InvalidOperationException("Invalid left hand side type.");
        }
Exemple #17
0
        // AnalyzeEltExpr returns and Expression for accessing an element of an
        // aggregate structure.  This also works for .NET objs with indexer Item
        // properties.  We handle analyzing Elt for assignment in AnalyzeAssignExpr.
        //
        public static Expression AnalyzeEltExpr(SymplEltExpr expr,
                                                AnalysisScope scope) {

            List<Expression> args = new List<Expression>();
            args.Add(AnalyzeExpr(expr.ObjectExpr, scope));
            args.AddRange(expr.Indexes.Select(e => AnalyzeExpr(e, scope)));

            return Expression.Dynamic(
                scope.GetRuntime().GetGetIndexBinder(
                                      new CallInfo(expr.Indexes.Length)),
                typeof(object),
                args
            );
        }
Exemple #18
0
 // AnalyzeQuoteExpr converts a list, literal, or id expr to a runtime quoted
 // literal and returns the Constant expression for it.
 //
 public static Expression AnalyzeQuoteExpr(SymplQuoteExpr expr,
                                           AnalysisScope scope)
 {
     return(Expression.Constant(MakeQuoteConstant(
                                    expr.Expr, scope.GetRuntime())));
 }
Exemple #19
0
 public static DynamicExpression AnalyzeDefunExpr(SymplDefunExpr expr,
                                                   AnalysisScope scope) {
     if (!scope.IsModule) {
         throw new InvalidOperationException(
             "Use Defmethod or Lambda when not defining top-level function.");
     }
     return Expression.Dynamic(
                scope.GetRuntime().GetSetMemberBinder(expr.Name),
                typeof(object),
                scope.ModuleExpr,
                AnalyzeLambdaDef(expr.Params, expr.Body, scope,
                                 "defun " + expr.Name));
 }
Exemple #20
0
		// Returns a dynamic InvokeMember or Invoke expression, depending on the
		// Function expression.
		//
        public static DynamicExpression AnalyzeFunCallExpr(
                SymplFunCallExpr expr, AnalysisScope scope) {
            if (expr.Function is SymplDottedExpr) {
                SymplDottedExpr dottedExpr = (SymplDottedExpr)expr.Function;
                Expression objExpr;
                int length = dottedExpr.Exprs.Length;
                if (length > 1) {
                    objExpr = AnalyzeDottedExpr(
                        // create a new dot expression for the object that doesn't
                        // include the last part
                        new SymplDottedExpr(
                               dottedExpr.ObjectExpr, 
                               RuntimeHelpers.RemoveLast(dottedExpr.Exprs)),
                        scope
                    );
                } else {
                    objExpr = AnalyzeExpr(dottedExpr.ObjectExpr, scope);
                }
                List<Expression> args = new List<Expression>();
                args.Add(objExpr);
                args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));

                // last expr must be an id
                var lastExpr = (SymplIdExpr)(dottedExpr.Exprs.Last());
                return Expression.Dynamic(
                    scope.GetRuntime().GetInvokeMemberBinder(
                        new InvokeMemberBinderKey(
                            lastExpr.IdToken.Name,
                            new CallInfo(expr.Arguments.Length))),
                    typeof(object),
                    args
                );
            } else {
                var fun = AnalyzeExpr(expr.Function, scope);
                List<Expression> args = new List<Expression>();
                args.Add(fun);
                args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));
                // Use DynExpr so that I don't always have to have a delegate to call,
                // such as what happens with IPy interop.
                return Expression.Dynamic(
                    scope.GetRuntime()
                         .GetInvokeBinder(new CallInfo(expr.Arguments.Length)),
                    typeof(object),
                    args
                );
            }
        }