// closure conversion
// this version uses heap allocation of continuation closures.

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

struct _cont;

typedef void (*factk)(int, struct _cont *);

// we'll just use this one type of continuation closure
typedef struct _cont {
  factk fun;
  struct _cont * k;
  int n;
} cont;

static int the_result = 0;
static cont cont_heap[100];
static int cont_counter = 0;

static
cont *
get_cont()
{
  return &cont_heap[cont_counter++];
}

// note that ret_cps ignores its continuation
static
void
ret_cps (int n, cont * k)
{
  the_result = n;
}

static
void
factcps_3 (int f, cont * k) {
  k->fun (k->n * f, k->k);
}

void
factcps (int n, cont * k)
{
  if (n == 0) {
    k->fun (1, k->k);
  } else {
    cont * k0 = get_cont();
    k0->fun = factcps_3;
    k0->k = k;
    k0->n = n;
    factcps (n-1, k0);
  }
}

int
main (int argc, char * argv[])
{
  cont k = { ret_cps, NULL, 1 };
  //factcps (5, &k);
  // use a random number so llvm doesn't try to unroll the loop.
  factcps (getpid()%10, &k);
  fprintf (stdout, "factcps(5)==%d\n", the_result);
  return 0;
}