// 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 )); } }
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) )); }
// 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); }
// 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 )); }
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) )); }
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 )); }
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))); }
// 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() )); } } }
// 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()))); }
// 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."); }