|
| 1 | +open EcAst |
| 2 | +open EcTypes |
| 3 | +open EcModules |
| 4 | +open EcSymbols |
| 5 | + |
| 6 | +(*---------------------------------------------------------------------------------------*) |
| 7 | +type u_error = |
| 8 | + | UE_InvalidRetInstr |
| 9 | + | UE_UnexpectedReturn |
| 10 | + | UE_ExprNotInLockstep of expr * expr |
| 11 | + | UE_InstrNotInLockstep of instr * instr |
| 12 | + | UE_DifferentProgramLengths of stmt * stmt |
| 13 | + |
| 14 | +exception UnificationError of u_error |
| 15 | + |
| 16 | +(*---------------------------------------------------------------------------------------*) |
| 17 | +type u_value = |
| 18 | + | Empty |
| 19 | + | Fixed of expr |
| 20 | + |
| 21 | +type umap = u_value Msym.t |
| 22 | + |
| 23 | +(*---------------------------------------------------------------------------------------*) |
| 24 | +let rec unify_exprs umap e1 e2 = |
| 25 | + match e1.e_node, e2.e_node with |
| 26 | + | Eint _, Eint _ -> umap |
| 27 | + | Elocal _, Elocal _ -> umap |
| 28 | + | Evar pv, e2n -> |
| 29 | + let var = symbol_of_pv pv in |
| 30 | + |
| 31 | + (* Only update a value if it hasn't been fixed previously *) |
| 32 | + let update value = |
| 33 | + match value with |
| 34 | + | None -> |
| 35 | + begin |
| 36 | + match e2n with |
| 37 | + | Evar _ -> None |
| 38 | + | _ -> raise (UnificationError (UE_ExprNotInLockstep (e1, e2))) |
| 39 | + end |
| 40 | + | Some Empty -> Some (Fixed e2) |
| 41 | + | _ -> value |
| 42 | + in |
| 43 | + |
| 44 | + Msym.change update var umap |
| 45 | + | Eop _, Eop _ -> umap |
| 46 | + | Eapp (f1, a1), Eapp (f2, a2) -> |
| 47 | + let umap = unify_exprs umap f1 f2 in |
| 48 | + List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine a1 a2) |
| 49 | + | Equant (_, _, e1), Equant (_, _, e2) -> |
| 50 | + unify_exprs umap e1 e2 |
| 51 | + | Elet (_, e1, u1), Elet (_, e2, u2) -> |
| 52 | + let umap = unify_exprs umap e1 e2 in |
| 53 | + unify_exprs umap u1 u2 |
| 54 | + | Etuple t1, Etuple t2 -> |
| 55 | + List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine t1 t2) |
| 56 | + | Eif (c1, t1, f1), Eif (c2, t2, f2) -> |
| 57 | + let umap = unify_exprs umap c1 c2 in |
| 58 | + let umap = unify_exprs umap t1 t2 in |
| 59 | + unify_exprs umap f1 f2 |
| 60 | + | Ematch (c1, p1, _), Ematch (c2, p2, _) -> |
| 61 | + let umap = unify_exprs umap c1 c2 in |
| 62 | + List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine p1 p2) |
| 63 | + | Eproj (e1, _), Eproj (e2, _) -> |
| 64 | + unify_exprs umap e1 e2 |
| 65 | + | _ -> raise (UnificationError (UE_ExprNotInLockstep (e1, e2))) |
| 66 | + |
| 67 | +(*---------------------------------------------------------------------------------------*) |
| 68 | +let rec unify_instrs umap i1 i2 = |
| 69 | + match i1.i_node, i2.i_node with |
| 70 | + | Sasgn(_, e1), Sasgn(_, e2) |
| 71 | + | Srnd(_, e1), Srnd(_, e2) -> |
| 72 | + unify_exprs umap e1 e2 |
| 73 | + | Scall(_, _, args1), Scall(_, _, args2) -> |
| 74 | + List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine args1 args2) |
| 75 | + | Sif(e1, st1, sf1), Sif(e2, st2, sf2) -> |
| 76 | + let umap = unify_exprs umap e1 e2 in |
| 77 | + let umap = unify_stmts umap st1 st2 in |
| 78 | + unify_stmts umap sf1 sf2 |
| 79 | + | Swhile(e1, s1), Swhile(e2, s2) -> |
| 80 | + let umap = unify_exprs umap e1 e2 in |
| 81 | + unify_stmts umap s1 s2 |
| 82 | + | Smatch(e1, bs1), Smatch(e2, bs2) -> |
| 83 | + let umap = unify_exprs umap e1 e2 in |
| 84 | + List.fold_left (fun umap (b1, b2) -> unify_stmts umap (snd b1) (snd b2)) umap (List.combine bs1 bs2) |
| 85 | + | Sassert e1, Sassert e2 -> |
| 86 | + unify_exprs umap e1 e2 |
| 87 | + | Sabstract _, Sabstract _ -> umap |
| 88 | + | _ -> raise (UnificationError (UE_InstrNotInLockstep (i1, i2))); |
| 89 | + |
| 90 | +and unify_stmts umap s1 s2 = |
| 91 | + let s1n, s2n = s1.s_node, s2.s_node in |
| 92 | + if List.length s1n <> List.length s2n then |
| 93 | + raise (UnificationError (UE_DifferentProgramLengths (s1, s2))); |
| 94 | + List.fold_left (fun umap (i1, i2) -> unify_instrs umap i1 i2) umap (List.combine s1n s2n) |
| 95 | + |
| 96 | +(*---------------------------------------------------------------------------------------*) |
| 97 | +(* Given a function definition attempt to unify its body with the statements `sb` |
| 98 | + and if a return statement is given, also unify it's expression. *) |
| 99 | +let unify_func umap fdef sb sr = |
| 100 | + (* Unify the body *) |
| 101 | + let umap = unify_stmts umap fdef.f_body sb in |
| 102 | + |
| 103 | + (* Unify the return stmt (if it exists) and retrieve its lv *) |
| 104 | + match sr with |
| 105 | + | Some i -> begin |
| 106 | + (* Check that there is a return expression to unify with *) |
| 107 | + if fdef.f_ret = None then |
| 108 | + raise (UnificationError UE_UnexpectedReturn); |
| 109 | + |
| 110 | + (* Only unify with assignment instructions *) |
| 111 | + match i.i_node with |
| 112 | + | Sasgn (lv, e) -> Some lv, unify_exprs umap (Option.get fdef.f_ret) e |
| 113 | + | _ -> raise (UnificationError UE_InvalidRetInstr) |
| 114 | + end |
| 115 | + | _ -> None, umap |
0 commit comments