private static LinqExpression Compile(ElementExpression value, CompilationData data)
{
data.Cache ??= new Dictionary <CachedExpression, ParameterExpression>();
data.GroupCache ??= new Dictionary <ExpressionGroup, LinqExpression[]>();
switch (value)
{
case ICLRExpression s:
return(s.Compile(e => Compile(e, data)));
case Constant c:
return(LinqExpression.Constant(c.Value));
case Binary b:
var ea = Compile(b.OpA, data);
var eb = Compile(b.OpB, data);
if (b.Operation == Binary.Op.Pow)
{
var o = LinqExpression.Call(typeof(Math).GetMethod(nameof(Math.Pow)),
LinqExpression.Convert(ea, typeof(double)), LinqExpression.Convert(eb, typeof(double)));
return(LinqExpression.Convert(o, typeof(float)));
}
if (b.Operation == Binary.Op.Atan2)
{
var o = LinqExpression.Call(typeof(Math).GetMethod(nameof(Math.Atan2)),
LinqExpression.Convert(ea, typeof(double)), LinqExpression.Convert(eb, typeof(double)));
return(LinqExpression.Convert(o, typeof(float)));
}
return(BinaryOps[b.Operation](ea, eb));
case Unary u:
var input = Compile(u.Operand, data);
var output = LinqExpression.Call(MethodOps[u.Operation], LinqExpression.Convert(input, typeof(double)));
return(LinqExpression.Convert(output, typeof(float)));
case CachedExpression v:
if (!data.Cache.TryGetValue(v, out var varExpr))
{
var result = Compile(v.Value, data);
data.Cache.Add(v, varExpr = LinqExpression.Parameter(result.Type));
data.Statements.Add(LinqExpression.Assign(varExpr, result));
data.Variables.Add(varExpr);
}
return(varExpr);
case Mux m:
if (m.Operands.Count == 2)
{
return(LinqExpression.Condition(
LinqExpression.LessThan(Compile(m.Selector, data), LinqExpression.Constant(1f)),
Compile(m.Operands[0], data), Compile(m.Operands[1], data)));
}
var sel = LinqExpression.Convert(Compile(m.Selector, data), typeof(int));
var clampedSel =
LinqExpression.Condition(
LinqExpression.GreaterThanOrEqual(sel, LinqExpression.Constant(m.Operands.Count)),
LinqExpression.Constant(m.Operands.Count - 1), sel);
var cases = m.Operands.Select(
(c, i) => LinqExpression.SwitchCase(Compile(c, data), LinqExpression.Constant(i)))
.ToArray();
return(LinqExpression.Switch(clampedSel, cases[0].Body, cases));
case State s:
if (data.ResolveState == null)
{
throw new Exception("Tried to compile a State expression outside of an ExpressionGroup");
}
return(data.ResolveState(s));
case ExpressionGroupElement groupElement:
if (!data.GroupCache.TryGetValue(groupElement.Group, out var groupList))
{
data.GroupCache.Add(groupElement.Group, groupList = CompileGroup(groupElement.Group, data));
}
return(groupList[groupElement.Index]);
}
throw new Exception("Unknown expression " + value);
}