Source file type_expr.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
type t =
| Arrow of t * t
| Tycon of string * t list
| Tuple of t list
| Tyvar of int
| Wildcard
| Unhandled
let rec equal a b =
match (a, b) with
| Unhandled, Unhandled | Wildcard, Wildcard -> true
| Tyvar a, Tyvar b -> Int.equal a b
| Tuple a, Tuple b -> List.equal equal a b
| Tycon (ka, a), Tycon (kb, b) -> String.equal ka kb && List.equal equal a b
| Arrow (ia, oa), Arrow (ib, ob) -> equal ia ib && equal oa ob
| Arrow (_, _), _
| Tycon (_, _), _
| Tuple _, _
| Tyvar _, _
| Wildcard, _
| Unhandled, _ -> false
let parens x = "(" ^ x ^ ")"
let tyvar_to_string x =
let rec aux acc i =
let c = Char.code 'a' + (i mod 26) |> Char.chr in
let acc = acc ^ String.make 1 c in
if i < 26 then acc else aux acc (i - 26)
in
aux "'" x
let unhandled = "?"
let rec to_string = function
| Unhandled -> unhandled
| Wildcard -> "_"
| Tyvar i -> tyvar_to_string i
| Tycon (constr, []) -> constr
| Tycon (constr, [ x ]) -> with_parens x ^ " " ^ constr
| Tycon (constr, xs) -> (xs |> as_list "" |> parens) ^ " " ^ constr
| Tuple xs -> as_tuple "" xs
| Arrow (a, b) -> with_parens a ^ " -> " ^ to_string b
and with_parens = function
| (Arrow _ | Tuple _) as t -> t |> to_string |> parens
| t -> to_string t
and as_list acc = function
| [] -> acc ^ unhandled
| [ x ] -> acc ^ to_string x
| x :: xs ->
let acc = acc ^ to_string x ^ ", " in
as_list acc xs
and as_tuple acc = function
| [] -> acc ^ unhandled
| [ x ] -> acc ^ with_parens x
| x :: xs ->
let acc = acc ^ with_parens x ^ " * " in
as_tuple acc xs
module SMap = Map.Make (String)
let map_with_state f i map list =
let i, map, r =
list
|> List.fold_left
(fun (i, map, acc) x ->
let i, map, elt = f i map x in
(i, map, elt :: acc))
(i, map, [])
in
(i, map, List.rev r)
let normalize_type_parameters ty =
let rec aux i map = function
| Type_parsed.Unhandled -> (i, map, Unhandled)
| Type_parsed.Wildcard -> (i, map, Wildcard)
| Type_parsed.Arrow (a, b) ->
let i, map, a = aux i map a in
let i, map, b = aux i map b in
(i, map, Arrow (a, b))
| Type_parsed.Tycon (s, r) ->
let i, map, r = map_with_state aux i map r in
(i, map, Tycon (s, r))
| Type_parsed.Tuple r ->
let i, map, r = map_with_state aux i map r in
(i, map, Tuple r)
| Type_parsed.Tyvar var ->
let i, map, value =
match SMap.find_opt var map with
| Some value -> (i, map, value)
| None ->
let i = succ i in
let map = SMap.add var i map in
(i, map, i)
in
(i, map, Tyvar value)
in
let _, _, normalized = aux ~-1 SMap.empty ty in
normalized
let from_string str =
try
str |> Lexing.from_string
|> Type_parser.main Type_lexer.token
|> normalize_type_parameters |> Option.some
with _ -> None