Skip to content

Commit ee07770

Browse files
committed
feat: print an individual procedure (print [proc] M.p)
Add support for printing a single procedure instead of a whole module. Procedures of an un-instantiated functor print in suspended mode, with the functor parameters kept abstract.
1 parent dde99a1 commit ee07770

6 files changed

Lines changed: 128 additions & 36 deletions

File tree

src/ecCommands.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ let process_pr fmt scope p =
390390
| Pr_th qs -> EcPrinting.ObjectInfo.pr_th fmt env (unloc qs)
391391
| Pr_ax qs -> EcPrinting.ObjectInfo.pr_ax fmt env (unloc qs)
392392
| Pr_mod qs -> EcPrinting.ObjectInfo.pr_mod fmt env (unloc qs)
393+
| Pr_proc qs -> EcPrinting.ObjectInfo.pr_fun fmt env (unloc qs)
393394
| Pr_mty qs -> EcPrinting.ObjectInfo.pr_mty fmt env (unloc qs)
394395
| Pr_any qs -> EcPrinting.ObjectInfo.pr_any fmt env (unloc qs)
395396

src/ecCorePrinting.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ module type PrinterAPI = sig
136136
val pr_th : Format.formatter -> EcEnv.env -> qsymbol -> unit
137137
val pr_ax : Format.formatter -> EcEnv.env -> qsymbol -> unit
138138
val pr_mod : Format.formatter -> EcEnv.env -> qsymbol -> unit
139+
val pr_fun : Format.formatter -> EcEnv.env -> qsymbol -> unit
139140
val pr_mty : Format.formatter -> EcEnv.env -> qsymbol -> unit
140141
val pr_rw : Format.formatter -> EcEnv.env -> qsymbol -> unit
141142
val pr_at : Format.formatter -> EcEnv.env -> symbol -> unit

src/ecParser.mly

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3849,6 +3849,7 @@ print:
38493849
| AXIOM qs=qident { Pr_ax qs }
38503850
| LEMMA qs=qident { Pr_ax qs }
38513851
| MODULE qs=qident { Pr_mod qs }
3852+
| PROC qs=qident { Pr_proc qs }
38523853
| MODULE TYPE qs=qident { Pr_mty qs }
38533854
| GLOB qs=loc(mod_qident) { Pr_glob qs }
38543855
| GOAL n=sword { Pr_goal n }

src/ecParsetree.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,7 @@ type pprint =
12541254
| Pr_pr of pqsymbol
12551255
| Pr_ax of pqsymbol
12561256
| Pr_mod of pqsymbol
1257+
| Pr_proc of pqsymbol
12571258
| Pr_mty of pqsymbol
12581259
| Pr_glob of pmsymbol located
12591260
| Pr_goal of int

src/ecPrinting.ml

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3645,6 +3645,44 @@ and pp_block ppe fmt s =
36453645
and pp_stmt ppe fmt s =
36463646
pp_list "@," (pp_instr ppe) fmt s.s_node
36473647

3648+
let pp_function ppe fmt (fun_ : function_) =
3649+
let pp_item ppe fmt = function
3650+
| `Var pv ->
3651+
Format.fprintf fmt "@[<hov 2>var %a;@]" (pp_pvdecl ppe) pv
3652+
| `Instr i ->
3653+
Format.fprintf fmt "%a" (pp_instr ppe) i
3654+
| `Return e ->
3655+
Format.fprintf fmt "@[<hov 2>return@ @[%a@];@]" (pp_expr ppe) e
3656+
in
3657+
3658+
let pp_funhdr ppe fmt fun_ =
3659+
let with_sig = match fun_.f_def with FBalias _ -> false | _ -> true in
3660+
Format.fprintf fmt "%a" (pp_funsig ~with_sig ppe) fun_.f_sig in
3661+
3662+
let pp_fundef ppe fmt fun_ =
3663+
match fun_.f_def with
3664+
| (FBdef def) ->
3665+
let dummy_mem = EcIdent.create "&hr_dummy" in
3666+
let _, me = EcEnv.Fun.actmem_body dummy_mem fun_ in
3667+
let ppe = PPEnv.push_mem ppe ~active:true me in
3668+
let vars = List.map (fun x -> `Var x) def.f_locals in
3669+
let stmt = List.map (fun x -> `Instr x) def.f_body.s_node in
3670+
let ret = List.map (fun x -> `Return x) (otolist def.f_ret) in
3671+
let all = List.filter (fun x -> not (List.is_empty x)) [vars; stmt; ret] in
3672+
3673+
if List.is_empty all then Format.fprintf fmt "{}" else
3674+
Format.fprintf fmt "{@, @[<v>%a@]@,}"
3675+
(pp_list "@,@," (pp_list "@," (pp_item ppe))) all;
3676+
3677+
| FBalias g ->
3678+
Format.fprintf fmt "%a" (pp_funname ppe) g
3679+
3680+
| FBabs _ ->
3681+
Format.fprintf fmt "?ABSTRACT?"
3682+
in
3683+
3684+
Format.fprintf fmt "@[<v>%a = %a@]" (pp_funhdr ppe) fun_ (pp_fundef ppe) fun_
3685+
36483686
let rec pp_modexp ppe fmt (p, me) =
36493687
let params =
36503688
match me.me_body with
@@ -3676,42 +3714,7 @@ and pp_moditem ppe fmt (p, i) =
36763714
Format.fprintf fmt "@[<hov 2>var %a@]" (pp_pvdecl ppe) v
36773715

36783716
| MI_Function f ->
3679-
let pp_item ppe fmt = function
3680-
| `Var pv ->
3681-
Format.fprintf fmt "@[<hov 2>var %a;@]" (pp_pvdecl ppe) pv
3682-
| `Instr i ->
3683-
Format.fprintf fmt "%a" (pp_instr ppe) i
3684-
| `Return e ->
3685-
Format.fprintf fmt "@[<hov 2>return@ @[%a@];@]" (pp_expr ppe) e
3686-
in
3687-
3688-
let pp_funsig ppe fmt fun_ =
3689-
let with_sig = match fun_.f_def with FBalias _ -> false | _ -> true in
3690-
Format.fprintf fmt "%a" (pp_funsig ~with_sig ppe) fun_.f_sig in
3691-
3692-
let pp_fundef ppe fmt fun_ =
3693-
match fun_.f_def with
3694-
| (FBdef def) ->
3695-
let dummy_mem = EcIdent.create "&hr_dummy" in
3696-
let _, me = EcEnv.Fun.actmem_body dummy_mem fun_ in
3697-
let ppe = PPEnv.push_mem ppe ~active:true me in
3698-
let vars = List.map (fun x -> `Var x) def.f_locals in
3699-
let stmt = List.map (fun x -> `Instr x) def.f_body.s_node in
3700-
let ret = List.map (fun x -> `Return x) (otolist def.f_ret) in
3701-
let all = List.filter (fun x -> not (List.is_empty x)) [vars; stmt; ret] in
3702-
3703-
if List.is_empty all then Format.fprintf fmt "{}" else
3704-
Format.fprintf fmt "{@, @[<v>%a@]@,}"
3705-
(pp_list "@,@," (pp_list "@," (pp_item ppe))) all;
3706-
3707-
| FBalias g ->
3708-
Format.fprintf fmt "%a" (pp_funname ppe) g
3709-
3710-
| FBabs _ ->
3711-
Format.fprintf fmt "?ABSTRACT?"
3712-
in
3713-
3714-
Format.fprintf fmt "@[<v>%a = %a@]" (pp_funsig ppe) f (pp_fundef ppe) f
3717+
pp_function ppe fmt f
37153718

37163719
let pp_modexp ppe fmt (mp, me) =
37173720
Format.fprintf fmt "%a." (pp_modexp ppe) (mp, me)
@@ -4103,6 +4106,31 @@ module ObjectInfo = struct
41034106

41044107
let pr_mod = pr_gen pr_mod_r
41054108

4109+
(* ------------------------------------------------------------------ *)
4110+
let pr_fun_r =
4111+
(* Prefer the substituting lookup so that a concrete or fully-applied
4112+
procedure prints with its instantiated names. When the enclosing
4113+
module still has functor parameters, that lookup fails; we then fall
4114+
back to the suspended view, which keeps the parameters abstract. *)
4115+
let lookup qs env =
4116+
try
4117+
let (xp, f) = EcEnv.Fun.lookup qs env in
4118+
(xp, { EcEnv.sp_target = f; sp_params = (0, []); })
4119+
with EcEnv.LookupFailure _ -> EcEnv.Fun.sp_lookup qs env in
4120+
{ od_name = "procedures";
4121+
od_lookup = lookup;
4122+
od_printer =
4123+
(fun ppe fmt (_, susp) ->
4124+
let (_, params) = susp.EcEnv.sp_params in
4125+
let (ppe, pp_params) = pp_mod_params ppe params in
4126+
if List.is_empty params then
4127+
pp_function ppe fmt susp.EcEnv.sp_target
4128+
else
4129+
Format.fprintf fmt "@[<v>(* in functor %t *)@ %a@]"
4130+
pp_params (pp_function ppe) susp.EcEnv.sp_target); }
4131+
4132+
let pr_fun = pr_gen pr_fun_r
4133+
41064134
(* ------------------------------------------------------------------ *)
41074135
let pr_mty_r =
41084136
{ od_name = "module types";
@@ -4148,6 +4176,7 @@ module ObjectInfo = struct
41484176
pr_gen_r ~prcat:true pr_th_r ;
41494177
pr_gen_r ~prcat:true pr_ax_r ;
41504178
pr_gen_r ~prcat:true pr_mod_r;
4179+
pr_gen_r ~prcat:true pr_fun_r;
41514180
pr_gen_r ~prcat:true pr_mty_r;
41524181
pr_gen_r ~prcat:true pr_rw_r ;
41534182
pr_gen_r ~prcat:true pr_at_r ; ] in

tests/print-proc.ec

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
(* Unit tests for `print proc M.p` and printing a procedure via the
2+
untyped `print M.p` lookup. Uses the `expect "..." by print ...`
3+
command (String.trim-based comparison). *)
4+
5+
require import Int.
6+
7+
module type T = { proc o (x : int) : int }.
8+
9+
module M = {
10+
var g : int
11+
12+
proc k () : int = {
13+
return 3;
14+
}
15+
16+
proc w () : unit = {
17+
g <- g + 1;
18+
}
19+
}.
20+
21+
module F (A : T) = {
22+
var g : int
23+
24+
proc run (x : int) : unit = {
25+
g <@ A.o(x);
26+
}
27+
}.
28+
29+
module Impl = { proc o (x : int) : int = { return x; } }.
30+
module G = F(Impl).
31+
32+
(* explicit `print proc`, simple body *)
33+
expect "proc k() : int = {
34+
return 3;
35+
}" by print proc M.k.
36+
37+
(* explicit `print proc`, statement body referencing a module variable *)
38+
expect "proc w() : unit = {
39+
M.g <- M.g + 1;
40+
}" by print proc M.w.
41+
42+
(* bare `print M.k` finds the procedure via the untyped lookup *)
43+
expect "* In [procedures]:
44+
45+
proc k() : int = {
46+
return 3;
47+
}" by print M.k.
48+
49+
(* a procedure of an un-instantiated functor prints in suspended mode,
50+
with the call to the abstract parameter [A] kept abstract *)
51+
expect "(* in functor (A : T) *)
52+
proc run(x : int) : unit = {
53+
F.g <@ A.o(x);
54+
}" by print proc F.run.
55+
56+
(* once the functor is applied, the call to [A] is resolved concretely *)
57+
expect "proc run(x : int) : unit = {
58+
F.g <@ Impl.o(x);
59+
}" by print proc G.run.

0 commit comments

Comments
 (0)