A Tutorial on Programming Features in ATS: | ||
---|---|---|
Prev | Chapter 29. Automatic Code Generation |
A fprint-function takes a file-handle (of the type FILEref) and a value and then outputs a text representation of the value to the file-handle. Given a datatype, one is often in need of a function that can output certain kind of text representation for values of this datatype. For instance, such a function can be of great use in debugging.
Let us first declare a function template fprint_expr_ as follows:
We can then use the directive below to indicate (to the ATS compiler) that the fprint-function for the datatype expr needs to be generated: The third argument of the codegen2-directive can be omitted in this case as it coincides with the default. The generated code that implements fprint_expr_ is listed as follows:(* ****** ****** *) // extern fun{} fprint_expr_$Int: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Var: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Add: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Sub: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Mul: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Div: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez: $d2ctype(fprint_expr_<>) // (* ****** ****** *) // implement{} fprint_expr_ (out, arg0) = ( case+ arg0 of | Int _ => fprint_expr_$Int<>(out, arg0) | Var _ => fprint_expr_$Var<>(out, arg0) | Add _ => fprint_expr_$Add<>(out, arg0) | Sub _ => fprint_expr_$Sub<>(out, arg0) | Mul _ => fprint_expr_$Mul<>(out, arg0) | Div _ => fprint_expr_$Div<>(out, arg0) | Ifgtz _ => fprint_expr_$Ifgtz<>(out, arg0) | Ifgtez _ => fprint_expr_$Ifgtez<>(out, arg0) ) // (* ****** ****** *) // extern fun{} fprint_expr_$sep: (FILEref) -> void implement{} fprint_expr_$sep(out) = fprint(out, ",") // extern fun{} fprint_expr_$lpar: (FILEref) -> void implement{} fprint_expr_$lpar(out) = fprint(out, "(") // extern fun{} fprint_expr_$rpar: (FILEref) -> void implement{} fprint_expr_$rpar(out) = fprint(out, ")") // extern fun{a:t0p} fprint_expr_$carg: (FILEref, INV(a)) -> void implement{a} fprint_expr_$carg(out, arg) = fprint_val<a>(out, arg) // (* ****** ****** *) // extern fun{} fprint_expr_$Int$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Int$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Int$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Int$arg1: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Int(out, arg0) = { // val () = fprint_expr_$Int$con<>(out, arg0) val () = fprint_expr_$Int$lpar<>(out, arg0) val () = fprint_expr_$Int$arg1<>(out, arg0) val () = fprint_expr_$Int$rpar<>(out, arg0) // } implement{} fprint_expr_$Int$con(out, _) = fprint(out, "Int") implement{} fprint_expr_$Int$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Int$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Int$arg1(out, arg0) = let val-Int(arg1) = arg0 in fprint_expr_$carg(out, arg1) end // extern fun{} fprint_expr_$Var$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Var$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Var$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Var$arg1: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Var(out, arg0) = { // val () = fprint_expr_$Var$con<>(out, arg0) val () = fprint_expr_$Var$lpar<>(out, arg0) val () = fprint_expr_$Var$arg1<>(out, arg0) val () = fprint_expr_$Var$rpar<>(out, arg0) // } implement{} fprint_expr_$Var$con(out, _) = fprint(out, "Var") implement{} fprint_expr_$Var$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Var$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Var$arg1(out, arg0) = let val-Var(arg1) = arg0 in fprint_expr_$carg(out, arg1) end // extern fun{} fprint_expr_$Add$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Add$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Add$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Add$sep1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Add$arg1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Add$arg2: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Add(out, arg0) = { // val () = fprint_expr_$Add$con<>(out, arg0) val () = fprint_expr_$Add$lpar<>(out, arg0) val () = fprint_expr_$Add$arg1<>(out, arg0) val () = fprint_expr_$Add$sep1<>(out, arg0) val () = fprint_expr_$Add$arg2<>(out, arg0) val () = fprint_expr_$Add$rpar<>(out, arg0) // } implement{} fprint_expr_$Add$con(out, _) = fprint(out, "Add") implement{} fprint_expr_$Add$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Add$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Add$sep1(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Add$arg1(out, arg0) = let val-Add(arg1, _) = arg0 in fprint_expr_$carg(out, arg1) end implement{} fprint_expr_$Add$arg2(out, arg0) = let val-Add(_, arg2) = arg0 in fprint_expr_$carg(out, arg2) end // extern fun{} fprint_expr_$Sub$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Sub$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Sub$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Sub$sep1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Sub$arg1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Sub$arg2: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Sub(out, arg0) = { // val () = fprint_expr_$Sub$con<>(out, arg0) val () = fprint_expr_$Sub$lpar<>(out, arg0) val () = fprint_expr_$Sub$arg1<>(out, arg0) val () = fprint_expr_$Sub$sep1<>(out, arg0) val () = fprint_expr_$Sub$arg2<>(out, arg0) val () = fprint_expr_$Sub$rpar<>(out, arg0) // } implement{} fprint_expr_$Sub$con(out, _) = fprint(out, "Sub") implement{} fprint_expr_$Sub$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Sub$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Sub$sep1(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Sub$arg1(out, arg0) = let val-Sub(arg1, _) = arg0 in fprint_expr_$carg(out, arg1) end implement{} fprint_expr_$Sub$arg2(out, arg0) = let val-Sub(_, arg2) = arg0 in fprint_expr_$carg(out, arg2) end // extern fun{} fprint_expr_$Mul$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Mul$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Mul$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Mul$sep1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Mul$arg1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Mul$arg2: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Mul(out, arg0) = { // val () = fprint_expr_$Mul$con<>(out, arg0) val () = fprint_expr_$Mul$lpar<>(out, arg0) val () = fprint_expr_$Mul$arg1<>(out, arg0) val () = fprint_expr_$Mul$sep1<>(out, arg0) val () = fprint_expr_$Mul$arg2<>(out, arg0) val () = fprint_expr_$Mul$rpar<>(out, arg0) // } implement{} fprint_expr_$Mul$con(out, _) = fprint(out, "Mul") implement{} fprint_expr_$Mul$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Mul$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Mul$sep1(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Mul$arg1(out, arg0) = let val-Mul(arg1, _) = arg0 in fprint_expr_$carg(out, arg1) end implement{} fprint_expr_$Mul$arg2(out, arg0) = let val-Mul(_, arg2) = arg0 in fprint_expr_$carg(out, arg2) end // extern fun{} fprint_expr_$Div$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Div$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Div$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Div$sep1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Div$arg1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Div$arg2: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Div(out, arg0) = { // val () = fprint_expr_$Div$con<>(out, arg0) val () = fprint_expr_$Div$lpar<>(out, arg0) val () = fprint_expr_$Div$arg1<>(out, arg0) val () = fprint_expr_$Div$sep1<>(out, arg0) val () = fprint_expr_$Div$arg2<>(out, arg0) val () = fprint_expr_$Div$rpar<>(out, arg0) // } implement{} fprint_expr_$Div$con(out, _) = fprint(out, "Div") implement{} fprint_expr_$Div$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Div$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Div$sep1(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Div$arg1(out, arg0) = let val-Div(arg1, _) = arg0 in fprint_expr_$carg(out, arg1) end implement{} fprint_expr_$Div$arg2(out, arg0) = let val-Div(_, arg2) = arg0 in fprint_expr_$carg(out, arg2) end // extern fun{} fprint_expr_$Ifgtz$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz$sep1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz$sep2: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz$arg1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz$arg2: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtz$arg3: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Ifgtz(out, arg0) = { // val () = fprint_expr_$Ifgtz$con<>(out, arg0) val () = fprint_expr_$Ifgtz$lpar<>(out, arg0) val () = fprint_expr_$Ifgtz$arg1<>(out, arg0) val () = fprint_expr_$Ifgtz$sep1<>(out, arg0) val () = fprint_expr_$Ifgtz$arg2<>(out, arg0) val () = fprint_expr_$Ifgtz$sep2<>(out, arg0) val () = fprint_expr_$Ifgtz$arg3<>(out, arg0) val () = fprint_expr_$Ifgtz$rpar<>(out, arg0) // } implement{} fprint_expr_$Ifgtz$con(out, _) = fprint(out, "Ifgtz") implement{} fprint_expr_$Ifgtz$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Ifgtz$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Ifgtz$sep1(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Ifgtz$sep2(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Ifgtz$arg1(out, arg0) = let val-Ifgtz(arg1, _, _) = arg0 in fprint_expr_$carg(out, arg1) end implement{} fprint_expr_$Ifgtz$arg2(out, arg0) = let val-Ifgtz(_, arg2, _) = arg0 in fprint_expr_$carg(out, arg2) end implement{} fprint_expr_$Ifgtz$arg3(out, arg0) = let val-Ifgtz(_, _, arg3) = arg0 in fprint_expr_$carg(out, arg3) end // extern fun{} fprint_expr_$Ifgtez$con: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez$lpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez$rpar: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez$sep1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez$sep2: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez$arg1: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez$arg2: $d2ctype(fprint_expr_<>) extern fun{} fprint_expr_$Ifgtez$arg3: $d2ctype(fprint_expr_<>) // implement{} fprint_expr_$Ifgtez(out, arg0) = { // val () = fprint_expr_$Ifgtez$con<>(out, arg0) val () = fprint_expr_$Ifgtez$lpar<>(out, arg0) val () = fprint_expr_$Ifgtez$arg1<>(out, arg0) val () = fprint_expr_$Ifgtez$sep1<>(out, arg0) val () = fprint_expr_$Ifgtez$arg2<>(out, arg0) val () = fprint_expr_$Ifgtez$sep2<>(out, arg0) val () = fprint_expr_$Ifgtez$arg3<>(out, arg0) val () = fprint_expr_$Ifgtez$rpar<>(out, arg0) // } implement{} fprint_expr_$Ifgtez$con(out, _) = fprint(out, "Ifgtez") implement{} fprint_expr_$Ifgtez$lpar(out, _) = fprint_expr_$lpar(out) implement{} fprint_expr_$Ifgtez$rpar(out, _) = fprint_expr_$rpar(out) implement{} fprint_expr_$Ifgtez$sep1(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Ifgtez$sep2(out, _) = fprint_expr_$sep<>(out) implement{} fprint_expr_$Ifgtez$arg1(out, arg0) = let val-Ifgtez(arg1, _, _) = arg0 in fprint_expr_$carg(out, arg1) end implement{} fprint_expr_$Ifgtez$arg2(out, arg0) = let val-Ifgtez(_, arg2, _) = arg0 in fprint_expr_$carg(out, arg2) end implement{} fprint_expr_$Ifgtez$arg3(out, arg0) = let val-Ifgtez(_, _, arg3) = arg0 in fprint_expr_$carg(out, arg3) end // (* ****** ****** *)
implement fprint_expr_$Add$con<> (_, _) = () implement fprint_expr_$Add$sep1<> (out, _) = fprint! (out, "+")
After proper adaptation is done, one can introduce a (non-template) function as follows:
// extern fun fprint_expr (out: FILEref, x: expr): void // implement fprint_expr(out, x) = fprint_expr_<>(out, x) //
Please find on-line the entirety of this presented example plus a Makefile (for illustrating the code generation process).