Macro wast::annotation
source · macro_rules! annotation { ($name:ident) => { ... }; ($name:ident = $annotation:expr) => { ... }; }
Expand description
A macro, like custom_keyword
, to create a type which can be used to
parse/peek annotation directives.
Note that when you’re parsing custom annotations it can be somewhat tricky
due to the nature that most of them are skipped. You’ll want to be sure to
consult the documentation of Parser::register_annotation
when
using this macro.
§Examples
To see an example of how to use this macro, let’s invent our own syntax for the producers section which looks like:
(@producer "wat" "1.0.2")
Here, for simplicity, we’ll assume everything is a processed-by
directive,
but you could get much more fancy with this as well.
// First we define the custom annotation keyword we're using, and by
// convention we define it in an `annotation` module.
mod annotation {
wast::annotation!(producer);
}
struct Producer<'a> {
name: &'a str,
version: &'a str,
}
impl<'a> Parse<'a> for Producer<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// Remember that parser conventionally parse the *interior* of an
// s-expression, so we parse our `@producer` annotation and then we
// parse the payload of our annotation.
parser.parse::<annotation::producer>()?;
Ok(Producer {
name: parser.parse()?,
version: parser.parse()?,
})
}
}
Note though that this is only half of the parser for annotations. The other
half is calling the register_annotation
method at the right
time to ensure the parser doesn’t automatically skip our @producer
directive. Note that we can’t call it inside the Parse for Producer
definition because that’s too late and the annotation would already have
been skipped.
Instead we’ll need to call it from a higher level-parser before the parenthesis have been parsed, like so:
struct Module<'a> {
fields: Vec<ModuleField<'a>>,
}
impl<'a> Parse<'a> for Module<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// .. parse module header here ...
// register our custom `@producer` annotation before we start
// parsing the parentheses of each field
let _r = parser.register_annotation("producer");
let mut fields = Vec::new();
while !parser.is_empty() {
fields.push(parser.parens(|p| p.parse())?);
}
Ok(Module { fields })
}
}
enum ModuleField<'a> {
Producer(Producer<'a>),
// ...
}
impl<'a> Parse<'a> for ModuleField<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// and here `peek` works and our delegated parsing works because the
// annotation has been registered.
if parser.peek::<annotation::producer>()? {
return Ok(ModuleField::Producer(parser.parse()?));
}
// .. typically we'd parse other module fields here...
Err(parser.error("unknown module field"))
}
}