-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathanf_lang.ml
145 lines (121 loc) · 4.31 KB
/
anf_lang.ml
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
(** {0 Arithmetic expressions in A-Normal Form}
{{:https://en.wikipedia.org/wiki/A-normal_form} A-Normal Form} is an
intermediate representation that binds the result of each computation to an
intermediate definition. *)
(** {1 Syntax} *)
(** A uniquely assigned variable id *)
type id = int
(** Expressions in A-Normal Form *)
type expr =
| Let of string * id * comp * expr
| Let_join of string * id * (string * id) * expr * expr
| Join_app of id * atom
| If_then_else of atom * expr * expr
| Comp of comp
(** Computation expressions *)
and comp =
| Atom of atom
| Neg of atom
| Add of atom * atom
| Sub of atom * atom
| Mul of atom * atom
| Div of atom * atom
| Eq of atom * atom
(** Atomic expressions *)
and atom =
| Var of id
| Int of int
| Bool of bool
(** {2 Constructor functions} *)
let join_app x a = Join_app (x, a)
let comp c = Comp c
let atom a = Atom a
(** {1 Pretty printing} *)
let rec pp_expr names fmt = function
| Let (n, x, c, e) ->
let n = Format.sprintf "%s%i" n x in
Format.fprintf fmt "@[<2>@[let@ %s@ :=@]@ %a;@]@ %a" n
(pp_comp names) c
(pp_expr ((x, n) :: names)) e
| Let_join (n, x, (pn, px), e1, e2) ->
let n = Format.sprintf "%s%i" n x in
let pn = Format.sprintf "%s%i" pn px in
Format.fprintf fmt "@[<2>@[let join@ %s@ %s@ :=@]@ %a;@]@ %a" n pn
(pp_expr ((px, pn) :: names)) e1
(pp_expr ((x, n) :: names)) e2
| Join_app (n, a) ->
Format.fprintf fmt "@[jump@ j%i@ %a@]" n (pp_atom names) a
| If_then_else (a, e1, e2) ->
Format.fprintf fmt "@[<v 2>@[if@ %a@ then@]@ @[<v>%a@]@]@ @[<v 2>else@ @[<v>%a@]@]"
(pp_atom names) a
(pp_expr names) e1
(pp_expr names) e2
| Comp c ->
Format.fprintf fmt "@[%a@]" (pp_comp names) c
and pp_comp names fmt = function
| Atom a -> pp_atom names fmt a
| Neg a -> Format.fprintf fmt "neg %a" (pp_atom names) a
| Add (a1, a2) -> Format.fprintf fmt "add@ %a@ %a" (pp_atom names) a1 (pp_atom names) a2
| Sub (a1, a2) -> Format.fprintf fmt "sub@ %a@ %a" (pp_atom names) a1 (pp_atom names) a2
| Mul (a1, a2) -> Format.fprintf fmt "mul@ %a@ %a" (pp_atom names) a1 (pp_atom names) a2
| Div (a1, a2) -> Format.fprintf fmt "div@ %a@ %a" (pp_atom names) a1 (pp_atom names) a2
| Eq (a1, a2) -> Format.fprintf fmt "eq@ %a@ %a" (pp_atom names) a1 (pp_atom names) a2
and pp_atom names fmt = function
| Var x -> Format.fprintf fmt "%s" (List.assoc x names)
| Int i -> Format.pp_print_int fmt i
| Bool true -> Format.fprintf fmt "true"
| Bool false -> Format.fprintf fmt "false"
(** Semantics of arithmetic expressions *)
module Semantics = struct
module Env = Map.Make (Int)
type value =
| Int of int
| Bool of bool
type defn =
| Value of value
| Join of id * expr
let eval_atom env : atom -> value =
function
| Var x ->
begin match Env.find x env with
| Value e -> e
| _ -> failwith "not a value"
end
| Int i -> Int i
| Bool b -> Bool b
let eval_int env expr =
match eval_atom env expr with
| Int i -> i
| _ -> failwith "not an integer"
let eval_bool env expr =
match eval_atom env expr with
| Bool b -> b
| _ -> failwith "not a boolean"
let rec eval env : expr -> value =
function
| Let (_, x, c, e) -> eval (Env.add x (Value (eval_comp env c)) env) e
| Let_join (_, x, (_, px), e1, e2) -> eval (Env.add x (Join (px, e1)) env) e2
| Join_app (n, a) ->
begin match Env.find n env with
| Join (pn, e) -> eval (Env.add pn (Value (eval_atom env a)) env) e
| _ -> failwith "not a value"
end
| If_then_else (a, e1, e2) ->
if eval_bool env a then eval env e1 else eval env e2
| Comp c -> eval_comp env c
and eval_comp env : comp -> value =
function
| Atom a -> eval_atom env a
| Neg a -> Int (-(eval_int env a))
| Add (a1, a2) -> Int (eval_int env a1 + eval_int env a2)
| Sub (a1, a2) -> Int (eval_int env a1 - eval_int env a2)
| Mul (a1, a2) -> Int (eval_int env a1 * eval_int env a2)
| Div (a1, a2) -> Int (eval_int env a1 / eval_int env a2)
| Eq (a1, a2) -> Bool (eval_atom env a1 = eval_atom env a2)
let quote : value -> expr =
function
| Int i -> Comp (Atom (Int i))
| Bool b -> Comp (Atom (Bool b))
let normalise env e =
quote (eval env e)
end