5

I'm trying to build a syntax extension that expands an attribute into calls. Before:

#[flame]
fn flamed() {
    ..
}

After:

fn flamed() {
    flame::start_guard("flamed");
    ..
}

This already works. However, I'd also like it to work if I have the #[flame] attribute at the crate level (like #![flame]). Is this possible and if so, how?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
llogiq
  • 13,815
  • 8
  • 40
  • 72
  • What exactly do you expect the crate attribute to do? Insert the call into every function of the crate? – Lukas Kalbertodt May 11 '16 at 22:34
  • 2
    Did you try catching `ItemKind::Mod` in https://github.com/llogiq/flamer/blob/f4828cc91768109fa66f8cbbe57a285c0477c436/src/lib.rs#L29 and iterating over its contents (recursively)? – huon May 12 '16 at 03:36
  • @Lukas Kalbertodt: exactly. – llogiq May 12 '16 at 03:49
  • @huon: No I didn't try that, because I thought it would walk automatically. – llogiq May 12 '16 at 03:50
  • 2
    The compiler walks the AST to find all the things with syntax extension attributes, and passes each annotated one into the syntax extension, but doesn't do anything automatically for the children (unless those children have attributes, of course). If the syntax extension wants to handle children without attributes on each one, it has to do the walking itself. – huon May 12 '16 at 04:53

1 Answers1

2

@huon's comment

Did you try catching ItemKind::Mod in github.com/llogiq/flamer/blob/… and iterating over its contents (recursively)?

was spot on – I just added a commit that handles mod and trait items by walking them. I'll also probably add code to walk functions to handle inner items and fns.

The code looks like this:

fn flame_item(i: &Item) -> Item {
    let base = i.clone();
    Item {
        node: match i.node {
            ItemKind::Mod(ref m) =>
                ItemKind::Mod(flame_mod(m)),
            ItemKind::Trait(unsafety, ref generic, ref bounds, ref tis) =>
                ItemKind::Trait(unsafety,
                                generic.clone(),
                                bounds.clone(),
                                flame_items(tis)),
        .. // other item types as usual: items, traitimpls, implitems

            _ => return base
        },
        ..base
    }
}

fn flame_mod(m: &Mod) -> Mod {
    Mod {
        inner: m.inner,
        items: m.items.iter().map(|i| P(flame_item(i))).collect()
    }
}

fn flame_items(items: &[TraitItem]) -> Vec<TraitItem> {
    items.iter().map(flame_trait_item).collect()
}
llogiq
  • 13,815
  • 8
  • 40
  • 72