commit | 8a19e6d8b9b4c63b223381fc68321305d8fee2d8 | [log] [tgz] |
---|---|---|
author | David Tolnay <dtolnay@gmail.com> | Mon Oct 24 01:23:40 2016 -0700 |
committer | David Tolnay <dtolnay@gmail.com> | Mon Oct 24 01:23:40 2016 -0700 |
tree | 8993884b8aa750bec789240edfb37b2b65cb5590 | |
parent | 24b5ff7062058bb46133ae92fec8badc8837bf9c [diff] |
Hex, octal, binary integer literals
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.9" quote = "0.3" [lib] proc-macro = true
#![feature(proc_macro, proc_macro_lib)] extern crate proc_macro; use proc_macro::TokenStream; extern crate syn; #[macro_use] extern crate quote; #[proc_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(proc_macro, proc_macro_lib)] extern crate proc_macro; use proc_macro::TokenStream; extern crate syn; #[macro_use] extern crate quote; #[proc_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.