Skip to content

Commit 86db790

Browse files
committed
New vernacular command: eval
Target: evaluation of pWhile programs.
1 parent 86e8fc8 commit 86db790

File tree

10 files changed

+223
-1
lines changed

10 files changed

+223
-1
lines changed

src/ecCommands.ml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,37 @@ and process_dump scope (source, tc) =
630630

631631
scope
632632

633+
(* -------------------------------------------------------------------- *)
634+
and process_eval (scope : EcScope.scope) ((f, args) : pgamepath * pexpr list) =
635+
let env = EcScope.env scope in
636+
let fpath = EcTyping.trans_gamepath env f in
637+
let fun_ = EcEnv.Fun.by_xpath fpath env in
638+
let args =
639+
let ue = EcUnify.UniEnv.create None in
640+
let args, _ = EcTyping.trans_args env ue f.pl_loc fun_.f_sig args in
641+
if not (EcUnify.UniEnv.closed ue) then
642+
EcScope.hierror "cannot infer all type variables";
643+
let subst = EcUnify.UniEnv.close ue in
644+
let subst = EcCoreSubst.Tuni.subst subst in
645+
let args = List.map (EcCoreSubst.e_subst subst) args in
646+
args
647+
in
648+
649+
let aout = EcProcEval.eval env (fpath, args) in
650+
651+
begin
652+
match aout with
653+
| None ->
654+
EcScope.notify scope `Warning
655+
"%s" "cannot compute a concrete value"
656+
657+
| Some aout ->
658+
let ppe = EcPrinting.PPEnv.ofenv env in
659+
EcScope.notify scope `Info "%a" (EcPrinting.pp_expr ppe) aout
660+
end;
661+
662+
scope
663+
633664
(* -------------------------------------------------------------------- *)
634665
and process (ld : Loader.loader) (scope : EcScope.scope) g =
635666
let loc = g.pl_loc in
@@ -672,6 +703,7 @@ and process (ld : Loader.loader) (scope : EcScope.scope) g =
672703
| Greduction red -> `Fct (fun scope -> process_reduction scope red)
673704
| Ghint hint -> `Fct (fun scope -> process_hint scope hint)
674705
| GdumpWhy3 file -> `Fct (fun scope -> process_dump_why3 scope file)
706+
| Geval call -> `Fct (fun scope -> process_eval scope call)
675707
with
676708
| `Fct f -> Some (f scope)
677709
| `State f -> f scope; None

src/ecLexer.mll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
"dump" , DUMP ; (* KW: global *)
209209
"remove" , REMOVE ; (* KW: global *)
210210
"exit" , EXIT ; (* KW: global *)
211+
"eval" , EVAL ; (* KW: global *)
211212

212213
"fail" , FAIL ; (* KW: internal *)
213214
"time" , TIME ; (* KW: internal *)

src/ecModules.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ val mr_add_restr :
3636

3737
val change_oicalls : oracle_infos -> string -> xpath list -> oracle_infos
3838

39-
val oicalls_filter : oracle_infos -> string -> (xpath -> bool) -> oracle_infos
39+
val oicalls_filter : oracle_infos -> string -> (xpath -> bool) -> oracle_infos

src/ecParser.mly

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@
438438
%token EQ
439439
%token EQUIV
440440
%token ETA
441+
%token EVAL
441442
%token EXACT
442443
%token EXFALSO
443444
%token EXIST
@@ -3811,6 +3812,12 @@ user_red_option:
38113812
(* Search pattern *)
38123813
%inline search: x=sform_h { x }
38133814

3815+
(* -------------------------------------------------------------------- *)
3816+
(* Evaluation *)
3817+
eval:
3818+
| EVAL mp=loc(fident) args=paren(plist0(expr, COMMA))
3819+
{ (mp, args) }
3820+
38143821
(* -------------------------------------------------------------------- *)
38153822
(* Global entries *)
38163823

@@ -3848,6 +3855,7 @@ global_action:
38483855
| SEARCH x=search+ { Gsearch x }
38493856
| LOCATE x=qident { Glocate x }
38503857
| WHY3 x=STRING { GdumpWhy3 x }
3858+
| eval { Geval $1 }
38513859

38523860
| PRAGMA x=pragma { Gpragma x }
38533861
| PRAGMA PLUS x=pragma { Goption (x, `Bool true ) }

src/ecParsetree.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,7 @@ type global_action =
12651265
| Gpragma of psymbol
12661266
| Goption of (psymbol * [`Bool of bool | `Int of int])
12671267
| GdumpWhy3 of string
1268+
| Geval of (pgamepath * pexpr list)
12681269

12691270
type global = {
12701271
gl_action : global_action located;

src/ecProcEval.ml

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
(* -------------------------------------------------------------------- *)
2+
open EcUtils
3+
open EcPath
4+
open EcAst
5+
6+
(* -------------------------------------------------------------------- *)
7+
let eval (env : EcEnv.env) =
8+
let exception NotAValue in
9+
10+
let hyps = EcEnv.LDecl.init env [] in
11+
let cbv = EcCallbyValue.norm_cbv EcReduction.full_red hyps in
12+
13+
let rec get_function (fpath : xpath) =
14+
let fun_ = EcEnv.Fun.by_xpath fpath env in
15+
16+
match fun_.f_def with
17+
| FBdef def -> fun_, def
18+
| FBalias alias -> let _, def = get_function alias in fun_, def
19+
| _ -> raise NotAValue in
20+
21+
let rec is_literal (f : form) =
22+
match EcFol.sform_of_form f with
23+
| SFtrue | SFfalse | SFint _ -> true
24+
| SFtuple fs -> List.for_all is_literal fs
25+
| _ -> false in
26+
27+
let eval (subst : EcPV.PVM.subst) (v : form) =
28+
let aout = cbv (EcPV.PVM.subst env subst v) in
29+
if not (is_literal aout) then raise NotAValue;
30+
aout in
31+
32+
let rec doit (fpath : xpath) (args : form list) =
33+
let fun_, body = get_function fpath in
34+
let subst =
35+
List.fold_left2 (fun (subst : EcPV.PVM.subst) (var : ovariable) (arg : form) ->
36+
var.ov_name |> Option.fold ~none:subst ~some:(fun name ->
37+
let pv = EcTypes.pv_loc name in
38+
EcPV.PVM.add env pv mhr arg subst
39+
)
40+
) EcPV.PVM.empty fun_.f_sig.fs_anames args in
41+
42+
let subst = for_stmt subst body.f_body in
43+
44+
Option.map
45+
(eval subst -| EcFol.form_of_expr mhr)
46+
body.f_ret
47+
48+
and for_instr (subst : EcPV.PVM.subst) (instr : EcModules.instr) =
49+
match instr.i_node with
50+
| Sasgn (lvalue, rvalue) -> begin
51+
let rvalue = eval subst (EcFol.form_of_expr mhr rvalue) in
52+
match lvalue with
53+
| LvVar (pv, _) ->
54+
EcPV.PVM.add env pv mhr rvalue subst
55+
| LvTuple pvs ->
56+
let rvalue = EcFol.destr_tuple rvalue in
57+
List.fold_left2 (fun subst (pv, _) rvalue ->
58+
EcPV.PVM.add env pv mhr rvalue subst
59+
) subst pvs rvalue
60+
end
61+
62+
| Scall (lv, f, args) -> begin
63+
let args = List.map (eval subst -| EcFol.form_of_expr mhr) args in
64+
let aout = doit f args in
65+
66+
match lv with
67+
| None ->
68+
subst
69+
70+
| Some (LvVar (pv, _)) ->
71+
EcPV.PVM.add env pv mhr (Option.get aout) subst
72+
73+
| Some (LvTuple pvs) ->
74+
List.fold_left2 (fun subst (pv, _) aout ->
75+
EcPV.PVM.add env pv mhr aout subst
76+
) subst pvs (EcFol.destr_tuple (Option.get aout))
77+
end
78+
79+
| Sif (cond, strue, sfalse) ->
80+
let cond = eval subst (EcFol.form_of_expr mhr cond) in
81+
let branch =
82+
match EcFol.sform_of_form cond with
83+
| SFtrue -> strue
84+
| SFfalse -> sfalse
85+
| _ -> raise NotAValue in
86+
87+
for_stmt subst branch
88+
89+
| Swhile (cond, body) -> begin
90+
let cond = eval subst (EcFol.form_of_expr mhr cond) in
91+
92+
match EcFol.sform_of_form cond with
93+
| SFtrue ->
94+
let subst = for_stmt subst body in
95+
let subst = for_instr subst instr in
96+
subst
97+
98+
| SFfalse ->
99+
subst
100+
101+
| _ ->
102+
raise NotAValue
103+
end
104+
105+
| Sabstract _
106+
| Sassert _
107+
| Smatch _
108+
| Srnd _ -> raise NotAValue
109+
110+
and for_stmt (subst : EcPV.PVM.subst) (stmt : stmt) =
111+
List.fold_left for_instr subst stmt.s_node
112+
113+
in
114+
115+
fun ((fpath, args) : xpath * expr list) ->
116+
try
117+
let aout =
118+
doit fpath (List.map (cbv -| EcFol.form_of_expr mhr) args)
119+
in Option.map (EcFol.expr_of_form mhr) aout
120+
with NotAValue -> None

src/ecProcEval.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(* -------------------------------------------------------------------- *)
2+
open EcPath
3+
open EcAst
4+
5+
(* -------------------------------------------------------------------- *)
6+
val eval : EcEnv.env -> xpath * expr list -> expr option

src/ecTyping.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,7 @@ let transcall transexp env ue loc fsig args =
16571657
in
16581658
(args, fsig.fs_ret)
16591659

1660+
(* -------------------------------------------------------------------- *)
16601661
let trans_args env ue = transcall (transexp env `InProc ue) env ue
16611662

16621663
(* -------------------------------------------------------------------- *)

src/ecTyping.mli

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,25 @@ val trans_pattern : env -> ptnmap -> EcUnify.unienv -> pformula -> EcFol.form
234234
val trans_memtype :
235235
env -> EcUnify.unienv -> pmemtype -> EcMemory.memtype
236236

237+
(* -------------------------------------------------------------------- *)
238+
val transcall :
239+
('a located -> 'b * ty)
240+
-> EcEnv.env
241+
-> EcUnify.unienv
242+
-> EcLocation.t
243+
-> EcModules.funsig
244+
-> 'a located list
245+
-> 'b list * ty
246+
247+
(* -------------------------------------------------------------------- *)
248+
val trans_args :
249+
EcEnv.env
250+
-> EcUnify.unienv
251+
-> EcLocation.t
252+
-> EcModules.funsig
253+
-> pexpr list
254+
-> expr list * ty
255+
237256
(* -------------------------------------------------------------------- *)
238257
val trans_restr_for_modty :
239258
env -> module_type -> pmod_restr option -> mty_mr

tests/eval.ec

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
require import AllCore.
2+
3+
module type I = {
4+
proc bar(x : int) : int
5+
}.
6+
7+
module N : I = {
8+
proc bar(x : int) : int = {
9+
return 2*x;
10+
}
11+
}.
12+
13+
module M(O : I) = {
14+
proc foo(x : int, y : int) : int = {
15+
var z, t, u;
16+
17+
(z, t) <- (2 * x, 3 * y);
18+
19+
if (x-1 = 1) {
20+
y <- y + 1;
21+
}
22+
23+
while (0 < x) {
24+
z <- z + 2;
25+
x <- x - 1;
26+
}
27+
28+
u <@ O.bar(y);
29+
30+
return x + y + z * t + u;
31+
}
32+
}.
33+
34+
eval M(N).foo(2, 3).

0 commit comments

Comments
 (0)