Source file context.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
open Std
let { Logger.log } = Logger.for_section "context"
type t =
| Constructor of Types.constructor_description * Location.t
| Unknown_constructor
| Expr
| Label :
'rep Types.gen_label_description * 'rep Types.record_form
-> t
| Unknown_label
| Module_path
| Module_type
| Patt
| Type
| Constant
| Unknown
let to_string = function
| Constructor (cd, _) -> Printf.sprintf "constructor %s" cd.cstr_name
| Unknown_constructor -> Printf.sprintf "unknown constructor"
| Expr -> "expression"
| Label (lbl, Legacy) -> Printf.sprintf "record field %s" lbl.lbl_name
| Label (lbl, Unboxed_product) ->
Printf.sprintf "unboxed record field %s" lbl.lbl_name
| Unknown_label -> Printf.sprintf "(unboxed?) record field"
| Module_path -> "module path"
| Module_type -> "module type"
| Patt -> "pattern"
| Constant -> "constant"
| Type -> "type"
| Unknown -> "unknown"
let of_locate_context : Query_protocol.Locate_context.t -> t = function
| Expr -> Expr
| Module_path -> Module_path
| Module_type -> Module_type
| Patt -> Patt
| Type -> Type
| Constant -> Constant
| Constructor -> Unknown_constructor
| Label -> Unknown_label
| Unknown -> Unknown
let cursor_on_longident_end ~cursor:cursor_pos
~lid_loc:{ Asttypes.loc; txt = lid } name =
match lid with
| Longident.Lident _ -> true
| _ ->
let end_offset = loc.loc_end.pos_cnum in
let cstr_name_size =
let name_lenght = String.length name in
if Pprintast.needs_parens name then name_lenght + 2 else name_lenght
in
let constr_pos =
{ loc.loc_end with pos_cnum = end_offset - cstr_name_size }
in
Lexing.compare_pos cursor_pos constr_pos >= 0
let inspect_pattern (type a) ~cursor ~lid (p : a Typedtree.general_pattern) =
log ~title:"inspect_context" "%a" Logger.fmt (fun fmt ->
Format.fprintf fmt "current pattern is: %a" (Printtyped.pattern 0) p);
match p.pat_desc with
| Tpat_any when Longident.last lid = "_" -> None
| Tpat_var { name = str_loc; _ } when Longident.last lid = str_loc.txt -> None
| Tpat_alias { name = str_loc; _ } when Longident.last lid = str_loc.txt ->
None
| Tpat_construct (lid_loc, cd, _, _)
when cursor_on_longident_end ~cursor ~lid_loc cd.cstr_name
&& Longident.last lid = Longident.last lid_loc.txt ->
Some (Constructor (cd, lid_loc.loc))
| Tpat_construct _ -> Some Module_path
| _ -> Some Patt
let inspect_expression ~cursor ~lid e : t =
match e.Typedtree.exp_desc with
| Texp_construct (lid_loc, cd, _, _) ->
if Longident.last lid = Longident.last lid_loc.txt then
if cursor_on_longident_end ~cursor ~lid_loc cd.cstr_name then
Constructor (cd, lid_loc.loc)
else Module_path
else Module_path
| Texp_ident { path = p; lid = lid_loc; _ } ->
let name = Path.last p in
log ~title:"inspect_context" "name is: [%s]" name;
if name = "*type-error*" then
Module_path
else if cursor_on_longident_end ~cursor ~lid_loc name then Expr
else Module_path
| Texp_constant _ -> Constant
| _ -> Expr
let inspect_browse_tree ?let_pun_behavior ?record_pattern_pun_behavior ~cursor
lid browse : t option =
log ~title:"inspect_context" "current node is: [%s]"
(String.concat ~sep:"|" (List.map ~f:(Mbrowse.print ()) browse));
match
Mbrowse.enclosing ?let_pun_behavior ?record_pattern_pun_behavior cursor
browse
with
| [] ->
log ~title:"inspect_context" "no enclosing around: %a" Lexing.print_position
cursor;
Some Unknown
| enclosings -> (
let open Browse_raw in
let node = Browse_tree.of_browse enclosings in
log ~title:"inspect_context" "current enclosing node is: %s"
(string_of_node node.Browse_tree.t_node);
match node.Browse_tree.t_node with
| Pattern p -> inspect_pattern ~cursor ~lid p
| Value_description _
| Type_declaration _
| Extension_constructor _
| Module_binding_name _
| Module_declaration_name _
| Label_declaration _
| Constructor_declaration _ -> None
| Module_expr _ | Open_description _ -> Some Module_path
| Module_type _ -> Some Module_type
| Core_type { ctyp_desc = Ttyp_package _; _ } -> Some Module_type
| Core_type _ -> Some Type
| Record_field (_, lbl, record_form, _)
when Longident.last lid = lbl.lbl_name ->
Some (Label (lbl, record_form))
| Expression e -> Some (inspect_expression ~cursor ~lid e)
| _ -> Some Unknown)