Created
March 18, 2019 17:08
-
-
Save palladin/7f623217965c6c37759187cd32f9f202 to your computer and use it in GitHub Desktop.
Expression splicing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Subs : ExpressionVisitor | |
{ | |
private Dictionary<ParameterExpression, Expression> env; | |
public Subs(Dictionary<ParameterExpression, Expression> env) | |
{ | |
this.env = env; | |
} | |
protected override Expression VisitParameter(ParameterExpression node) | |
{ | |
if (env.ContainsKey(node)) | |
return env[node]; | |
return base.VisitParameter(node); | |
} | |
} | |
class Splicer : ExpressionVisitor | |
{ | |
protected override Expression VisitMethodCall(MethodCallExpression node) | |
{ | |
var (name, method, args) = node; | |
if (name == "Invoke" && method is LambdaExpression lambda) | |
{ | |
var env = lambda.Parameters.Zip(args, (param, arg) => (param, arg)) | |
.ToDictionary(t => t.param, t => t.arg); | |
return new Subs(env).Visit(lambda.Body); | |
} | |
return base.VisitMethodCall(node); | |
} | |
} | |
public static class SplicerExtensions | |
{ | |
public static void Deconstruct(this MethodCallExpression m, out string name, out Expression func, out Expression[] args) | |
{ | |
name = m.Method.Name; | |
if (name == "Invoke") | |
{ | |
var thunk = Expression.Lambda<Func<object>>(m.Arguments[0], new ParameterExpression[0]); | |
func = thunk.Compile().DynamicInvoke() as Expression; | |
} | |
else | |
func = m.Arguments[0]; | |
args = Enumerable.Range(1, m.Arguments.Count - 1).Select(i => m.Arguments[i]).ToArray(); | |
} | |
public static TResult Invoke<TSource, TResult>(this Expression<Func<TSource, TResult>> f, TSource src) | |
{ | |
throw new Exception("Stump call"); | |
} | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Expression<Func<int, int>> f = x => x + 1; | |
Expression<Func<int, int>> g = x => f.Invoke(x + 2); | |
var test = new Splicer().Visit(g); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment