private static Expression <T> Stitch <T>(Expression binding, LambdaSignature <T> signature) where T : class { Type targetType = typeof(T); Type siteType = typeof(CallSite <T>); var body = new ReadOnlyCollectionBuilder <Expression>(3); body.Add(binding); var site = Expression.Parameter(typeof(CallSite), "$site"); var @params = signature.Parameters.AddFirst(site); Expression updLabel = Expression.Label(CallSiteBinder.UpdateLabel); #if DEBUG // put the AST into the constant pool for debugging purposes updLabel = Expression.Block( Expression.Constant(binding, typeof(Expression)), updLabel ); #endif body.Add(updLabel); body.Add( Expression.Label( signature.ReturnLabel, Expression.Condition( Expression.Call( typeof(CallSiteOps).GetMethod("SetNotMatched"), @params.First() ), Expression.Default(signature.ReturnLabel.Type), Expression.Invoke( Expression.Property( Expression.Convert(site, siteType), typeof(CallSite <T>).GetProperty("Update") ), new TrueReadOnlyCollection <Expression>(@params) ) ) ) ); return(new Expression <T>( Expression.Block(body), "CallSite.Target", true, // always compile the rules with tail call optimization new TrueReadOnlyCollection <ParameterExpression>(@params) )); }
private static Expression <T> Stitch <T>(Expression binding, LambdaSignature <T> signature) where T : class { ParameterExpression expression; Type type = typeof(CallSite <T>); ReadOnlyCollectionBuilder <Expression> expressions = new ReadOnlyCollectionBuilder <Expression>(3) { binding }; ParameterExpression[] source = signature.Parameters.AddFirst <ParameterExpression>(expression = Expression.Parameter(typeof(CallSite), "$site")); Expression item = Expression.Label(UpdateLabel); expressions.Add(item); expressions.Add(Expression.Label(signature.ReturnLabel, Expression.Condition(Expression.Call(typeof(CallSiteOps).GetMethod("SetNotMatched"), source.First <ParameterExpression>()), Expression.Default(signature.ReturnLabel.Type), Expression.Invoke(Expression.Property(Expression.Convert(expression, type), typeof(CallSite <T>).GetProperty("Update")), new TrueReadOnlyCollection <Expression>(source))))); return(new Expression <T>(Expression.Block(expressions), "CallSite.Target", true, new TrueReadOnlyCollection <ParameterExpression>(source))); }
internal T BindCore <T>(CallSite <T> site, object[] args) where T : class { T local = this.BindDelegate <T>(site, args); if (local != null) { return(local); } LambdaSignature <T> instance = LambdaSignature <T> .Instance; Expression binding = this.Bind(args, instance.Parameters, instance.ReturnLabel); if (binding == null) { throw Error.NoOrInvalidRuleProduced(); } if (!AppDomain.CurrentDomain.IsHomogenous) { throw Error.HomogenousAppDomainRequired(); } T target = Stitch <T>(binding, instance).Compile(); this.CacheTarget <T>(target); return(target); }
// TODO: This should be merged into CallSiteBinder. private static LambdaExpression /*!*/ Stitch <T>(Expression binding, LambdaSignature <T> signature, LabelTarget returnLabel) where T : class { Expression updLabel = Expression.Label(CallSiteBinder.UpdateLabel); var site = Expression.Parameter(typeof(CallSite), "$site"); var @params = ArrayUtils.Insert(site, signature.Parameters); Expression body; if (returnLabel != signature.ReturnLabel) { // TODO: // This allows the binder to produce a strongly typed binding expression that gets boxed // if the call site's return value is of type object. // The current implementation of CallSiteBinder is too strict as it requires the two types to be reference-assignable. var tmp = Expression.Parameter(typeof(object)); body = Expression.Convert( Expression.Block(new[] { tmp }, binding, updLabel, Expression.Label( returnLabel, Expression.Condition( Expression.NotEqual( Expression.Assign( tmp, Expression.Invoke( Expression.Property( Expression.Convert(site, typeof(CallSite <T>)), typeof(CallSite <T>).GetProperty("Update") ), @params ) ), AstUtils.Constant(null) ), Expression.Convert(tmp, returnLabel.Type), Expression.Default(returnLabel.Type) ) ) ), typeof(object) ); } else { body = Expression.Block( binding, updLabel, Expression.Label( returnLabel, Expression.Invoke( Expression.Property( Expression.Convert(site, typeof(CallSite <T>)), typeof(CallSite <T>).GetProperty("Update") ), @params ) ) ); } return(Expression.Lambda <T>( body, "CallSite.Target", true, // always compile the rules with tail call optimization @params )); }