So, we can convert a brainfuck program into a bunch of very unconventional C# code. But what about compiling at runtime? You were told it worked at runtime! Now Reflection will save the day! S&box exposes a simplified reflection library, but it's enough for our purposes.
Here's how we construct constants:
private static Type MakeGeneric(Type base_ty, Type[] args) {
return TypeLibrary.GetType(base_ty).MakeGenericType(args);
}
private static Type GetDigit(int n) {
switch (n) {
case 0: return typeof(D0);
case 1: return typeof(D1);
case 2: return typeof(D2);
case 3: return typeof(D3);
case 4: return typeof(D4);
case 5: return typeof(D5);
case 6: return typeof(D6);
case 7: return typeof(D7);
case 8: return typeof(D8);
case 9: return typeof(D9);
case 0xA: return typeof(DA);
case 0xB: return typeof(DB);
case 0xC: return typeof(DC);
case 0xD: return typeof(DD);
case 0xE: return typeof(DE);
case 0xF: return typeof(DF);
}
throw new Exception("die");
}
private static Type GenerateConst(int n) {
if (n < 0) {
return MakeGeneric(typeof(Neg<>),[GenerateConst(-n)]);
}
if (n < 16) {
return GetDigit(n);
} else if (n < 256) {
return MakeGeneric(typeof(Num<,>),[GetDigit(n>>4),GetDigit(n&0xF)]);
} else {
throw new Exception("const too large "+n);
}
}
Building instructions is basically the same. You can take a look at the
full code, if you want.