ocaml/parsing/ast_invariants.ml

155 lines
4.9 KiB
OCaml

(**************************************************************************)
(* *)
(* 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 =
super.pat self pat;
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 =
super.expr self exp;
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