(* Author:  Cristiano Calcagno
   Date:    Fri Aug 31 03:03:11 EDT 2001 *)

type instr = Add | Num of int | For of instr list

let rec exec stack ops = match ops with
 | [] -> stack
 | Add::ops' ->
   begin match stack with
         | x::y::stack' -> exec ((x+y)::stack') ops'
	 | _ -> assert false
   end
 | (Num n)::ops' -> exec (n::stack) ops'
 | (For l)::ops' ->
     begin match stack with
      | n::stack' ->
        let rec f n stk = if n=0 then stk
	                           else f (n-1) (exec stk l)
	in f n stack'
      | _ -> assert false
     end   
 
let rec exec2 stack ops = match ops with
 | [] -> stack
 | Add::ops' ->
   .<begin 
     match .~ stack with
         | x::y::stack' -> .~(exec2 .<(x+y)::stack'>. ops')
         | _ -> assert false
   end>.
 | (Num n)::ops' -> exec2 .<n :: .~stack>. ops'
 | (For l)::ops' ->
     .<begin match .~stack with
        | n::stack' ->
          let rec f n stk =
	    if n=0 then stk
                   else f (n-1) .~(exec2 .<stk>. l)
	  in f n stack'
        | _ -> assert false
       end>.   

let prog = [Num 0; Num 1000000; For [Num 1; Add; Num 0; Add; Num 0; Add;
                                     Num 3; Num (-3); Num 0; Add; Add; Add]]

let prog2 = [Num 0; Num 1000; For [Num 1000; For [Num 1; Num 0; Num 0; Num 0;
                                                Add; Add; Add; Add]]]

let _ = Trx.init_times ()

let _ = Trx.time 1 "unstaged" (fun () -> exec [] prog2)

let a = Trx.time 1 "stage 1 " (fun () -> exec2 .<[]>. prog2)
let b = Trx.time 1 "compilation" (fun () -> .! .<fun () -> .~a>.)
let _ = Trx.time 1 "stage 2" (fun () -> b ())

let _ = Trx.print_times ()
