(*
** Course: Concepts of Programming Languages (BU CAS CS 320)
** Semester: Summer I, 2009
** Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
*)

//
// Author: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// Time: Wednesday, June 3, 2009
//

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

// Part I: Imperative programming with references

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

#include "BUCASCS320.hats"

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

// creating a reference to an integer 
val intref = ref_make_elt<int> (0)

val () = begin
  printf ("intref = %i\n", @(!intref))
end

val () = !intref := !intref + 1

val () = begin
  printf ("intref = %i\n", @(!intref))
end

typedef dbl = double

// creating a reference to a double
val dblref = ref_make_elt<dbl> (0.0)

val () = begin
  printf ("dblref = %f\n", @(!dblref))
end

val () = !dblref := !dblref + 1.0

val () = begin
  printf ("dblref = %f\n", @(!dblref))
end

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

// implementing integer counters

abstype counter_t

extern fun counter_make (): counter_t

extern fun counter_get (c: counter_t): int
extern fun counter_inc (c: counter_t): void
extern fun counter_get_inc (c: counter_t): int
extern fun counter_reset (c: counter_t): void

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

local

assume counter_t = ref (int)

in // in of [local]

implement counter_make () = ref_make_elt<int> (0)

implement counter_get (c) =  !c

implement counter_inc (c) =  !c := !c + 1

implement counter_get_inc (c) = let
  val n = !c; val () = !c := n + 1 in n
end // end of [counter_get_inc]

implement counter_reset (c) = !c := 0

end // end of [local]

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

// creating a counter and using it

val mycnt1 = counter_make ()
val n0 = counter_get_inc (mycnt1)
val () = printf ("n0 = %i\n", @(n0))
val n1 = counter_get_inc (mycnt1)
val () = printf ("n1 = %i\n", @(n1))
val n2 = counter_get_inc (mycnt1)
val () = printf ("n2 = %i\n", @(n2))

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

// Part II: Imperative programming with arrays

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

// implementing two-dimensional arrays

abstype array2 (a:t@ype)

extern fun{a:t@ype}
  array2_make_elt (nrow: int, ncol: int, ini: a): array2 a

extern fun{a:t@ype}
  array2_get_elt_at (A: array2 a, ncol: int, i: int, j: int): a

extern fun{a:t@ype}
  array2_set_elt_at (A: array2 a, ncol: int, i: int, j: int, x: a): void

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

local

assume array2 (a:t@ype) = array0 (a) 

in // in of [local]

implement{a}
  array2_make_elt (nrow, ncol, ini) = let
  val asz = nrow * ncol
  val asz = int1_of_int asz
  val () = assert (asz >= 0)
  val asz = size_of_int1 (asz)
in
  array0_make_elt (asz, ini)
end // end of [array2_make_elt]

implement{a}
  array2_get_elt_at (A, ncol, i, j) = let
  val n = i * ncol + j
  val n = int1_of_int n   
  val () = assert (n >= 0)
  val n = size_of_int1 (n)
in
  array0_get_elt_at<a> (A, n)
end // end of [array2_get_elt]

implement{a}
  array2_set_elt_at (A, ncol, i, j, x) = let
  val n = i * ncol + j
  val n = int1_of_int n   
  val () = assert (n >= 0)
  val n = size_of_int1 (n)
in
  array0_set_elt_at<a> (A, n, x)
end // end of [array2_set_elt]

end // end of [local]

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

implement main () = ()

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

(* end of [code-2009-06-03.dats] *)