Rust – il linguaggio – 40

12096619

Ancora macro, continuo da qui e oggi sono qui: /usr/local/share/doc/rust/html/book/macros.html#recursive-macros.

Macros ricorsive

A macro’s expansion can include more macro invocations, including invocations of the very same macro being expanded. These recursive macros are useful for processing tree-structured input, as illustrated by this (simplistic) HTML shorthand:

#![allow(unused_must_use)]
macro_rules! write_html {
    ($w:expr, ) => (());

    ($w:expr, $e:tt) => (write!($w, "{}", $e));

    ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{
        writeln!($w, "<{}>", stringify!($tag));
        write_html!($w, $($inner)*);
        write!($w, "", stringify!($tag));
        write_html!($w, $($rest)*);
    }};
}

fn main() {
  // FIXME(#21826)
    use std::fmt::Write;
    let mut out = String::new();

    write_html!(&mut out,
        html[
            head[title["Macros guide"]]
            body[h1["Macros are the best!"]]
        ]);

    println!("{}", out);
}

rs40-11

Ho fatto una piccola modifica con grande effetto: sostituito il primo write! con writeln! 😀

Debug del codice delle macros

To see the results of expanding macros, run rustc --pretty expanded. The output represents a whole crate, so you can also feed it back in to rustc, which will sometimes produce better error messages than the original compilation. Note that the --pretty expanded output may have a different meaning if multiple variables of the same name (but different syntax contexts) are in play in the same scope. In this case --pretty expanded, hygiene will tell you about the syntax contexts.

rs40-12

Questa è solo la parte iniziale dell’output che poi continua con righe molto indentate, eccone un pezzettino:

#![feature(prelude_import)]
#![no_std]
#![allow(unused_must_use)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std as std;



fn main() {
    // FIXME(#21826)
    use std::fmt::Write;
    let mut out = String::new();
    {



        &mut out.write_fmt(::std::fmt::Arguments::new_v1({
                                                             static __STATIC_FMTSTR:
                                                                    &'static [&'static str]
                                                                    =
                                                                 &["<", ">\n"];
                                                             __STATIC_FMTSTR
                                                         },
                                                         &match (&"html",) {
                                                              (__arg0,) =>
                                                              [::std::fmt::ArgumentV1::new(__arg0,
                                                                                           ::std::fmt::Display::fmt)],
                                                          }));
        {
            &mut out.write_fmt(::std::fmt::Arguments::new_v1({
                                                                 static __STATIC_FMTSTR:
                                                                        &'static [&'static str]

Paura? 😉

rustc provides two syntax extensions that help with macro debugging. For now, they are unstable and require feature gates.

  • log_syntax!(...) will print its arguments to standard output, at compile time, and “expand” to nothing.
  • trace_macros!(true) will enable a compiler message every time a macro is expanded. Use trace_macros!(false) later in expansion to turn it off.

Requisiti sintattici

Even when Rust code contains un-expanded macros, Non copio il paragrafo, troppo specifico. Se ricordo bene dallo scorso millennio il debug è una specializzazione (o una punizione) 😉

Visibilità e import/export delle macros

Macros are expanded at an early stage in compilation, before name resolution. One downside is that scoping works differently for macros, compared to other constructs in the language.

Definition and expansion of macros both happen in a single depth-first, lexical-order traversal of a crate’s source. So a macro defined at module scope is visible to any subsequent code in the same module, which includes the body of any subsequent child mod items.

A macro defined within the body of a single fn, or anywhere else not at module scope, is visible only within that item.

If a module has the macro_use attribute, its macros are also visible in its parent module after the child’s mod item. If the parent also has macro_use then the macros will be visible in the grandparent after the parent’s mod item, and so forth.

The macro_use attribute can also appear on extern crate. In this context it controls which macros are loaded from the external crate, e.g.

#[macro_use(foo, bar)]
extern crate baz;

If the attribute is given simply as #[macro_use], all macros are loaded. If there is no #[macro_use] attribute then no macros are loaded. Only macros defined with the #[macro_export] attribute may be loaded.

To load a crate’s macros without linking it into the output, use #[no_link] as well.

An example:

macro_rules! m1 { () => (()) }

// visible here: m1

mod foo {
    // visible here: m1

    #[macro_export]
    macro_rules! m2 { () => (()) }

    // visible here: m1, m2
}

// visible here: m1

macro_rules! m3 { () => (()) }

// visible here: m1, m3

#[macro_use]
mod bar {
    // visible here: m1, m3

    macro_rules! m4 { () => (()) }

    // visible here: m1, m3, m4
}

// visible here: m1, m3, m4
fn main() { }

When this library is loaded with #[macro_use] extern crate, only m2 will be imported.

The Rust Reference has a listing of macro-related attributes [/usr/local/share/doc/rust/html/reference.html#macro-related-attributes].

😦 dai, ci siamo quasi 😉

:mrgreen:

Posta un commento o usa questo indirizzo per il trackback.

Trackback

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: