summaryrefslogtreecommitdiff
path: root/src/rewrites.ml
diff options
context:
space:
mode:
authorJon French2018-06-11 16:38:53 +0100
committerJon French2018-06-11 16:38:53 +0100
commit6b70f78c3c9477d4c5f417ed0a5d96abc19c9fb0 (patch)
tree5d8bdfd982c5c0efde9c7eac021f6341af124e7f /src/rewrites.ml
parent0cc7d50e08b36d036771493920bb2e20251def64 (diff)
parent22aff19aeea53719004cca2b5c6b25d0a7ed0835 (diff)
Merge branch 'mappings' into sail2
Diffstat (limited to 'src/rewrites.ml')
-rw-r--r--src/rewrites.ml662
1 files changed, 661 insertions, 1 deletions
diff --git a/src/rewrites.ml b/src/rewrites.ml
index 0ea6ef79..b938d2d7 100644
--- a/src/rewrites.ml
+++ b/src/rewrites.ml
@@ -690,6 +690,7 @@ let remove_vector_concat_pat pat =
; p_tup = (fun ps -> P_tup (List.map (fun p -> p false) ps))
; p_list = (fun ps -> P_list (List.map (fun p -> p false) ps))
; p_cons = (fun (p,ps) -> P_cons (p false, ps false))
+ ; p_string_append = (fun (ps) -> P_string_append (List.map (fun p -> p false) ps))
; p_aux =
(fun (pat,((l,_) as annot)) contained_in_p_as ->
match pat with
@@ -710,10 +711,12 @@ let remove_vector_concat_pat pat =
let p_vector_concat pats =
let rec aux ((P_aux (p,((l,_) as a))) as pat) = match p with
| P_vector _ -> P_aux (P_as (pat,fresh_id_v l),a)
+ | P_lit _ -> P_aux (P_as (pat, fresh_id_v l), a)
| P_id id -> P_aux (P_id id,a)
| P_as (p,id) -> P_aux (P_as (p,id),a)
| P_typ (typ, pat) -> P_aux (P_typ (typ, aux pat),a)
| P_wild -> P_aux (P_wild,a)
+ | P_app (id, pats) when Env.is_mapping id (env_of_annot a) -> P_aux (P_app (id, List.map aux pats), a)
| _ ->
raise
(Reporting_basic.err_unreachable
@@ -804,6 +807,9 @@ let remove_vector_concat_pat pat =
let (lb,decl,info) = letbind_vec typ_opt (rootid,rannot) (cname,cannot) (pos,index_j) in
(pos', pat_acc @ [P_aux (P_id cname,cannot)], decl_acc @ [((lb,decl),info)])
| P_typ (typ, pat) -> aux (Some typ) (pos,pat_acc,decl_acc) (pat, is_last)
+ (* | P_app (cname, pats) if Env.is_mapping cname (en) ->
+ * let (lb,decl,info) = letbind_vec typ_opt (rootid,rannot) (cname,cannot) (pos,index_j) in
+ * (pos', pat_acc @ [P_aux (P_app (cname,pats),cannot)], decl_acc @ [((lb,decl),info)]) *)
(* normal vector patterns are fine *)
| _ -> (pos', pat_acc @ [P_aux (p,cannot)],decl_acc)) in
let pats_tagged = tag_last pats in
@@ -832,6 +838,8 @@ let remove_vector_concat_pat pat =
(P_tup ps,List.flatten decls))
; p_list = (fun ps -> let (ps,decls) = List.split ps in
(P_list ps,List.flatten decls))
+ ; p_string_append = (fun ps -> let (ps,decls) = List.split ps in
+ (P_string_append ps,List.flatten decls))
; p_cons = (fun ((p,decls),(p',decls')) -> (P_cons (p,p'), decls @ decls'))
; p_aux = (fun ((pat,decls),annot) -> p_aux ((pat,decls),annot))
; fP_aux = (fun ((fpat,decls),annot) -> (FP_aux (fpat,annot),decls))
@@ -1086,6 +1094,8 @@ let rec pat_to_exp (P_aux (pat,(l,annot))) =
| P_tup pats -> rewrap (E_tuple (List.map pat_to_exp pats))
| P_list pats -> rewrap (E_list (List.map pat_to_exp pats))
| P_cons (p,ps) -> rewrap (E_cons (pat_to_exp p, pat_to_exp ps))
+ | P_string_append (ps) -> raise (Reporting_basic.err_unreachable l
+ "pat_to_exp not implemented for P_string_append")
and fpat_to_fexp (FP_aux (FP_Fpat (id,pat),(l,annot))) =
FE_aux (FE_Fexp (id, pat_to_exp pat),(l,annot))
@@ -1174,6 +1184,7 @@ let rec contains_bitvector_pat (P_aux (pat,annot)) = match pat with
| P_app (_,pats) | P_tup pats | P_list pats ->
List.exists contains_bitvector_pat pats
| P_cons (p,ps) -> contains_bitvector_pat p || contains_bitvector_pat ps
+| P_string_append (ps) -> List.exists contains_bitvector_pat ps
| P_record (fpats,_) ->
List.exists (fun (FP_aux (FP_Fpat (_,pat),_)) -> contains_bitvector_pat pat) fpats
@@ -1199,6 +1210,7 @@ let remove_bitvector_pat (P_aux (_, (l, _)) as pat) =
; p_record = (fun (fpats,b) -> P_record (fpats, b))
; p_vector = (fun ps -> P_vector (List.map (fun p -> p false) ps))
; p_vector_concat = (fun ps -> P_vector_concat (List.map (fun p -> p false) ps))
+ ; p_string_append = (fun ps -> P_string_append (List.map (fun p -> p false) ps))
; p_tup = (fun ps -> P_tup (List.map (fun p -> p false) ps))
; p_list = (fun ps -> P_list (List.map (fun p -> p false) ps))
; p_cons = (fun (p,ps) -> P_cons (p false, ps false))
@@ -1350,6 +1362,8 @@ let remove_bitvector_pat (P_aux (_, (l, _)) as pat) =
(P_vector ps, flatten_guards_decls gdls))
; p_vector_concat = (fun ps -> let (ps,gdls) = List.split ps in
(P_vector_concat ps, flatten_guards_decls gdls))
+ ; p_string_append = (fun ps -> let (ps,gdls) = List.split ps in
+ (P_string_append ps, flatten_guards_decls gdls))
; p_tup = (fun ps -> let (ps,gdls) = List.split ps in
(P_tup ps, flatten_guards_decls gdls))
; p_list = (fun ps -> let (ps,gdls) = List.split ps in
@@ -1488,7 +1502,7 @@ let rewrite_exp_guarded_pats rewriters (E_aux (exp,(l,annot)) as full_exp) =
| Pat_aux (Pat_exp (pat, body), annot) ->
(pat, None, rewrite_rec body, annot)
| Pat_aux (Pat_when (pat, guard, body), annot) ->
- (pat, Some guard, rewrite_rec body, annot) in
+ (pat, Some (rewrite_rec guard), rewrite_rec body, annot) in
let clauses = rewrite_guarded_clauses l (List.map clause ps) in
if (effectful e) then
let e = rewrite_rec e in
@@ -2803,12 +2817,436 @@ let rewrite_defs_internal_lets =
; rewrite_defs = rewrite_defs_base
}
+
+let fold_guards guards =
+ match guards with
+ | [] -> (mk_exp (E_lit (mk_lit L_true)))
+ | g :: gs -> List.fold_left (fun g g' -> mk_exp (E_app (mk_id "and_bool", [strip_exp g; strip_exp g']))) g gs
+
+let fold_typed_guards env guards =
+ match guards with
+ | [] -> annot_exp (E_lit (mk_lit L_true)) Parse_ast.Unknown env bool_typ
+ | g :: gs -> List.fold_left (fun g g' -> annot_exp (E_app (mk_id "and_bool", [g; g'])) Parse_ast.Unknown env bool_typ) g gs
+
+
+let rewrite_pexp_with_guards rewrite_pat (Pat_aux (pexp_aux, (annot: tannot annot)) as pexp) =
+ let guards = ref [] in
+
+ match pexp_aux with
+ | Pat_exp (pat, exp) ->
+ begin
+ let pat = fold_pat { id_pat_alg with p_aux = rewrite_pat guards } pat in
+ match !guards with
+ | [] -> pexp
+ | gs ->
+ let unchecked_pexp = mk_pexp (Pat_when (strip_pat pat, List.map strip_exp gs |> fold_guards, strip_exp exp)) in
+ check_case (pat_env_of pat) (pat_typ_of pat) unchecked_pexp (typ_of exp)
+ end
+ | Pat_when (pat, guard, exp) ->
+ begin
+ let pat = fold_pat { id_pat_alg with p_aux = rewrite_pat guards } pat in
+ let unchecked_pexp = mk_pexp (Pat_when (strip_pat pat, List.map strip_exp !guards |> fold_guards, strip_exp exp)) in
+ check_case (pat_env_of pat) (pat_typ_of pat) unchecked_pexp (typ_of exp)
+ end
+
+
+let pexp_rewriters rewrite_pexp =
+ let alg = { id_exp_alg with pat_aux = (fun (pexp_aux, annot) -> rewrite_pexp (Pat_aux (pexp_aux, annot))) } in
+ rewrite_defs_base { rewriters_base with rewrite_exp = (fun _ -> fold_exp alg) }
+
+
+let stringappend_counter = ref 0
+
+let fresh_stringappend_id () =
+ let id = mk_id ("_stringappend_" ^ (string_of_int !stringappend_counter) ^ "#") in
+ stringappend_counter := !stringappend_counter + 1;
+ id
+
+let unk = Parse_ast.Unknown
+let unkt = (Parse_ast.Unknown, None)
+
+let construct_bool_match env (match_on : tannot exp) (pexp : tannot pexp) : tannot exp =
+ let true_exp = annot_exp (E_lit (mk_lit L_true)) unk env bool_typ in
+ let false_exp = annot_exp (E_lit (mk_lit L_false)) unk env bool_typ in
+ let true_pexp =
+ match pexp with
+ | Pat_aux (Pat_exp (pat, exp), annot) ->
+ Pat_aux (Pat_exp (pat, true_exp), unkt)
+ | Pat_aux (Pat_when (pat, guards, exp), annot) ->
+ Pat_aux (Pat_when (pat, guards, true_exp), unkt)
+ in
+ let false_pexp = Pat_aux (Pat_exp (annot_pat P_wild unk env (typ_of match_on), false_exp), unkt) in
+ annot_exp (E_case (match_on, [true_pexp; false_pexp])) unk env bool_typ
+
+
+let rec rewrite_defs_pat_string_append =
+ let rec rewrite_pat env ((pat : tannot pat), (guards : tannot exp list), (expr : tannot exp)) =
+ let guards_ref = ref guards in
+ let expr_ref = ref expr in
+ let folder p =
+ let p, g, e = rewrite_pat env (p, !guards_ref, !expr_ref) in
+ guards_ref := g;
+ expr_ref := e;
+ p
+ in
+ match pat with
+ (*
+ "lit" ^^ pat2 => expr ---> s# if startswith(s#, "lit")
+ && match str_drop(s#, strlen("lit")) {
+ pat2 => true, _ => false
+ }
+ => match str_drop(s#, strlen("lit")) {
+ pat2 => expr
+ }
+ *)
+ | P_aux (P_string_append (
+ P_aux (P_lit (L_aux (L_string s, _) as lit), _)
+ :: pats
+ ), psa_annot) ->
+
+ let id = mk_id ("_stringappend_" ^ (string_of_int !stringappend_counter) ^ "#") in
+ stringappend_counter := !stringappend_counter + 1;
+
+ (* construct drop expression -- string_drop(s#, strlen("lit")) *)
+ let drop_exp = annot_exp (E_app (mk_id "string_drop", [annot_exp (E_id id) unk env string_typ; annot_exp (E_app (mk_id "string_length", [annot_exp (E_lit lit) unk env string_typ])) unk env nat_typ])) unk env string_typ in
+
+ (* recurse into pat2 *)
+ let new_pat2_pexp =
+ match rewrite_pat env (P_aux (P_string_append (pats), psa_annot), guards, expr) with
+ | pat, [], expr -> Pat_aux (Pat_exp (pat, expr), unkt)
+ | pat, gs, expr -> Pat_aux (Pat_when (pat, fold_typed_guards env gs, expr), unkt)
+ in
+
+ (* construct the two new guards *)
+ let guard1 = annot_exp (E_app (mk_id "string_startswith",
+ [annot_exp (E_id id) unk env string_typ;
+ annot_exp (E_lit lit) unk env string_typ]
+ )) unk env bool_typ in
+ let guard2 = construct_bool_match env drop_exp new_pat2_pexp in
+
+ (* construct new match expr *)
+ let new_expr = annot_exp (E_case (drop_exp, [new_pat2_pexp])) unk env (typ_of expr) in
+
+ (* construct final result *)
+ annot_pat (P_id id) unk env string_typ, guard1 :: guard2 :: guards, new_expr
+
+ (*
+ (builtin x) ^^ pat2 => expr ---> s# if match maybe_atoi s# {
+ Some (n#, len#) =>
+ match string_drop(s#, len#) {
+ pat2 => true, _ => false
+ }
+ None => false
+ }
+ => let (x, len#) = match maybe_int_of_prefix s# {
+ Some (n#, len#) => (n#, len#)
+ } in
+ match string_drop(s#, len#) {
+ pat2 => expr
+ }
+ *)
+
+ | P_aux (P_string_append (
+ P_aux (P_app (mapping_id, arg_pats) , _)
+ :: pats
+ ), psa_annot)
+ when Env.is_mapping mapping_id env ->
+
+ (* common things *)
+ let mapping_prefix_func =
+ match mapping_id with
+ | Id_aux (Id id, _)
+ | Id_aux (DeIid id, _) -> id ^ "_matches_prefix"
+ in
+ let mapping_inner_typ =
+ match Env.get_val_spec (mk_id mapping_prefix_func) env with
+ | (_, Typ_aux (Typ_fn (_, Typ_aux (Typ_app (_, [Typ_arg_aux (Typ_arg_typ typ, _)]), _), _), _)) -> typ
+ | _ -> typ_error Parse_ast.Unknown "mapping prefix func without correct function type?"
+ in
+
+ let s_id = fresh_stringappend_id () in
+ let n_id = fresh_stringappend_id () in
+ let len_id = fresh_stringappend_id () in
+
+ (* construct drop expression -- string_drop(s#, len#) *)
+ let drop_exp = annot_exp (E_app (mk_id "string_drop",
+ [annot_exp (E_id s_id) unk env string_typ;
+ annot_exp (E_id len_id) unk env nat_typ]))
+ unk env string_typ in
+ (* construct func expression -- maybe_atoi s# *)
+ let func_exp = annot_exp (E_app (mk_id mapping_prefix_func,
+ [annot_exp (E_id s_id) unk env string_typ]))
+ unk env mapping_inner_typ in
+ (* construct some pattern -- Some (n#, len#) *)
+ let opt_typ = app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (tuple_typ [mapping_inner_typ; nat_typ]), unk)] in
+ let some_pat = annot_pat (P_app (mk_id "Some",
+ [annot_pat (P_id n_id) unk env mapping_inner_typ;
+ annot_pat (P_id len_id) unk env nat_typ]))
+ unk env opt_typ in
+ (* construct None pattern *)
+ let none_pat = annot_pat (P_app (mk_id "None", [annot_pat (P_lit (mk_lit L_unit)) unk env unit_typ])) unk env opt_typ in
+
+ (* recurse into pat2 *)
+ let new_pat2_pexp =
+ match rewrite_pat env (P_aux (P_string_append (pats), psa_annot), guards, expr) with
+ | pat, [], expr -> Pat_aux (Pat_exp (pat, expr), unkt)
+ | pat, gs, expr -> Pat_aux (Pat_when (pat, fold_typed_guards env gs, expr), unkt)
+ in
+
+ (* construct the new guard *)
+ let guard_inner_match = construct_bool_match env drop_exp new_pat2_pexp in
+ let new_guard = annot_exp (E_case (func_exp, [
+ Pat_aux (Pat_exp (some_pat, guard_inner_match), unkt);
+ Pat_aux (Pat_exp (none_pat, annot_exp (E_lit (mk_lit (L_false))) unk env bool_typ), unkt)
+ ])) unk env bool_typ in
+
+ (* construct the new match *)
+ let new_match = annot_exp (E_case (drop_exp, [new_pat2_pexp])) unk env (typ_of expr) in
+
+ (* construct the new let *)
+ let new_binding = annot_exp (E_cast (mapping_inner_typ,
+ annot_exp (E_case (func_exp, [
+ Pat_aux (Pat_exp (some_pat,
+ annot_exp (E_tuple [
+ annot_exp (E_id n_id) unk env mapping_inner_typ;
+ annot_exp (E_id len_id) unk env nat_typ
+ ]) unk env (tuple_typ [mapping_inner_typ; nat_typ])
+ ), unkt)
+ ])) unk env (tuple_typ [mapping_inner_typ; nat_typ])
+ )) unk env mapping_inner_typ in
+ let new_letbind =
+ match arg_pats with
+ | [] -> assert false
+ | [arg_pat] -> annot_letbind
+ (P_tup [arg_pat; annot_pat (P_id len_id) unk env nat_typ], new_binding)
+ unk env (tuple_typ [pat_typ_of arg_pat; nat_typ])
+ | arg_pats -> annot_letbind
+ (P_tup
+ [annot_pat (P_tup arg_pats) unk env (tuple_typ (List.map pat_typ_of arg_pats));
+ annot_pat (P_id len_id) unk env nat_typ],
+ new_binding)
+ unk env (tuple_typ [tuple_typ (List.map pat_typ_of arg_pats); nat_typ])
+ in
+ let new_let = annot_exp (E_let (new_letbind, new_match)) unk env (typ_of expr) in
+
+ (* construct final result *)
+ annot_pat (P_id s_id) unk env string_typ,
+ new_guard :: guards,
+ new_let
+
+ | P_aux (P_string_append [pat], _) ->
+ pat, guards, expr
+
+ | P_aux (P_string_append [], (l, _)) ->
+ annot_pat (P_lit (L_aux (L_string "", l))) l env string_typ, guards, expr
+
+ | P_aux (P_string_append _, _) ->
+ failwith ("encountered a variety of string append pattern that is not yet implemented: " ^ string_of_pat pat)
+
+ | P_aux (P_as (inner_pat, inner_id), p_annot) ->
+ let inner_pat, guards, expr = rewrite_pat env (inner_pat, guards, expr) in
+ P_aux (P_as (inner_pat, inner_id), p_annot), guards, expr
+ | P_aux (P_typ (inner_typ, inner_pat), p_annot) ->
+ let inner_pat, guards, expr = rewrite_pat env (inner_pat, guards, expr) in
+ P_aux (P_typ (inner_typ, inner_pat), p_annot), guards, expr
+ | P_aux (P_var (inner_pat, typ_pat), p_annot) ->
+ let inner_pat, guards, expr = rewrite_pat env (inner_pat, guards, expr) in
+ P_aux (P_var (inner_pat, typ_pat), p_annot), guards, expr
+ | P_aux (P_record _, p_annot) ->
+ failwith "record patterns not yet implemented"
+ | P_aux (P_vector pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_vector pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_vector_concat pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_vector_concat pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_tup pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_tup pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_list pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_list pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_app (f, pats), p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_app (f, pats), p_annot), !guards_ref, !expr_ref
+ | P_aux (P_cons (pat1, pat2), p_annot) ->
+ let pat1, guards, expr = rewrite_pat env (pat1, guards, expr) in
+ let pat2, guards, expr = rewrite_pat env (pat2, guards, expr) in
+ P_aux (P_cons (pat1, pat2), p_annot), guards, expr
+ | P_aux (P_id _, _)
+ | P_aux (P_lit _, _)
+ | P_aux (P_wild, _) -> pat, guards, expr
+ in
+
+ let rec rewrite_pexp (Pat_aux (pexp_aux, pexp_annot) as pexp) =
+
+ (* merge cases of Pat_exp and Pat_when *)
+ let (P_aux (p_aux, p_annot) as pat, guards, expr) =
+ match pexp_aux with
+ | Pat_exp (pat, expr) -> (pat, [], expr)
+ | Pat_when (pat, guard, expr) -> (pat, [guard], expr)
+ in
+
+ let env = env_of_annot p_annot in
+
+ let (new_pat, new_guards, new_expr) =
+ rewrite_pat env (pat, guards, expr)
+ in
+
+ (* un-merge Pat_exp and Pat_when cases *)
+ let new_pexp = match new_guards with
+ | [] -> Pat_aux (Pat_exp (new_pat, new_expr), pexp_annot)
+ | gs -> Pat_aux (Pat_when (new_pat, fold_typed_guards env gs, new_expr), pexp_annot)
+ in
+ new_pexp
+
+ in
+ pexp_rewriters rewrite_pexp
+
+
+let mappingpatterns_counter = ref 0
+
+let fresh_mappingpatterns_id () =
+ let id = mk_id ("_mappingpatterns_" ^ (string_of_int !mappingpatterns_counter) ^ "#") in
+ mappingpatterns_counter := !mappingpatterns_counter + 1;
+ id
+
+let rewrite_defs_mapping_patterns =
+ let rec rewrite_pat env (pat, guards, expr) =
+ let guards_ref = ref guards in
+ let expr_ref = ref expr in
+ let folder p =
+ let p, g, e = rewrite_pat env (p, !guards_ref, !expr_ref) in
+ guards_ref := g;
+ expr_ref := e;
+ p
+ in
+ let env = pat_env_of pat in
+ match pat with
+ (*
+ mapping(args) => expr ----> s# if mapping_matches(s#) => let args = mapping(s#) in expr
+
+ (plus 'infer the mapping type' shenanigans)
+ *)
+ | P_aux (P_app (mapping_id, arg_pats), p_annot) when Env.is_mapping mapping_id env ->
+
+ let mapping_in_typ = typ_of_annot p_annot in
+
+ let x = Env.get_val_spec mapping_id env in
+ let (_, Typ_aux(Typ_bidir(typ1, typ2), _)) = x in
+
+ let mapping_direction =
+ if mapping_in_typ = typ1 then
+ "forwards"
+ else
+ "backwards"
+ in
+
+ let mapping_out_typ =
+ if mapping_in_typ = typ2 then
+ typ2
+ else
+ typ1
+ in
+
+ let mapping_name =
+ match mapping_id with
+ | Id_aux (Id id, _)
+ | Id_aux (DeIid id, _) -> id
+ in
+
+ let mapping_matches_id = mk_id (mapping_name ^ "_" ^ mapping_direction ^ "_matches") in
+ let mapping_perform_id = mk_id (mapping_name ^ "_" ^ mapping_direction) in
+ let s_id = fresh_mappingpatterns_id () in
+
+ let s_exp = annot_exp (E_id s_id) unk env mapping_in_typ in
+ let new_guard = annot_exp (E_app (mapping_matches_id, [s_exp])) unk env bool_typ in
+ let new_binding = annot_exp (E_app (mapping_perform_id, [s_exp])) unk env typ2 in
+ let new_letbind = match arg_pats with
+ | [] -> assert false
+ | [arg_pat] -> LB_aux (LB_val (arg_pat, new_binding), unkt)
+ | arg_pats ->
+ let checked_tup = annot_pat (P_tup arg_pats) unk env mapping_out_typ in
+ LB_aux (LB_val (checked_tup, new_binding), unkt)
+ in
+
+ let new_let = annot_exp (E_let (new_letbind, expr)) unk env (typ_of expr) in
+
+ annot_pat (P_id s_id) unk env mapping_in_typ, new_guard :: guards, new_let
+
+ | P_aux (P_as (inner_pat, inner_id), p_annot) ->
+ let inner_pat, guards, expr = rewrite_pat env (inner_pat, guards, expr) in
+ P_aux (P_as (inner_pat, inner_id), p_annot), guards, expr
+ | P_aux (P_typ (inner_typ, inner_pat), p_annot) ->
+ let inner_pat, guards, expr = rewrite_pat env (inner_pat, guards, expr) in
+ P_aux (P_typ (inner_typ, inner_pat), p_annot), guards, expr
+ | P_aux (P_var (inner_pat, typ_pat), p_annot) ->
+ let inner_pat, guards, expr = rewrite_pat env (inner_pat, guards, expr) in
+ P_aux (P_var (inner_pat, typ_pat), p_annot), guards, expr
+ | P_aux (P_record _, p_annot) ->
+ failwith "record patterns not yet implemented"
+ | P_aux (P_vector pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_vector pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_vector_concat pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_vector_concat pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_tup pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_tup pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_list pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_list pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_app (f, pats), p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_app (f, pats), p_annot), !guards_ref, !expr_ref
+ | P_aux (P_string_append pats, p_annot) ->
+ let pats = List.map folder pats in
+ P_aux (P_string_append pats, p_annot), !guards_ref, !expr_ref
+ | P_aux (P_cons (pat1, pat2), p_annot) ->
+ let pat1, guards, expr = rewrite_pat env (pat1, guards, expr) in
+ let pat2, guards, expr = rewrite_pat env (pat2, guards, expr) in
+ P_aux (P_cons (pat1, pat2), p_annot), guards, expr
+ | P_aux (P_id _, _)
+ | P_aux (P_lit _, _)
+ | P_aux (P_wild, _) -> pat, guards, expr
+ in
+
+ let rec rewrite_pexp (Pat_aux (pexp_aux, pexp_annot) as pexp) =
+
+ (* merge cases of Pat_exp and Pat_when *)
+ let (P_aux (p_aux, p_annot) as pat, guards, expr) =
+ match pexp_aux with
+ | Pat_exp (pat, expr) -> (pat, [], expr)
+ | Pat_when (pat, guard, expr) -> (pat, [guard], expr)
+ in
+
+ let env = env_of_annot p_annot in
+
+ let (new_pat, new_guards, new_expr) =
+ rewrite_pat env (pat, guards, expr)
+ in
+
+ (* un-merge Pat_exp and Pat_when cases *)
+ let new_pexp = match new_guards with
+ | [] -> Pat_aux (Pat_exp (new_pat, new_expr), pexp_annot)
+ | gs -> Pat_aux (Pat_when (new_pat, fold_typed_guards env gs, new_expr), pexp_annot)
+ in
+ typ_debug (lazy (Printf.sprintf "rewritten pexp: %s\n%!" (Pretty_print_sail.doc_pexp new_pexp |> Pretty_print_sail.to_string)));
+ new_pexp
+
+ in
+ pexp_rewriters rewrite_pexp
+
+
let rewrite_defs_pat_lits =
let rewrite_pexp (Pat_aux (pexp_aux, annot) as pexp) =
let guards = ref [] in
let counter = ref 0 in
let rewrite_pat = function
+ (* HACK: ignore strings for now *)
+ | P_lit (L_aux (L_string _, _)) as p_aux, p_annot -> P_aux (p_aux, p_annot)
| P_lit lit, p_annot ->
let env = env_of_annot p_annot in
let typ = typ_of_annot p_annot in
@@ -3260,9 +3698,222 @@ let merge_funcls (Defs defs) =
| d -> d
in Defs (List.map merge_in_def defs)
+
+let rec exp_of_mpat (MP_aux (mpat, annot)) =
+ let empty_vec = E_aux (E_vector [], annot) in
+ let concat_vectors annot vec1 vec2 = (* TODO FIXME, this should be OK for typing but doesn't attach location information properly *)
+ E_aux (E_vector_append (vec1, vec2), annot)
+ in
+ let empty_string = E_aux (E_lit (L_aux (L_string "", Parse_ast.Unknown)), annot) in
+ let string_append annot str1 str2 =
+ E_aux (E_app (mk_id "string_append", [str1; str2]), annot)
+ in
+ match mpat with
+ | MP_lit lit -> E_aux (E_lit lit, annot)
+ | MP_id id -> E_aux (E_id id, annot)
+ | MP_app (id, args) -> E_aux (E_app (id, (List.map exp_of_mpat args)), annot)
+ | MP_record (mfpats, flag) -> E_aux (E_record (fexps_of_mfpats mfpats flag annot), annot)
+ | MP_vector mpats -> E_aux (E_vector (List.map exp_of_mpat mpats), annot)
+ | MP_vector_concat mpats -> List.fold_right (concat_vectors annot) (List.map exp_of_mpat mpats) empty_vec
+ | MP_tup mpats -> E_aux (E_tuple (List.map exp_of_mpat mpats), annot)
+ | MP_list mpats -> E_aux (E_list (List.map exp_of_mpat mpats), annot)
+ | MP_cons (mpat1, mpat2) -> E_aux (E_cons (exp_of_mpat mpat1, exp_of_mpat mpat2), annot)
+ | MP_string_append mpats -> List.fold_right (string_append annot) (List.map exp_of_mpat mpats) empty_string
+ | MP_typ (mpat, typ) -> E_aux (E_cast (typ, exp_of_mpat mpat), annot)
+
+and fexps_of_mfpats mfpats flag annot =
+ let fexp_of_mfpat (MFP_aux (MFP_mpat (id, mpat), annot)) =
+ FE_aux (FE_Fexp (id, exp_of_mpat mpat), annot)
+ in
+ FES_aux (FES_Fexps (List.map fexp_of_mfpat mfpats, flag), annot)
+
+let rec pat_of_mpat (MP_aux (mpat, annot)) =
+ match mpat with
+ | MP_lit lit -> P_aux (P_lit lit, annot)
+ | MP_id id -> P_aux (P_id id, annot)
+ | MP_app (id, args) -> P_aux (P_app (id, (List.map pat_of_mpat args)), annot)
+ | MP_record (mfpats, flag) -> P_aux (P_record ((fpats_of_mfpats mfpats), flag), annot)
+ | MP_vector mpats -> P_aux (P_vector (List.map pat_of_mpat mpats), annot)
+ | MP_vector_concat mpats -> P_aux (P_vector_concat (List.map pat_of_mpat mpats), annot)
+ | MP_tup mpats -> P_aux (P_tup (List.map pat_of_mpat mpats), annot)
+ | MP_list mpats -> P_aux (P_list (List.map pat_of_mpat mpats), annot)
+ | MP_cons (mpat1, mpat2) -> P_aux ((P_cons (pat_of_mpat mpat1, pat_of_mpat mpat2), annot))
+ | MP_string_append (mpats) -> P_aux ((P_string_append (List.map pat_of_mpat mpats), annot))
+ | MP_typ (mpat, typ) -> P_aux (P_typ (typ, pat_of_mpat mpat), annot)
+
+and fpats_of_mfpats mfpats =
+ let fpat_of_mfpat (MFP_aux (MFP_mpat (id, mpat), annot)) =
+ FP_aux (FP_Fpat (id, pat_of_mpat mpat), annot)
+ in
+ List.map fpat_of_mfpat mfpats
+
+let rewrite_defs_realise_mappings (Defs defs) =
+ let realise_mpexps forwards mpexp1 mpexp2 =
+ let mpexp_pat, mpexp_exp =
+ if forwards then mpexp1, mpexp2
+ else mpexp2, mpexp1
+ in
+ let exp =
+ match mpexp_exp with
+ | MPat_aux ((MPat_pat mpat), _) -> exp_of_mpat mpat
+ | MPat_aux ((MPat_when (mpat, _), _)) -> exp_of_mpat mpat
+ in
+ match mpexp_pat with
+ | MPat_aux (MPat_pat mpat, annot) -> Pat_aux (Pat_exp (pat_of_mpat mpat, exp), annot)
+ | MPat_aux (MPat_when (mpat, guard), annot) -> Pat_aux (Pat_when (pat_of_mpat mpat, guard, exp), annot)
+ in
+ let realise_mapcl forwards id (MCL_aux (MCL_mapcl (mpexp1, mpexp2), (l, ()))) =
+ realise_mpexps forwards mpexp1 mpexp2
+ in
+ let realise_bool_mapcl forwards id (MCL_aux (MCL_mapcl (mpexp1, mpexp2), (l, ()))) =
+ let mpexp = if forwards then mpexp1 else mpexp2 in
+ realise_mpexps true mpexp (mk_mpexp (MPat_pat (mk_mpat (MP_lit (mk_lit L_true)))))
+ in
+ let arg_id = mk_id "arg#" in
+ let arg_exp = (mk_exp (E_id arg_id)) in
+ let arg_pat = mk_pat (P_id arg_id) in
+ let placeholder_id = mk_id "s#" in
+ let append_placeholder = function
+ | MPat_aux (MPat_pat (MP_aux (MP_string_append mpats, p_annot)), aux_annot) ->
+ MPat_aux (MPat_pat (MP_aux (MP_string_append (mpats @ [mk_mpat (MP_id placeholder_id)]), p_annot)), aux_annot)
+ | MPat_aux (MPat_when (MP_aux (MP_string_append mpats, p_annot), guard), aux_annot) ->
+ MPat_aux (MPat_when (MP_aux (MP_string_append (mpats @ [mk_mpat (MP_id placeholder_id)]), p_annot), guard), aux_annot)
+ | MPat_aux (MPat_pat mpat, aux_annot) ->
+ MPat_aux (MPat_pat (mk_mpat (MP_string_append [mpat; mk_mpat (MP_id placeholder_id)])), aux_annot)
+ | MPat_aux (MPat_when (mpat, guard), aux_annot) ->
+ MPat_aux (MPat_when (mk_mpat (MP_string_append [mpat; mk_mpat (MP_id placeholder_id)]), guard), aux_annot)
+ in
+ let realise_prefix_mapcl forwards id (MCL_aux (MCL_mapcl (mpexp1, mpexp2), (l, ()))) =
+ let mpexp = if forwards then mpexp1 else mpexp2 in
+ let other = if forwards then mpexp2 else mpexp1 in
+ let strlen = (
+ mk_mpat (MP_app ( mk_id "sub_nat",
+ [
+ mk_mpat (MP_app ( mk_id "string_length" , [mk_mpat (MP_id arg_id )]));
+ mk_mpat (MP_app ( mk_id "string_length" , [mk_mpat (MP_id placeholder_id)]));
+ ]
+ ))
+ ) in
+ match other with
+ | MPat_aux (MPat_pat mpat2, _)
+ | MPat_aux (MPat_when (mpat2, _), _)->
+ realise_mpexps true (append_placeholder mpexp) (mk_mpexp (MPat_pat (mk_mpat (MP_app ((mk_id "Some"), [ mk_mpat (MP_tup [mpat2; strlen]) ])))))
+ in
+ let realise_mapdef (MD_aux (MD_mapping (id, _, mapcls), ((l, (tannot:tannot)) as annot))) =
+ let forwards_id = mk_id (string_of_id id ^ "_forwards") in
+ let forwards_matches_id = mk_id (string_of_id id ^ "_forwards_matches") in
+ let backwards_id = mk_id (string_of_id id ^ "_backwards") in
+ let backwards_matches_id = mk_id (string_of_id id ^ "_backwards_matches") in
+
+ let non_rec = (Rec_aux (Rec_nonrec, Parse_ast.Unknown)) in
+ let effect_pure = (Effect_opt_aux (Effect_opt_pure, Parse_ast.Unknown)) in
+ let env = match mapcls with
+ | MCL_aux (_, mapcl_annot) :: _ -> env_of_annot mapcl_annot
+ | _ -> Type_check.typ_error l "mapping with no clauses?"
+ in
+ let (typq, bidir_typ) = Env.get_val_spec id env in
+ let (typ1, typ2, l) = match bidir_typ with
+ | Typ_aux (Typ_bidir (typ1, typ2), l) -> typ1, typ2, l
+ | _ -> Type_check.typ_error l "non-bidir type of mapping?"
+ in
+ let forwards_typ = Typ_aux (Typ_fn (typ1, typ2, no_effect), l) in
+ let forwards_matches_typ = Typ_aux (Typ_fn (typ1, bool_typ, no_effect), l) in
+ let backwards_typ = Typ_aux (Typ_fn (typ2, typ1, no_effect), l) in
+ let backwards_matches_typ = Typ_aux (Typ_fn (typ2, bool_typ, no_effect), l) in
+
+ let forwards_spec = VS_aux (VS_val_spec (mk_typschm typq forwards_typ, forwards_id, (fun _ -> None), false), (Parse_ast.Unknown,())) in
+ let backwards_spec = VS_aux (VS_val_spec (mk_typschm typq backwards_typ, backwards_id, (fun _ -> None), false), (Parse_ast.Unknown,())) in
+ let forwards_matches_spec = VS_aux (VS_val_spec (mk_typschm typq forwards_matches_typ, forwards_matches_id, (fun _ -> None), false), (Parse_ast.Unknown,())) in
+ let backwards_matches_spec = VS_aux (VS_val_spec (mk_typschm typq backwards_matches_typ, backwards_matches_id, (fun _ -> None), false), (Parse_ast.Unknown,())) in
+
+ let forwards_spec, env = Type_check.check_val_spec env forwards_spec in
+ let backwards_spec, env = Type_check.check_val_spec env backwards_spec in
+ let forwards_matches_spec, env = Type_check.check_val_spec env forwards_matches_spec in
+ let backwards_matches_spec, env = Type_check.check_val_spec env backwards_matches_spec in
+
+ let no_tannot = (Typ_annot_opt_aux (Typ_annot_opt_none, Parse_ast.Unknown)) in
+ let forwards_match = mk_exp (E_case (arg_exp, (List.map (fun mapcl -> strip_mapcl mapcl |> realise_mapcl true forwards_id) mapcls))) in
+ let backwards_match = mk_exp (E_case (arg_exp, (List.map (fun mapcl -> strip_mapcl mapcl |> realise_mapcl false backwards_id) mapcls))) in
+
+ let wildcard = mk_pexp (Pat_exp (mk_pat P_wild, mk_exp (E_lit (mk_lit L_false)))) in
+ let forwards_matches_match = mk_exp (E_case (arg_exp, (List.map (fun mapcl -> strip_mapcl mapcl |> realise_bool_mapcl true forwards_matches_id) mapcls) @ [wildcard])) in
+ let backwards_matches_match = mk_exp (E_case (arg_exp, (List.map (fun mapcl -> strip_mapcl mapcl |> realise_bool_mapcl false backwards_matches_id) mapcls) @ [wildcard])) in
+
+ let forwards_fun = (FD_aux (FD_function (non_rec, no_tannot, effect_pure, [mk_funcl forwards_id arg_pat forwards_match]), (l, ()))) in
+ let backwards_fun = (FD_aux (FD_function (non_rec, no_tannot, effect_pure, [mk_funcl backwards_id arg_pat backwards_match]), (l, ()))) in
+ let forwards_matches_fun = (FD_aux (FD_function (non_rec, no_tannot, effect_pure, [mk_funcl forwards_matches_id arg_pat forwards_matches_match]), (l, ()))) in
+ let backwards_matches_fun = (FD_aux (FD_function (non_rec, no_tannot, effect_pure, [mk_funcl backwards_matches_id arg_pat backwards_matches_match]), (l, ()))) in
+
+ typ_debug (lazy (Printf.sprintf "forwards for mapping %s: %s\n%!" (string_of_id id) (Pretty_print_sail.doc_fundef forwards_fun |> Pretty_print_sail.to_string)));
+ typ_debug (lazy (Printf.sprintf "backwards for mapping %s: %s\n%!" (string_of_id id) (Pretty_print_sail.doc_fundef backwards_fun |> Pretty_print_sail.to_string)));
+ typ_debug (lazy (Printf.sprintf "forwards matches for mapping %s: %s\n%!" (string_of_id id) (Pretty_print_sail.doc_fundef forwards_matches_fun |> Pretty_print_sail.to_string)));
+ typ_debug (lazy (Printf.sprintf "backwards matches for mapping %s: %s\n%!" (string_of_id id) (Pretty_print_sail.doc_fundef backwards_matches_fun |> Pretty_print_sail.to_string)));
+ let forwards_fun, _ = Type_check.check_fundef env forwards_fun in
+ let backwards_fun, _ = Type_check.check_fundef env backwards_fun in
+ let forwards_matches_fun, _ = Type_check.check_fundef env forwards_matches_fun in
+ let backwards_matches_fun, _ = Type_check.check_fundef env backwards_matches_fun in
+
+ let prefix_id = mk_id (string_of_id id ^ "_matches_prefix") in
+ let prefix_wildcard = mk_pexp (Pat_exp (mk_pat P_wild, mk_exp (E_app (mk_id "None", [mk_exp (E_lit (mk_lit L_unit))])))) in
+ let string_defs =
+ begin if subtype_check env typ1 string_typ && subtype_check env string_typ typ1 then
+ let forwards_prefix_typ = Typ_aux (Typ_fn (typ1, app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (tuple_typ [typ2; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
+ let forwards_prefix_spec = VS_aux (VS_val_spec (mk_typschm typq forwards_prefix_typ, prefix_id, (fun _ -> None), false), (Parse_ast.Unknown,())) in
+ let forwards_prefix_spec, env = Type_check.check_val_spec env forwards_prefix_spec in
+ let forwards_prefix_match = mk_exp (E_case (arg_exp, (List.map (fun mapcl -> strip_mapcl mapcl |> realise_prefix_mapcl true prefix_id) mapcls) @ [prefix_wildcard])) in
+ let forwards_prefix_fun = (FD_aux (FD_function (non_rec, no_tannot, effect_pure, [mk_funcl prefix_id arg_pat forwards_prefix_match]), (l, ()))) in
+ typ_debug (lazy (Printf.sprintf "forwards prefix matches for mapping %s: %s\n%!" (string_of_id id) (Pretty_print_sail.doc_fundef forwards_prefix_fun |> Pretty_print_sail.to_string)));
+ let forwards_prefix_fun, _ = Type_check.check_fundef env forwards_prefix_fun in
+ forwards_prefix_spec @ forwards_prefix_fun
+ else
+ if subtype_check env typ2 string_typ && subtype_check env string_typ typ2 then
+ let backwards_prefix_typ = Typ_aux (Typ_fn (typ2, app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (tuple_typ [typ1; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
+ let backwards_prefix_spec = VS_aux (VS_val_spec (mk_typschm typq backwards_prefix_typ, prefix_id, (fun _ -> None), false), (Parse_ast.Unknown,())) in
+ let backwards_prefix_spec, env = Type_check.check_val_spec env backwards_prefix_spec in
+ let backwards_prefix_match = mk_exp (E_case (arg_exp, (List.map (fun mapcl -> strip_mapcl mapcl |> realise_prefix_mapcl false prefix_id) mapcls) @ [prefix_wildcard])) in
+ let backwards_prefix_fun = (FD_aux (FD_function (non_rec, no_tannot, effect_pure, [mk_funcl prefix_id arg_pat backwards_prefix_match]), (l, ()))) in
+ typ_debug (lazy (Printf.sprintf "backwards prefix matches for mapping %s: %s\n%!" (string_of_id id) (Pretty_print_sail.doc_fundef backwards_prefix_fun |> Pretty_print_sail.to_string)));
+ let backwards_prefix_fun, _ = Type_check.check_fundef env backwards_prefix_fun in
+ backwards_prefix_spec @ backwards_prefix_fun
+ else
+ []
+ end
+ in
+
+ forwards_spec
+ @ forwards_fun
+ @ backwards_spec
+ @ backwards_fun
+ @ forwards_matches_spec
+ @ forwards_matches_fun
+ @ backwards_matches_spec
+ @ backwards_matches_fun
+ @ string_defs
+ in
+ let rewrite_def def =
+ match def with
+ | DEF_mapdef mdef -> realise_mapdef mdef
+ | d -> [d]
+ in
+ Defs (List.map rewrite_def defs |> List.flatten)
+
let recheck_defs defs = fst (Type_error.check initial_env defs)
+let remove_mapping_valspecs (Defs defs) =
+ let allowed_def def =
+ match def with
+ | DEF_spec (VS_aux (VS_val_spec (TypSchm_aux (TypSchm_ts (_, Typ_aux (Typ_bidir _, _)), _), _, _, _), _)) -> false
+ | _ -> true
+ in
+ Defs (List.filter allowed_def defs)
+
+
let rewrite_defs_lem = [
+ ("realise_mappings", rewrite_defs_realise_mappings);
+ ("remove_mapping_valspecs", remove_mapping_valspecs);
+ ("pat_string_append", rewrite_defs_pat_string_append);
+ ("mapping_builtins", rewrite_defs_mapping_patterns);
+ ("pat_lits", rewrite_defs_pat_lits);
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
("simple_assignments", rewrite_simple_assignments);
@@ -3297,6 +3948,9 @@ let rewrite_defs_lem = [
let rewrite_defs_ocaml = [
(* ("undefined", rewrite_undefined); *)
("no_effect_check", (fun defs -> opt_no_effects := true; defs));
+ ("realise_mappings", rewrite_defs_realise_mappings);
+ ("pat_string_append", rewrite_defs_pat_string_append);
+ ("mapping_builtins", rewrite_defs_mapping_patterns);
("pat_lits", rewrite_defs_pat_lits);
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
@@ -3316,6 +3970,9 @@ let rewrite_defs_ocaml = [
let rewrite_defs_c = [
("no_effect_check", (fun defs -> opt_no_effects := true; defs));
+ ("realise_mappings", rewrite_defs_realise_mappings);
+ ("pat_string_append", rewrite_defs_pat_string_append);
+ ("mapping_builtins", rewrite_defs_mapping_patterns);
("pat_lits", rewrite_defs_pat_lits);
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
@@ -3333,6 +3990,9 @@ let rewrite_defs_c = [
let rewrite_defs_interpreter = [
("no_effect_check", (fun defs -> opt_no_effects := true; defs));
+ ("realise_mappings", rewrite_defs_realise_mappings);
+ ("pat_string_append", rewrite_defs_pat_string_append);
+ ("mapping_builtins", rewrite_defs_mapping_patterns);
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
("simple_assignments", rewrite_simple_assignments);