123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543open!Stdppxopen!Import(** This module defines the underlying DSL of [ppx_template]. Below, we provide an
overview of the semantics of the DSL, as well as a grammar for how the surface syntax
corresponds to the DSL.
While inside of a [[%template]] node, an environment ([Env.t]) is accumulated that
maps identifiers ([Identifier.t]) to values ([Value.t]). Each identifier and value is
associated with a type ([Type.t]) and identifiers are namespaced by their type.
The environment is updated by two types of attributes:
1. poly-attributes; a poly-attribute is either:
a. floating (in which case it updates the environment for all subsequent items in
the current structure/signature), e.g. [[@@@kind k = bits64]] or
b. attached to an item (in which case it updates the environment for the item it is
directly attached to), e.g. [[@@kind k = bits64]]
2. define-attributes; a define attribute is always floating attribute, and is used to
bind a set in the namespace [[@@@kind_set.define ks = (value, bits64)]]
Poly-attributes and define-attributes both consist of a list of bindings; if there are
multiple such attributes, the lists of bindings can conceptually be concatenated to
form a single list of bindings. Bindings are evaluated sequentially. An individual
binding maps a pattern ([Pattern.t]) to a single expression ([Expression.t]). For a
pattern of type ['a], the associated expression evaluates to a set of values
([Value.t]) of type ['a].
- For a poly-attribute, evaluation is split into a branch for each value in the set.
The value is combined with the pattern to form new (identifier x expression) entries
which are added to the environment for the branch.
- For a define-attribute, no branching occurs; rather, the whole set is bound to the
name in the environment.
Note the distinction between:
- [[@@@kind_set ks = (value, bits64)]], which is a poly-attribute that causes the
following code to be templated with the two singleton sets [ks = value] and
[ks = bits64] and
- [[@@@kind_set.define ks = (value, bits64)]], which is a define-attribute and binds
the name [ks] to the set [value, bits64] once.
The environment is used to update the OCaml AST in two ways:
1) Each type is associated with a node in the OCaml AST (via [Node.t]), and when such
a node is reached within a [[%template]] body, any OCaml identifiers within that
node will be looked up in the current environment and, if found, replaced with
their associated value.
2) If a mono-attribute is encountered (a [[@kind]], [[@mode]], [[@modality]], or
[[@alloc]] attribute attached to an identifier), its payload (a list of
expressions) is evaluated in the current environment, and is used to mangle the
attached identifier. If there are multiple mono-attributes, the lists of
expressions are concatenated. *)moduleDefinitions=structmoduleType=struct(*_ Note: we only provide concrete definitions for these types so that the compiler
knows they are distinct. They are [private] so that they can only ever be used as
phantom types. *)typekind__=privateKindtypemode_=privateModetypemodality_=privateModalitytypealloc_=privateAlloctypesynchro_=privateSynchrotype_non_tuple=|Kind:kind__non_tuple|Mode:mode_non_tuple|Modality:modality_non_tuple|Alloc:alloc_non_tuple|Synchro:synchro_non_tupletypekind=kind__non_tupletypemode=mode_non_tupletypemodality=modality_non_tupletypealloc=alloc_non_tupletypesynchro=synchro_non_tupletype_t=|Non_tuple:'anon_tuple->'anon_tuplet|Tuple:('a*'b)tuple->('a*'b)t(*_ Tuples have at least one element *)and_tuple=|[]:unittuple|(::):'at*'btuple->('a*'b)tupletypepacked=P:'at->packed[@@unboxed]moduleNon_tuple=structtypepacked=P:'anon_tuplet->packed[@@unboxed]endendmoduleUntyped=structmoduleAxis=structtypet=|Kind|Mode|Modality|Alloc|Synchro|SetoftendmoduleIdentifier=structtypet={ident:string}endmoduleExpression=structtypet=|IdentifierofIdentifier.t|Kind_productoftNonempty_list.t|Kind_modoft*tNonempty_list.t|Kind_coercionoft*t|Comma_separatedoftNonempty_list.t|Typedoft*Type.packedendmoduleValue=structtypet=|IdentifierofIdentifier.t|Kind_productoftNonempty_list.t|Kind_modoft*tNonempty_list.t|TupleoftNonempty_list.tendmodulePattern=structtypet=|Wildcard|IdentifierofIdentifier.t|TupleoftNonempty_list.tendendmoduleTyped=structmoduleAxis=structtype_singleton=|Kind:Type.kindsingleton|Mode:Type.modesingleton|Modality:Type.modalitysingleton|Alloc:Type.allocsingleton|Synchro:Type.synchrosingletontype_t=|Singleton:'asingleton->'at|Set:'asingleton->'attypepacked=P:_t->packed[@@unboxed]moduleSub_axis=structmoduleModal=structtypet=|Locality|Portability|Contention|Statefulness|Visibility|Linearity|Uniqueness|Yielding|ForkableendmoduleMode=structtypet=ModeofModal.t[@@unboxed]endmoduleModality=structtypet=ModalityofModal.t[@@unboxed]endmoduleOr_unrecognized=structtype'at=|Knownof'a|Unrecognizedendtype_t=|Kind:Type.kindt|Mode:Mode.tOr_unrecognized.t->Type.modet|Modality:Modality.tOr_unrecognized.t->Type.modalityt|Alloc:Type.alloct|Synchro:Type.synchrottypepacked=P:_t->packed[@@unboxed]endmoduleNamespace=structtype_t=|Singleton:'aSub_axis.t->'at|Set:'aSub_axis.t->'at|Tuple:('a*'b)tuple->('a*'b)t(*_ Tuples have at least one element *)and_tuple=|[]:unittuple|(::):'at*'btuple->('a*'b)tupleendendmoduleIdentifier=structtype'at={type_:'aType.t;ident:string}endmoduleExpression=struct(** Expressions that recursively do not contain any syntactic unions, e.g.
[k mod m], [base_with_imm], and [heap @ global]. These expressions can still be
interpreted as sets when identifiers bound to sets are expanded. *)typesingleton=privateSingleton(** Expressions that might contain a syntactic union, such as any singleton, and
also expressions like [(k1, k2) & k3]. *)typeset=privateSettype('err,'which)allow_set=|Singleton_only:{why_no_set:'err}->('err,singleton)allow_set(** Error hint for expressions that contain illegal unions *)|Set_or_singleton:(_,set)allow_set(** ['a] is the type of [Value]s to which an [Expression] evaluates. ['s] is whether
the expression is allowed to syntactically contain sets (corresponding to the
[Union] constructor). If an [('a, singleton) t] is evaluated without expanding
identifiers bound to sets, the result is just one ['a Value.t]. If a
[('a, set) t] is evaluated, or when any [('a, _) t] is evaluated by expanding
identifiers bound to sets, the result of evaluation is a list of ['a Value.t]s. *)type('a,'s)t=|Identifier:'aIdentifier.t->('a,_)t|Kind_product:(Type.kind,'s)tNonempty_list.t->(Type.kind,'s)t|Kind_mod:(Type.kind,'s)t*(Type.modality,singleton)tNonempty_list.t->(Type.kind,'s)t|Kind_coercion:(Type.kind,'s)t*(Type.kind,set)t->(Type.kind,'s)t|Tuple:('a*'b)tuple->('a*'b,_)t(*_ Tuples have at least one element *)|Union:('a,_)tNonempty_list.t->('a,set)tand'atuple=|[]:unittuple|(::):('a,singleton)t*'btuple->('a*'b)tupletypepacked=P:('a,'s)t->packed[@@unboxed]moduleBasic=structtypepacked=P:('aType.non_tuple,singleton)t->packed[@@unboxed]endendmoduleValue=structtype'at=|Identifier:'aType.non_tupleIdentifier.t->'aType.non_tuplet|Kind_product:Type.kindtNonempty_list.t->Type.kindt|Kind_mod:Type.kindt*Type.modalitytNonempty_list.t->Type.kindt|Tuple:('a*'b)tuple->('a*'b)t(*_ Tuples have at least one element *)and_tuple=|[]:unittuple|(::):'at*'btuple->('a*'b)tupletypepacked=P:'at->packed[@@unboxed]moduleBasic=structtypepacked=P:'aType.non_tuplet->packed[@@unboxed]endmoduleDefaultness=structtypet=|Actual_default(** Actual defaults in the mode/kind system. *)|Default_for_standard_mangling(** The special case of [[@kind value_or_null]] is mangled as default for
pragmatic reasons. [[@kind.explicit_plus_unmangled value_or_null]] is not
treated as default. *)|Not_a_default(** Values that are not a default for any purpose. *)endendmodulePattern=structtype'at=|Wildcard:'at|Identifier:'aIdentifier.t->'at|Tuple:('a*'b)tuple->('a*'b)t(*_ Tuples have at least one element *)and_tuple=|[]:unittuple|(::):'at*'btuple->('a*'b)tupleendendmoduleNode=struct(** A type used as the output of [Value.to_node]. *)type'at=|Jkind_annotation:jkind_annotation->Type.kindt|Mode:modeloc->Type.modet|Modality:modalityloc->Type.modalityt|Alloc:Type.alloct|Synchro:Type.synchrotendmoduleType_error=structtypet=|Type_mismatch:{kind:string;sexp_of_kind:'value->Sexp.t;value:'value;expected_type:_Type.t;expected_sets:(string,_)Typed.Expression.allow_setoption;hint:stringoption}->t|Tuple_length_mismatch:{kind:string;sexp_of_kind:'value->Sexp.t;value:'value;expected_type:_Type.t}->tendendmoduletypeLanguage=sigincludemoduletypeofstructincludeDefinitionsendmoduleType:sigincludemoduletypeofstructincludeTypeendmoduleNon_tuple:sigincludemoduletypeofstructincludeNon_tupleendendvalsexp_of_t:_t->Sexp.tvalkind:kindtvalmode:modetvalmodality:modalitytvalalloc:alloctvalsynchro:synchrotvaltuple2:'at->'bt->('a*('b*unit))tendmoduleUntyped:sigincludemoduletypeofstructincludeUntypedendmoduleAxis:sigincludemoduletypeofstructincludeAxisendmoduleMap:Map.Swithtypekey=tendmoduleIdentifier:sigincludemoduletypeofstructincludeIdentifierendvalcompare:t->t->intvalsexp_of_t:t->Sexp.tendmoduleExpression:sigincludemoduletypeofstructincludeExpressionendvalcompare:t->t->intvalsexp_of_t:t->Sexp.tendmoduleValue:sigincludemoduletypeofstructincludeValueendvalcompare:t->t->intvalsexp_of_t:t->Sexp.tendmodulePattern:sigincludemoduletypeofstructincludePatternendvalcompare:t->t->intvalsexp_of_t:t->Sexp.tendendmoduleTyped:sigincludemoduletypeofstructincludeTypedendmoduleAxis:sigincludemoduletypeofstructincludeAxisendmoduleMap:Map.Swithtypekey:=packedvalof_type:'aType.non_tupleType.t->'aType.non_tupletvalis_set:'at->boolmoduleSub_axis:sigincludemoduletypeofstructincludeSub_axisendmoduleModal:sigincludemoduletypeofstructincludeModalendendmoduleMode:sigincludemoduletypeofstructincludeModeendendmoduleModality:sigincludemoduletypeofstructincludeModalityendendmoduleOr_unrecognized:sigincludemoduletypeofstructincludeOr_unrecognizedendendmoduleMap:Stdlib.Map.Swithtypekey:=packedvalof_identifier:'aType.non_tupleIdentifier.t->'aType.non_tupletvalof_value:'aType.non_tupleValue.t->'aType.non_tupletendmoduleNamespace:sigincludemoduletypeofstructincludeNamespaceendvalsexp_of_t:_t->Sexp.tvalsame_namespace:'at->'bt->boolvalof_value:is_set:bool->'aValue.t->'atendendmoduleIdentifier:sigincludemoduletypeofstructincludeIdentifierendvalequal_witness:'at->'bt->('a,'b)Stdlib.Type.eqoptionendmoduleValue:sigincludemoduletypeofstructincludeValueendvalcompare:'at->'at->intvalsexp_of_t:_t->Sexp.t(** Checks whether a value is a default value for its axis. When not using
[.explicit] or [.explicit_plus_unmangled] attributes, we leave identifiers
untemplated over a particular axis [is_default] holds for all values in the
mangling set for that axis.
Returns [Actual_default] for values representing actual OxCaml defaults. These
are the modes, kinds, etc. that OxCaml infers when there are no other
annotations or constraints.
Returns [Default_for_standard_mangling] for the kind [value_or_null], which is
mangled as if it were default for standard "poly" attributes like
[[@@kind k = (value_or_null, ...)]]. It is not mangled as default for
[[@@kind.explicit_plus_unmangled ...]].
Returns [Not_a_default] for all other values. *)valdefaultness:'aType.non_tuplet->Defaultness.tvalas_expression:'at->('a,Expression.singleton)Expression.t(** Convert a value in the template language to a concrete OCaml AST node. *)valto_node:'aType.non_tuplet->loc:location->'aType.non_tupleNode.tendmodulePattern:sigincludemoduletypeofstructincludePatternendvaluntype:'at->Untyped.Pattern.tvaltype_check:Untyped.Pattern.t->expected:'aType.t->('at,Type_error.t)resultendmoduleExpression:sigincludemoduletypeofstructincludeExpressionendvalof_parsetree_jkind:Ppxlib_jane.jkind_annotation->((Type.kind,_)t,stringloc)resultvaltype_:('a,_)t->'aType.tvalto_set:('a,_)t->('a,set)tvaluntype:('a,'allow_set)t->Untyped.Expression.tvaltype_check:Untyped.Expression.t->expected:'aType.t->allow_set:(string,'s)allow_set->(('a,'s)t,Type_error.t)resultendendmoduleType_error:sigincludemoduletypeofstructincludeType_errorendvalto_error:loc:Location.t->t->Syntax_error.tvallift_to_error_result:loc:Location.t->('a,t)result->('a,Syntax_error.t)resultendend