extendr / rextendr

An R package that helps scaffolding extendr-enabled packages or compiling Rust code dynamically
https://extendr.github.io/rextendr/
Other
174 stars 25 forks source link

Cannot use `extendrsrc` with a macro that contains `#[extendr]` #350

Open JosiahParry opened 2 months ago

JosiahParry commented 2 months ago
```{extendrsrc macro}
macro_rules! make_heck_fn {
    ($fn_name:ident) => {
        #[extendr]
        /// @export
        fn $fn_name(x: Strings) -> Strings {
            x.into_iter()
                .map(|xi| match xi.is_na() {
                    true => Rstr::na(),
                    false => Rstr::from(xi.as_str().$fn_name()),
                })
                .collect::<Strings>()
        }
    };
}

Error in purrr::map2(): ℹ In index: 1. Caused by error in extract_meta(): ! Rust code contains invalid attribute macros. • ✖ No valid fn or impl block found in the following sample: • #[extendr] • fn $fn_name(x: Strings) -> Strings { •
Backtrace:

  1. global .main()
  2. execute(...)
  3. rmarkdown::render(...)
  4. knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
  5. knitr:::process_file(text, output) ... at rextendr/R/make_module_macro.R:22:3
    1. purrr::map2(start, end, ~extract_meta(clean_lns[.x:.y]))
    2. purrr:::map2_("list", .x, .y, .f, ..., .progress = .progress)
    3. rextendr (local) .f(.x[[i]], .y[[i]], ...)
    4. rextendr:::extract_meta(clean_lns[.x:.y])

Execution halted

Ilia-Kosenkov commented 2 months ago

~It should not work like this if I am not mistaken, the contents of extendrsrc go into a generated rust function.~

It could also be that it does not understand macros (which is definitely on another level).

JosiahParry commented 2 months ago

Its worth noting that it does compile the macro iff #[extendr] is not present and it can even be called later down (pretty neat)!

Ilia-Kosenkov commented 2 months ago

Ok I get it. The issue here is two-fold. We generate exports based on simple scanning for #[extendr] attribute. Here we find it in the macros. We do not do macros expansion so it captures macros declaration verbatim, which is garbage in this case (because of function name interpolation). We can solve it as follows: