Metaprogramming
Body-generating rules — generates and replace
A generates body of rule replaces a method's body outright and discards the original, for stubs whose body is machine-filled.
since 0.1.0-alpha.1linuxwindowswasm
Description
generates body of <bind> is the sibling of rewrites. It overwrites the target's body wholesale and
discards the original, for a rule whose point is that there is no original to compose with: a binding
stub, a foreign-function shim, a codec, any "declare the signature, machine-fill the body" generator. The
signature and the data that drives generation, such as an @Extern-shaped attribute, sit on the
hand-written declaration, and only the body is generated.
rule name generates body of m {
match @Attr(a) on method m
replace `<template>`
}
Here every @Extern method forwards to a host object through its operation name. The placeholder body
=> "" is thrown away and never runs:
Generating a body
namespace Bindgen {
attribute Extern { string op; }
rule bindStr generates body of m {
match @Extern(e) on method m
replace `return host.call($e.op, $_args);`
}
}
uses Bindgen;
class Host {
string call(string op, string arg) => op + "(" + arg + ")";
}
class Widget {
Host host = Host();
@Extern("getAttribute")
string attr(string name) => "";
}
console.writeln(Widget().attr("id"));
getAttribute(id)
$_args forwards the matched method's own parameters, so host.call($e.op, $_args) passes name through
without writing the parameter list again.
Rules
- The header is
rule name generates body of m { match … replace<template>}. As withrewrites, the rule usesreplace, notinject, and the matched bind must be a method or function. $bodyis unavailable in ageneratestemplate. Naming it is a compile error that says the original body is discarded and suggestsrewrites. This is the opt-in counterpart of therewritesrule that a template must keep its$bodyexactly once:generatesmakes the drop explicit in the rule header.$_argsforwards the matched method's parameters verbatim. A hand-written family of overloaded helpers can then place each argument by its type, so ageneratestemplate needs no branching even when different call shapes need different handling.- A declaration whose body is missing, such as
string attr(string name);, is accepted as the target, and the rule supplies the body. A placeholder body is equally fine. - Everything else about
rewritesapplies unchanged: the matched bind must be callable, two whole-body replacements on one body do not compose,reentrantworks, and rewriters and generators run after all additiveinjectrules.
Examples
The method may be declared without any body at all:
A declaration with no body
namespace Bindgen {
attribute Constant { int value; }
rule constant generates body of m {
match @Constant(c) on method m
replace `return $c.value;`
}
}
uses Bindgen;
class Limits {
@Constant(64) int maxItems();
@Constant(8) int maxDepth() => 0;
}
Limits l = Limits();
console.writeln(l.maxItems());
console.writeln(l.maxDepth());
64
8
Notes
- A rule's trigger attribute should be your own. Attributes whose names begin with two underscores are reserved for the standard library's own rules, so a user attribute never collides with them.
See also
- Body-replacing rules — rewrites, replace and $body — A
rewrites body ofrule replaces a method's body with a template that splices the original back in with$body. - Rules — match a shape, inject code — A rule matches declarations by shape and injects quasiquoted code at a named anchor, with
match,where, andinject … at. - Quasiquote templates and holes — Backtick-delimited templates hold the code a rule injects, and
$holes fill them from the match. - Splices — $for, $if, $ident and friends — Repeat, choose and name pieces of a template at expansion time with
$for,$if,$ident(...), composite identifiers and$_params. - Compile-time metaprogramming — A map of the four compile-time layers, procedural macros, and the
--expandflag that shows what a rule produced.