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
open Std
let { Logger.log } = Logger.for_section "context"
type t =
| Constructor of Data_types.constructor_description * Location.t
| Expr
| Label of Data_types.label_description
| Module_path
| Module_type
| Patt
| Type
| Constant
| Unknown
let to_string = function
| Constructor (cd, _) -> Printf.sprintf "constructor %s" cd.cstr_name
| Expr -> "expression"
| Label lbl -> Printf.sprintf "record field %s" lbl.lbl_name
| Module_path -> "module path"
| Module_type -> "module type"
| Patt -> "pattern"
| Constant -> "constant"
| Type -> "type"
| 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 ~kind:Other 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 (_, str_loc, _) when Longident.last lid = str_loc.txt -> None
| Tpat_alias (_, _, 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 (p, 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 ~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 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, _) when Longident.last lid = lbl.lbl_name ->
Some (Label lbl)
| Expression e -> Some (inspect_expression ~cursor ~lid e)
| _ -> Some Unknown)