Way to define multiple templates sharing ${define ..} and ${defcond }
Consider the problem posed in #35. This ticket requests item 2 in #35 (comment 3015694)
Overall scheme
The user can supply some common template pieces, which they can then reuse in multiple template definitions.
Open question - unified invocation vs named modules
In principle it might be possible to have these template pieces be exported from one place to another in the program, by embedding them in macro_rules!
macros (macro_rules! derive_deftly_module_Castable
) but this would involve the macro body threading trick and be quite fiddly. Also there are semver implications, because you'd be able to mix template fragments from different crates. (But that would only happen with a pub
d-d module.)
Simpler would be to have the user provide all of the pieces together, in one proc_macro invocation.
In both cases the natural form for common template pieces is either a shared piece of text, or individual ${define}
/${defcond}
. (Henceforth, "$define
s".) For reasons that will become clear, I think it ought to be $define
s.
In principle we could intend to implement both, if we wanted. We probably shouldn't implement the unified invocation facility unless we are happy to have both in the future.
Syntax
The user must supply:
- Zero or more loose
$define
with distinct names. - Zero or more template definitions
Proposed syntax (unified invocation)
ISTM that the input syntax should resemble the "normal" invocation as much as possible.
define_derive_deftly_several! {
${define CASTABLE {
impl Castable ...
}}
define_derive_deftly! { Castable = $CASTABLE }
define_derive_deftly! {
Object =
$CASTABLE
impl Object ...
}
}
Within the invocation define_derive_deftly
isn't scoped; it's just matched by identifier precisely.
Proposed syntax (reusable modules)
define_derive_deftly_module! { Castable = ${define CASTABLE { impl ... } } }
define_derive_deftly! { Castable use Castable = $CASTABLE }
define_derive_deftly! {
Object use Castable =
$CASTABLE
impl Object ...
}
${define}/${defcond}
Meta attr and unused We want meta attr checking to be precise. If we simply prepend the $define
s to each template, that template will accept even attrs tested by $define
s that that template didn't use.
I propose the following semantics:
We scan each template fragment ($define
s and define_derive_deftly
s) for references to the shared definitions. This is done lexically. This generates a digraph, whose roots are the define_derive_deftly
s.
We then prepend to each output template definition the transitive closure. So it will have precisely the $define
s that it uses (or might use - again, this is done lexically).
Or to put it another way, we elide the $define
s that are statically unreachable. This (statically and lexically) is how meta attr checking works. It's not detectable at expansion time because you can't refer to the $define
without causing it to appear.
With module-style reuse, this must be done per define_derive_deftly!