233 lines
5.4 KiB
OCaml
233 lines
5.4 KiB
OCaml
|
|
open! Base
|
||
|
|
open! Ppxlib
|
||
|
|
|
||
|
|
module To_lift = struct
|
||
|
|
type 'a t = { to_lift : 'a } [@@unboxed]
|
||
|
|
end
|
||
|
|
|
||
|
|
open To_lift
|
||
|
|
|
||
|
|
let default =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.default"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr (pstr_eval __ nil ^:: nil))
|
||
|
|
(fun x -> { to_lift = x })
|
||
|
|
;;
|
||
|
|
|
||
|
|
let drop_default =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.sexp_drop_default"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr (alt_option (pstr_eval __ nil ^:: nil) nil))
|
||
|
|
(function
|
||
|
|
| None -> None
|
||
|
|
| Some x -> Some { to_lift = x })
|
||
|
|
;;
|
||
|
|
|
||
|
|
let drop_default_equal =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.@sexp_drop_default.equal"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let drop_default_compare =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.@sexp_drop_default.compare"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let drop_default_sexp =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.@sexp_drop_default.sexp"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let drop_if =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.sexp_drop_if"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr (pstr_eval __ nil ^:: nil))
|
||
|
|
(fun x -> { to_lift = x })
|
||
|
|
;;
|
||
|
|
|
||
|
|
let opaque =
|
||
|
|
Attribute.declare "sexp.opaque" Attribute.Context.core_type Ast_pattern.(pstr nil) ()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let omit_nil =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.omit_nil"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let option =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.option"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let list =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.list"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let array =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.array"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let bool =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.bool"
|
||
|
|
Attribute.Context.label_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let list_variant =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.list"
|
||
|
|
Attribute.Context.constructor_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let list_exception =
|
||
|
|
Attribute.declare "sexp.list" Attribute.Context.type_exception Ast_pattern.(pstr nil) ()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let list_poly =
|
||
|
|
Attribute.declare "sexp.list" Attribute.Context.rtag Ast_pattern.(pstr nil) ()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let allow_extra_fields_td =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.allow_extra_fields"
|
||
|
|
Attribute.Context.type_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let allow_extra_fields_cd =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp.allow_extra_fields"
|
||
|
|
Attribute.Context.constructor_declaration
|
||
|
|
Ast_pattern.(pstr nil)
|
||
|
|
()
|
||
|
|
;;
|
||
|
|
|
||
|
|
let grammar_custom =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp_grammar.custom"
|
||
|
|
Attribute.Context.core_type
|
||
|
|
Ast_pattern.(single_expr_payload __)
|
||
|
|
(fun x -> x)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let grammar_any =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp_grammar.any"
|
||
|
|
Attribute.Context.core_type
|
||
|
|
Ast_pattern.(alt_option (single_expr_payload (estring __)) (pstr nil))
|
||
|
|
(fun x -> x)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let tag_attribute_for_context context =
|
||
|
|
let open Ast_pattern in
|
||
|
|
let key_equals_value =
|
||
|
|
Ast_pattern.(
|
||
|
|
pexp_apply (pexp_ident (lident (string "="))) (no_label __ ^:: no_label __ ^:: nil)
|
||
|
|
|> pack2)
|
||
|
|
in
|
||
|
|
let get_captured_values ast_pattern context expression =
|
||
|
|
Ast_pattern.to_func ast_pattern context expression.pexp_loc expression (fun x -> x)
|
||
|
|
in
|
||
|
|
let rec collect_sequence expression =
|
||
|
|
match expression.pexp_desc with
|
||
|
|
| Pexp_sequence (l, r) -> l :: collect_sequence r
|
||
|
|
| _ -> [ expression ]
|
||
|
|
in
|
||
|
|
let esequence ast_pattern =
|
||
|
|
Ast_pattern.of_func (fun context _loc expression k ->
|
||
|
|
collect_sequence expression
|
||
|
|
|> List.map ~f:(get_captured_values ast_pattern context)
|
||
|
|
|> k)
|
||
|
|
in
|
||
|
|
Attribute.declare
|
||
|
|
"sexp_grammar.tag"
|
||
|
|
context
|
||
|
|
(pstr (pstr_eval (esequence key_equals_value) nil ^:: nil))
|
||
|
|
(fun x -> x)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let tag_type = tag_attribute_for_context Core_type
|
||
|
|
let tag_ld = tag_attribute_for_context Label_declaration
|
||
|
|
let tag_cd = tag_attribute_for_context Constructor_declaration
|
||
|
|
let tag_poly = tag_attribute_for_context Rtag
|
||
|
|
|
||
|
|
let tags_attribute_for_context context =
|
||
|
|
Attribute.declare
|
||
|
|
"sexp_grammar.tags"
|
||
|
|
context
|
||
|
|
Ast_pattern.(single_expr_payload __)
|
||
|
|
(fun x -> x)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let tags_type = tags_attribute_for_context Core_type
|
||
|
|
let tags_ld = tags_attribute_for_context Label_declaration
|
||
|
|
let tags_cd = tags_attribute_for_context Constructor_declaration
|
||
|
|
let tags_poly = tags_attribute_for_context Rtag
|
||
|
|
|
||
|
|
let invalid_attribute ~loc attr description =
|
||
|
|
Location.raise_errorf
|
||
|
|
~loc
|
||
|
|
"ppx_sexp_conv: [@%s] is only allowed on type [%s]."
|
||
|
|
(Attribute.name attr)
|
||
|
|
description
|
||
|
|
;;
|
||
|
|
|
||
|
|
let fail_if_allow_extra_field_cd ~loc x =
|
||
|
|
if Option.is_some (Attribute.get allow_extra_fields_cd x)
|
||
|
|
then
|
||
|
|
Location.raise_errorf
|
||
|
|
~loc
|
||
|
|
"ppx_sexp_conv: [@@allow_extra_fields] is only allowed on inline records."
|
||
|
|
;;
|
||
|
|
|
||
|
|
let fail_if_allow_extra_field_td ~loc x =
|
||
|
|
if Option.is_some (Attribute.get allow_extra_fields_td x)
|
||
|
|
then (
|
||
|
|
match x.ptype_kind with
|
||
|
|
| Ptype_variant cds
|
||
|
|
when List.exists cds ~f:(fun cd ->
|
||
|
|
match cd.pcd_args with
|
||
|
|
| Pcstr_record _ -> true
|
||
|
|
| _ -> false) ->
|
||
|
|
Location.raise_errorf
|
||
|
|
~loc
|
||
|
|
"ppx_sexp_conv: [@@@@allow_extra_fields] only works on records. For inline \
|
||
|
|
records, do: type t = A of { a : int } [@@allow_extra_fields] | B [@@@@deriving \
|
||
|
|
sexp]"
|
||
|
|
| _ ->
|
||
|
|
Location.raise_errorf
|
||
|
|
~loc
|
||
|
|
"ppx_sexp_conv: [@@@@allow_extra_fields] is only allowed on records.")
|
||
|
|
;;
|