module withbody;


extern fn int printf(char *, ...);

struct Foo
{
    int x;
}

fn int Foo.mutate(Foo *foo)
{
    printf("Mutating\n");
    return 10 * ++foo.x;
}

macro @macro_with_body(foo, #x; @body(x, y))
{
    #x = foo.x;
    @body(foo.mutate(), #x);
}

macro @repeat(int times; @body(x))
{
    for (int i = 0; i < times; i++)
    {
       @body(i + 1);
    }
}

fn void main()
{
    Foo f = { 33 };
    int y;
    @macro_with_body(f, y; int x, int dy)
    {
        printf("Got values %d, %d\n", x, dy);
    };
    @repeat(10; int loop)
    {
        printf("Repeat %d\n", loop);
    };

}

/* #expect: withbody.ll

define i32 @withbody.Foo.mutate(ptr %0) #0 {
entry:
  %1 = call i32 (ptr, ...) @printf(ptr @.str.2)
  %2 = load i32, ptr %0, align 4
  %add = add i32 %2, 1
  store i32 %add, ptr %0, align 4
  %mul = mul i32 10, %add
  ret i32 %mul
}

define void @withbody.main() #0 {
entry:
  %f = alloca %Foo, align 4
  %y = alloca i32, align 4
  %foo = alloca %Foo, align 4
  %x = alloca i32, align 4
  %dy = alloca i32, align 4
  %i = alloca i32, align 4
  %loop = alloca i32, align 4
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %f, ptr align 4 @.__const, i32 4, i1 false)
  store i32 0, ptr %y, align 4
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %foo, ptr align 4 %f, i32 4, i1 false)
  %0 = load i32, ptr %foo, align 4
  store i32 %0, ptr %y, align 4
  %1 = call i32 @withbody.Foo.mutate(ptr %foo)
  store i32 %1, ptr %x, align 4
  %2 = load i32, ptr %y, align 4
  store i32 %2, ptr %dy, align 4
  %3 = load i32, ptr %x, align 4
  %4 = load i32, ptr %dy, align 4
  %5 = call i32 (ptr, ...) @printf(ptr @.str, i32 %3, i32 %4)
  store i32 0, ptr %i, align 4
  br label %loop.cond

loop.cond:                                        ; preds = %loop.body, %entry
  %6 = load i32, ptr %i, align 4
  %lt = icmp slt i32 %6, 10
  br i1 %lt, label %loop.body, label %loop.exit

loop.body:                                        ; preds = %loop.cond
  %7 = load i32, ptr %i, align 4
  %add = add i32 %7, 1
  store i32 %add, ptr %loop, align 4
  %8 = load i32, ptr %loop, align 4
  %9 = call i32 (ptr, ...) @printf(ptr @.str.1, i32 %8)
  %10 = load i32, ptr %i, align 4
  %add1 = add i32 %10, 1
  store i32 %add1, ptr %i, align 4
  br label %loop.cond

loop.exit:                                        ; preds = %loop.cond
  ret void
}
