-
Notifications
You must be signed in to change notification settings - Fork 1
/
ast.ml
executable file
·122 lines (113 loc) · 3.46 KB
/
ast.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
module Set = Set.Make (String)
module Map = Map.Make (String)
type typ =
| TVar of string
| TInt
| TBool
| TUnit
| TFun of typ * typ
| TTup of typ list
let string_of_typ ty =
let rec str_simple ty =
match ty with
| TVar v -> v
| TInt -> "int"
| TBool -> "bool"
| TUnit -> "unit"
| TFun (p, r) -> str_paren p ^ " -> " ^ str_simple r
| TTup l ->
let buf = Buffer.create 50 in
let append ty = str_paren ty |> Buffer.add_string buf in
let rec iter = function
| [] -> ()
| [ ty ] -> append ty
| h :: t ->
append h;
Buffer.add_string buf " * ";
iter t
in
iter l;
Buffer.to_bytes buf |> Bytes.to_string
and str_paren ty =
match ty with
| TFun (_, _) | TTup _ -> "(" ^ str_simple ty ^ ")"
| _ -> str_simple ty
in
str_simple ty
type exp =
| Var of string
| App of exp * exp
| Fun of string list * exp
| Let of string * exp * exp
| If of exp * exp * exp
| Tup of exp list
| Lit of lit
| Annot of exp * typ
and lit = Bool of bool | Int of int
let string_of_exp exp =
let rec str_simple = function
| Var v -> Printf.sprintf "Var %s" v
| App (f, a) -> "App (" ^ str_simple f ^ ") (" ^ str_simple a ^ ")"
| Fun (xs, b) ->
List.fold_left (fun acc x -> acc ^ " " ^ x) "Fun" xs
^ " (" ^ str_simple b ^ ")"
| Let (x, v, b) ->
"Let " ^ x ^ " (" ^ str_simple v ^ ") (" ^ str_simple b ^ ")"
| If (c, t, e) ->
"If (" ^ str_simple c ^ ") (" ^ str_simple t ^ ") (" ^ str_simple e
^ ")"
| Tup [] -> "Unit"
| Tup l ->
let buf = Buffer.create 50 in
let append ty = str_simple ty |> Buffer.add_string buf in
let rec iter = function
| [] -> ()
| [ ty ] -> append ty
| h :: t ->
append h;
Buffer.add_string buf ", ";
iter t
in
iter l;
"Tup (" ^ (Buffer.to_bytes buf |> Bytes.to_string) ^ ")"
| Lit (Bool b) -> Printf.sprintf "Bool %b" b
| Lit (Int i) -> Printf.sprintf "Int %d" i
| Annot (e, ty) -> "Annot (" ^ str_simple e ^ ") :: " ^ string_of_typ ty
in
str_simple exp
type scheme = Scheme of string list * typ
let string_of_scheme = function
| Scheme ([], ty) -> string_of_typ ty
| Scheme (vars, ty) ->
let rec rename ty (v1, v2) =
match ty with
| TVar v -> TVar (if v = v1 then v2 else v)
| TBool | TInt | TUnit -> ty
| TFun (p, r) -> TFun (rename p (v1, v2), rename r (v1, v2))
| TTup l -> TTup (List.map (fun ty -> rename ty (v1, v2)) l)
in
let scheme_var i =
let off, count = (i mod 26, i / 26) in
let chr = Char.code 'a' + off |> Char.chr in
"\'" ^ String.make (count + 1) chr
in
let vars' = List.mapi (fun i v -> (v, scheme_var i)) vars in
let ty' = List.fold_left rename ty vars' in
let buf = Buffer.create 50 in
Buffer.add_string buf "forall";
List.iter
(fun (_, v) ->
Buffer.add_char buf ' ';
Buffer.add_string buf v)
vars';
Buffer.add_string buf ". ";
(Buffer.to_bytes buf |> Bytes.to_string) ^ string_of_typ ty'
type ctx = scheme Map.t
let string_of_ctx ctx =
let buf = Buffer.create 50 in
Map.iter
(fun v scheme ->
v ^ " :: " ^ string_of_scheme scheme |> Buffer.add_string buf;
Buffer.add_char buf '\n')
ctx;
Buffer.to_bytes buf |> Bytes.to_string