Simplify the API for inlined records in constructors
This commit is contained in:
parent
b48b1a168b
commit
48cd886bfc
|
@ -339,18 +339,26 @@ module Of_sexp = struct
|
||||||
module Constructor_args_spec = struct
|
module Constructor_args_spec = struct
|
||||||
type 'a conv = 'a t
|
type 'a conv = 'a t
|
||||||
type ('a, 'b) t =
|
type ('a, 'b) t =
|
||||||
| Nil : ('a, 'a) t
|
| Nil : ('a, 'a) t
|
||||||
| Rest : 'a conv -> ('a list -> 'b, 'b) t
|
| Rest : 'a conv -> ('a list -> 'b, 'b) t
|
||||||
| Loc : ('a, 'b) t -> (Loc.t -> 'a, 'b) t
|
| Record : 'a record_parser -> ('a -> 'b, 'b) t
|
||||||
| Cons : 'a conv * ('b, 'c) t -> ('a -> 'b, 'c) t
|
| Loc : ('a, 'b) t -> (Loc.t -> 'a, 'b) t
|
||||||
|
| Cons : 'a conv * ('b, 'c) t -> ('a -> 'b, 'c) t
|
||||||
|
|
||||||
let rec convert : type a b. (a, b) t -> Ast.t -> Ast.t list -> a -> b
|
let rec convert : type a b. (a, b) t -> Ast.t -> Ast.t list -> a -> b
|
||||||
= fun t sexp sexps f ->
|
= fun t sexp sexps f ->
|
||||||
match t, sexps with
|
match t, sexps with
|
||||||
| Nil, [] -> f
|
| Nil, [] -> f
|
||||||
| Rest conv, l -> f (List.map l ~f:conv)
|
| Rest conv, l -> f (List.map l ~f:conv)
|
||||||
| Loc t, sexps -> convert t sexp sexps (f (Ast.loc sexp))
|
| Record rp, l -> begin
|
||||||
| Cons (conv, t), s :: sexps -> convert t sexp sexps (f (conv s))
|
match sexp with
|
||||||
|
| Atom (_, A s) | Quoted_string (_, s) ->
|
||||||
|
of_sexp_errorf sexp "'%s' expect arguments" s
|
||||||
|
| List (loc, _) ->
|
||||||
|
f (record rp (List (loc, l)))
|
||||||
|
end
|
||||||
|
| Loc t, l -> convert t sexp l (f (Ast.loc sexp))
|
||||||
|
| Cons (conv, t), s :: l -> convert t sexp l (f (conv s))
|
||||||
| Cons _, [] -> of_sexp_error sexp "not enough arguments"
|
| Cons _, [] -> of_sexp_error sexp "not enough arguments"
|
||||||
| Nil, _ :: _ -> of_sexp_error sexp "too many arguments"
|
| Nil, _ :: _ -> of_sexp_error sexp "too many arguments"
|
||||||
end
|
end
|
||||||
|
@ -359,6 +367,7 @@ module Of_sexp = struct
|
||||||
let ( @> ) a b = Constructor_args_spec.Cons (a, b)
|
let ( @> ) a b = Constructor_args_spec.Cons (a, b)
|
||||||
let rest f = Constructor_args_spec.Rest f
|
let rest f = Constructor_args_spec.Rest f
|
||||||
let cstr_loc x = Constructor_args_spec.Loc x
|
let cstr_loc x = Constructor_args_spec.Loc x
|
||||||
|
let rest_as_record rp = Constructor_args_spec.Record rp
|
||||||
|
|
||||||
let field_multi name ?default args_spec f state =
|
let field_multi name ?default args_spec f state =
|
||||||
match find_single state name with
|
match find_single state name with
|
||||||
|
@ -384,32 +393,19 @@ module Of_sexp = struct
|
||||||
(res, consume name state)
|
(res, consume name state)
|
||||||
|
|
||||||
module Constructor_spec = struct
|
module Constructor_spec = struct
|
||||||
type ('a, 'b) tuple =
|
type ('a, 'b) unpacked =
|
||||||
{ name : string
|
{ name : string
|
||||||
; args : ('a, 'b) Constructor_args_spec.t
|
; args : ('a, 'b) Constructor_args_spec.t
|
||||||
; make : 'a
|
; make : 'a
|
||||||
}
|
}
|
||||||
|
|
||||||
type 'a record =
|
type 'a t = T : (_, 'a) unpacked -> 'a t [@@unboxed]
|
||||||
{ name : string
|
|
||||||
; parse : 'a record_parser
|
|
||||||
}
|
|
||||||
|
|
||||||
type 'a t =
|
let name (T t) = t.name
|
||||||
| Tuple : (_, 'a) tuple -> 'a t
|
|
||||||
| Record : 'a record -> 'a t
|
|
||||||
|
|
||||||
let name = function
|
|
||||||
| Tuple x -> x.name
|
|
||||||
| Record x -> x.name
|
|
||||||
end
|
end
|
||||||
module C = Constructor_spec
|
module C = Constructor_spec
|
||||||
|
|
||||||
let cstr name args make =
|
let cstr name args make = C.T { name; args; make }
|
||||||
C.Tuple { name; args; make }
|
|
||||||
|
|
||||||
let cstr_record name parse =
|
|
||||||
C.Record { name; parse }
|
|
||||||
|
|
||||||
let equal_cstr_name a b = Name.compare a b = Eq
|
let equal_cstr_name a b = Name.compare a b = Eq
|
||||||
|
|
||||||
|
@ -422,27 +418,23 @@ module Of_sexp = struct
|
||||||
| None ->
|
| None ->
|
||||||
of_sexp_errorf sexp
|
of_sexp_errorf sexp
|
||||||
~hint:{ on = String.uncapitalize name
|
~hint:{ on = String.uncapitalize name
|
||||||
; candidates = List.map cstrs ~f:(fun c ->
|
; candidates = List.map cstrs ~f:C.name
|
||||||
String.uncapitalize (C.name c))
|
|
||||||
}
|
}
|
||||||
"Unknown constructor %s" name
|
"Unknown constructor %s" name
|
||||||
|
|
||||||
let sum cstrs sexp =
|
let sum cstrs sexp =
|
||||||
match sexp with
|
match sexp with
|
||||||
| Atom (_, A s) -> begin
|
| Atom (_, A s) ->
|
||||||
match find_cstr cstrs sexp s with
|
let (C.T cstr) = find_cstr cstrs sexp s in
|
||||||
| C.Tuple t -> Constructor_args_spec.convert t.args sexp [] t.make
|
Constructor_args_spec.convert cstr.args sexp [] cstr.make
|
||||||
| C.Record _ -> of_sexp_error sexp "'%s' expect arguments"
|
|
||||||
end
|
|
||||||
| Quoted_string _ -> of_sexp_error sexp "Atom expected"
|
| Quoted_string _ -> of_sexp_error sexp "Atom expected"
|
||||||
| List (_, []) -> of_sexp_error sexp "non-empty list expected"
|
| List (_, []) -> of_sexp_error sexp "non-empty list expected"
|
||||||
| List (loc, name_sexp :: args) ->
|
| List (_, name_sexp :: args) ->
|
||||||
match name_sexp with
|
match name_sexp with
|
||||||
| Quoted_string _ | List _ -> of_sexp_error name_sexp "Atom expected"
|
| Quoted_string _ | List _ -> of_sexp_error name_sexp "Atom expected"
|
||||||
| Atom (_, A s) ->
|
| Atom (_, A s) ->
|
||||||
match find_cstr cstrs sexp s with
|
let (C.T cstr) = find_cstr cstrs sexp s in
|
||||||
| C.Tuple t -> Constructor_args_spec.convert t.args sexp args t.make
|
Constructor_args_spec.convert cstr.args sexp args cstr.make
|
||||||
| C.Record r -> record r.parse (List (loc, args))
|
|
||||||
|
|
||||||
let enum cstrs sexp =
|
let enum cstrs sexp =
|
||||||
match sexp with
|
match sexp with
|
||||||
|
|
|
@ -133,6 +133,9 @@ module Of_sexp : sig
|
||||||
(** Parse all remaining arguments using the following parser *)
|
(** Parse all remaining arguments using the following parser *)
|
||||||
val rest : 'a t -> ('a list -> 'b, 'b) Constructor_args_spec.t
|
val rest : 'a t -> ('a list -> 'b, 'b) Constructor_args_spec.t
|
||||||
|
|
||||||
|
(** Parse all remaining arguments using the following record parser *)
|
||||||
|
val rest_as_record : 'a record_parser -> ('a -> 'b, 'b) Constructor_args_spec.t
|
||||||
|
|
||||||
(** Capture the location of the constructor *)
|
(** Capture the location of the constructor *)
|
||||||
val cstr_loc
|
val cstr_loc
|
||||||
: ('a, 'b) Constructor_args_spec.t
|
: ('a, 'b) Constructor_args_spec.t
|
||||||
|
@ -159,10 +162,6 @@ module Of_sexp : sig
|
||||||
-> ('a, 'b) Constructor_args_spec.t
|
-> ('a, 'b) Constructor_args_spec.t
|
||||||
-> 'a
|
-> 'a
|
||||||
-> 'b Constructor_spec.t
|
-> 'b Constructor_spec.t
|
||||||
val cstr_record
|
|
||||||
: string
|
|
||||||
-> 'a record_parser
|
|
||||||
-> 'a Constructor_spec.t
|
|
||||||
|
|
||||||
val sum
|
val sum
|
||||||
: 'a Constructor_spec.t list
|
: 'a Constructor_spec.t list
|
||||||
|
|
|
@ -63,10 +63,12 @@ module Context = struct
|
||||||
| List (_, List _ :: _) as sexp -> Opam (record (Opam.t ~profile) sexp)
|
| List (_, List _ :: _) as sexp -> Opam (record (Opam.t ~profile) sexp)
|
||||||
| sexp ->
|
| sexp ->
|
||||||
sum
|
sum
|
||||||
[ cstr_record "default"
|
[ cstr "default"
|
||||||
(Default.t ~profile >>= fun x -> return (Default x))
|
(rest_as_record (Default.t ~profile))
|
||||||
; cstr_record "opam"
|
(fun x -> Default x)
|
||||||
(Opam.t ~profile >>= fun x -> return (Opam x))
|
; cstr "opam"
|
||||||
|
(rest_as_record (Opam.t ~profile))
|
||||||
|
(fun x -> Opam x)
|
||||||
]
|
]
|
||||||
sexp
|
sexp
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue