BrainFlood: Runtime code generation via reflection in .NET
Posted 23 hours ago
If you're familiar with brainfuck, you'll know it doesn't need to represent constants; however, they're really useful for some optimizations. My interpreter converts the brainfuck code into a bytecode which contains integer offsets. My compiler works by converting the bytecode into a disgusting ball of generic types. So I needed constants, and if I couldn't handle constants, the project was probably doomed anyway.

Behold:
interface Const {
    int Run();
}

// Single Hex Digits
struct D0 : Const { public int Run() => 0; }
struct D1 : Const { public int Run() => 1; }
struct D2 : Const { public int Run() => 2; }
// D3 - DD omitted
struct DE : Const { public int Run() => 0xE; }
struct DF : Const { public int Run() => 0xF; }

// Two Hex Digits
struct Num<A,B> : Const
    where A: struct, Const
    where B: struct, Const
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int Run() {
        return default(A).Run()<<4 | default(B).Run();
    }
}

// Negatives
struct Neg<A> : Const
    where A: struct, Const
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int Run() {
        return -default(A).Run();
    }
}
With these building blocks, we can represent any integer constant. We can verify it works with Sharplab:
class Example {
    int Run() {
        return default(Neg<Num<D2,DF>>).Run();
    }
}
// compiles to
    L0000: mov eax, 0xffffffd1
    L0005: ret