Time_util.init_times ()

type exp = I of int
         | V of string
         | A of string * exp
         | Add of exp * exp
         | Sub of exp * exp  
         | Dec of exp
         | C of exp * exp * exp
type def = D of string * string * exp
type prog = P of def list * exp

exception Yiikes
let env0 = fun x -> raise Yiikes
let ext env x v = fun y -> if x=y then v else env y

let rec eval e env fenv =
match e with
  I i -> i
| V s -> env s
| A (s,e2) -> (fenv s)(eval e2 env fenv)
| Add (e1,e2) -> (eval e1 env fenv)+ (eval e2 env fenv)
| Sub (e1,e2) -> (eval e1 env fenv)-(eval e2 env fenv)
| Dec e -> (eval e env fenv)-1
| C (e1,e2,e3) -> if (eval e1 env fenv)=0
                     then (eval e2 env fenv)
                     else (eval e3 env fenv)

let rec deceval p env fenv=
    match p with
     P ([],e) -> eval e env fenv
    |P (D(s1,s2,e1)::tl,e) ->
        let rec f x = eval e1 (ext env s2 x) (ext fenv s1 f)
        in deceval (P(tl,e)) env (ext fenv s1 f)     

let term1 = P ([D("pp","x",Add(V "x",I 817))],A("pp",I 99))
let term2 = P ([D("sum","x",C(V "x", I 0, Add(V "x",A("sum", Dec (V "x")))))],A("sum",I 15))
let term3 = P ([D("f","x",C(V "x", I 42, A("f", Dec(V "x"))))], A("f", I 100000)
)
(* stack overflow during evaluation (looping recursion?) *)

let unstage = 
     Time_util.timenew "unstaged running" (fun () ->deceval term3 env0 env0)
let _ = Time_util.print_times ()







