//
// An example used in class on 2009-01-15
//

// Author: Hongwei Xi (hwxi AT cs DOT bu DOT edu)

//
// How to compile:
//   atscc -o calc calc-2009-01-15.dats
//

#define nil list0_nil
#define cons list0_cons
#define :: list_cons0

datatype exp =
  | EXPint of int | EXPopr of (string, list0 exp)

val exp1 = EXPint 1 and exp2 = EXPint 2
val exp3 = EXPopr ("+", cons (exp1, cons (exp2, nil)))
val exp4 = EXPopr ("*", cons (exp1, nil ()))

extern fun eval (e: exp): int

fun eval_add (es: list0 exp): int = case+ es of
  | cons (e1, cons (e2, nil ())) => eval e1 + eval e2
  | _ => begin
      prerr ("eval_add: arity error"); prerr_newline (); exit {int} (1)
    end // end of [_]
// end of [eval_add]

fun eval_sub (es: list0 exp): int = case+ es of
  | cons (e1, cons (e2, nil ())) => eval e1 - eval e2
  | _ => begin
      prerr ("eval_sub: arity error"); prerr_newline (); exit {int} (1)
    end // end of [_]
// end of [eval_sub]

fun eval_mul (es: list0 exp): int = case+ es of
  | cons (e1, cons (e2, nil ())) => eval e1 * eval e2
  | _ => begin
      prerr ("eval_mul: arity error"); prerr_newline (); exit {int} (1)
    end // end of [_]
// end of [eval_mul]

fun eval_div (es: list0 exp): int = case+ es of
  | cons (e1, cons (e2, nil ())) => eval e1 / eval e2
  | _ => begin
      prerr ("eval_div: arity error"); prerr_newline (); exit {int} (1)
    end // end of [_]
// end of [eval_div]

(* ****** ****** *)

implement eval (e) = case+ e of
  | EXPint i => i
  | EXPopr (opr, es) => begin case+ opr of
    | "+" => eval_add (es)
    | "-" => eval_sub (es)
    | "*" => eval_mul (es)
    | "/" => eval_div (es)
    | _ => begin
        prerrf ("The operator [%s] is unrecognized.\n", @(opr)); exit {int} (1)
      end // end of [_]
   end // end of [EXPopr]
// end of [eval]

(* ****** ****** *)

implement main () = let
  val ans3 = eval (exp3)
  val () = (print "ans3 = "; print ans3; print_newline ())
  val ans4 = eval (exp4)
  val () = (print "ans4 = "; print ans4; print_newline ())  
in
  // empty
end // end of [main]

(* ****** ****** *)

(* end of [calc-2009-01-15.dats] *)