forked from ocaml/ocaml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathast_invariants.ml
166 lines (160 loc) · 5.38 KB
/
ast_invariants.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
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Jeremie Dimino, Jane Street Europe *)
(* *)
(* Copyright 2015 Jane Street Group LLC *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
open Asttypes
open Parsetree
open Ast_iterator
let err = Syntaxerr.ill_formed_ast
let empty_record loc = err loc "Records cannot be empty."
let empty_variant loc = err loc "Variant types cannot be empty."
let invalid_tuple loc = err loc "Tuples must have at least 2 components."
let no_args loc = err loc "Function application with no argument."
let empty_let loc = err loc "Let with no bindings."
let empty_type loc = err loc "Type declarations cannot be empty."
let complex_id loc = err loc "Functor application not allowed here."
let simple_longident id =
let rec is_simple = function
| Longident.Lident _ -> true
| Longident.Ldot (id, _) -> is_simple id
| Longident.Lapply _ -> false
in
if not (is_simple id.txt) then complex_id id.loc
let iterator =
let super = Ast_iterator.default_iterator in
let type_declaration self td =
super.type_declaration self td;
let loc = td.ptype_loc in
match td.ptype_kind with
| Ptype_record [] -> empty_record loc
| Ptype_variant [] -> empty_variant loc
| _ -> ()
in
let typ self ty =
super.typ self ty;
let loc = ty.ptyp_loc in
match ty.ptyp_desc with
| Ptyp_tuple ([] | [_]) -> invalid_tuple loc
| Ptyp_class (id, _) -> simple_longident id
| Ptyp_package (_, cstrs) ->
List.iter (fun (id, _) -> simple_longident id) cstrs
| _ -> ()
in
let pat self pat =
begin match pat.ppat_desc with
| Ppat_construct (_, Some ({ppat_desc = Ppat_tuple _} as p))
when Builtin_attributes.explicit_arity pat.ppat_attributes ->
super.pat self p (* allow unary tuple, see GPR#523. *)
| _ ->
super.pat self pat
end;
let loc = pat.ppat_loc in
match pat.ppat_desc with
| Ppat_tuple ([] | [_]) -> invalid_tuple loc
| Ppat_record ([], _) -> empty_record loc
| Ppat_construct (id, _) -> simple_longident id
| Ppat_record (fields, _) ->
List.iter (fun (id, _) -> simple_longident id) fields
| _ -> ()
in
let expr self exp =
begin match exp.pexp_desc with
| Pexp_construct (_, Some ({pexp_desc = Pexp_tuple _} as e))
when Builtin_attributes.explicit_arity exp.pexp_attributes ->
super.expr self e (* allow unary tuple, see GPR#523. *)
| _ ->
super.expr self exp
end;
let loc = exp.pexp_loc in
match exp.pexp_desc with
| Pexp_tuple ([] | [_]) -> invalid_tuple loc
| Pexp_record ([], _) -> empty_record loc
| Pexp_apply (_, []) -> no_args loc
| Pexp_let (_, [], _) -> empty_let loc
| Pexp_ident id
| Pexp_construct (id, _)
| Pexp_field (_, id)
| Pexp_setfield (_, id, _)
| Pexp_new id
| Pexp_open (_, id, _) -> simple_longident id
| Pexp_record (fields, _) ->
List.iter (fun (id, _) -> simple_longident id) fields
| _ -> ()
in
let extension_constructor self ec =
super.extension_constructor self ec;
match ec.pext_kind with
| Pext_rebind id -> simple_longident id
| _ -> ()
in
let class_expr self ce =
super.class_expr self ce;
let loc = ce.pcl_loc in
match ce.pcl_desc with
| Pcl_apply (_, []) -> no_args loc
| Pcl_constr (id, _) -> simple_longident id
| _ -> ()
in
let module_type self mty =
super.module_type self mty;
match mty.pmty_desc with
| Pmty_alias id -> simple_longident id
| _ -> ()
in
let open_description self opn =
super.open_description self opn;
simple_longident opn.popen_lid
in
let with_constraint self wc =
super.with_constraint self wc;
match wc with
| Pwith_type (id, _)
| Pwith_module (id, _) -> simple_longident id
| _ -> ()
in
let module_expr self me =
super.module_expr self me;
match me.pmod_desc with
| Pmod_ident id -> simple_longident id
| _ -> ()
in
let structure_item self st =
super.structure_item self st;
let loc = st.pstr_loc in
match st.pstr_desc with
| Pstr_type (_, []) -> empty_type loc
| Pstr_value (_, []) -> empty_let loc
| _ -> ()
in
let signature_item self sg =
super.signature_item self sg;
let loc = sg.psig_loc in
match sg.psig_desc with
| Psig_type (_, []) -> empty_type loc
| _ -> ()
in
{ super with
type_declaration
; typ
; pat
; expr
; extension_constructor
; class_expr
; module_expr
; module_type
; open_description
; with_constraint
; structure_item
; signature_item
}
let structure st = iterator.structure iterator st
let signature sg = iterator.signature iterator sg