/*
Program HelloWorld.doo translated in C

Dodo source of the program:


def loop = fun (int n, Stdout out -> return():
    if (n < 7) console!out.Puts("Hello World!"), $loop(n+1, out)
    else return().
)

def Start: Start() {loop(0, Stdout())}.


*/
#include <stdlib.h>
#include <stdio.h>

#define INIT_DODO unsigned char buf[100]; unsigned char* stack = buf; int label = l_init; while(1) switch (label)
#define STOR(type, ofs, val) (*(type*)(stack + ofs) = val)
#define READ(type, ofs) (*(type*)(stack + ofs))
#define PUSH(type, val) (*(type*)stack = val, stack += sizeof(type))
#define POP(type) (*(type*)(stack -= sizeof(type)))
#define STORJ(ofs, label) STOR(int, ofs, label)
#define READJ(ofs) READ(int, ofs)
#define PUSHJ(label) PUSH(int, label)
#define POPJ POP(int)
#define JUMP(ofs)  (label = READ(int, ofs)); break
#define LABEL(num) case num
#define GOTO(num) (label = num); break

int main(int argc, char* args[])
{
   enum labels {l_init, l_Start, l_Start_return, l_loop, l_loop_return, l_exit};

   INIT_DODO
   {
       LABEL(l_init):

       // Initialise Start class by calling Start()
       PUSHJ(l_exit);    // push return
       // Jump to Start
       GOTO(l_Start);
       // Exit program
       LABEL(l_exit):
       exit(0);


       // Function def loop = fun{int n; Stdout out -> return()...
       // ---Arguments on stack:
       // int n
       // Stdout out
       // return()
       #define loop_return sizeof(int)
       #define loop_out (loop_return + sizeof(FILE*))
       #define loop_n (loop_out + sizeof(int))
       LABEL(l_loop):

       // if (n < 7)
       if (READ(int, -loop_n) < 7)
       {
           // console!out.Puts("Hello World!")
           fprintf(READ(FILE*, -loop_out), "%s\n", "Hello World!");
           // Tail recursion loop(n+1, out)
           STOR(int, -loop_n , READ(int, -loop_n) + 1);   // update n
           // Unwind stack: nothing to do
           // Jump to loop
           GOTO(l_loop);
       }
       else
       {
           // return()
           GOTO(l_loop_return);
       }
       // End of loop
       LABEL(l_loop_return):
       // Unwind stack
       label = POPJ;   // pop return
       POP(FILE*);      // pop out
       POP(int);       // pop n
       // Use continuation return()
       GOTO(label);


       // Constructor Start()
       // ---Arguments on stack:
       // return()
       LABEL(l_Start):
   
       // loop(0, Stdout())
       PUSH(int, 0);              // push n
       PUSH(FILE*, stdout);        // push out
       PUSHJ(l_Start_return);       // push return
       // Jump to loop
       GOTO(l_loop);
       // End of Start
       LABEL(l_Start_return):
       // Unwind stack
       label = POPJ;            // pop return
       // Use continuation return()
       GOTO(label);
   }
}