// Pseudocode:
//I input =>
//{
// var i = (UI)input;
// var result = new char[base64sizeof(UI)];
// for (int j = 0; j == 0 || i > 0; j++)
// {
// result[j] = _mapChar[i & 0x3f];
// i >>= 6;
// }
//}
private LambdaExpression toLambda(Type from)
{
var input = Ex.Parameter(from, "input");
var result = Ex.Parameter(typeof(char[]), "result");
var i = workingType(from) == from ? input : Ex.Parameter(workingType(from), "i");
var j = Ex.Parameter(typeof(int), "j");
var loopstart = Ex.Label("loopstart");
var loopend = Ex.Label("loopend");
var loop = Ex.Block(
Ex.Label(loopstart),
Ex.IfThen(Ex.MakeBinary(ExpressionType.AndAlso,
Ex.MakeBinary(ExpressionType.GreaterThan, j, Ex.Constant(0)),
i.Type == typeof(BigInteger)
? (Ex)Ex.Call(i, nameof(BigInteger.Equals), Type.EmptyTypes, Ex.Constant(BigInteger.Zero))
: Ex.MakeBinary(ExpressionType.Equal, i, Ex.Convert(Ex.Constant(0), i.Type))),
Ex.Goto(loopend)),
Ex.Assign(
Ex.ArrayAccess(result, j),
Ex.ArrayIndex(Ex.Constant(_mapChars),
Ex.Convert(Ex.MakeBinary(ExpressionType.And, i, Ex.Convert(Ex.Constant(0x3f), i.Type)), typeof(int)))),
Ex.RightShiftAssign(i, Ex.Constant(6)),
Ex.PostIncrementAssign(j),
Ex.Goto(loopstart));
var ret = Result(typeof(string),
Ex.New(typeof(string).GetTypeInfo().DeclaredConstructors
.Select(c => new { c, p = c.GetParameters() })
.First(c => c.p.Length == 3 && c.p[0].ParameterType == typeof(char[]) && c.p[1].ParameterType == typeof(int) && c.p[2].ParameterType == typeof(int)).c,
result, Ex.Constant(0), j));
var block = Ex.Block(Ex.Assign(j, Ex.Constant(0)),
Ex.Assign(result, Ex.NewArrayBounds(typeof(char), Ex.Constant(charbound(from)))),
loop,
Ex.Label(loopend),
ret);
block = input == i
? Ex.Block(new[] { j, result },
block)
: Ex.Block(new[] { i, j, result },
Ex.Assign(i, Ex.Convert(input, i.Type)),
block);
return(Ex.Lambda(block, input));
}