summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlasdair Armstrong2018-02-06 19:56:30 +0000
committerAlasdair Armstrong2018-02-06 19:56:30 +0000
commit14f2feae793d9fef39268f6caabf2378ad9d0d9f (patch)
tree9faa07c1fa7a607ce9f22e81e0c6587dfa601bd6 /src
parentc719cba2428ccca3eb8646176cd9da7795deb029 (diff)
Compile union types in C backend
Diffstat (limited to 'src')
-rw-r--r--src/c_backend.ml238
-rw-r--r--src/type_check.ml4
2 files changed, 183 insertions, 59 deletions
diff --git a/src/c_backend.ml b/src/c_backend.ml
index 757f84b9..429040ad 100644
--- a/src/c_backend.ml
+++ b/src/c_backend.ml
@@ -67,8 +67,32 @@ let lvar_typ = function
| Local (_, typ) -> typ
| Register typ -> typ
| Enum typ -> typ
+ (* | Union (_, typ) -> typ *)
| _ -> assert false
+(** Fragments are small pure snippets of C code, mostly expressions,
+ used by the AV_C_fragment and CV_C_fragment constructors. *)
+type fragment =
+ | F_id of id
+ | F_lit of string
+ | F_field of fragment * string
+ | F_op of fragment * string * fragment
+ | F_unary of string * fragment
+
+let rec string_of_fragment = function
+ | F_id id -> Util.zencode_string (string_of_id id)
+ | F_lit str -> str
+ | F_field (f, field) ->
+ Printf.sprintf "%s.%s" (string_of_fragment' f) field
+ | F_op (f1, op, f2) ->
+ Printf.sprintf "%s %s %s" (string_of_fragment' f1) op (string_of_fragment f2)
+ | F_unary (op, f) ->
+ op ^ string_of_fragment' f
+and string_of_fragment' f =
+ match f with
+ | F_op _ -> "(" ^ string_of_fragment f ^ ")"
+ | _ -> string_of_fragment f
+
(**************************************************************************)
(* 1. Conversion to A-normal form (ANF) *)
(**************************************************************************)
@@ -119,7 +143,7 @@ type aexp =
and apat =
| AP_tup of apat list
| AP_id of id
- | AP_app of id * apat list
+ | AP_app of id * apat
| AP_wild
and aval =
@@ -129,7 +153,7 @@ and aval =
| AV_tuple of aval list
| AV_list of aval list * typ
| AV_vector of aval list * typ
- | AV_C_fragment of string * typ
+ | AV_C_fragment of fragment * typ
(* Map over all the avals in an aexp. *)
let rec map_aval f = function
@@ -254,7 +278,7 @@ and pp_apat = function
| AP_wild -> string "_"
| AP_id id -> pp_id id
| AP_tup apats -> parens (separate_map (comma ^^ space) pp_apat apats)
- | AP_app (id, apats) -> pp_id id ^^ parens (separate_map (comma ^^ space) pp_apat apats)
+ | AP_app (id, apat) -> pp_id id ^^ parens (pp_apat apat)
and pp_cases cases = surround 2 0 lbrace (separate_map (comma ^^ hardline) pp_case cases) rbrace
@@ -271,7 +295,7 @@ and pp_aval = function
| AV_id (id, lvar) -> pp_lvar lvar (pp_id id)
| AV_tuple avals -> parens (separate_map (comma ^^ space) pp_aval avals)
| AV_ref (id, lvar) -> string "ref" ^^ space ^^ pp_lvar lvar (pp_id id)
- | AV_C_fragment (str, typ) -> pp_annot typ (string (str |> Util.cyan |> Util.clear))
+ | AV_C_fragment (frag, typ) -> pp_annot typ (string (string_of_fragment frag |> Util.cyan |> Util.clear))
| AV_vector (avals, typ) ->
pp_annot typ (string "[" ^^ separate_map (comma ^^ space) pp_aval avals ^^ string "]")
| AV_list (avals, typ) ->
@@ -301,7 +325,8 @@ let rec anf_pat (P_aux (p_aux, _) as pat) =
| P_id id -> AP_id id
| P_wild -> AP_wild
| P_tup pats -> AP_tup (List.map anf_pat pats)
- | P_app (id, pats) -> AP_app (id, List.map anf_pat pats)
+ | P_app (id, [pat]) -> AP_app (id, anf_pat pat)
+ | P_app (id, pats) -> AP_app (id, AP_tup (List.map anf_pat pats))
| _ -> failwith ("anf_pat: " ^ string_of_pat pat)
let rec anf (E_aux (e_aux, exp_annot) as exp) =
@@ -421,7 +446,10 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
| E_id id ->
let lvar = Env.lookup_id id (env_of exp) in
- AE_val (AV_id (id, lvar))
+ begin match lvar with
+ | Union (_, typ) -> AE_app (id, [AV_lit (mk_lit L_unit, unit_typ)], typ)
+ | _ -> AE_val (AV_id (id, lvar))
+ end
| E_ref id ->
let lvar = Env.lookup_id id (env_of exp) in
@@ -620,24 +648,24 @@ let is_stack_typ ctx typ = is_stack_ctyp (ctyp_of_typ ctx typ)
(* 3. Optimization of primitives and literals *)
(**************************************************************************)
-let literal_to_cstring (L_aux (l_aux, _) as lit) =
+let literal_to_fragment (L_aux (l_aux, _) as lit) =
match l_aux with
| L_num n when Big_int.less_equal min_int64 n && Big_int.less_equal n max_int64 ->
- Some (Big_int.to_string n ^ "L")
+ Some (F_lit (Big_int.to_string n ^ "L"))
| L_hex str when String.length str <= 16 ->
let padding = 16 - String.length str in
- Some ("0x" ^ String.make padding '0' ^ str ^ "ul")
- | L_unit -> Some "UNIT"
- | L_true -> Some "true"
- | L_false -> Some "false"
+ Some (F_lit ("0x" ^ String.make padding '0' ^ str ^ "ul"))
+ | L_unit -> Some (F_lit "UNIT")
+ | L_true -> Some (F_lit "true")
+ | L_false -> Some (F_lit "false")
| _ -> None
let c_literals ctx =
let rec c_literal = function
| AV_lit (lit, typ) as v when is_stack_ctyp (ctyp_of_typ ctx typ) ->
begin
- match literal_to_cstring lit with
- | Some str -> AV_C_fragment (str, typ)
+ match literal_to_fragment lit with
+ | Some frag -> AV_C_fragment (frag, typ)
| None -> v
end
| AV_tuple avals -> AV_tuple (List.map c_literal avals)
@@ -657,8 +685,8 @@ let mask m =
let rec c_aval ctx = function
| AV_lit (lit, typ) as v ->
begin
- match literal_to_cstring lit with
- | Some str -> AV_C_fragment (str, typ)
+ match literal_to_fragment lit with
+ | Some frag -> AV_C_fragment (frag, typ)
| None -> v
end
| AV_C_fragment (str, typ) -> AV_C_fragment (str, typ)
@@ -667,7 +695,7 @@ let rec c_aval ctx = function
begin
match lvar with
| Local (_, typ) when is_stack_typ ctx typ ->
- AV_C_fragment (Util.zencode_string (string_of_id id), typ)
+ AV_C_fragment (F_id id, typ)
| _ -> v
end
| AV_tuple avals -> AV_tuple (List.map (c_aval ctx) avals)
@@ -676,8 +704,8 @@ let is_c_fragment = function
| AV_C_fragment _ -> true
| _ -> false
-let c_fragment_string = function
- | AV_C_fragment (str, _) -> str
+let c_fragment = function
+ | AV_C_fragment (frag, _) -> frag
| _ -> assert false
let analyze_primop' ctx id args typ =
@@ -695,7 +723,7 @@ let analyze_primop' ctx id args typ =
if Big_int.less_equal min_int64 n && Big_int.less_equal m max_int64 then
let x, y = c_aval ctx x, c_aval ctx y in
if is_c_fragment x && is_c_fragment y then
- AE_val (AV_C_fragment (c_fragment_string x ^ " + " ^ c_fragment_string y, typ))
+ AE_val (AV_C_fragment (F_op (c_fragment x, "+", c_fragment y), typ))
else
no_change
else
@@ -707,7 +735,7 @@ let analyze_primop' ctx id args typ =
begin
match List.map (c_aval ctx) args with
| [x; y] when is_c_fragment x && is_c_fragment y ->
- AE_val (AV_C_fragment ("(" ^ c_fragment_string x ^ " == " ^ c_fragment_string y ^ ")", typ))
+ AE_val (AV_C_fragment (F_op (c_fragment x, "==", c_fragment y), typ))
| _ ->
no_change
end
@@ -723,7 +751,7 @@ let analyze_primop' ctx id args typ =
| Nexp_aux (Nexp_constant n, _) when Big_int.less_equal n (Big_int.of_int 64) ->
let x, y = c_aval ctx x, c_aval ctx y in
if is_c_fragment x && is_c_fragment y then
- AE_val (AV_C_fragment (c_fragment_string x ^ " ^ " ^ c_fragment_string y, typ))
+ AE_val (AV_C_fragment (F_op (c_fragment x, "^", c_fragment y), typ))
else
no_change
| _ -> no_change
@@ -740,7 +768,7 @@ let analyze_primop' ctx id args typ =
| Nexp_aux (Nexp_constant n, _) when Big_int.less_equal n (Big_int.of_int 64) ->
let x, y = c_aval ctx x, c_aval ctx y in
if is_c_fragment x && is_c_fragment y then
- AE_val (AV_C_fragment ("(" ^ c_fragment_string x ^ " + " ^ c_fragment_string y ^ ") & " ^ mask n, typ))
+ AE_val (AV_C_fragment (F_op (F_op (c_fragment x, "+", c_fragment y), "^", F_lit (mask n)), typ))
else
no_change
| _ -> no_change
@@ -791,7 +819,7 @@ let ctype_def_ctyps = function
type cval =
| CV_id of id * ctyp
- | CV_C_fragment of string * ctyp
+ | CV_C_fragment of fragment * ctyp
let cval_ctyp = function
| CV_id (_, ctyp) -> ctyp
@@ -864,7 +892,7 @@ let pp_keyword str =
let pp_cval = function
| CV_id (id, ctyp) -> parens (pp_ctyp ctyp) ^^ (pp_id id)
- | CV_C_fragment (str, ctyp) -> parens (pp_ctyp ctyp) ^^ (string (str |> Util.cyan |> Util.clear))
+ | CV_C_fragment (frag, ctyp) -> parens (pp_ctyp ctyp) ^^ (string (string_of_fragment frag |> Util.cyan |> Util.clear))
let rec pp_clexp = function
| CL_id id -> pp_id id
@@ -924,32 +952,32 @@ let is_ct_tup = function
| _ -> false
let rec compile_aval ctx = function
- | AV_C_fragment (code, typ) ->
- [], CV_C_fragment (code, ctyp_of_typ ctx typ), []
+ | AV_C_fragment (frag, typ) ->
+ [], CV_C_fragment (frag, ctyp_of_typ ctx typ), []
| AV_id (id, typ) ->
begin
match ctyp_of_typ ctx (lvar_typ typ) with
| CT_enum (_, elems) when IdSet.mem id elems ->
- [], CV_C_fragment (Util.zencode_upper_string (string_of_id id), ctyp_of_typ ctx (lvar_typ typ)), []
+ [], CV_C_fragment (F_id id, ctyp_of_typ ctx (lvar_typ typ)), []
| _ ->
[], CV_id (id, ctyp_of_typ ctx (lvar_typ typ)), []
end
| AV_lit (L_aux (L_string str, _), typ) ->
- [], CV_C_fragment ("\"" ^ str ^ "\"", ctyp_of_typ ctx typ), []
+ [], CV_C_fragment (F_lit ("\"" ^ str ^ "\""), ctyp_of_typ ctx typ), []
| AV_lit (L_aux (L_num n, _), typ) when Big_int.less_equal min_int64 n && Big_int.less_equal n max_int64 ->
let gs = gensym () in
[I_decl (CT_mpz, gs);
- I_init (CT_mpz, gs, CV_C_fragment (Big_int.to_string n ^ "L", CT_int64))],
+ I_init (CT_mpz, gs, CV_C_fragment (F_lit (Big_int.to_string n ^ "L"), CT_int64))],
CV_id (gs, CT_mpz),
[I_clear (CT_mpz, gs)]
| AV_lit (L_aux (L_num n, _), typ) ->
let gs = gensym () in
[ I_decl (CT_mpz, gs);
- I_init (CT_mpz, gs, CV_C_fragment ("\"" ^ Big_int.to_string n ^ "\"", CT_string)) ],
+ I_init (CT_mpz, gs, CV_C_fragment (F_lit ("\"" ^ Big_int.to_string n ^ "\""), CT_string)) ],
CV_id (gs, CT_mpz),
[I_clear (CT_mpz, gs)]
@@ -1016,24 +1044,43 @@ let compile_funcall ctx id args typ =
let rec compile_match ctx apat cval case_label =
match apat, cval with
| AP_id pid, CV_C_fragment (code, ctyp) when is_ct_enum ctyp ->
- [ I_if (CV_C_fragment (Util.zencode_upper_string (string_of_id pid) ^ " != " ^ code, CT_bool), [I_goto case_label], [], CT_unit) ]
+ [I_if (CV_C_fragment (F_op (F_id pid, "!=", code), CT_bool), [I_goto case_label], [], CT_unit)], []
| AP_id pid, CV_id (id, ctyp) when is_ct_enum ctyp ->
- [ I_if (CV_C_fragment (Util.zencode_upper_string (string_of_id pid) ^ " != " ^ Util.zencode_string (string_of_id id), CT_bool), [I_goto case_label], [], CT_unit) ]
- | AP_id pid, CV_C_fragment (code, ctyp) ->
- [ I_decl (cval_ctyp cval, pid); I_copy (CL_id pid, cval) ]
- | AP_id pid, CV_id _ ->
- [ I_decl (cval_ctyp cval, pid); I_copy (CL_id pid, cval) ]
+ [I_if (CV_C_fragment (F_op (F_id pid, "!=", F_id id), CT_bool), [I_goto case_label], [], CT_unit)], []
+ | AP_id pid, _ ->
+ let ctyp = cval_ctyp cval in
+ let init, cleanup = if is_stack_ctyp ctyp then I_decl (ctyp, pid), [] else I_alloc (ctyp, pid), [I_clear (ctyp, pid)] in
+ [init; I_copy (CL_id pid, cval)], cleanup
| AP_tup apats, CV_id (id, ctyp) ->
begin
- let get_tup n ctyp = CV_C_fragment (Util.zencode_string (string_of_id id) ^ ".ztup" ^ string_of_int n, ctyp) in
+ let get_tup n ctyp = CV_C_fragment (F_field (F_id id, "ztup" ^ string_of_int n), ctyp) in
+ let fold (instrs, cleanup, n) apat ctyp =
+ let instrs', cleanup' = compile_match ctx apat (get_tup n ctyp) case_label in
+ instrs @ instrs', cleanup' @ cleanup, n + 1
+ in
match ctyp with
| CT_tup ctyps ->
- fst (List.fold_left2 (fun (instrs, n) apat ctyp -> instrs @ compile_match ctx apat (get_tup n ctyp) case_label, n + 1) ([], 0) apats ctyps)
+ let instrs, cleanup, _ = List.fold_left2 fold ([], [], 0) apats ctyps in
+ instrs, cleanup
| _ -> assert false
end
- | _, _ -> []
+ | AP_app (ctor, apat), CV_id (id, ctyp) ->
+ begin match ctyp with
+ | CT_variant (_, ctors) ->
+ let ctor_c_id = Util.zencode_string (string_of_id ctor) in
+ let ctor_ctyp = Bindings.find ctor ctors in
+ let instrs, cleanup = compile_match ctx apat (CV_C_fragment (F_field (F_id id, ctor_c_id), ctor_ctyp)) case_label in
+ [ I_if (CV_C_fragment (F_op (F_field (F_id id, "kind"), "!=", F_lit ("Kind_" ^ ctor_c_id)), CT_bool),
+ [I_goto case_label],
+ [],
+ CT_unit) ]
+ @ instrs,
+ cleanup
+ | _ -> failwith "AP_app constructor with non-variant type"
+ end
+ | _, _ -> [], []
-let unit_fragment = CV_C_fragment ("UNIT", CT_unit)
+let unit_fragment = CV_C_fragment (F_lit "UNIT", CT_unit)
(** GLOBAL: label_counter is used to make sure all labels have unique
names. Like gensym_counter it should be safe to reset between
@@ -1074,11 +1121,11 @@ let rec compile_aexp ctx = function
let compile_case (apat, guard, body) =
let trivial_guard = match guard with
| AE_val (AV_lit (L_aux (L_true, _), _))
- | AE_val (AV_C_fragment ("true", _)) -> true
+ | AE_val (AV_C_fragment (F_lit "true", _)) -> true
| _ -> false
in
let case_label = label "case_" in
- let destructure = compile_match ctx apat cval case_label in
+ let destructure, destructure_cleanup = compile_match ctx apat cval case_label in
let guard_setup, _, guard_call, guard_cleanup = compile_aexp ctx guard in
let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
@@ -1086,10 +1133,10 @@ let rec compile_aexp ctx = function
destructure @ [I_comment "end destructuring"]
@ (if not trivial_guard then
guard_setup @ [I_decl (CT_bool, gs); guard_call (CL_id gs)] @ guard_cleanup
- @ [I_if (CV_C_fragment (Printf.sprintf "!%s" (Util.zencode_string (string_of_id gs)), CT_bool), [I_goto case_label], [], CT_unit)]
+ @ [I_if (CV_C_fragment (F_unary ("!", F_id gs), CT_bool), destructure_cleanup @ [I_goto case_label], [], CT_unit)]
@ [I_comment "end guard"]
else [])
- @ body_setup @ [body_call (CL_id case_return_id)] @ body_cleanup
+ @ body_setup @ [body_call (CL_id case_return_id)] @ body_cleanup @ destructure_cleanup
@ [I_goto finish_match_label]
in
[I_block case_instrs; I_label case_label]
@@ -1112,12 +1159,12 @@ let rec compile_aexp ctx = function
let compile_case (apat, guard, body) =
let trivial_guard = match guard with
| AE_val (AV_lit (L_aux (L_true, _), _))
- | AE_val (AV_C_fragment ("true", _)) -> true
+ | AE_val (AV_C_fragment (F_lit "true", _)) -> true
| _ -> false
in
let try_label = label "try_" in
- let exn_cval = CV_C_fragment ("*current_exception", ctyp_of_typ ctx (mk_typ (Typ_id (mk_id "exception")))) in
- let destructure = compile_match ctx apat exn_cval try_label in
+ let exn_cval = CV_C_fragment (F_lit "*current_exception", ctyp_of_typ ctx (mk_typ (Typ_id (mk_id "exception")))) in
+ let destructure, destructure_cleanup = compile_match ctx apat exn_cval try_label in
let guard_setup, _, guard_call, guard_cleanup = compile_aexp ctx guard in
let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
@@ -1125,7 +1172,7 @@ let rec compile_aexp ctx = function
destructure @ [I_comment "end destructuring"]
@ (if not trivial_guard then
guard_setup @ [I_decl (CT_bool, gs); guard_call (CL_id gs)] @ guard_cleanup
- @ [I_if (CV_C_fragment (Printf.sprintf "!%s" (Util.zencode_string (string_of_id gs)), CT_bool), [I_goto try_label], [], CT_unit)]
+ @ [I_if (CV_C_fragment (F_unary ("!", F_id gs), CT_bool), [I_goto try_label], [], CT_unit)]
@ [I_comment "end guard"]
else [])
@ body_setup @ [body_call (CL_id case_return_id)] @ body_cleanup
@@ -1136,7 +1183,7 @@ let rec compile_aexp ctx = function
[],
ctyp,
(fun clexp -> I_try_block (aexp_setup @ [aexp_call clexp] @ aexp_cleanup)),
- [I_if (CV_C_fragment ("!have_exception", CT_bool), [I_goto handled_exception_label], [], CT_unit)]
+ [I_if (CV_C_fragment (F_lit "!have_exception", CT_bool), [I_goto handled_exception_label], [], CT_unit)]
@ List.concat (List.map compile_case cases)
@ [I_raw "sail_match_failure();"]
@ [I_label handled_exception_label]
@@ -1204,7 +1251,7 @@ let rec compile_aexp ctx = function
let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
let unit_gs = gensym () in
- let loop_test = CV_C_fragment (Printf.sprintf "!%s" (Util.zencode_string (string_of_id gs)), CT_bool) in
+ let loop_test = CV_C_fragment (F_unary ("!", F_id gs), CT_bool) in
cond_setup @ [I_decl (CT_bool, gs); I_decl (CT_unit, unit_gs)]
@ [I_label loop_start_label]
@ [I_block ([cond_call (CL_id gs); I_if (loop_test, [I_goto loop_end_label], [], CT_unit)]
@@ -1272,7 +1319,6 @@ let compile_type_def ctx (TD_aux (type_def, _)) =
{ ctx with records = Bindings.add id ctors ctx.records }
| TD_variant (id, _, _, tus, _) ->
- c_debug ("Compiling variant " ^ string_of_id id);
let compile_tu (Tu_aux (tu_aux, _)) =
match tu_aux with
| Tu_id id -> CT_unit, id
@@ -1467,7 +1513,7 @@ let sgen_ctyp_name = function
| CT_string -> "sail_string"
let sgen_cval = function
- | CV_C_fragment (c, _) -> c
+ | CV_C_fragment (frag, _) -> string_of_fragment frag
| CV_id (id, _) -> sgen_id id
| _ -> "CVAL??"
@@ -1494,6 +1540,9 @@ let rec codegen_instr ctx = function
| I_if (cval, [then_instr], [], ctyp) ->
string (Printf.sprintf " if (%s)" (sgen_cval cval)) ^^ hardline
^^ twice space ^^ codegen_instr ctx then_instr
+ | I_if (cval, then_instrs, [], ctyp) ->
+ string " if" ^^ space ^^ parens (string (sgen_cval cval)) ^^ space
+ ^^ surround 2 0 lbrace (separate_map hardline (codegen_instr ctx) then_instrs) (twice space ^^ rbrace)
| I_if (cval, then_instrs, else_instrs, ctyp) ->
string " if" ^^ space ^^ parens (string (sgen_cval cval)) ^^ space
^^ surround 2 0 lbrace (separate_map hardline (codegen_instr ctx) then_instrs) (twice space ^^ rbrace)
@@ -1600,8 +1649,75 @@ let codegen_type_def ctx = function
^^ codegen_init "clear" id ctors
| CTD_variant (id, tus) ->
- let codegen_tu (id, ctyp) =
- separate space [string "struct"; lbrace; string (sgen_ctyp ctyp); codegen_id id ^^ semi; rbrace]
+ let codegen_tu (ctor_id, ctyp) =
+ separate space [string "struct"; lbrace; string (sgen_ctyp ctyp); codegen_id ctor_id ^^ semi; rbrace]
+ in
+ (* Create an if, else if, ... block that does something for each constructor *)
+ let rec each_ctor v f = function
+ | [] -> string "{}"
+ | [(ctor_id, ctyp)] ->
+ string (Printf.sprintf "if (%skind == Kind_%s)" v (sgen_id ctor_id)) ^^ lbrace ^^ hardline
+ ^^ jump 0 2 (f ctor_id ctyp)
+ ^^ hardline ^^ rbrace
+ | (ctor_id, ctyp) :: ctors ->
+ string (Printf.sprintf "if (%skind == Kind_%s) " v (sgen_id ctor_id)) ^^ lbrace ^^ hardline
+ ^^ jump 0 2 (f ctor_id ctyp)
+ ^^ hardline ^^ rbrace ^^ string " else " ^^ each_ctor v f ctors
+ in
+ let codegen_init =
+ let n = sgen_id id in
+ let ctor_id, ctyp = List.hd (Bindings.bindings tus) in
+ string (Printf.sprintf "void init_%s(struct %s *op)" n n)
+ ^^ hardline
+ ^^ surround 2 0 lbrace
+ (string (Printf.sprintf "op->kind = Kind_%s;" (sgen_id ctor_id)) ^^ hardline
+ ^^ if not (is_stack_ctyp ctyp) then
+ string (Printf.sprintf "init_%s(&op->%s);" (sgen_ctyp_name ctyp) (sgen_id ctor_id))
+ else empty)
+ rbrace
+ in
+ let clear_field v ctor_id ctyp =
+ if is_stack_ctyp ctyp then
+ string (Printf.sprintf "/* do nothing */")
+ else
+ string (Printf.sprintf "clear_%s(&%s->%s);" (sgen_ctyp_name ctyp) v (sgen_id ctor_id))
+ in
+ let codegen_clear =
+ let n = sgen_id id in
+ string (Printf.sprintf "void clear_%s(struct %s *op)" n n) ^^ hardline
+ ^^ surround 2 0 lbrace
+ (each_ctor "op->" (clear_field "op") (Bindings.bindings tus) ^^ semi)
+ rbrace
+ in
+ let codegen_ctor (ctor_id, ctyp) =
+ string (Printf.sprintf "void %s(struct %s *rop, %s op)" (sgen_id ctor_id) (sgen_id id) (sgen_ctyp ctyp)) ^^ hardline
+ ^^ surround 2 0 lbrace
+ (each_ctor "rop->" (clear_field "rop") (Bindings.bindings tus) ^^ hardline
+ ^^ string ("rop->kind = Kind_" ^ sgen_id ctor_id) ^^ semi ^^ hardline
+ ^^ if is_stack_ctyp ctyp then
+ string (Printf.sprintf "rop->%s = op;" (sgen_id ctor_id))
+ else
+ string (Printf.sprintf "init_%s(&rop->%s);" (sgen_ctyp_name ctyp) (sgen_id ctor_id)) ^^ hardline
+ ^^ string (Printf.sprintf "set_%s(&rop->%s, op);" (sgen_ctyp_name ctyp) (sgen_id ctor_id)))
+ rbrace
+ in
+ let codegen_setter =
+ let n = sgen_id id in
+ let set_field ctor_id ctyp =
+ if is_stack_ctyp ctyp then
+ string (Printf.sprintf "rop->%s = op.%s;" (sgen_id ctor_id) (sgen_id ctor_id))
+ else
+ string (Printf.sprintf "init_%s(&rop->%s);" (sgen_ctyp_name ctyp) (sgen_id ctor_id))
+ ^^ string (Printf.sprintf " set_%s(&rop->%s, op.%s);" (sgen_ctyp_name ctyp) (sgen_id ctor_id) (sgen_id ctor_id))
+ in
+ string (Printf.sprintf "void set_%s(struct %s *rop, struct %s op)" n n n) ^^ hardline
+ ^^ surround 2 0 lbrace
+ (each_ctor "rop->" (clear_field "rop") (Bindings.bindings tus)
+ ^^ semi ^^ hardline
+ ^^ string "rop->kind = op.kind"
+ ^^ semi ^^ hardline
+ ^^ each_ctor "op." set_field (Bindings.bindings tus))
+ rbrace
in
string (Printf.sprintf "// union %s" (string_of_id id)) ^^ hardline
^^ string "enum" ^^ space
@@ -1609,7 +1725,7 @@ let codegen_type_def ctx = function
^^ separate space [ lbrace;
separate_map (comma ^^ space) (fun id -> string ("Kind_" ^ sgen_id id)) (List.map fst (Bindings.bindings tus));
rbrace ^^ semi ]
- ^^ hardline ^^ hardline
+ ^^ twice hardline
^^ string "struct" ^^ space ^^ codegen_id id ^^ space
^^ surround 2 0 lbrace
(separate space [string "enum"; string ("kind_" ^ sgen_id id); string "kind" ^^ semi]
@@ -1621,9 +1737,17 @@ let codegen_type_def ctx = function
^^ semi)
rbrace
^^ semi
+ ^^ twice hardline
+ ^^ codegen_init
+ ^^ twice hardline
+ ^^ codegen_clear
+ ^^ twice hardline
+ ^^ codegen_setter
+ ^^ twice hardline
+ ^^ separate_map (twice hardline) codegen_ctor (Bindings.bindings tus)
(* If this is the exception type, then we setup up some global variables to deal with exceptions. *)
^^ if string_of_id id = "exception" then
- hardline ^^ hardline
+ twice hardline
^^ separate space [string "struct"; codegen_id id; string "*current_exception = NULL;"]
^^ hardline
^^ string "bool have_exception = false;"
diff --git a/src/type_check.ml b/src/type_check.ml
index f455b5b0..3d694a1c 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -2572,7 +2572,7 @@ and bind_typ_pat env (TP_aux (typ_pat_aux, l) as typ_pat) (Typ_aux (typ_aux, _)
| nexps ->
typ_error l ("Type " ^ string_of_typ typ ^ " has multiple numeric expressions. Cannot bind " ^ string_of_kid kid)
end
- | TP_app (f1, tpats), Typ_app (f2, typs) when Id.compare f1 f2 = 0->
+ | TP_app (f1, tpats), Typ_app (f2, typs) when Id.compare f1 f2 = 0 ->
List.fold_left2 bind_typ_pat_arg env tpats typs
| _, _ -> typ_error l ("Couldn't bind type " ^ string_of_typ typ ^ " with " ^ string_of_typ_pat typ_pat)
and bind_typ_pat_arg env (TP_aux (typ_pat_aux, l) as typ_pat) (Typ_arg_aux (typ_arg_aux, _) as typ_arg) =
@@ -2583,7 +2583,7 @@ and bind_typ_pat_arg env (TP_aux (typ_pat_aux, l) as typ_pat) (Typ_arg_aux (typ_
| _, Typ_arg_typ typ -> bind_typ_pat env typ_pat typ
| _, Typ_arg_order _ -> typ_error l "Cannot bind type pattern against order"
| _, _ -> typ_error l ("Couldn't bind type argument " ^ string_of_typ_arg typ_arg ^ " with " ^ string_of_typ_pat typ_pat)
-
+
and bind_assignment env (LEXP_aux (lexp_aux, _) as lexp) (E_aux (_, (l, ())) as exp) =
let annot_assign lexp exp = E_aux (E_assign (lexp, exp), (l, Some (env, mk_typ (Typ_id (mk_id "unit")), no_effect))) in
let annot_lexp_effect lexp typ eff = LEXP_aux (lexp, (l, Some (env, typ, eff))) in