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
type t = { words : string list; type_expr : Type_expr.t option }
let equal { words = words_a; type_expr = type_expr_a }
{ words = words_b; type_expr = type_expr_b } =
List.equal String.equal words_a words_b
&& Option.equal Type_expr.equal type_expr_a type_expr_b
let to_string { words; type_expr } =
let words = String.concat "; " words in
let type_expr =
type_expr
|> Option.map Type_expr.to_string
|> Option.value ~default:"<no type-query>"
in
"[" ^ words ^ "] " ^ type_expr
let balance_parens len str =
let rec aux i open_parens close_parens =
if i >= len then (open_parens, close_parens)
else
match str.[i] with
| '(' -> aux (succ i) (succ open_parens) close_parens
| ')' when open_parens > 0 -> aux (succ i) (pred open_parens) close_parens
| ')' -> aux (succ i) open_parens (succ close_parens)
| _ -> aux (succ i) open_parens close_parens
in
let o, c = aux 0 0 0 in
let o = String.make c '(' and c = String.make o ')' in
o ^ str ^ c
let naive_of_string str =
str |> String.split_on_char ' '
|> List.filter (fun s -> not (String.equal s String.empty))
let guess_type_search len str =
len >= 1
&& (Char.equal str.[0] '\''
|| String.contains str '-' || String.contains str '(')
let from_string str =
let len = String.length str in
let words, type_expr =
match String.index_opt str ':' with
| None ->
if guess_type_search len str then
let str = balance_parens len str in
("", Type_expr.from_string str)
else (str, None)
| Some loc ->
let str_name = String.sub str 0 loc
and str_type = String.sub str (succ loc) (len - loc - 1) in
let len = String.length str_type in
let str_type = balance_parens len str_type in
(str_name, Type_expr.from_string str_type)
in
let words = naive_of_string words in
{ words; type_expr }
let distance_for { words; type_expr } ~path candidate =
let type_cost =
type_expr
|> Option.map (fun query -> Type_distance.compute ~query ~entry:candidate)
|> Option.value ~default:0
in
let name_cost = Name_cost.best_distance words path in
name_cost + type_cost