3 (* Copyright Jeremy Yallop 2007.
4 This file is free software, distributed under the MIT license.
5 See the file COPYING for details.
8 (* Extend the OCaml grammar to include the `deriving' clause after
9 type declarations in structure and signatures. *)
13 module Deriving
(Syntax
: Camlp4.Sig.Camlp4Syntax
) =
19 let fatal_error loc msg
=
20 Syntax.print_warning loc msg
;
23 let display_errors loc f p
=
27 Base.Underivable msg
| Failure msg
->
30 let derive proj
(loc
: Loc.t
) tdecls classname
=
31 let context = display_errors loc
(Base.setup_context loc
) tdecls
in
33 (proj
(Base.find classname
)) (loc
, context, tdecls
)
35 let derive_str loc
(tdecls
: Type.decl list
) classname
: Ast.str_item
=
36 derive fst loc tdecls classname
38 let derive_sig loc tdecls classname
: Ast.sig_item
=
39 derive snd loc tdecls classname
42 DELETE_RULE Gram str_item
: "type"; type_declaration END
43 DELETE_RULE Gram sig_item
: "type"; type_declaration END
49 [[ "type"; types
= type_declaration
-> <:str_item
< type $types$
>>
50 | "type"; types
= type_declaration
; "deriving"; "("; cl
= LIST0
[x
= UIDENT
-> x
] SEP
","; ")" ->
51 let decls = display_errors loc
Type.Translate.decls types
in
52 let module U
= Type.Untranslate
(struct let loc = loc end) in
53 let tdecls = List.map
U.decl
decls in
54 <:str_item
< type $list
:tdecls$
; $list
:List.map
(derive_str loc decls) cl$
>>
58 [[ "type"; types
= type_declaration
-> <:sig_item
< type $types$
>>
59 | "type"; types
= type_declaration
; "deriving"; "("; cl
= LIST0
[x
= UIDENT
-> x
] SEP
"," ; ")" ->
60 let decls = display_errors loc Type.Translate.decls types
in
61 let module U
= Type.Untranslate
(struct let loc = loc end) in
62 let tdecls = List.concat_map
U.sigdecl
decls in
63 let ms = List.map
(derive_sig loc decls) cl
in
64 <:sig_item
< type $list
:tdecls$
; $list
:ms$
>> ]]
69 let pr = print_endline
70 let pr2 x y = pr (x ^ " " ^ y)
72 let mk_anti ?
(c
= "") n s
= "\\$"^n^c^
":"^s
74 let derive_ast loc classname methodname t
=
79 [e1 = TRY val_longident ; "<" ; t = ctyp; ">" ->
81 | <:ident< $uid:classname$ . $lid:methodname$ >> ->
83 if not
(Base.is_registered classname
) then
84 fatal_error loc ("deriving: "^ classname ^
" is not a known `class'")
86 let module U
= Type.Untranslate
(struct let loc = loc end) in
87 let binding = Ast.TyDcl
(loc, "inline", [], t
, []) in
88 let decls = display_errors loc Type.Translate.decls binding in
89 if List.exists
Base.contains_tvars_decl
decls then
90 fatal_error loc ("deriving: type variables cannot be used in `method' instantiations")
92 let tdecls = List.map
U.decl
decls in
93 let m = derive_str loc decls classname
in
94 <:expr
< let module $uid
:classname$
=
98 include $uid
:classname ^
"_inline"$
;
100 in $uid
:classname$
.$lid
:methodname$
>>
103 DELETE_RULE Gram expr
: val_longident END
;
104 with Not_found
-> () (* ocaml >= 3.12.0 *)
111 a
= ident2
-> match a
with
112 | `Ident i
-> <:expr
< $id
:i$
>>
113 | `Deriving
(c
,m,t
) -> derive_ast loc c
m t
116 [ [ `ANTIQUOT
((""|"id"|"anti"|"list" as n
),s
) ->
117 `Ident
<:ident
< $anti
:mk_anti ~c
:"ident" n s$
>>
118 | i
= a_UIDENT
-> (*pr2 "UID" i;*) `Ident
<:ident
< $uid
:i$
>>
119 | i
= a_LIDENT
-> (*pr2 "LID" i;*) `Ident
<:ident
< $lid
:i$
>>
120 | i
= a_UIDENT
; "."; j
= a_LIDENT
; "<"; t
= ctyp
; ">" -> (*pr "RULE";*) `Deriving
(i
,j
,t
)
121 | i
= a_UIDENT
; "."; j
= a_LIDENT
-> `Ident
<:ident
< $uid
:i$
.$lid
:j$
>>
122 | `ANTIQUOT
((""|"id"|"anti"|"list" as n
),s
); "."; i
= ident
->
123 `Ident
<:ident
< $anti
:mk_anti ~c
:"ident" n s$
.$i$
>>
124 | i
= a_UIDENT
; "."; j
= ident
-> (*pr2 "COMPOSE" i;*) `Ident
<:ident
< $uid
:i$
.$j$
>> ] ]
130 module M
= Camlp4.Register.OCamlSyntaxExtension
(Id
)(Deriving
)