1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
exception UnsupportedAst of string
let raise_unsupported_ast (type a) (f : Format.formatter -> a -> unit) (x : a) =
let buf = Buffer.create 16 in
let fmt = Format.formatter_of_buffer buf in
f fmt x;
Format.pp_print_flush fmt ();
raise (UnsupportedAst (Buffer.contents buf))
let raise_unsupported_expr = raise_unsupported_ast (Printast.expression 0)
type prim = [ `Add ] [@@deriving show { with_path = false }]
type expr =
| App of expr * expr
| Int of int
| Lam of string * expr
| Prim of prim
| Var of string
[@@deriving show { with_path = false }]
let rec expr_of_parsetree (expr : Parsetree.expression) : expr =
match expr.pexp_desc with
| Pexp_apply (f, xs) ->
List.fold_left
(fun f -> function
| Asttypes.Nolabel, x -> App (f, expr_of_parsetree x)
| _ -> raise_unsupported_expr expr)
(expr_of_parsetree f) xs
| Pexp_constant (Pconst_integer (n, None)) -> Int (int_of_string n)
| Pexp_fun (Nolabel, None, arg_pat, body) -> (
match arg_pat.ppat_desc with
| Ppat_var { txt = name; _ } -> Lam (name, expr_of_parsetree body)
| _ -> raise_unsupported_expr expr)
| Pexp_ident { txt = Lident "+"; _ } -> Prim `Add
| Pexp_ident { txt = Lident name; _ } -> Var name
| _ -> raise_unsupported_expr expr
let rec parsetree_of_expr : expr -> Parsetree.expression =
let expression (pexp_desc : Parsetree.expression_desc) : Parsetree.expression
=
{
pexp_desc;
pexp_loc = Location.none;
pexp_loc_stack = [];
pexp_attributes = [];
}
and ident (name : string) : Longident.t Asttypes.loc =
{ txt = Lident name; loc = Location.none }
and pattern (ppat_desc : Parsetree.pattern_desc) : Parsetree.pattern =
{
ppat_desc;
ppat_loc = Location.none;
ppat_loc_stack = [];
ppat_attributes = [];
}
and var (name : string) : string Asttypes.loc =
{ txt = name; loc = Location.none }
in
let list_of_apps expr =
let rec loop = function
| App (f, x) ->
let f, xs = loop f in
(f, x :: xs)
| f -> (f, [])
in
let f, xs = loop expr in
(f, List.rev xs)
in
function
| App (_, _) as expr ->
let f, xs = list_of_apps expr in
let xs = List.map (fun x -> (Asttypes.Nolabel, parsetree_of_expr x)) xs in
expression (Pexp_apply (parsetree_of_expr f, xs))
| Int n -> expression (Pexp_constant (Pconst_integer (Int.to_string n, None)))
| Lam (x, b) ->
expression
(Pexp_fun
(Nolabel, None, pattern (Ppat_var (var x)), parsetree_of_expr b))
| Prim `Add -> expression (Pexp_ident (ident "+"))
| Var name -> expression (Pexp_ident (ident name))
|