commit | 438c905863cc901b2893afc1794361bb9709be23 | [log] [tgz] |
---|---|---|
author | David Tolnay <dtolnay@gmail.com> | Fri Oct 07 23:24:48 2016 -0700 |
committer | David Tolnay <dtolnay@gmail.com> | Fri Oct 07 23:24:48 2016 -0700 |
tree | 62544ac24d8ef461c977b3499983f0f92cfdbd52 | |
parent | 19f9bdc01f61163bb8525c64e689649a340f69ed [diff] |
Parsing of remaining expression types
Parse Rust structs and enums without a Syntex dependency, intended for use with Macros 1.1.
Designed for fast compile time.
syn
(from scratch including all dependencies): 4 secondssyntex
/quasi
/aster
stack: 60+ seconds[dependencies] syn = "0.8" quote = "0.2" [lib] rustc-macro = true
#![feature(rustc_macro, rustc_macro_lib)] extern crate rustc_macro; use rustc_macro::TokenStream; extern crate syn; #[macro_use] extern crate quote; #[rustc_macro_derive(MyMacro)] pub fn my_macro(input: TokenStream) -> TokenStream { let source = input.to_string(); // Parse the string representation to an AST let ast = syn::parse_macro_input(&source).unwrap(); // Build the output, possibly using quasi-quotation let expanded = quote! { // ... }; // Parse back to a token stream and return it expanded.to_string().parse().unwrap() }
Suppose we have the following simple trait which returns the number of fields in a struct:
trait NumFields { fn num_fields() -> usize; }
A complete Macros 1.1 implementation of #[derive(NumFields)]
based on syn
and quote
looks like this:
#![feature(rustc_macro, rustc_macro_lib)] extern crate rustc_macro; use rustc_macro::TokenStream; extern crate syn; #[macro_use] extern crate quote; #[rustc_macro_derive(NumFields)] pub fn num_fields(input: TokenStream) -> TokenStream { let source = input.to_string(); // Parse the string representation to an AST let ast = syn::parse_macro_input(&source).unwrap(); // Build the output let expanded = expand_num_fields(ast); // Parse back to a token stream and return it expanded.to_string().parse().unwrap() } fn expand_num_fields(ast: syn::MacroInput) -> quote::Tokens { let n = match ast.body { syn::Body::Struct(ref data) => data.fields().len(), syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"), }; // Used in the quasi-quotation below as `#name` let name = &ast.ident; // Helper is provided for handling complex generic types correctly and effortlessly let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); quote! { // Preserve the input struct unmodified #ast // The generated impl impl #impl_generics ::mycrate::NumFields for #name #ty_generics #where_clause { fn num_fields() -> usize { #n } } } }
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.