1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912[@@@warning"-27"]openPpxlibopenPpxlib.Ast_pattern(**
This PPX deriver can synthesize glue code for Elpi. The following kind of data
types are supported:
- Opaque, eg [type t] (or types with a definition that one does not
want to expose to Elpi). See the [@@elpi.opaque e] attribute. Phantom
parameters are not supported for now.
- Alias, eg [type 'a t = ('a * int) list ].
- Algebraic (variants and records), eg [type t = K | S]. Such a type can
have two roles:
- a datum: a syntax tree, potentially with binders
- the context for a datum: all data with binders must be equipped with
one or more data types describing the info attached to bound variables.
The type must come with a pretty printer named following the usual
convention (named pp if the type is named t, pp_ty otherwise). Using both
[@@deriving show, elpi] on each data type is the simplest option (show is
the one from ppx_deriving, hence preprocess with
[(pps ppx_deriving.show ppx_elpi)]). See also [@@elpi.pp].
Example of a HOAS data type
type lctx =
| Entry of (string[@elpi.key "term"]) * ty
[@@elpi.index (module String)]
[@@deriving show, elpi]
type term =
| Lam of string * ty * (term[@elpi.binder "term" lctx (fun s ty -> Entry(s,ty))])
| Var of string [@elpi.var lctx]
[@@deriving show, elpi]
Output (for term):
class type ctx_for_term = object
inherit Elpi.API.PPX.ctx
method lctx : lctx Elpi.API.PPX.ctx_field
end
val term : 'c 'csts. (term, #ctx_for_term as 'c, 'csts) ContextualConversion.t
val in_ctx_for_term : (ctx_for_term, 'csts) ContextualConversion.ctx_readback
Usage: predicates using HOAS arguments must specify a context large enough
for all arguments. They are declared with ContextualPred, whose FFI is
BuiltInPredicate.PPX.ffi (it has the constructors of the FFI of Pred, but
the conversions of the arguments are contextual).
ContextualPred("term->string", in_ctx_for_term,
In(term, "T",
Out(BuiltInData.stringC, "S",
Read("what else"))),
fun (x : term) _ ~depth:_ (c : ctx_for_term) (_ : Data.constraints) (_ : State.t) ->
... x ... c#lctx ...)
Here in_ctx_for_term is a context rich enough to support the readback of
data of type term and string.
In Elpi the context type is not a data type: each of its constructors is
declared as
builtin func entry term -> string, ty.
that is, a function from the bound variable (of the type given by
[@elpi.key "term"]) to all the fields of the constructor, in order. The
entry of a variable is a rule of that function, added under the binder
(eg [entry x "x" tt ==> ...]).
Several data under different contexts
A predicate has a single context, hence one taking in input data of types
t1 and t2 living under different contexts needs a context rich enough for
both. The structure item
[%%elpi.compose_ctx both [t1; t2]]
defines it, given that t1 and t2 are derived (with a context each, say c1
and c2, see above). It expands to
class ctx_for_both : Data.hyps -> Data.state -> object
inherit ctx_for_t1
inherit ctx_for_t2
end
val in_ctx_for_both : (ctx_for_both,'csts) ContextualConversion.ctx_readback
where in_ctx_for_both reads back the context of t1, then the one of t2, and
builds the object. The predicate then declares in_ctx_for_both as its context
and gets, in the object it receives, the methods c1 and c2:
ContextualPred("t1->t2->string", in_ctx_for_both,
In(t1, "A", In(t2, "B", Out(string, "S", Read("...")))),
fun (a : t1) (b : t2) _ ~depth:_ c _ _ -> ... c#c1 ... c#c2 ...)
The list must contain at least one type, and the types are read back in the
order they are listed. A context shared by several of them is read back
once for each (the result is the same). See test_compose_contextual.ml.
Deriving directives:
[@@deriving elpi]
Derive a Elpi.API.ContextualConversion.t for the data types in the
mutually recursive block. The name of the conversion is the one of the
type. See the Conventions section of this doc for more info on the
naming of generated code.
[@@deriving elpi { context = [ty1; ...; tyn]}]
Specify the types describing the context under which the data type lives
and the order in which they should be read back. Default is the list
of types mentioned in [@elpi.binder] and [@elpi.var], in no specified
order.
[@@deriving elpi { declaration = l }]
Also add to l (made by Elpi.API.PPX.empty_declaration ()) the MLDataC
declarations that were derived, each one followed by the LPCode of its
deep copy function (see below). Elpi.API.PPX.to_list l returns them in
the order they were added.
Deep copy:
For each data type ty (but not for context types) the
string elpi__ty__deep_copy contains the Elpi code of a deep copy function,
eg
func ty.copy ty -> ty.
(with a copy function for each parameter if the type is a container,
eg func t.copy (func X -> Y), t X -> t Y). The LPCode of this string is
added to the list passed as [{ declaration = l }]. The copy is the identity,
it is up to the user to place his code before it and override the cases
he wants in order to implement a non trivial copy (eg a substitution).
The elements of lists are copied by list.copy, the ones of the other
containers in the standard library by option.copy, pair.copy, triple.copy
and quadruple.copy, and the fields of any other type by the function
ty.copy, that is assumed to exist (it does for the types of the standard
library, eg int.copy, and for the types derived by this ppx; ty is the
default Elpi name of the type, hence a type with a custom name given by
[@@elpi.type_code] is only found if it is derived in the same block). A
type abbreviation is copied as its definition is, and an opaque type is
copied by the identity. A field below a binder is copied under the binder,
in the context extended with the entry for the bound variable, which is
copied to itself:
pi x\ entry x B0 ==> term.copy x x ==> term.copy (A1 x) (B1 x)
where entry is the constructor built by the function of the binder (it
must have the shape fun p1 ... pn -> C (e1, ..., ek) with the ei among the
pi, otherwise no entry is added to the context), B0 is the copy of the
field that is the argument of the function and term is the type of the
bound variable (the first argument of [@elpi.binder]), that must come with
its copy function. The variables that are not bound by the data being
copied are not copied by the generated rules: the user has to add the
rule, eg term.copy x x ==> ..., for the ones that occur in the data.
This code currently sucks, it generates a string and not an AST.
Type attributes:
[@@elpi.pp f]
[f] mandatory: code for pretty printing the data. Its type is the one
ppx_deriving.show would produce.
[@@elpi.type_code "name" "code"]
[name] mandatory: a string, the name of the type in Elpi. The default is
the name of the OCaml type in lowercase where _ is replaced by - .
[code] optional: a string used as the Elpi kind declaration of the type
(instead of the generated one).
[@@elpi.type_doc s]
[s] mandatory: a string, a comment printed before the declaration of the
type. By default there is none.
[@@elpi.default_constructor_readback f]
[f] mandatory: a function of type
Elpi.API.ContextualConversion.(readback -> readback)
called when the term is not any of the constructors (variants and
records only). Its argument is the default behavior, a runtime type
error. This option can be used to read back flexible terms (in addition
to regular constructors).
[@@elpi.index (module M)]
[M] mandatory: is an OrderedType and Show, it is used to instantiate the
functor Elpi.API.Utils.Map.Make. When used in a type, each
constructors must have exactly one argument with attribute [@elpi.key]
and that argument must be of type M.t.
[@@elpi.opaque e]
[e] mandatory: is a Elpi.API.OpaqueData.declaration, it is necessary for
opaque data types.
Constructor attributes:
[@elpi.var ctx to_key] An Elpi bound variable.
[ctx] mandatory: is the name of the context in which the variable
is bound.
[to_key] optional: is a function from the constructor arguments to the
value being the [@elpi.key] for the context [ctx].
[@elpi.skip] Not exposed to Elpi.
[@elpi.variant n] The variant of the global symbol of the constructor.
[n] mandatory: an integer literal, >= 1. Constructors with the same name
(eg in different types) must have different variants, and the Elpi
declaration is [builtin symb name : ... = "n"].
[@elpi.embed f] Custom embedding code.
[f] mandatory: function of type
Elpi.API.ContextualConversion.(embedding -> embedding)
where the input function is the one this ppx would generate. If you
want to override it only in some cases, just call this argument in the
other ones.
[@elpi.readback f] Custom readback code.
[f] mandatory: function of type
Elpi.API.ContextualConversion.(readback -> readback)
see [@elpi.embed].
[@elpi.code name code] Custom Elpi declaration.
[name] mandatory: a string that stands for the name of the constructor
in Elpi. The default is the name of the OCaml constructor in lowercase
where _ is replaced by - . Eg Foo_BAR becomes foo-bar.
[code] optional: is a string used as the Elpi type declaration for the
constructor. Default is derived from the types of the fields. Example
"type lam (term -> term) -> term. % Lam"
[@elpi.doc s] Custom documentation.
[s] mandatory: a string. Default doc is the name of the OCaml constructor,
see the example above.
Constructor field attributes:
[@elpi.key "ty"] Field used as a key in the Map to values of this type. It
can be any of the fields of the constructor.
[ty] mandatory: name (string) of the elpi type of the variables bound
by this context, eg the "term" in [@elpi.binder "term" ctx ...].
If the type has parameters, a list of strings ["term"; "A"; ...]:
the parameters are called A, B, C, ... in Elpi, in order.
A constructor of the context is declared as
[builtin func name ty -> field1, ..., fieldN] in Elpi (no data type).
[@elpi.binder ty ctx mk_ctx_entry] Field is below one binder.
[ty] optional: name (string) of the elpi abstraction type,
eg the "XXX" in (XXX -> term), or the list ["XXX"; "A"; ...] if the
type has parameters. Default is the type name.
[ctx] mandatory: name of the context in which the variable is bound
[mk_ctx_entry] mandatory: function taking all other fields and returning
a ctx entry (a value in the type [ctx]).
Extensions:
[%elpi : ty] the conversion of type ty
This does not synthesize the conversion code but rather compose the
existing ones.
[%%elpi.compose_ctx name [ty1; ...; tyn]] a context for several data
Structure item generating the class ctx_for_<name> and the value
in_ctx_for_<name>, a context in which data of type ty1, ..., tyn can all
be read back even if they live under different contexts. See the section
"Several data under different contexts" above.
Conventions:
<ty> is a value of type Elpi.API.ContextualConversion.t for type ty.
in_ctx_for_<ty> is a value of type
Elpi.API.ContextualConversion.ctx_readback for type <ty>, and
ctx_for_<ty> is the class type of the context it builds.
ctx_for_<name> and in_ctx_for_<name> are the class and the ctx_readback
generated by [%%elpi.compose_ctx name [...]], same shape as the ones
generated for a type.
Elpi_<ctx>_Map is a module of signature Elpi.API.Utils.Map.S built using
Elpi.API.Utils.Map.Make(M) where type is annotated with
[@@elpi.index (module M)].
Internal conventions:
Variables are named elpi__something so that they don't collide with
any variable named elpi_something or something.
*)letarguments=Deriving.Args.(empty+>arg"declaration"__+>arg"context"__)letatt_elpi_tcode=Attribute.(declare"elpi.type_code"Context.type_declaration(single_expr_payload__)(funx->x))letatt_elpi_tdoc=Attribute.(declare"elpi.type_doc"Context.type_declaration(single_expr_payload(estring__))(funx->x))letatt_elpi_def_k_readback=Attribute.(declare"elpi.default_constructor_readback"Context.type_declaration(single_expr_payload__)(funx->x))letatt_elpi_tpp=Attribute.(declare"elpi.pp"Context.type_declaration(single_expr_payload__)(funx->x))letatt_elpi_tindex=Attribute.(declare"elpi.index"Context.type_declaration(single_expr_payload(pexp_pack__))(funx->x))letatt_elpi_tcdata=Attribute.(declare"elpi.opaque"Context.type_declaration(single_expr_payload__)(funx->x))letatt_elpi_var=Attribute.(declare"elpi.var"Context.constructor_declaration(single_expr_payload__)(funx->x))letatt_elpi_skip=Attribute.(declare"elpi.skip"Context.constructor_declaration(pstrnil)())letatt_elpi_embed=Attribute.(declare"elpi.embed"Context.constructor_declaration(single_expr_payload__)(funx->x))letatt_elpi_readback=Attribute.(declare"elpi.readback"Context.constructor_declaration(single_expr_payload__)(funx->x))letatt_elpi_code=Attribute.(declare"elpi.code"Context.constructor_declaration(single_expr_payload__)(funx->x))letatt_elpi_variant=Attribute.(declare"elpi.variant"Context.constructor_declaration(single_expr_payload(eint__))(funx->x))letatt_elpi_doc=Attribute.(declare"elpi.doc"Context.constructor_declaration(single_expr_payload(estring__))(funx->x))letatt_elpi_key=Attribute.(declare"elpi.key"Context.core_type(single_expr_payload__)(funx->x))letatt_elpi_binder=Attribute.(declare"elpi.binder"Context.core_type(single_expr_payload__)(funx->x))letelpi_name_mangletxt=String.map(function'_'->'-'|x->x)@@String.lowercase_asciitxtletelpi_map_namex="Elpi_"^x^"_Map"letelpi_state_namex="elpi_"^x^"_state"letelpi_ctx_class_module_namex="Ctx_for_"^xletelpi_ctx_class_namex=elpi_ctx_class_module_namex^".t"letelpi_ctx_object_namex="ctx_for_"^xletdeep_copy_namex="elpi__"^x^"__deep_copy"letelpi_readback_ctx_namex="context_made_of_"^xletelpi_in_ctx_for_namex="in_"^elpi_ctx_object_namexletelpi_to_keyx="elpi_"^x^"_to_key"letelpi_is_ctx_entry_namex="elpi_is_"^xletelpi_embed_namex="elpi_embed_"^xletelpi_readback_namex="elpi_readback_"^xletelpi_pushx="elpi_push_"^xletelpi_popx="elpi_pop_"^xletelpi_knametk="elpi_constant_constructor_"^t^"_"^k^"c"letelpi_tnamet="elpi_constant_type_"^t^"c"letelpi_kname_strtk="elpi_constant_constructor_"^t^"_"^kletelpi_tname_strt="elpi_constant_type_"^tletelpi_cdata_namex="elpi_opaque_data_decl_"^xletparam_prefix="elpi__param__"letfresh=letx=ref0infun()->incrx;Printf.sprintf"elpi__%d"!xletelpi_Map~locxf=Ast_builder.Default.evar~loc("Elpi_"^x^"_Map."^f)letoption_is_some=functionSome_->true|_->falseletoption_get=functionSomex->x|_->assertfalseletoption_mapf=functionSomex->Some(fx)|_->Noneletoption_defaultd=functionSomex->x|_->dletoption_to_list=functionSomex->[x]|None->[]letrecfilter_mapf=function|[]->[]|x::xs->matchfxwith|None->filter_mapfxs|Somey->y::filter_mapfxsleterror?loc=Location.raise_errorf?locletnYI~loc~__LOC__()=error~loc"nYI: %s"__LOC__letelpi_loc_of_position(moduleB:Ast_builder.S)pos=letopenBinletopenLocationinletopenLexingin[%expr{Elpi.API.Ast.Loc.client_payload=None;source_name=[%eestring@@pos.pos_fname];source_start=[%eeint@@pos.pos_cnum];source_stop=[%eeint@@pos.pos_cnum];line=[%eeint@@pos.pos_lnum];line_starts_at=[%eeint@@pos.pos_bol];}]letpexp_disable_warnings(moduleB:Ast_builder.S)x=letopenBinlet_=locin[%expr[%ex][@warning"-26-27-32-39-60"]]letrecon_lastf=function|[]->assertfalse|[x]->[fx]|y::ys->y::on_lastfystypecodegen_directive=|Standard|Customof{ml:expression;pos:position}|Nameof{get_key:expression;ctx_name:string}letis_name=functionName_->true|_->falsetypearg_type=|FOof{key:stringlistoption;(* [@elpi.key "ty"] attribute, ty is the type of the bound variable, see [parse_elpi_ty] *)readback:expression;embed:expression;ty_ast:expression;ty:core_type;}|HOof{(* [@elpi.binder ctx build_ctx] *)ctx:string;build_ctx:expression;arrow_src_elpi:stringlist;(* type of the bound variable in elpi, see [parse_elpi_ty] *)readback:expression;embed:expression;ty_ast:expression;(* to generate the elpi type of the constructor *)ty:core_type;}(* The Elpi type of the variables bound by a context, as written in the
[@elpi.key] and [@elpi.binder] attributes: either "ty", or ["ty"; "A"; ...]
if the type is polymorphic (the type parameters are called A, B, ... as in
the declaration of the type). The result is [ty; "A"; ...] *)letparse_elpi_ty~loce=letstr=function|{pexp_desc=Pexp_constant(Pconst_string(s,_,None));_}->s|_->error~loc"string or list of strings expected as the type of the bound variable"inletreclist=function|[%expr[]]->[]|[%expr[%e?hd]::[%e?tl]]->strhd::listtl|_->error~loc"string or list of strings expected as the type of the bound variable"inmatchewith|{pexp_desc=Pexp_constant_;_}->[stre]|_->matchlistewith[]->error~loc"empty list as the type of the bound variable"|l->lletelpi_ty_ast(moduleB:Ast_builder.S)l=letopenBinmatchlwith|[]->assertfalse|[x]->[%exprElpi.API.ContextualConversion.TyName[%eestringx]]|x::args->letasta=[%exprElpi.API.ContextualConversion.TyName[%eestringa]]in[%exprElpi.API.ContextualConversion.TyApp([%eestringx],[%east(List.hdargs)],[%eelist(List.mapast(List.tlargs))])]letis_key=functionFO{key=Some_;_}->true|_->falseletis_HO=functionHO_->true|_->false(* The index of a context entry is the bound variable (a constant), whose
type in Elpi is [name], as declared by [@elpi.key name] *)letctx_index_ty(moduleB:Ast_builder.S)name=letopenBinFO{readback=[%exprfun~depthelpi__hypselpi__constraintselpi__stateelpi__t->matchElpi.API.RawData.look~depthelpi__twith|Elpi.API.RawData.Constelpi__iwhenelpi__i>=0->elpi__state,elpi__i,[]|_->Elpi.API.Utils.type_error"not a bound variable"];embed=[%exprfun~depthelpi__hypselpi__constraintselpi__stateelpi__i->ifelpi__i<0thenElpi.API.Utils.type_error"not a bound variable";elpi__state,Elpi.API.RawData.mkConstelpi__i,[]];ty_ast=elpi_ty_ast(moduleB)name;ty=[%type:Elpi.API.Data.constant];key=None;}(* The name of the type bound by the context entry whose constructor has
arguments [arg_types] *)letctx_index_ty_of_args(moduleB:Ast_builder.S)arg_types=matchList.find_map(functionFO{key=Somename;_}->Somename|_->None)arg_typeswith|Somename->ctx_index_ty(moduleB)name|None->assertfalse(* consistency_check *)typeelpi_constructor=|Skipof{constructor_name:string;has_args:bool}|Exposeofexposeandexpose={declaration:structure_itemlist;(* constants for constructor *)constant:expression;constant_name:string;variant:int;(* [@elpi.variant n], 0 by default *)constructor:expressionlist->expression;pattern:patternlist->pattern;arg_types:arg_typelist;embed:codegen_directive;readback:codegen_directive;elpi_code:expressionoption;(* string *)elpi_doc:string;ctx_names:stringlist;}typeelpi_type_decl=|Opaqueofexpression|Aliasofcore_type|Algebraicofelpi_constructorlist*expressionoption(* default readback *)typeelpi_type={name:string;elpi_name:string;elpi_code:stringoption;elpi_doc:string;params:stringlist;type_decl:elpi_type_decl;pp:expressionoption;index:module_exproption;}moduleSSet=struct(* We need to preserve the order *)moduleSSet=Elpi.API.Utils.Set.Make(structincludeStringletppfmtx=Format.pp_print_stringfmtxletshowx=xend)typet=stringlistletmem=List.memletis_emptyx=x=[]letelementsl=lletof_listl=lletsubsetl1l2=SSet.subset(List.fold_rightSSet.addl1SSet.empty)(List.fold_rightSSet.addl2SSet.empty)letempty=[]letaddxl=ifList.memxlthenlelsex::lletppfmtl=Elpi.API.RawPp.listFormat.pp_print_string" "fmtlletdiffl1l2=SSet.diff(List.fold_rightSSet.addl1SSet.empty)(List.fold_rightSSet.addl2SSet.empty)|>SSet.elementsendtypeelpi_mutual_type={types:elpi_typelist;names:stringlist;ctx_names:SSet.t;context:(string*module_expr*elpi_type)option;}typetype_extras={ty_constants:structure_itemlist;ty_embed:value_binding;ty_readback:value_binding;ty_ctx_class_type:structure_item;ty_conversion:value_bindinglist;ty_conversion_name:string;ty_elpi_declaration:elpi_declaration;ty_opaque:bool;ty_in_ctx:structure_itemlist;(* for contextual ADTs *)ty_deep_copy:stringoption;(* the Elpi code of the deep copy *)}andelpi_declaration={decl:structure_item;decl_name:expression}typecontext_extras={ty_context_helpers:structure_itemlist;ty_context_readback:structure_itemlist;}typemutual_type_extras={ty_extras:type_extraslist;ctx_extras:context_extrasoption;}letis_predcontextname=matchcontextwithNone->false|Some(n,_,_)->n=nameletctx_fork=function|None->assertfalse|Somel->tryList.assocklwithNot_found->error"cannot find context type for %s"kletrecdrop_skip=function|[]->[]|Skip_::l->drop_skipl|Exposex::l->x::drop_skiplletreckeep_skip=function|[]->[]|Skip{constructor_name;has_args}::l->(constructor_name,has_args)::keep_skipl|Expose_::l->keep_skiplletreclist_takei=function|[]->[]|_::_wheni=0->[]|x::xs->x::list_take(i-1)xsletrecembed_k(moduleB:Ast_builder.S)call_kargsall_tmpkargstmptysn=letopenBinmatchkargs,tmp,tyswith|[],[],[]->[%exprelpi__state,Elpi.API.RawData.mkAppGlobalL[%ec][%eelist@@List.mapevar@@List.mapfstall_kargs],List.concat[%eelistall_tmp]]|(px,ex)::xs,y::ys,(FO{embed=t;_})::ts->[%exprletelpi__state,[%ppvarpx],[%ppvary]=[%et]~depth:elpi__depthelpi__hypselpi__constraintselpi__state[%eex]in[%eembed_k(moduleB:Ast_builder.S)call_kargsall_tmpxsysts(n+1)]]|(px,ex)::xs,y::ys,HO{build_ctx=f;embed=t;ctx=ctx_name;_}::ts->letxtmp=fresh()inletelpi_to_key=evar(elpi_to_keyctx_name)inletelpi_push=evar(elpi_pushctx_name)inletelpi_pop=evar(elpi_popctx_name)in[%exprletelpi__ctx_entry=[%eeapplyf(List.mapsnd@@list_takenall_kargs)]inletelpi__ctx_key=[%eelpi_to_key]~depth:elpi__depthelpi__ctx_entryinletelpi__ctx_entry={Elpi.API.PPX.entry=elpi__ctx_entry;depth=elpi__depth}inletelpi__state=[%eelpi_push]~depth:elpi__depthelpi__stateelpi__ctx_keyelpi__ctx_entryinletelpi__state,[%ppvarxtmp],[%ppvary]=[%et]~depth:(elpi__depth+1)elpi__hypselpi__constraintselpi__state[%eex]inlet[%ppvarpx]=Elpi.API.RawData.mkLam[%eevarxtmp]inletelpi__state=[%eelpi_pop]~depth:elpi__depthelpi__stateelpi__ctx_keyin[%eembed_k(moduleB:Ast_builder.S)call_kargsall_tmpxsysts(n+1)]]|_->assertfalse;;letembed_var(moduleB:Ast_builder.S)ctx_nameargsp=letopenBinletelpi_Map=elpi_Map~locctx_namein[%exprletelpi__ctx2dbl,_=Elpi.API.State.get[%eevar(elpi_state_namectx_name)]elpi__stateinletelpi__key=[%eeapplypargs]inifnot([%eelpi_Map"mem"]elpi__keyelpi__ctx2dbl)thenElpi.API.Utils.error"Unbound variable";elpi__state,Elpi.API.RawData.mkBound([%eelpi_Map"find"]elpi__keyelpi__ctx2dbl),[]]leterror_constructor_not_supported(moduleB:Ast_builder.S)(constructor,has_args)=letopenBincase~guard:None~lhs:(ppat_construct(Located.lidentconstructor)(ifhas_argsthenSome(pvar"_")elseNone))~rhs:[%exprElpi.API.Utils.error("constructor "^[%eestringconstructor]^" is not supported")]letabstract_standard_branch_embed(moduleB:Ast_builder.S)le=letopenBinletrecaux=function|[]->e|x::xs->[%exprfun[%ppvarx]->[%eauxxs]]in[%exprfun~depth:elpi__depthelpi__hypselpi__constraintselpi__state->[%eauxl]]letembed_branch(moduleB:Ast_builder.S)is_pred=function|Skip{constructor_name;has_args}->error_constructor_not_supported(moduleB)(constructor_name,has_args)|Expose{constant;arg_types;embed;pattern;_}->letopenBinletpvl,pattern,types=letpvl=List.map(fun_->fresh())arg_typesinletkpattern=pattern(List.mappvarpvl)inifis_predthenletidx=fresh()inidx::pvl,ppat_tuple[pvaridx;kpattern],ctx_index_ty_of_args(moduleB)arg_types::arg_typeselsepvl,kpattern,arg_typesinletstandard=letevl=List.map(fun_->fresh())typesinletpvl2=List.map(funx->fresh(),evarx)pvlinembed_k(moduleB)constantpvl2(List.mapevarevl)pvl2evltypes0incase~guard:None~lhs:pattern~rhs:beginmatchembedwith|Custom{ml;_}->eapply[%expr[%eml][%eabstract_standard_branch_embed(moduleB)pvlstandard]~depth:elpi__depthelpi__hypselpi__constraintselpi__state](List.mapevarpvl)|Standard->standard|Name{get_key;ctx_name}->embed_var(moduleB)ctx_name(List.mapevarpvl)get_keyend(* [function cases] as [fun x -> match x with cases]: [pexp_function] takes
different arguments depending on the version of ppxlib (OCaml's AST) *)letpexp_function_of_cases(moduleB:Ast_builder.S)cases=letopenBin[%exprfunelpi__fun_arg->[%epexp_match[%exprelpi__fun_arg]cases]]letembed(moduleB:Ast_builder.S)is_predkl=letopenBin[%exprfun~depth:elpi__depthelpi__hypselpi__constraintselpi__state->[%epexp_function_of_cases(moduleB)(List.map(embed_branch(moduleB)is_pred)kl)]]letreadback_k(moduleB:Ast_builder.S)cmk_ktts=letopenBinletoneall_kargsnp1e1txkont=matchtwith|FO{readback=t;_}->[%exprletelpi__state,[%ppvarp1],[%ppvare1]=[%et]~depth:elpi__depthelpi__hypselpi__constraintselpi__state[%ex]in[%ekont]]|HO{build_ctx=f;readback=t;ctx=ctx_name;_}->letelpi_to_key=evar(elpi_to_keyctx_name)inletelpi_push=evar(elpi_pushctx_name)inletelpi_pop=evar(elpi_popctx_name)in[%exprletelpi__ctx_entry=[%eeapplyf(List.mapevar@@list_takenall_kargs)]inletelpi__ctx_key=[%eelpi_to_key]~depth:elpi__depthelpi__ctx_entryinletelpi__ctx_entry={Elpi.API.PPX.entry=elpi__ctx_entry;depth=elpi__depth}inletelpi__state=[%eelpi_push]~depth:elpi__depthelpi__stateelpi__ctx_keyelpi__ctx_entryinletelpi__state,[%ppvarp1],[%ppvare1]=matchElpi.API.RawData.look~depth:elpi__depth[%ex]with|Elpi.API.RawData.Lamelpi__bo->[%et]~depth:(elpi__depth+1)elpi__hypselpi__constraintselpi__stateelpi__bo|_->assertfalseinletelpi__state=[%eelpi_pop]~depth:elpi__depthelpi__stateelpi__ctx_keyin[%ekont]]inletrecroll_readbackall_kargsnall_tmpkargstmptys=matchkargs,tmp,tyswith|[],[],[]->[%expr(elpi__state,[%emk_k(List.mapevarall_kargs)],List.concat[%eelist@@List.mapevarall_tmp])]|x::xs,y::ys,t::ts->oneall_kargsnxyt(evarx)(roll_readbackall_kargs(n+1)all_tmpxsysts)|_->assertfalseinletrecroll_pat=function|[]->[%pat?[]]|x::xs->[%pat?[%ppvarx]::[%proll_patxs]]inletps=List.map(fun_->fresh())tsinletes=List.map(fun_->fresh())tsinletp1,e1=fresh(),fresh()inletall_kargs=p1::psinoneall_kargs0p1e1t[%exprelpi__x][%exprmatchelpi__xswith|[%proll_patps]->[%eroll_readbackall_kargs1(e1::es)psests]|_->Elpi.API.Utils.type_error("Not enough arguments to constructor: "^Elpi.API.RawData.Constants.show[%ec])]letreadback_var(moduleB:Ast_builder.S)ctx_nameconstructor=letopenBinletelpi_to_key=evar(elpi_to_keyctx_name)inletelpi_state_component=evar(elpi_state_namectx_name)in[%exprlet_,elpi__dbl2ctx=Elpi.API.State.get[%eelpi_state_component]elpi__stateinifnot(Elpi.API.RawData.Constants.Map.memelpi__hdelpi__dbl2ctx)thenElpi.API.Utils.error(Format.asprintf"Unbound variable: %s in %a"(Elpi.API.RawData.Constants.showelpi__hd)(Elpi.API.RawData.Constants.Map.pp(Elpi.API.PPX.pp_ctx_entry[%eevar("pp_"^ctx_name)]))elpi__dbl2ctx);let{Elpi.API.PPX.entry=elpi__entry;depth=elpi__depth}=Elpi.API.RawData.Constants.Map.findelpi__hdelpi__dbl2ctxinelpi__state,[%econstructor[[%expr[%eelpi_to_key]~depth:elpi__depthelpi__entry]]],[]]letabstract_standard_branch_readback(moduleB:Ast_builder.S)pose=letopenBin[%exprfun~depth:elpi__depthelpi__hypselpi__constraintselpi__state->function|[]->[%ee]|_->Elpi.API.Utils.error~loc:[%eelpi_loc_of_position(moduleB)pos]"standard branch readback takes 0 arguments"]letabstract_standard_branch_readback2(moduleB:Ast_builder.S)pose=letopenBin[%exprfun~depth:elpi__depthelpi__hypselpi__constraintselpi__state->function|elpi__x::elpi__xs->[%ee]|[]->Elpi.API.Utils.error~loc:[%eelpi_loc_of_position(moduleB)pos]"standard branch readback takes 1 argument or more"]letreadback_branch(moduleB:Ast_builder.S)is_pred{constant;constructor;arg_types;readback;_}=letopenBinlettypes,mk_k=ifis_predthenctx_index_ty_of_args(moduleB)arg_types::arg_types,(functionx::xs->pexp_tuple[x;constructorxs]|[]->assertfalse)elsearg_types,constructorinmatchtypeswith|[]->letstandard=[%exprelpi__state,[%econstructor[]],[]]incase~lhs:[%pat?Elpi.API.RawData.Constelpi__hd]~guard:(Some[%exprelpi__hd==[%econstant]])~rhs:beginmatchreadbackwith|Standard->standard|Custom{ml;pos}->[%expr[%eml][%eabstract_standard_branch_readback(moduleB)posstandard]~depth:elpi__depth[]]|Name_->assertfalseend|t::ts->letstandard=readback_k(moduleB)constantmk_kttsinmatchreadbackwith|Standard->case~lhs:[%pat?Elpi.API.RawData.App(elpi__hd,elpi__x,elpi__xs)]~guard:(Some[%exprelpi__hd==[%econstant]])~rhs:standard|Custom{ml;pos}->case~lhs:[%pat?Elpi.API.RawData.App(elpi__hd,elpi__x,elpi__xs)]~guard:(Some[%exprelpi__hd==[%econstant]])~rhs:([%expr[%eml][%eabstract_standard_branch_readback2(moduleB)posstandard]~depth:elpi__depthelpi__hypselpi__constraintselpi__state(elpi__x::elpi__xs)])|Name{ctx_name;_}->assert(ts=[]);case~lhs:[%pat?Elpi.API.RawData.Constelpi__hd]~guard:(Some[%exprelpi__hd>=0])~rhs:(readback_var(moduleB)ctx_nameconstructor)letabstract_standard_default_readback(moduleB:Ast_builder.S)e=letopenBin[%exprfun~depth:elpi__depthelpi__hypselpi__constraintselpi__stateelpi__x->[%ee]]letreadback(moduleB:Ast_builder.S)nameis_preddefault_readbackkl=letopenBin[%exprfun~depth:elpi__depthelpi__hypselpi__constraintselpi__stateelpi__x->[%epexp_match[%exprElpi.API.RawData.look~depth:elpi__depthelpi__x](List.map(readback_branch(moduleB)is_pred)(drop_skipkl)@[case~guard:None~lhs:[%pat?_]~rhs:beginletstandard=[%exprElpi.API.Utils.type_error(Format.asprintf"Not a constructor of type %s: %a"[%eestringname](Elpi.API.RawPp.termelpi__depth)elpi__x)]inmatchdefault_readbackwith|None->standard|Somee->[%expr[%ee][%eabstract_standard_default_readback(moduleB)standard]~depth:elpi__depthelpi__hypselpi__constraintselpi__stateelpi__x]end])]]letctx_entry_key(moduleB:Ast_builder.S)kl=letopenBinletproject{pattern;arg_types;_}=letpvl=List.map(functionFO{key=Some_;_}->fresh()|_->"_")arg_typesinletrecfind_keyvltl=matchvl,tlwith|v::_,FO{key=Some_;_}::_->evarv|_::vs,_::ts->find_keyvsts|_->assertfalseincase~lhs:(pattern(List.mappvarpvl))~guard:None~rhs:(find_keypvlarg_types)in[%exprfun~depth:_->[%epexp_function_of_cases(moduleB)(List.mapproject(drop_skipkl)@List.map(error_constructor_not_supported(moduleB))(keep_skipkl))]]letis_ctx_entry(moduleB:Ast_builder.S)kl=letopenBin[%exprfun{Elpi.API.Data.hdepth=elpi__depth;hsrc=elpi__x}->matchElpi.API.RawData.look~depth:elpi__depthelpi__xwith|Elpi.API.RawData.Const_->None|Elpi.API.RawData.App(elpi__hd,elpi__idx,_)->if[%eList.fold_left(fune->function|Skip_->e|Expose{constant;_}->[%expr[%ee]||elpi__hd==[%econstant]])[%exprfalse]kl]thenmatchElpi.API.RawData.look~depth:elpi__depthelpi__idxwith|Elpi.API.RawData.Constx->Somex|_->Elpi.API.Utils.type_error"context entry applied to a non bound variable"elseNone|_->None](*
let ctx_readback (module B : Ast_builder.S) name = let open B in
let elpi_Map = elpi_Map ~loc name in
let elpi_push = evar (elpi_push name) in
let elpi_to_key = evar (elpi_to_key name) in
let elpi_is_ctx_entry = evar (elpi_is_ctx_entry_name name) in
let elpi_state_component = evar (elpi_state_name name) in
[%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state ->
let module CMap = Elpi.API.RawData.Constants.Map in
let elpi__filtered_hyps =
List.fold_left (fun elpi__m ({ Elpi.API.RawData.hdepth = elpi__i; hsrc = elpi__hsrc } as elpi__hyp) ->
match [%e elpi_is_ctx_entry ] ~depth:elpi__i elpi__hsrc with
| None -> elpi__m
| Some elpi__idx ->
if CMap.mem elpi__idx elpi__m then
Elpi.API.Utils.type_error "more than one context entry for the same bound variable";
CMap.add elpi__idx elpi__hyp elpi__m
) CMap.empty (Elpi.API.RawData.of_hyps elpi__hyps) in
let rec elpi__aux elpi__state elpi__gls elpi__i =
if elpi__i = elpi__depth then
elpi__state, List.concat (List.rev elpi__gls)
else if not (CMap.mem elpi__i elpi__filtered_hyps) then
elpi__aux elpi__state elpi__gls (elpi__i+1)
else
let elpi__hyp = CMap.find elpi__i elpi__filtered_hyps in
let elpi__hyp_depth = elpi__hyp.Elpi.API.RawData.hdepth in
let elpi__state, (elpi__bound_var, elpi__t), elpi__gls_t =
[%e evar name].Elpi.API.ContextualConversion.readback ~depth: elpi__hyp_depth elpi__hyps elpi__constraints elpi__state elpi__hyp.Elpi.API.RawData.hsrc in
assert(elpi__bound_var = elpi__i);
let elpi__s = [%e elpi_to_key ] ~depth: elpi__hyp_depth elpi__t in
let elpi__state = [%e elpi_push ] ~depth:elpi__i elpi__state elpi__s { Elpi.API.PPX.entry = elpi__t; depth = elpi__hyp_depth } in
elpi__aux elpi__state (elpi__gls_t :: elpi__gls) (elpi__i+1) in
let elpi__state = Elpi.API.State.set [%e elpi_state_component ] elpi__state
([%e elpi_Map "empty" ], CMap.empty) in
let elpi__state, elpi__gls = elpi__aux elpi__state [] 0 in
let _, elpi__dbl2ctx = Elpi.API.State.get [%e elpi_state_component ] elpi__state in
elpi__state, elpi__dbl2ctx, elpi__constraints, elpi__gls]
*)(* [compose_ctx_readback name [ty1;...;tyn]] generates the context in which
data of type ty1, ..., tyn can all be read back, even if they live under
different contexts, eg to be used by a predicate taking all of them as
input. It generates:
class ctx_for_<name> h s : object inherit ctx_for_ty1 .. inherit ctx_for_tyn end
val in_ctx_for_<name> : (ctx_for_<name>,'csts) ctx_readback
where the latter runs the readback of the context of each tyi in turn.
A context shared by some of the tyi is simply read back more than once. *)letcompose_ctx_readback(moduleB:Ast_builder.S)nametys=letopenBiniftys=[]thenerror~loc"compose_ctx needs at least one type";lethyps=ptyp_constr(Located.lident"Elpi.API.Data.hyps")[]inletstate=ptyp_constr(Located.lident"Elpi.API.Data.state")[]inletcls=pstr_class[class_infos~virt:Concrete~params:[]~name:(Located.mk@@elpi_ctx_object_namename)~expr:(pcl_funNolabelNone(ppat_constraint(pvar"h")hyps)@@pcl_funNolabelNone(ppat_constraint(pvar"s")state)@@pcl_structure@@class_structure~self:(pvar"_")~fields:(pcf_inheritFresh(pcl_apply(pcl_constr(Located.lident"Elpi.API.PPX.ctx")[])[Nolabel,evar"h"])None::List.map(funty->pcf_inheritOverride(pcl_apply(pcl_constr(Located.lident@@elpi_ctx_object_namety)[])[Nolabel,evar"h";Nolabel,evar"s"])None)tys))]inletgls=List.mapi(funi_->Printf.sprintf"gls%d"i)tysinletrecaux=function|[]->[%exprs,[%epexp_new@@Located.lident@@elpi_ctx_object_namename]hs,c,List.concat[%eelist@@List.mapevargls]]|(ty,gls)::rest->[%exprlets,_,c,[%ppvargls]=[%eevar@@elpi_in_ctx_for_namety]~depthhcsin[%eauxrest]]inletreadback=[%strilet[%ppvar@@elpi_in_ctx_for_namename]:([%tptyp_constr(Located.lident@@elpi_ctx_object_namename)[]],'csts)Elpi.API.ContextualConversion.ctx_readback=fun~depthhcs->[%eaux(List.combinetysgls)]]in[cls;readback]letctx_push(moduleB:Ast_builder.S)name=letopenBinletelpi_Map=elpi_Map~locnamein[%exprfun~depth:elpi__depthelpi__stateelpi__nameelpi__ctx_item->letelpi__ctx2dbl,elpi__dbl2ctx=Elpi.API.State.get[%eevar(elpi_state_namename)]elpi__stateinletelpi__i=elpi__depthinletelpi__ctx2dbl=[%eelpi_Map"add"]elpi__nameelpi__ielpi__ctx2dblinletelpi__dbl2ctx=Elpi.API.RawData.Constants.Map.addelpi__ielpi__ctx_itemelpi__dbl2ctxinletelpi__state=Elpi.API.State.set[%eevar(elpi_state_namename)]elpi__state(elpi__ctx2dbl,elpi__dbl2ctx)inelpi__state]letctx_pop(moduleB:Ast_builder.S)name=letopenBinletelpi_Map=elpi_Map~locnamein[%exprfun~depth:elpi__depthelpi__stateelpi__name->letelpi__ctx2dbl,elpi__dbl2ctx=Elpi.API.State.get[%eevar(elpi_state_namename)]elpi__stateinletelpi__i=elpi__depthinletelpi__ctx2dbl=[%eelpi_Map"remove"]elpi__nameelpi__ctx2dblinletelpi__dbl2ctx=Elpi.API.RawData.Constants.Map.removeelpi__ielpi__dbl2ctxinletelpi__state=Elpi.API.State.set[%eevar(elpi_state_namename)]elpi__state(elpi__ctx2dbl,elpi__dbl2ctx)inelpi__state]letrecfmapf=function[]->[]|x::xs->matchfxwithNone->fmapfxs|Somex->x::fmapfxsletconversion_of(moduleB:Ast_builder.S)ty=letopenBinletrecaux=function|[%type:string]->[%exprElpi.API.BuiltInData.stringC]|[%type:int]->[%exprElpi.API.BuiltInData.intC]|[%type:float]->[%exprElpi.API.BuiltInData.floatC]|[%type:bool]->[%exprElpi.Builtin.PPX.bool]|[%type:char]->[%exprElpi.Builtin.PPX.char]|[%type:[%t?typ]list]->[%exprElpi.API.BuiltInData.listC[%eauxtyp]]|[%type:[%t?typ]option]->[%exprElpi.Builtin.PPX.option[%eauxtyp]]|[%type:[%t?typ1]*[%t?typ2]]->[%exprElpi.Builtin.PPX.pair[%eauxtyp1][%eauxtyp2]]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]]->[%exprElpi.Builtin.PPX.triple[%eauxtyp1][%eauxtyp2][%eauxtyp3]]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]*[%t?typ4]]->[%exprElpi.Builtin.PPX.quadruple[%eauxtyp1][%eauxtyp2][%eauxtyp3][%eauxtyp4]]|{ptyp_desc=Ptyp_tuple_;_}->error~loc"I don't have quintuples or above at hand, file a bugreport"|{ptyp_desc=Ptyp_constr({txt=id;_},params);_}->letid=pexp_ident@@Located.mkidineapplyid(List.mapauxparams)|t->error~loc"cannot compute conversion for type %a"Pprintast.core_typetinauxtyletis_parameterid=Re.(Str.string_match(Str.regexp_stringparam_prefix)id0)letrecfind_embed_of(moduleB:Ast_builder.S)current_mutrec_blockty=letopenBinletrecauxty=matchtywith|[%type:[%t?typ]list]->[%expr(letembed=[%eauxtyp]in(fun~depthhcsl->lets,l,eg=Elpi.API.Utils.map_acc(embed~depthhc)slins,Elpi.API.Utils.list_to_lp_listl,eg))]|[%type:[%t?typ]option]->[%exprElpi.Builtin.PPX.embed_option[%eauxtyp]]|[%type:[%t?typ1]*[%t?typ2]]->[%exprElpi.Builtin.PPX.embed_pair[%eauxtyp1][%eauxtyp2]]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]]->[%exprElpi.Builtin.PPX.embed_triple[%eauxtyp1][%eauxtyp2][%eauxtyp3]]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]*[%t?typ4]]->[%exprElpi.Builtin.PPX.embed_quadruple[%eauxtyp1][%eauxtyp2][%eauxtyp3][%eauxtyp4]]|{ptyp_desc=Ptyp_constr({txt=Longident.Lidentid;_},params);_}whenList.memidcurrent_mutrec_block||is_parameterid->eapply(evar(elpi_embed_nameid))(List.map(find_embed_of(moduleB:Ast_builder.S)current_mutrec_block)params)|t->[%expr[%econversion_of(moduleB)t].Elpi.API.ContextualConversion.embed]in[%exprfun~depthhcst->[%eauxty]~depthhcst]letrecfind_readback_of(moduleB:Ast_builder.S)current_mutrec_blockty=letopenBinletrecauxty=matchtywith|[%type:[%t?typ]list]->[%expr(letreadback=[%eauxtyp]in(fun~depthhcst->Elpi.API.Utils.map_acc(readback~depthhc)s(Elpi.API.Utils.lp_list_to_list~deptht)))]|[%type:[%t?typ]option]->[%exprElpi.Builtin.PPX.readback_option[%eauxtyp]]|[%type:[%t?typ1]*[%t?typ2]]->[%exprElpi.Builtin.PPX.readback_pair[%eauxtyp1][%eauxtyp2]]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]]->[%exprElpi.Builtin.PPX.readback_triple[%eauxtyp1][%eauxtyp2][%eauxtyp3]]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]*[%t?typ4]]->[%exprElpi.Builtin.PPX.readback_quadruple[%eauxtyp1][%eauxtyp2][%eauxtyp3][%eauxtyp4]]|{ptyp_desc=Ptyp_constr({txt=Longident.Lidentid;_},params);_}whenList.memidcurrent_mutrec_block||is_parameterid->eapply(evar(elpi_readback_nameid))(List.map(find_readback_of(moduleB:Ast_builder.S)current_mutrec_block)params)|t->[%expr[%econversion_of(moduleB)t].Elpi.API.ContextualConversion.readback]in[%exprfun~depthhcst->[%eauxty]~depthhcst]letrecfind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blockty=letopenBinmatchtywith|{ptyp_desc=Ptyp_constr({txt=Longident.Lidentid;_},[]);_}whenList.memidcurrent_mutrec_block->[%exprElpi.API.ContextualConversion.TyName([%eevar@@elpi_tname_strid])]|{ptyp_desc=Ptyp_constr({txt=Longident.Lidentid;_},p::ps);_}whenList.memidcurrent_mutrec_block->[%exprElpi.API.ContextualConversion.TyApp([%eevar@@elpi_tname_strid],[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blockp],[%eelist@@List.map(find_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_block)ps])]|[%type:[%t?typ]list]->[%exprElpi.API.ContextualConversion.TyApp("list",[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp],[])]|[%type:[%t?typ]option]->[%exprElpi.API.ContextualConversion.TyApp("option",[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp],[])]|[%type:[%t?typ1]*[%t?typ2]]->[%exprElpi.API.ContextualConversion.TyApp("pair",[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp1],[[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp2]])]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]]->[%exprElpi.API.ContextualConversion.TyApp("triple",[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp1],[[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp2];[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp3]])]|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]*[%t?typ4]]->[%exprElpi.API.ContextualConversion.TyApp("quadruple",[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp1],[[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp2];[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp3];[%efind_ty_ast_of(moduleB:Ast_builder.S)current_mutrec_blocktyp4]])]|t->[%expr[%econversion_of(moduleB)t].Elpi.API.ContextualConversion.ty](* The deep copy code is computed here, by the ppx, as a string. [elpi_names]
maps the OCaml name of the types of the block to their Elpi name, [params]
the type parameters to the variable holding their copy function.
Returns the goal copying a value in v1 to v2 *)letfind_mapper_ofelpi_namesparamsty(v1,v2):string=letrecauxty=matchtywith|[%type:[%t?typ]list]->Printf.sprintf"(list.copy %s)"(auxtyp)|[%type:[%t?typ]option]->Printf.sprintf"(option.copy %s)"(auxtyp)|[%type:[%t?typ1]*[%t?typ2]]->Printf.sprintf"(pair.copy %s %s)"(auxtyp1)(auxtyp2)|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]]->Printf.sprintf"(triple.copy %s %s %s)"(auxtyp1)(auxtyp2)(auxtyp3)|[%type:[%t?typ1]*[%t?typ2]*[%t?typ3]*[%t?typ4]]->Printf.sprintf"(quadruple.copy %s %s %s %s)"(auxtyp1)(auxtyp2)(auxtyp3)(auxtyp4)|{ptyp_desc=Ptyp_constr({txt=Longident.Lidentid;_},[]);_}whenList.mem_associdparams->List.associdparams(* any other type is assumed to come with a copy function, name.copy, which
is the case for the types of the standard library and for the types
derived by this ppx *)|{ptyp_desc=Ptyp_constr({txt=lid;_},ps);_}->letid=Longident.last_exnlidinletname=tryList.associdelpi_nameswithNot_found->elpi_name_mangleidinifps=[]thenname^".copy"else"("^name^".copy "^String.concat" "(List.mapauxps)^")"|{ptyp_loc=loc;_}->Location.raise_errorf~loc"deep copy: unsupported type"in"("^auxty^" "^v1^" "^v2^")";;letone_lident=function|{pexp_desc=Pexp_ident{txt=Lidentx;_};_}->Somex|_->Noneletone_string=function|{pexp_desc=Pexp_constant(Pconst_string(s,_,None));_}->Somes|_->Noneletone_or_two_strings(moduleB:Ast_builder.S)=function|Pexp_constant(Pconst_string(s,_,None))->s,None|Pexp_apply(x,[_,y])whenoption_is_some(one_stringx)&&option_is_some(one_stringy)->option_get(one_stringx),one_stringy|_->error"string or ident expected"letget_elpi_code(moduleB:Ast_builder.S)knamekattributes=matchAttribute.getatt_elpi_codekattributeswith|None->elpi_name_manglekname,None|Somepayload->one_or_two_strings(moduleB)payload.pexp_descletget_elpi_tcode(moduleB:Ast_builder.S)knamekattributes=matchAttribute.getatt_elpi_tcodekattributeswith|None->elpi_name_manglekname,None|Somepayload->one_or_two_strings(moduleB)payload.pexp_descletget_elpi_docknamekattributes=option_defaultkname(Attribute.getatt_elpi_dockattributes)letget_elpi_tdocknamekattributes=option_defaultkname(Attribute.getatt_elpi_tdockattributes)letget_elpi_tdefkreadbacktattributes=Attribute.getatt_elpi_def_k_readbacktattributesletget_elpi_pptattributes=Attribute.getatt_elpi_tpptattributesletget_elpi_tindextattributes=Attribute.getatt_elpi_tindextattributesletget_elpi_tcdata~loctattributes=matchAttribute.getatt_elpi_tcdatatattributeswith|None->error~loc"opaque data types must have a [@@elpi.opaque d] attribute"|Somec->clethas_elpi_tcdatatattributes=option_is_some(Attribute.getatt_elpi_tcdatatattributes)letparse_lident_list(moduleB:Ast_builder.S)=letopenBinletrecaux=function|[%expr[]]->[]|[%expr[%e?{pexp_desc=Pexp_ident{txt=Lidentid;_};_}]::[%e?tl]]->id::auxtl|_->error~loc"ident expected"inauxletanalyze_tuple_constructor(moduleB:Ast_builder.S)tynameknamekattributestlconstructorpatternsame_mutrec_block=letopenBinletc_str=elpi_kname_strtynameknameinletc=elpi_knametynameknameinletelpi_doc=get_elpi_docknamekattributesinletstr,elpi_code=get_elpi_code(moduleB)knamekattributesinletdecl_str=value_binding~pat:(pvarc_str)~expr:(estringstr)inletvariant=Attribute.getatt_elpi_variantkattributesinletdecl=matchvariantwith|None->value_binding~pat:(pvarc)~expr:[%exprElpi.API.RawData.Constants.declare_global_symbol[%eevar@@c_str]]|Somen->value_binding~pat:(pvarc)~expr:[%exprElpi.API.RawData.Constants.declare_global_symbol~variant:[%eeintn][%eevar@@c_str]]inlettl=tl|>List.map(funty->matchAttribute.getatt_elpi_bindertywith|Some[%expr[%e?arrow_src_elpi][%e?{pexp_desc=Pexp_ident{txt=Lidentctx;_};_}][%e?build_ctx]]->letarrow_src_elpi=parse_elpi_ty~locarrow_src_elpiinHO{ty;ctx;build_ctx;arrow_src_elpi;readback=find_readback_of(moduleB)same_mutrec_blockty;embed=find_embed_of(moduleB)same_mutrec_blockty;ty_ast=find_ty_ast_of(moduleB)same_mutrec_blockty;}|Some[%expr[%e?{pexp_desc=Pexp_ident{txt=Lidentctx;_};_}][%e?build_ctx]]->HO{ty;ctx;build_ctx;arrow_src_elpi=[tyname];readback=find_readback_of(moduleB)same_mutrec_blockty;embed=find_embed_of(moduleB)same_mutrec_blockty;ty_ast=find_ty_ast_of(moduleB)same_mutrec_blockty;}|Some_->error~loc"use [@elpi.binder \"ty\" ctx mk_ctx_entry]"|None->letkey=Option.map(parse_elpi_ty~loc)(Attribute.getatt_elpi_keyty)inFO{ty;key;readback=find_readback_of(moduleB)same_mutrec_blockty;embed=find_embed_of(moduleB)same_mutrec_blockty;ty_ast=find_ty_ast_of(moduleB)same_mutrec_blockty;})inletvar_=matchAttribute.getatt_elpi_varkattributeswith|Some[%expr[%e?ctx_name][%e?get_key]]whenoption_is_some(one_lidentctx_name)->Some(Name{get_key;ctx_name=option_get(one_lidentctx_name)})|Some[%expr[%e?ctx_name]]whenoption_is_some(one_lidentctx_name)->Some(Name{get_key=[%exprfunx->x];ctx_name=option_get(one_lidentctx_name)})|Some_->error~loc"use [@elpi.var ctx to_key]"|None->Noneinletreadback=Attribute.getatt_elpi_readbackkattributesinletembed=Attribute.getatt_elpi_embedkattributesinletreadback,embed=letopt2custom=functionNone->Standard|Someml->Custom{ml;pos=B.loc.loc_end}inmatchreadback,embed,var_with|_,_,None->opt2customreadback,opt2customembed|None,None,Somep->ifList.lengthtl=1thenp,pelseerror~loc"[@elpi.var] on a constructor with zero or more than one argument and not [@elpi.readback]"|None,(Some_ase),Somep->ifList.lengthtl=1thenp,opt2customeelseerror~loc"[@elpi.var] on a constructor with more than one argument and not [@elpi.readback]"|(Some_asr),None,Somep->opt2customr,p|Some_,Some_,Some_->error~loc"[@elpi.var] on a constructor with [@elpi.readback] and [@elpi.embed]"inletctx_names_of_directive=function|Custom_->[]|Standard->[]|Name{ctx_name;_}->[ctx_name]inletctx_names=List.concat(ctx_names_of_directiveembed::ctx_names_of_directivereadback::List.map(functionHO{ctx;_}->[ctx]|_->[])tl)inExpose{declaration=[pstr_valueNonrecursive[decl_str];pstr_valueNonrecursive[decl]];constant=evarc;constant_name=str;variant=option_default0variant;elpi_code=option_mapestringelpi_code;elpi_doc;arg_types=tl;constructor;pattern;embed;readback;ctx_names;};;letanalyze_constructor(moduleB:Ast_builder.S)tynamesame_mutrec_blockdecl=letopenBinmatchdeclwith|{pcd_name={txt=kname;_};pcd_args;_}whenAttribute.getatt_elpi_skipdecl=Some()->Skip{constructor_name=kname;has_args=not(pcd_args=Pcstr_tuple[])}|{pcd_name={txt=kname;_};pcd_args=Pcstr_tupletl;pcd_res=None;_}->letmake_kargs=ifargs=[]thenpexp_construct(Located.lidentkname)Noneelsepexp_construct(Located.lidentkname)(Some(pexp_tupleargs))inletmatch_kargs=ifargs=[]thenppat_construct(Located.lidentkname)Noneelseppat_construct(Located.lidentkname)(Some(ppat_tupleargs))inanalyze_tuple_constructor(moduleB)tynameknamedecltlmake_kmatch_ksame_mutrec_block|{pcd_name={txt=kname;_};pcd_args=Pcstr_recordlbltl;pcd_res=None;_}->letlbls,tl=List.(split(map(fun{pld_name={txt;_};pld_type;_}->txt,pld_type)lbltl))inletmake_kargs=pexp_construct(Located.lidentkname)(Some(pexp_record(List.map2(funxy->B.Located.lidentx,y)lblsargs)None))inletmatch_kargs=ppat_construct(Located.lidentkname)(Some(ppat_record(List.map2(funxy->B.Located.lidentx,y)lblsargs)Closed))inanalyze_tuple_constructor(moduleB)tynameknamedecltlmake_kmatch_ksame_mutrec_block|{pcd_loc=loc;_}->error~loc"unsupportd constructor declaration"letextract_tyvar(x,_)=matchx.ptyp_descwith|Ptyp_vars->s|_->error~loc:x.ptyp_loc"Type abstracted over something that is not a type variable"letanalyze_params(moduleB:Ast_builder.S)params=letopenBinlettyvars=List.mapextract_tyvarparamsinletmapper=objectinheritAst_traverse.mapassupermethod!core_typex=matchx.ptyp_descwith|Ptyp_varxwhenList.memxtyvars->ptyp_constr(B.Located.mk(Longident.parse@@param_prefix^x))[]|_->super#core_typexendinList.map((^)param_prefix)tyvars,mapperletmk_kind(moduleB:Ast_builder.S)vlname=letopenBinmatchList.map(funx->[%expr[%eevarx].Elpi.API.ContextualConversion.ty])vlwith|[]->[%exprElpi.API.ContextualConversion.TyName[%ename]]|x::xs->[%exprElpi.API.ContextualConversion.TyApp([%ename],[%ex],[%eelist@@xs])]letconsistency_check~loctyds=letcontext=refNoneinList.iter(funtyd->letname,csts=matchtydwith|{name;type_decl=Algebraic(l,_);_}->name,drop_skipl|{name;_}->name,[]inletsome_have_key=List.exists(fun{arg_types;_}->List.existsis_keyarg_types)cstsinletall_have_1_key=List.for_all(fun{arg_types;_}->1=List.(length(filteris_keyarg_types)))cstsinmatchtyd.indexwith|Nonewhensome_have_key->error~loc"type %s has [@elpi.key] but no index was provided. Use [@@elpi.index (module M)]"name|Some_whensome_have_key&&(notall_have_1_key)->error~loc"type %s has constructor that does not have exactly one argumet marked as [@elpi.key]"name|Some_whenall_have_1_key&&tyd.params<>[]->error~loc"type %s has [@elpi.key] but has parameters, not supported"name|Some_when!context<>None->letother,_,_=option_get!contextinerror~loc"context cannot be a mutual type (%s and %s both have [@elpi.key])"nameother|Somemwhenall_have_1_key->context:=Some(name,m,tyd)|_->())tyds;!context;;letpp_doc(moduleB:Ast_builder.S)kindelpi_nameelpi_codeelpi_docis_predcsts=letopenBinletty_ast_of_arg=function|FO{ty_ast;_}->ty_ast|HO{arrow_src_elpi=s;ty_ast;_}->[%exprElpi.API.ContextualConversion.TyApp("->",[%eelpi_ty_ast(moduleB)s],[[%ety_ast]])]in[%exprfunfmt()->[%e(* the entries of a context are predicates, there is no type to declare *)ifis_predthen[%expr()]elsematchelpi_codewith|None->[%exprElpi.API.PPX.Doc.kindfmt[%ekind]~doc:[%eestringelpi_doc]]|Somecode->[%exprFormat.fprintffmt"%s"("% "^[%eestringelpi_doc]);Format.fprintffmt"@\n@[<hov2>kind %s@[<hov> %s.@]@]@\n"[%eelpi_name][%ecode]]];[%e(* the constructors declared by Doc.constructor are aligned *)letmax_name_len=List.fold_left(funm{constant_name=c;embed;readback;elpi_code;_}->ifis_nameembed||is_namereadback||elpi_code<>Nonethenmelsemaxm(String.lengthc))0(drop_skipcsts)inesequence@@List.(concat@@(drop_skipcsts|>map(fun{constant_name=c;variant;arg_types;embed;readback;elpi_code;elpi_doc;_}->ifis_nameembed||is_namereadbackthen[]else[matchelpi_codewith|Somecode->[%exprFormat.fprintffmt"@[<hov2>type %s@[<hov> %s. %% %s@]@]@\n"[%eestringc][%ecode][%eestringelpi_doc]]|Nonewhenis_pred->(* func name Key -> Field1, ..., FieldN, where Key is the type
of the bound variable the entry is about *)[%exprElpi.API.PPX.Doc.context_entryfmt~name:[%eestringc]~doc:[%eestringelpi_doc]~key:[%ety_ast_of_arg(ctx_index_ty_of_args(moduleB)arg_types)]~args:[%eelist@@List.mapty_ast_of_argarg_types]]|None->[%exprElpi.API.PPX.Doc.constructorfmt~max_name_len:[%eeintmax_name_len]~variant:[%eeintvariant]~ty:[%ekind]~name:[%eestringc]~doc:[%eestringelpi_doc]~args:[%eelist@@List.mapty_ast_of_argarg_types]]])))]];;(* The name in Elpi of the i-th type parameter: A, B, ..., as in
[data pair A B] *)letpoly_param_namei=ifi<26thenString.make1(Char.chr(Char.code'A'+i))elsePrintf.sprintf"A%d"i(* The conversion standing for the i-th type parameter of a type being
derived, to be applied to the conversion of the type *)letpoly_param_conversion(moduleB:Ast_builder.S)i=letopenBin[%exprElpi.API.BuiltInData.polyC[%eestring(poly_param_namei)]]lettypeabbrev_for(moduleB:Ast_builder.S)fparams=letopenBinletvars=List.mapi(funi_->poly_param_namei)paramsinifparams=[]thenfelse[%expr"("^[%ef]^" "^[%eestring(String.concat" "vars)]^")"]lettypeabbrev_for_conv(moduleB:Ast_builder.S)ct=letopenBin[%exprElpi.API.PPX.Doc.(show_ty_ast~prec:AppArg)@@[%econversion_of(moduleB)ct].Elpi.API.ContextualConversion.ty]letmk_pp_name(moduleB:Ast_builder.S)name=function|None->ifname="t"thenB.evar"pp"elseB.evar("pp_"^name)|Somee->eletpp_for_conversion(moduleB:Ast_builder.S)nameis_predparamspp=letopenBinletpp=mk_pp_name(moduleB)nameppinifis_predthen[%exprfunfmt(_,x)->[%epp]fmtx]elseeapplypp(List.map(funx->[%expr[%eevarx].pp])params)letquantify_ty_over_params(moduleB:Ast_builder.S)paramst=letopenBinptyp_poly(List.mapLocated.mkparams)t(* The type of the context in which a type is converted: an object having the
methods for all the contexts the type depends on. If there is none, no
constraint is put on it. The result is named 'c. *)letctx_obj(moduleB:Ast_builder.S)name_is_predall_ctx=letopenBinifSSet.is_emptyall_ctxthen[%type:'c]else[%type:[%tptyp_poly[](ptyp_class(Located.lident(elpi_ctx_class_namename))[])]as'c]letconversion_type(moduleB:Ast_builder.S)nameparamsis_predall_ctx=letopenBinletrecaux=function|[]->lett=ptyp_constr(Located.lidentname)(List.mapptyp_varparams)inlett=ifis_predthenptyp_tuple[[%type:Elpi.API.RawData.constant];t]elsetin[%type:([%tt],[%tctx_obj(moduleB)nameis_predall_ctx],'csts)Elpi.API.ContextualConversion.t]|t::ts->[%type:([%tptyp_vart],[%tctx_obj(moduleB)nameis_predall_ctx],'csts)Elpi.API.ContextualConversion.t->[%tauxts]]inquantify_ty_over_params(moduleB)(params@["c";"csts"])(auxparams)letreadback_type(moduleB:Ast_builder.S)nameparamsis_predall_ctx=letopenBinletrecaux=function|[]->lett=ptyp_constr(Located.lidentname)(List.mapptyp_varparams)inlett=ifis_predthenptyp_tuple[[%type:Elpi.API.RawData.constant];t]elsetin[%type:([%tt],[%tctx_obj(moduleB)nameis_predall_ctx],'csts)Elpi.API.ContextualConversion.readback]|t::ts->[%type:([%tptyp_vart],[%tctx_obj(moduleB)nameis_predall_ctx],'csts)Elpi.API.ContextualConversion.readback->[%tauxts]]inquantify_ty_over_params(moduleB)(params@["c";"csts"])(auxparams)letembed_type(moduleB:Ast_builder.S)nameparamsis_predall_ctx=letopenBinletrecaux=function|[]->lett=ptyp_constr(Located.lidentname)(List.mapptyp_varparams)inlett=ifis_predthenptyp_tuple[[%type:Elpi.API.RawData.constant];t]elsetin[%type:([%tt],[%tctx_obj(moduleB)nameis_predall_ctx],'csts)Elpi.API.ContextualConversion.embedding]|t::ts->[%type:([%tptyp_vart],[%tctx_obj(moduleB)nameis_predall_ctx],'csts)Elpi.API.ContextualConversion.embedding->[%tauxts]]inquantify_ty_over_params(moduleB)(params@["c";"csts"])(auxparams)letlift_conversion(moduleB:Ast_builder.S)e=letopenBin[%exprlet{Elpi.API.Conversion.embed;readback;ty;pp_doc;pp}=[%ee]inletembed=(fun~depth__st->embed~depthst)inletreadback=(fun~depth__st->readback~depthst)in{Elpi.API.ContextualConversion.embed;readback;ty;pp_doc;pp}]letcoversion_for_opaque(moduleB:Ast_builder.S)elpi_namename=letopenBinvalue_binding~pat:(ppat_constraint(pvarname)(quantify_ty_over_params(moduleB)["c"][%type:([%tptyp_constr(Located.lidentname)[]],'c,'csts)Elpi.API.ContextualConversion.t]))~expr:(lift_conversion(moduleB)(evar@@elpi_cdata_namename))letabstract_expr_over_params(moduleB:Ast_builder.S)vlfe=letopenBinletrecaux=function|[]->e|v::vs->[%exprfun[%ppvar(fv)]->[%eauxvs]]inauxvlletctx_class_type_for_tyd(moduleB:Ast_builder.S)all_ctx{name;_}=letopenBinpstr_module@@module_binding~name:(Located.mk(Some(elpi_ctx_class_module_namename)))~expr:(pmod_structure[pstr_class_type[class_infos~virt:Concrete~params:[]~name:(Located.mk"t")~expr:(pcty_signature@@class_signature~self:[%type:_]~fields:((pctf_inherit(pcty_constr(Located.lident"Elpi.API.PPX.ctx")[]))::List.flatten(SSet.elementsall_ctx|>List.(map(func->[pctf_inherit(pcty_constr(Located.lident@@elpi_ctx_class_namec)[]);pctf_method(Located.mkc,Public,Concrete,[%type:[%tptyp_constr(Located.lidentc)[]]Elpi.API.PPX.ctx_field]);])))))]])letconversion_for_tyd(moduleB:Ast_builder.S)all_ctx{name;params;elpi_name;elpi_code;elpi_doc;type_decl;pp;index}=letopenBinletis_pred=option_is_someindexinmatchtype_declwith|Opaque_->[coversion_for_opaque(moduleB)(estringelpi_name)name]|Alias_->[value_binding~pat:(ppat_constraint(pvarname)(conversion_type(moduleB)nameparamsis_predall_ctx))~expr:(abstract_expr_over_params(moduleB)params(funx->x)([%exprletkind=[%emk_kind(moduleB)params(estringelpi_name)]in{Elpi.API.ContextualConversion.ty=kind;pp_doc=[%epp_doc(moduleB)[%exprkind](estringelpi_name)(option_mapestringelpi_code)(ifelpi_doc=namethen""elseelpi_doc)is_pred[]];pp=[%epp_for_conversion(moduleB)nameis_predparamspp];embed=[%eeapply(evar(elpi_embed_namename))(List.map(funx->[%expr[%eevarx].Elpi.API.ContextualConversion.embed])params)];readback=[%eeapply(evar(elpi_readback_namename))(List.map(funx->[%expr[%eevarx].Elpi.API.ContextualConversion.readback])params)];}]))]|Algebraic(csts,_)->[value_binding~pat:(ppat_constraint(pvarname)(conversion_type(moduleB)nameparamsis_predall_ctx))~expr:(abstract_expr_over_params(moduleB)params(funx->x)([%exprletkind=[%emk_kind(moduleB)params(estringelpi_name)]in{Elpi.API.ContextualConversion.ty=kind;pp_doc=[%epp_doc(moduleB)[%exprkind](estringelpi_name)(option_mapestringelpi_code)(ifelpi_doc=namethen""elseelpi_doc)is_predcsts];pp=[%epp_for_conversion(moduleB)nameis_predparamspp];embed=[%eeapply(evar(elpi_embed_namename))(List.map(funx->[%expr[%eevarx].Elpi.API.ContextualConversion.embed])params)];readback=[%eeapply(evar(elpi_readback_namename))(List.map(funx->[%expr[%eevarx].Elpi.API.ContextualConversion.readback])params)];}]))];;letinitial_state(moduleB:Ast_builder.S)name=letopenBinletelpi_Map=elpi_Map~locnamein[%expr([%eelpi_Map"empty"]:[%tptyp_constr(Located.lident(elpi_map_namename^".t"))[[%type:Elpi.API.RawData.constant]]]),(Elpi.API.RawData.Constants.Map.empty:[%tptyp_constr(Located.lidentname)[]]Elpi.API.PPX.ctx_entryElpi.API.RawData.Constants.Map.t)]letconversion_context_for_tyd(moduleB:Ast_builder.S)name=letopenBin[[%strilet[%ppvar@@elpi_readback_ctx_namename]={Elpi.API.PPX.is_entry_for_bound_var=[%eevar@@elpi_is_ctx_entry_namename];to_key=[%eevar@@elpi_to_keyname];push=[%eevar@@elpi_pushname];pop=[%eevar@@elpi_popname];conv=[%eevarname];init=(funstate->Elpi.API.State.set[%eevar@@elpi_state_namename]state[%einitial_state(moduleB)name]);get=(funstate->snd@@Elpi.API.State.get[%eevar@@elpi_state_namename]state);}]]letembed_for_tyd(moduleB:Ast_builder.S)same_mutrec_blockall_ctx{name;params;type_decl;index;_}=letopenBinletis_pred=option_is_someindexinmatchtype_declwith|Opaque_->ifparams<>[]thenerror~loc"opaque data type with parameters not supported";value_binding~pat:(pvar(elpi_embed_namename))~expr:[%expr[%eevarname].Elpi.API.ContextualConversion.embed]|Aliasorig->value_binding~pat:(ppat_constraint(pvar(elpi_embed_namename))(embed_type(moduleB)nameparamsis_predall_ctx))~expr:(abstract_expr_over_params(moduleB)paramselpi_embed_name@@find_embed_of(moduleB)same_mutrec_blockorig)|Algebraic(csts,_)->value_binding~pat:(ppat_constraint(pvar(elpi_embed_namename))(embed_type(moduleB)nameparamsis_predall_ctx))~expr:(abstract_expr_over_params(moduleB)paramselpi_embed_name@@embed(moduleB)is_predcsts)letreadback_for_tyd(moduleB:Ast_builder.S)same_mutrec_blockall_ctx{name;params;type_decl;index;_}=letopenBinletis_pred=option_is_someindexinmatchtype_declwith|Opaque_->ifparams<>[]thenerror~loc"opaque data type with parameters not supported";value_binding~pat:(pvar(elpi_readback_namename))~expr:[%expr[%eevarname].Elpi.API.ContextualConversion.readback]|Aliasorig->value_binding~pat:(ppat_constraint(pvar(elpi_readback_namename))(readback_type(moduleB)nameparamsis_predall_ctx))~expr:(abstract_expr_over_params(moduleB)paramselpi_readback_name@@find_readback_of(moduleB)same_mutrec_blockorig)|Algebraic(csts,def_readback)->value_binding~pat:(ppat_constraint(pvar(elpi_readback_namename))(readback_type(moduleB)nameparamsis_predall_ctx))~expr:(abstract_expr_over_params(moduleB)paramselpi_readback_name@@readback(moduleB)nameis_preddef_readbackcsts)letin_ctx_for_tyd(moduleB:Ast_builder.S)ctx{name;_}=letopenBinletctx=SSet.elementsctxin[pstr_class[class_infos~virt:Concrete~params:[]~name:(Located.mk@@elpi_ctx_object_namename)~expr:(pcl_funNolabelNone(ppat_constraint(pvar"h")(ptyp_constr(Located.lident"Elpi.API.Data.hyps")[]))@@pcl_funNolabelNone(ppat_constraint(pvar"s")(ptyp_constr(Located.lident"Elpi.API.Data.state")[]))@@pcl_constraint(pcl_structure@@class_structure~self:(pvar"_")~fields:(pcf_inheritFresh(pcl_apply(pcl_constr(Located.lident"Elpi.API.PPX.ctx")[])[Nolabel,evar"h"])None::List.flatten(ctx|>List.map(func->[pcf_inheritOverride(pcl_apply(pcl_constr(Located.lident@@elpi_ctx_object_namec)[])[Nolabel,evar"h";Nolabel,evar"s"])None;pcf_method(Located.mkc,Public,Cfk_concrete(Fresh,[%expr[%eevar@@elpi_readback_ctx_namec].Elpi.API.PPX.gets]))]))))(pcty_constr(Located.lident@@elpi_ctx_class_namename)[]))];(* apparently you cannot declare a class type and a class with the same name *)[%strilet[%ppvar@@elpi_in_ctx_for_namename]:([%tptyp_constr(Located.lident@@elpi_ctx_class_namename)[]],'csts)Elpi.API.ContextualConversion.ctx_readback=fun~depthhcs->[%eletgls=List.mapi(funi_->Printf.sprintf"gls%d"i)ctxinletrecaux=function|[]->[%exprs,[%epexp_new@@Located.lident@@elpi_ctx_object_namename]hs,c,List.concat[%eelist@@List.mapevargls]]|(c,gls)::cs->[%exprletctx=[%epexp_new@@Located.lident@@elpi_ctx_object_namec]hsinlets,[%ppvargls]=Elpi.API.PPX.readback_context~depth[%eevar@@elpi_readback_ctx_namec]ctxhcsin[%eauxcs]]inaux(List.combinectxgls)]]]letconstants_of_tyd(moduleB:Ast_builder.S){type_decl;elpi_name;name;_}=letopenBinletc_str=elpi_tname_strnameinletdecl_str=value_binding~pat:(pvarc_str)~expr:(estringelpi_name)inletdecl=letc=elpi_tnamenameinvalue_binding~pat:(pvarc)~expr:[%exprElpi.API.RawData.Constants.declare_global_symbol[%eevarc_str]]inpstr_valueNonrecursive[decl_str]::pstr_valueNonrecursive[decl]::matchtype_declwith|Alias_->[]|Opaqueopaque_data->[pstr_valueNonrecursive[value_binding~pat:(pvar@@elpi_cdata_namename)~expr:[%exprElpi.API.OpaqueData.declare[%eopaque_data]]]]|Algebraic(csts,_)->List.flatten@@List.map(funx->x.declaration)@@drop_skipcstsletelpi_declaration_of_tyd(moduleB:Ast_builder.S)tyd=letopenBinletdecl_name="elpi_"^tyd.nameinletdecl=matchtyd.type_declwith|Aliasorig->(iftyd.params=[]then(funx->x)elsepexp_letNonrecursive(List.mapi(funix->value_binding~pat:(pvarx)~expr:(poly_param_conversion(moduleB)i))tyd.params))[%exprElpi.API.BuiltIn.LPCode("typeabbrev "^[%etypeabbrev_for(moduleB)(estringtyd.elpi_name)tyd.params]^" "^[%etypeabbrev_for_conv(moduleB)orig]^". % "^[%eestringtyd.elpi_doc])]|Opaque_->[%exprElpi.API.BuiltIn.MLDataC[%eiftyd.params=[]thenevartyd.nameelseerror~loc"opaque with params"]]|Algebraic_->letvars=List.mapi(funi_->poly_param_conversion(moduleB)i)tyd.paramsin[%exprElpi.API.BuiltIn.MLDataC[%eiftyd.params=[]thenevartyd.nameelseeapply(evartyd.name)vars]]in{decl=pstr_valueNonrecursive[value_binding~pat:(pvardecl_name)~expr:decl];decl_name=evardecl_name;}(* The function of a binder, [fun p1 ... pn -> C (e1, ..., ek)], builds the
entry of the context. If the ei are among the pi, returns the name of C and,
for each ei, the position of the pi it is, that is the position of the
field of the constructor (not counting the field below the binder) that
is the i-th argument of C. *)letanalyze_build_ctxbuild_ctx=letps,body=Ppx_elpi_compat.fun_paramsbuild_ctxinletindexv=letrecauxi=function|[]->None|x::xs->ifx=vthenSomeielseaux(i+1)xsinaux0psinmatchbody.pexp_descwith|Pexp_construct({txt=Longident.Lidentc;_},arg)->letargs=matchargwith|None->[]|Some{pexp_desc=Pexp_tuplel;_}->l|Somee->[e]inletidx=List.map(function|{pexp_desc=Pexp_ident{txt=Longident.Lidentv;_};_}->indexv|_->None)argsinifList.memNoneidxthenNoneelseSome(c,List.mapOption.getidx)|_->Noneletdeep_copy_for_tydelpi_namestyd:stringoption=ifoption_is_sometyd.indexthenNoneelselettyvars=List.mapi(funi_->Printf.sprintf"X%d"i)tyd.paramsinlettyvars1=List.mapi(funi_->Printf.sprintf"Y%d"i)tyd.paramsinletty_w_paramsvars=ifvars=[]thentyd.elpi_nameelsetyd.elpi_name^" "^String.concat" "varsinletfvars=List.mapi(funi_->Printf.sprintf"F%d"i)tyd.paramsinletparam2fv=List.combinetyd.paramsfvarsin(* the copy function of each parameter *)letty_fvars=iftyvars=[]then""elseString.concat", "(List.map2(Printf.sprintf"(func %s -> %s)")tyvarstyvars1)^", "inletpred_decl=Printf.sprintf"func %s.copy %s%s -> %s."tyd.elpi_namety_fvars(ty_w_paramstyvars)(ty_w_paramstyvars1)in(* does the type mention a parameter? *)letrecmentionspty=matchty.ptyp_descwith|Ptyp_constr({txt=Longident.Lidentid;_},args)->id=p||List.exists(mentionsp)args|Ptyp_constr(_,args)->List.exists(mentionsp)args|Ptyp_tuplel->List.exists(mentionsp)l|Ptyp_arrow(_,a,b)->mentionspa||mentionspb|_->falsein(* the copy of a bound variable of Elpi type [ty; "A"; ...]: its copy
function, applied to the copy functions of the parameters A, ... *)letbound_copy=function|[]->assertfalse|ty::args->letfva=matchList.find_opt(fun(i,_)->poly_param_namei=a)(List.mapi(funi(_,f)->i,f)param2fv)with|Some(_,f)->f|None->Location.raise_errorf"type %s: the parameter %s of the type of a bound variable is not a parameter of the type"tyd.elpi_nameainString.concat" "((ty^".copy")::List.mapfvargs)in(* the copy functions of the parameters, unused ones are discarded *)letfvars_strtys=String.concat""(List.map(fun(p,f)->ifList.exists(mentionsp)tysthenf^" "else"_ ")param2fv)inmatchtyd.type_declwith|Opaque_->Some(Printf.sprintf"func %s.copy %s -> %s.\n%s.copy X X.\n"tyd.elpi_nametyd.elpi_nametyd.elpi_nametyd.elpi_name)|Aliasorig->letcopy=Printf.sprintf"%s.copy %sA B :- %s."tyd.elpi_name(fvars_str[orig])(find_mapper_ofelpi_namesparam2fvorig("A","B"))inSome(String.concat"\n"[pred_decl;copy])|Algebraic(csts,_)->(* the field below a binder is copied under the binder, in the context
extended with the entry of the bound variable *)letcopykaarg_typesiarg(v1,v2)=matchargwith|FO{ty;_}->find_mapper_ofelpi_namesparam2fvty(v1,v2)|HO{build_ctx;ty;arrow_src_elpi;_}->beginmatchanalyze_build_ctxbuild_ctxwith|Some(c,idx)->(* the other fields of the constructor, in order *)letothers=List.filter(funj->j<>i)(List.mapi(funj_->j)arg_types)inletentry_args=List.map(funk->Printf.sprintf"B%d"(List.nthothersk))idxin(* the bound variable is called x, or x<i> if there are several
binders *)letfirst_binder=letrecauxj=function|[]->i|HO_::_->j|_::rest->aux(j+1)restinaux0arg_typesinletx=ifi=first_binderthen"x"else"x"^string_of_intiinletentryv=String.concat" "(elpi_name_manglec::v::entry_args)in(* if the type of the bound variable has parameters, the bound
variable of the copy has a different type than the one
of the original, hence it is a different variable *)letpoly=List.lengtharrow_src_elpi>1inlety=ifpolythen"y"^String.subx1(String.lengthx-1)elsexinletbody_goal=find_mapper_ofelpi_namesparam2fvty(Printf.sprintf"(%s %s)"v1x,Printf.sprintf"(%s %s)"v2y)inifpolythenPrintf.sprintf"(pi %s\\ pi %s\\ %s ==> %s ==> (%s %s %s :- !) ==> %s)"xy(entryx)(entryy)(bound_copyarrow_src_elpi)xybody_goalelse(* the bound variable is copied to itself *)Printf.sprintf"(pi %s\\ %s ==> %s %s %s ==> %s)"x(entryx)(bound_copyarrow_src_elpi)xxbody_goal|None->(* the function of the binder is not of the expected shape: no
entry is added to the context *)letx="x"^string_of_intiinletpoly=List.lengtharrow_src_elpi>1inlety=ifpolythen"y"^string_of_intielsexinletbody_goal=find_mapper_ofelpi_namesparam2fvty(Printf.sprintf"(%s %s)"v1x,Printf.sprintf"(%s %s)"v2y)inifpolythenPrintf.sprintf"(pi %s\\ pi %s\\ (%s %s %s :- !) ==> %s)"xy(bound_copyarrow_src_elpi)xybody_goalelsePrintf.sprintf"(pi %s\\ %s %s %s ==> %s)"x(bound_copyarrow_src_elpi)xxbody_goalendinletcopyk{constant_name;arg_types;_}=ifarg_types=[]thenPrintf.sprintf"%s.copy %s%s %s."tyd.elpi_name(fvars_str[])constant_nameconstant_nameelseletvars=List.mapi(funi_->Printf.sprintf"A%d"i)arg_typesinletvars1=List.mapi(funi_->Printf.sprintf"B%d"i)arg_typesinletvars_s=String.concat" "varsinletvars1_s=String.concat" "vars1inletbody=List.mapi(funi(arg,v)->copykaarg_typesiargv)(List.combinearg_types(List.combinevarsvars1))inPrintf.sprintf"%s.copy %s(%s %s) (%s %s) :- %s."tyd.elpi_name(fvars_str(List.map(functionFO{ty;_}|HO{ty;_}->ty)arg_types))constant_namevars_sconstant_namevars1_s(String.concat", "body)in(* bound variables are not constructors, they are constants that the
user can relate with a rule under the binder *)letcsts=List.filter(fun{embed;readback;_}->not(is_nameembed||is_namereadback))(drop_skipcsts)inletcopy=List.mapcopykcstsinSome(String.concat"\n"(pred_decl::copy@["\n"]));;letextras_of_task(moduleB:Ast_builder.S){types;names;context;ctx_names}=letopenBinletis_opaque=functionOpaque_->true|_->falseinletelpi_names=List.map(funt->t.name,t.elpi_name)typesinletty_extras=types|>List.map(funtyd->{ty_constants=constants_of_tyd(moduleB)tyd;ty_embed=embed_for_tyd(moduleB)namesctx_namestyd;ty_readback=readback_for_tyd(moduleB)namesctx_namestyd;ty_ctx_class_type=ctx_class_type_for_tyd(moduleB)ctx_namestyd;ty_conversion=conversion_for_tyd(moduleB)ctx_namestyd;ty_conversion_name=tyd.name;ty_elpi_declaration=elpi_declaration_of_tyd(moduleB)tyd;ty_opaque=is_opaquetyd.type_decl;ty_deep_copy=deep_copy_for_tydelpi_namestyd;ty_in_ctx=in_ctx_for_tyd(moduleB)ctx_namestyd;})inletctx_extras=matchcontextwith|None->None|Some(name,m,tyd)->letelpi_name=tyd.elpi_nameinletcsts=matchtyd.type_declwithAlgebraic(x,_)->x|_->error"context ADT must be explicit"inSome{ty_context_helpers=[pstr_module(module_binding~name:(Located.mk(Some(elpi_map_namename)))~expr:(pmod_apply(pmod_ident(Located.mk(Longident.parse"Elpi.API.Utils.Map.Make")))m));pstr_valueNonrecursive[value_binding~pat:(pvar(elpi_state_namename))~expr:[%exprElpi.API.State.declare_component~name:[%eestringelpi_name]~pp:(funfmt_->Format.fprintffmt"TODO")~init:(fun()->[%einitial_state(moduleB)name])~start:(funx->x)();]];pstr_valueNonrecursive[value_binding~pat:(pvar(elpi_to_keyname))~expr:(ctx_entry_key(moduleB)csts)];pstr_valueNonrecursive[value_binding~pat:(pvar(elpi_is_ctx_entry_namename))~expr:(is_ctx_entry(moduleB)csts)];pstr_valueNonrecursive[value_binding~pat:(pvar(elpi_pushname))~expr:(ctx_push(moduleB)name)];pstr_valueNonrecursive[value_binding~pat:(pvar(elpi_popname))~expr:(ctx_pop(moduleB)name)];];ty_context_readback=conversion_context_for_tyd(moduleB)tyd.name;}in{ty_extras;ctx_extras};;letanalyze_typedecl(moduleB:Ast_builder.S)same_mutrec_blocktdecl=matchtdeclwith|{ptype_name={txt=name;_};ptype_params=params;ptype_cstrs=_;ptype_kind=k;ptype_manifest;_}when(k=Ptype_abstract&&ptype_manifest=None)||has_elpi_tcdatatdecl->letparams,_=analyze_params(moduleB)paramsinletelpi_name,elpi_code=get_elpi_tcode(moduleB)nametdeclinletelpi_doc=get_elpi_tdocnametdeclinletpp=get_elpi_pptdeclinletindex=get_elpi_tindextdeclinletcdata=get_elpi_tcdata~loc:B.loctdeclin{name;params;type_decl=Opaquecdata;elpi_name;elpi_code;elpi_doc;pp;index}|{ptype_name={txt=name;_};ptype_params=params;ptype_cstrs=_;ptype_kind=Ptype_abstract;ptype_manifest=Somealias;_}->letparams,typ=analyze_params(moduleB)paramsinletalias=typ#core_typealiasinletelpi_name,elpi_code=get_elpi_tcode(moduleB)nametdeclinletelpi_doc=get_elpi_tdocnametdeclinletpp=get_elpi_pptdeclinletindex=get_elpi_tindextdeclin{name;params;type_decl=Aliasalias;elpi_name;elpi_code;elpi_doc;pp;index}|{ptype_name={txt=name;_};ptype_params=params;ptype_cstrs=_;ptype_kind=Ptype_variantcsts;_}->letparams,typ=analyze_params(moduleB)paramsinletcsts=List.maptyp#constructor_declarationcstsinletcsts=List.map(analyze_constructor(moduleB)namesame_mutrec_block)cstsinletelpi_name,elpi_code=get_elpi_tcode(moduleB)nametdeclinletelpi_doc=get_elpi_tdocnametdeclinletdefault_readback=get_elpi_tdefkreadbacktdeclinletpp=get_elpi_pptdeclinletindex=get_elpi_tindextdeclin{name;params;type_decl=Algebraic(csts,default_readback);elpi_name;elpi_code;elpi_doc;pp;index}|{ptype_name={txt=name;_};ptype_params=params;ptype_cstrs=_;ptype_kind=Ptype_recordlbltl;ptype_attributes;_}->letparams,typ=analyze_params(moduleB)paramsinletlbltl=List.maptyp#label_declarationlbltlinletlbls,tl=List.(split(map(fun{pld_name={txt;_};pld_type;_}->txt,pld_type)lbltl))inletmake_kargs=B.pexp_record(List.map2(funxy->B.Located.lidentx,y)lblsargs)Noneinletmatch_kargs=B.ppat_record(List.map2(funxy->B.Located.lidentx,y)lblsargs)Closedinletkdecl={pcd_name=B.Located.mkname;pcd_args=Pcstr_tuple[];pcd_vars=[];pcd_res=None;pcd_loc=B.loc;pcd_attributes=ptype_attributes;}inletcsts=[analyze_tuple_constructor(moduleB)namenamekdecltlmake_kmatch_ksame_mutrec_block]inletelpi_name,elpi_code=get_elpi_tcode(moduleB)nametdeclinletelpi_doc=get_elpi_tdocnametdeclinletdefault_readback=get_elpi_tdefkreadbacktdeclinletpp=get_elpi_pptdeclinletindex=get_elpi_tindextdeclin{name;params;type_decl=Algebraic(csts,default_readback);elpi_name;elpi_code;elpi_doc;pp;index}|_->error~loc:B.loc"unsupportd type declaration";;lettypedecl_extras(moduleB:Ast_builder.S)all_contexttyds=lettyd_names=List.map(funx->x.ptype_name.txt)tydsinlettyds=List.map(analyze_typedecl(moduleB)tyd_names)tydsinletctx_names=List.fold_left(funaccx->matchx.type_declwith|Opaque_|Alias_->acc|Algebraic(cl,_)->List.fold_left(funacc->function|Skip_->acc|Expose{ctx_names;_}->List.fold_rightSSet.addctx_namesacc)acccl)SSet.emptytydsinletctx_names=matchall_contextwith|None->ctx_names|Someall->letall=parse_lident_list(moduleB)allinletall=SSet.of_listallinifnot(SSet.subsetctx_namesall)thenerror~loc:B.loc"[deriving elpi { context }] directive contains %a but the type mentions more: %a"SSet.ppallSSet.pp(SSet.diffctx_namesall);allinletcontext=consistency_check~loc:B.loctydsinletmut={types=tyds;ctx_names;names=tyd_names;context}inextras_of_task(moduleB)mut;;lettydecls~locappend_declall_context_rtdls=letmoduleB=Ast_builder.Make(structletloc=locend)inletopenBinlet{ty_extras;ctx_extras}=typedecl_extras(moduleB)all_contexttdlsinletopaque_extra,non_opaque_extra=List.partition(funx->x.ty_opaque)ty_extrasinpstr_attribute{attr_name=Located.mk"warning";attr_payload=PStr[pstr_eval(estring"-26-27-32-39-60")[]];attr_loc=loc}::List.(concat(map(funx->x.ty_constants)ty_extras))@option_default[](option_map(funx->x.ty_context_helpers)ctx_extras)@List.(map(funx->x.ty_ctx_class_type)ty_extras)@beginifopaque_extra<>[]then[pstr_valueNonrecursiveList.(concat_map(funx->x.ty_conversion)opaque_extra)]@[pstr_valueNonrecursiveList.(map(funx->x.ty_embed)opaque_extra)]@[pstr_valueNonrecursiveList.(map(funx->x.ty_readback)opaque_extra)]else[]end@beginifnon_opaque_extra<>[]then[pstr_valueRecursive(List.map(funx->x.ty_embed)non_opaque_extra@List.map(funx->x.ty_readback)non_opaque_extra@List.concat_map(funx->x.ty_conversion)non_opaque_extra)]else[]end@option_default[](option_map(funx->x.ty_context_readback)ctx_extras)@List.(map(funx->x.ty_elpi_declaration.decl)ty_extras)@(* elpi__<ty>__deep_copy is the Elpi code of the deep copy of ty *)List.(concat_map(funx->matchx.ty_deep_copywith|None->[]|Somee->[pstr_valueNonrecursive[value_binding~pat:(pvar(deep_copy_namex.ty_conversion_name))~expr:(estringe)]])ty_extras)@List.(concat(map(funx->x.ty_in_ctx)ty_extras))@beginmatchappend_declwith|None->[]|Somel->[pstr_valueNonrecursive[value_binding~pat:(punit)~expr:[%exprElpi.API.PPX.add_declarations[%el](* the deep copy of a type follows its declaration *)[%eelist@@List.(concat_map(funx->x.ty_elpi_declaration.decl_name::(matchx.ty_deep_copywith|None->[]|Some_->[[%exprElpi.API.BuiltIn.LPCode[%eevar(deep_copy_namex.ty_conversion_name)]]]))ty_extras)]]]]end;;letconversion_of_expansion~loc~path:_ty=conversion_of(moduleAst_builder.Make(structletloc=locend))tyletconversion_extension=Extension.declare"elpi"Extension.Context.expressionAst_pattern.(ptyp__)conversion_of_expansionletexpand_str~loc~path:_(r,tydecl)(declaration:expressionoption)(context:expressionoption)=tydecls~locdeclarationcontextrtydeclletexpand_sig~loc~path:_(_r,_tydecl)(_index:module_exproption)=nYI~loc~__LOC__()letattributes=Attribute.([Tatt_elpi_tcode;Tatt_elpi_tdoc;Tatt_elpi_var;Tatt_elpi_skip;Tatt_elpi_embed;Tatt_elpi_readback;Tatt_elpi_code;Tatt_elpi_doc;Tatt_elpi_variant;Tatt_elpi_key;Tatt_elpi_binder])letstr_type_decl_generator=Deriving.Generator.make~attributesargumentsexpand_strletarguments=Deriving.Args.(empty+>arg"index"(pexp_pack__))letsig_type_decl_generator=Deriving.Generator.make~attributesargumentsexpand_sigletmy_deriver=Deriving.add~str_type_decl:str_type_decl_generator~sig_type_decl:sig_type_decl_generator"elpi"(* [%%elpi.compose_ctx name [ty1; ...; tyn]] *)letcompose_ctx_expansion~loc~path:_(name,tys)=letmoduleB=Ast_builder.Make(structletloc=locend)inletopenBinpstr_include(include_infos(pmod_structure(compose_ctx_readback(moduleB)nametys)))letcompose_ctx_extension=Extension.declare"elpi.compose_ctx"Extension.Context.structure_itemAst_pattern.(pstr(pstr_eval(pexp_apply(pexp_ident(lident__))((no_label(elist(pexp_ident(lident__))))^::nil))nil^::nil))(fun~loc~pathnametys->compose_ctx_expansion~loc~path(name,tys))let()=Driver.register_transformation~extensions:[conversion_extension;compose_ctx_extension]"elpi.conversion"