(***********************************************************************)
(*                                                                     *)
(*                         Applied Type System                         *)
(*                                                                     *)
(***********************************************************************)

(*
** ATS/Postiats - Unleashing the Potential of Types!
** Copyright (C) 2011-2015 Hongwei Xi, ATS Trustful Software, Inc.
** All rights reserved
**
** ATS is free software;  you can  redistribute it and/or modify it under
** the terms of  the GNU GENERAL PUBLIC LICENSE (GPL) as published by the
** Free Software Foundation; either version 3, or (at  your  option)  any
** later version.
** 
** ATS is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without  even  the  implied  warranty  of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License
** for more details.
** 
** You  should  have  received  a  copy of the GNU General Public License
** along  with  ATS;  see the  file COPYING.  If not, please write to the
** Free Software Foundation,  51 Franklin Street, Fifth Floor, Boston, MA
** 02110-1301, USA.
*)

(* ****** ****** *)
//
// Author: Hongwei Xi
// Authoremail: gmhwxiATgmailDOTcom
// Start Time: August, 2015
//
(* ****** ****** *)
//
staload
LAB = "./pats_label.sats"
overload
fprint with $LAB.fprint_label
//
(* ****** ****** *)
//
staload
SYM = "./pats_symbol.sats"
//
overload
fprint with $SYM.fprint_symbol
//
(* ****** ****** *)
//
staload "./pats_staexp1.sats"
//
staload "./pats_staexp2.sats"
staload "./pats_dynexp2.sats"
//
staload "./pats_trans2_env.sats"
//
(* ****** ****** *)

staload "./pats_codegen2.sats"

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

local

fun
aux_test
(
  x0: e1xp, name: string
) : bool = (
//
case+
x0.e1xp_node
of // case+
| E1XPide(id2) =>
  (
    name = $SYM.symbol_get_name(id2)
  ) (* end of [E1XPide] *)
| E1XPstring(name2) => (name = name2)
//
| _ (*rest-of-e1xp*) => false
//
) (* end of [aux_test] *)

in (* in-of-local *)
//
implement
datcon_test_e1xp(x0) = aux_test(x0, "datcon")
implement
datcontag_test_e1xp(x0) = aux_test(x0, "datcontag")
//
implement
fprint_test_e1xp(x0) = aux_test(x0, "fprint")
//
implement
absrec_test_e1xp(x0) = aux_test(x0, "absrec")
//
end // end of [local]

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

local

fun
aux_find
(
  name: symbol
) : Option_vt(s2cst) = let
//
val ans = the_s2expenv_find (name)
//
in
//
case+ ans of
//
| ~Some_vt(s2i) => (
  case+ s2i of
  | S2ITMcst(s2cs) =>
    (
      case+ s2cs of
      | list_cons(s2c, _) => Some_vt(s2c) | list_nil() => None_vt()
    )
  | _ (*non-S2ITMcst*) => None_vt()
  ) (* end of [Some_vt] *)
//
| ~None_vt((*void*)) => None_vt()
//
end // end of [aux_find]

in (* in-of-local *)

implement
codegen2_get_s2cst
  (x0) = let
(*
//
val () =
println!
  ("codegen2_get_s2cst: x0 = ", x0)
//
*)
in
//
case+
x0.e1xp_node
of // case+
//
| E1XPide(name) => aux_find(name)
//
(*
| E1XPstring
    (name) => let
    val name2 =
      $SYM.symbol_make_string(name)
    // end of [val]
  in
    aux_find(name2)
  end // end of [E1XPstring]
*)
//
| _(*rest-of-e1xp*) => None_vt((*void*))
//
end // end of [codegen2_get_s2cst]

end // end of [local]

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

implement
codegen2_get_tydef
  (x0) = let
//
val opt = codegen2_get_s2cst(x0)
//
in
//
case+ opt of
| Some_vt(s2c) =>
  (
    if s2cst_is_tydef(s2c)
      then (fold@{s2cst}(opt); opt)
      else (free@{s2cst}(opt); None_vt())
  ) (* end of [Some_vt] *)
//
| ~None_vt((*void*)) => None_vt()
//
end // end of [codegen2_get_tydef]

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

implement
codegen2_get_datype
  (x0) = let
//
val opt = codegen2_get_s2cst(x0)
//
in
//
case+ opt of
| Some_vt(s2c) =>
  (
    if s2cst_is_datype(s2c)
      then (fold@{s2cst}(opt); opt)
      else (free@{s2cst}(opt); None_vt())
  ) (* end of [Some_vt] *)
//
| ~None_vt((*void*)) => None_vt()
//
end // end of [codegen2_get_datype]

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

local

fun
aux_find
(
  name: symbol
) : Option_vt(d2cst) = let
//
val ans = the_d2expenv_find (name)
//
in
//
case+ ans of
//
| ~Some_vt(d2i) => (
  case+ d2i of
  | D2ITMcst(d2c) => Some_vt(d2c)
  | _ (*non-D2ITMcst*) => None_vt()
  ) (* end of [Some_vt] *)
//
| ~None_vt((*void*)) => None_vt()
//
end // end of [aux_find]

in (* in-of-local *)

implement
codegen2_get_d2cst
  (x0) = let
(*
//
val () =
println!
  ("codegen2_get_d2cst: x0 = ", x0)
//
*)
in
//
case+
x0.e1xp_node
of // case+
//
| E1XPide(name) => aux_find(name)
//
(*
| E1XPstring
    (name) => let
    val name2 =
      $SYM.symbol_make_string(name)
    // end of [val]
  in
    aux_find(name2)
  end // end of [E1XPstring]
*)
| _(*rest-of-e1xp*) => None_vt((*void*))
//
end // end of [codegen2_get_d2cst]

end // end of [local]

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

local

fun
aux_s2qua
(
  out: FILEref
, lpar: string, rpar: string, s2q: s2qua
) : void = let
//
fun
auxlst
(
  s2vs: s2varlst
) :<cloref1> void =
(
case+ s2vs of
| list_nil() => ()
| list_cons(s2v, s2vs) =>
  (
    fprint(out, s2var_get_sym(s2v)); auxlst(s2vs)
  )
)
//
in
  fprint(out, lpar); auxlst(s2q.s2qua_svs); fprint(out, rpar)
end // end of [aux_s2qua]

fun
aux_s2qualst
(
  out: FILEref
, lpar: string, rpar: string, s2qs: s2qualst
) : void =
(
case+ s2qs of
| list_nil() => ()
| list_cons
    (s2q, s2qs) => () where
  {
    val () = aux_s2qua(out, lpar, rpar, s2q)
    val () = aux_s2qualst(out, lpar, rpar, s2qs)
  }
) (* end of [aux_s2qualst] *)

in (* in-of-local *)

implement
codegen2_emit_tmpcstapp
  (out, d2cf) = let
//
val s2qs = d2cst_get_decarg(d2cf)
//
in
//
aux_s2qualst(out, "<", ">", s2qs)
//
end // end of [codegen2_emit_tmpcstapp]

implement
codegen2_emit_tmpcstimp
  (out, d2cf) = let
//
val s2qs = d2cst_get_decarg(d2cf)
//
in
//
aux_s2qualst(out, "{", "}", s2qs)
//
end // end of [codegen2_emit_tmpcstimp]

end // end of [local]

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

implement
codegen2_emit_tmpcstdec
  (out, d2cf) = let
//
fun
aux
(
  s2q: s2qua
) :<cloref1> void = let
//
fun
fprs2t
(
  out: FILEref, s2t: s2rt
) : void = (
//
if s2rt_is_prgm(s2t) then
{
  val () =
  if s2rt_is_lin(s2t) then fprint(out, "vt0p")
  val () =
  if s2rt_is_nonlin(s2t) then fprint(out, "t0p")
}
//
) (* end of [fprs2t] *)
//
fun
loop
(
  s2vs: s2varlst
) :<cloref1> void =
(
case+ s2vs of
| list_nil() => ()
| list_cons
    (s2v, s2vs) => let
    val sym = s2var_get_sym(s2v)
    val s2t = s2var_get_srt(s2v)
  in
    fprint(out, sym);
    fprint(out, ":");
    fprs2t(out, s2t); loop(s2vs)
  end // end of [list_cons]
)
//
val s2vs = s2q.s2qua_svs
//
in
  fprint(out, "{"); loop(s2vs); fprint(out, "}");
end // end of [aux]

fun
auxlst
(
  s2qs: s2qualst
) :<cloref1> void =
(
case+ s2qs of
| list_nil() => ()
| list_cons(s2q, s2qs) => (aux(s2q); auxlst(s2qs))
) (* end of [auxlst] *)
//
in
  auxlst(d2cst_get_decarg(d2cf))
end // end of [codegen2_emit_tmpcstdec]

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

implement
codegen2_emit_s2rt
  (out, s2t0) = let
//
fun
aux_s2rt
(
  s2t0: s2rt
) :<cloref1> void =
(
case+ s2t0 of
| S2RTbas
    (s2tb) =>
  {
    val () = aux_s2rtbas(s2tb)
  }
| S2RTfun
  (
    s2ts_arg, s2t_res
  ) => () where
  {
    val () = fprint(out, "(")
    val () =
      aux_s2rtlst(s2ts_arg, 0)
    // end of [val]
    val () = fprint(out, ") ->")
    val () = aux_s2rt(s2t_res)
  }
| _(*rest-of_s2rt*) => fprint(out, s2t0)
) (* end of [aux_s2rt] *)
//
and
aux_s2rtlst
(
  s2ts: s2rtlst, i: int
) :<cloref1> void =
(
case+ s2ts of
| list_nil() => ()
| list_cons(s2t, s2ts) =>
  {
    val () =
    if i > 0
      then fprint(out, ", ")
    // end of [if]
    val () = aux_s2rt(s2t)
    val () = aux_s2rtlst(s2ts, i+1)
  } (* end of [list_cons] *)
) (* end of [aux_s2rtlst] *)
//
and
aux_s2rtbas
(
  s2tb: s2rtbas
) :<cloref1> void =
(
case+ s2tb of
| S2RTBASpre
    (sym) => fprint(out, sym)
  // end of [S2RTBASpre]
| S2RTBASimp
    (knd, sym) => fprint(out, sym)
  // end of [S2RTBASimp]
| S2RTBASdef(s2td) =>
    fprint(out, s2rtdat_get_sym(s2td))
  // end of [S2RTBASdef]
) (* end of [aux_s2rtbas] *)
//
in
  aux_s2rt(s2t0)
end // end of [codegen2_emit_s2rt]

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

implement
codegen2_emit_s2cst
  (out, s2c0) = () where
{
  val () = fprint(out, s2cst_get_sym(s2c0))
} (* codegen2_emit_s2cst *)

implement
codegen2_emit_s2var
  (out, s2v0) = () where
{
  val () = fprint(out, s2var_get_sym(s2v0))
} (* codegen2_emit_s2var *)

(* ****** ****** *)
//
local

fun
aux_istup
(
  ls2es: labs2explst
) : bool =
(
case+ ls2es of
| list_nil() => true
| list_cons
    (ls2e, ls2es) => let
    val+SLABELED(l, _, _) = ls2e
  in
    if $LAB.label_is_int(l) then aux_istup(ls2es) else false
  end // end of [list_cons]
)

fun
aux_s2exp
(
  out: FILEref, s2e0: s2exp
) : void = let
//
(*
val () =
println!
  ("aux_s2exp: s2e0 = ", s2e0)
*)
//
in
//
case+
s2e0.s2exp_node
of (* case+ *)
//
| S2Ecst(s2c) =>
  {
    val () = codegen2_emit_s2cst(out, s2c)
  }
//
| S2Evar(s2v) => () where
  {
    val () = codegen2_emit_s2var(out, s2v)
  }
//
| S2Eapp(s2e_fun, s2es_arg) =>
  {
    val () = aux_s2exp(out, s2e_fun)
    val () = fprint(out, "(")
    val () = aux_s2explst(out, s2es_arg, 0)
    val () = fprint(out, ")")
  }
//
| S2Etyrec
    (knd, npf, ls2es) => () where
  {
//
    val
    istup = aux_istup(ls2es)
//
    val
    tuprec =
    (
      if istup then "$tup" else "$rec"
    ) : string // end of [val]
//
    val
    isflted =
    tyreckind_is_flted(knd)
    val () =
    if isflted then fprint(out, "@")
//
    val
    isboxed =
    tyreckind_is_boxed(knd)
    val () =
    if isboxed then
    (
      if s2exp_is_nonlin(s2e0)
        then fprint!(out, tuprec, "_t")
        else fprint!(out, tuprec, "_vt")
    ) (* end of [val] *)
//
    val () =
    if istup
      then fprint_string(out, "(")
      else fprint_string(out, "{")
    // end of [if]
//
    val () = aux_labs2explst(out, ls2es, 0)
//
    val () =
    if istup
      then fprint_string(out, ")")
      else fprint_string(out, "}")
    // end of [if]
//
  } (* end of [S2Etyrec] *)
//
| _ (*rest-of-s2exp*) => fprint_s2exp(out, s2e0)
//
end (* end of [aux_s2exp] *)

and
aux_s2explst
(
  out: FILEref
, s2es: s2explst, i: int
) : void = let
(*
val () =
println! ("aux_labs2explst")
*)
in
//
case+ s2es of
| list_nil() => ()
| list_cons(s2e, s2es) =>
  {
    val () =
    if i > 0 then fprint(out, ", ")
    val () = aux_s2exp(out, s2e)
    val () = aux_s2explst(out, s2es, i+1)
  } (* end of [list_cons] *)
//
end // end of [aux_s2explst]

and
aux_labs2explst
(
  out: FILEref
, ls2es: labs2explst, i: int
) : void = let
(*
val () =
println! ("aux_labs2explst")
*)
in
//
case+ ls2es of
| list_nil() => ()
| list_cons(ls2e, ls2es) =>
  {
//
    val () =
    if i > 0 then fprint(out, ", ")
//
    val+
    SLABELED(l, _(*name*), s2e) = ls2e
    val () =
    if $LAB.label_is_sym(l) then fprint!(out, l, "=")
//
    val () = aux_s2exp(out, s2e)
//
    val () = aux_labs2explst(out, ls2es, i+1)
  } (* end of [list_cons] *)
//
end // end of [aux_labs2explst]

in (* in-of-local *)

implement
codegen2_emit_s2exp
  (out, s2e0) = let
//
(*
val () =
println!
(
"codegen2_emit_s2exp: s2e0 = ", s2e0
) (* println! *)
*)
//
in
  aux_s2exp(out, s2e0)
end // codegen2_emit_s2exp

end // end of [local]
//
(* ****** ****** *)

(* end of [pats_codegen2_util.dats] *)