From efcf9da3798dddc5168a1b2f7efb6f8001e2e1d0 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 20 Jun 2018 10:20:09 +0200 Subject: [PATCH] Allow the use of the cpp! and cpp_class! macro within other macro The cpp! and cpp_class! macro still need to be verbatim in the source code, and cannot be generated by the macro_rules. But if they are present as it within other macro, cpp_build will now generate the code for them. https://github.com/mystor/rust-cpp/issues/19 --- cpp_build/src/lib.rs | 101 +++++++++++++++++++++++++++++-------------- test/src/lib.rs | 7 +++ 2 files changed, 76 insertions(+), 32 deletions(-) diff --git a/cpp_build/src/lib.rs b/cpp_build/src/lib.rs index 1e1ba25..928d99a 100644 --- a/cpp_build/src/lib.rs +++ b/cpp_build/src/lib.rs @@ -22,7 +22,7 @@ use std::path::{Path, PathBuf}; use std::fs::{create_dir, remove_dir_all, File}; use std::io::prelude::*; use syn::visit::Visitor; -use syn::{Mac, Span, Spanned, DUMMY_SPAN}; +use syn::{Mac, Spanned, DUMMY_SPAN, Ident, Token, TokenTree}; use cpp_common::{parsing, Capture, Closure, ClosureSig, Macro, Class, LIB_NAME, STRUCT_METADATA_MAGIC, VERSION, flags}; use cpp_synmap::SourceMap; @@ -745,40 +745,77 @@ impl<'a> Visitor for Handle<'a> { return; } if mac.path.segments[0].ident.as_ref() == "cpp" { - let tts = &mac.tts; - assert!(tts.len() >= 1); - let span = Span { - lo: tts[0].span().lo, - hi: tts[tts.len() - 1].span().hi, - }; - let src = self.sm.source_text(span).unwrap(); - let input = synom::ParseState::new(&src); - match parsing::build_macro(input).expect(&format!("cpp! macro at {}", self.sm.locinfo(span).unwrap())) { - Macro::Closure(mut c) => { - extract_with_span(&mut c.body, &src, span.lo, self.sm); - self.closures.push(c); + assert!(mac.tts.len() == 1); + self.handle_cpp(&mac.tts[0]); + } else if mac.path.segments[0].ident.as_ref() == "cpp_class" { + assert!(mac.tts.len() == 1); + self.handle_cpp_class(&mac.tts[0]); + } else { + self.parse_macro(&mac.tts); + } + } +} + +impl<'a> Handle<'a> { + fn handle_cpp(&mut self, tt: &TokenTree) { + let span = tt.span(); + let src = self.sm.source_text(span).unwrap(); + let input = synom::ParseState::new(&src); + match parsing::build_macro(input) + .expect(&format!("cpp! macro at {}", self.sm.locinfo(span).unwrap())) + { + Macro::Closure(mut c) => { + extract_with_span(&mut c.body, &src, span.lo, self.sm); + self.closures.push(c); + } + Macro::Lit(mut l) => { + extract_with_span(&mut l, &src, span.lo, self.sm); + self.snippets.push('\n'); + let (snip, extern_decl) = expand_sub_rust_macro(l.node.clone()); + self.snippets.push_str(&extern_decl); + self.snippets.push_str(&snip); + } + } + } + + fn handle_cpp_class(&mut self, tt: &TokenTree) { + let span = tt.span(); + let src = self.sm.source_text(span).unwrap(); + let input = synom::ParseState::new(&src); + let mut class = parsing::class_macro(input).expect(&format!( + "cpp_class! macro at {}", + self.sm.locinfo(span).unwrap() + )); + class.line = line_directive(span, self.sm); + self.classes.push(class); + } + + fn parse_macro(&mut self, tts: &Vec) { + let mut last_ident: Option<&Ident> = None; + let mut is_macro = false; + for t in tts { + match t { + TokenTree::Token(Token::Not, _) => is_macro = true, + TokenTree::Token(Token::Ident(ref i), _) => { + is_macro = false; + last_ident = Some(&i); } - Macro::Lit(mut l) => { - extract_with_span(&mut l, &src, span.lo, self.sm); - self.snippets.push('\n'); - let (snip, extern_decl) = expand_sub_rust_macro(l.node.clone()); - self.snippets.push_str(&extern_decl); - self.snippets.push_str(&snip); + TokenTree::Delimited(ref d, _) => { + if is_macro && last_ident.map_or(false, |i| i.as_ref() == "cpp") { + self.handle_cpp(&t) + } else if is_macro && last_ident.map_or(false, |i| i.as_ref() == "cpp_class") { + self.handle_cpp_class(&t) + } else { + self.parse_macro(&d.tts) + } + is_macro = false; + last_ident = None; + } + _ => { + is_macro = false; + last_ident = None; } } } - if mac.path.segments[0].ident.as_ref() == "cpp_class" { - let tts = &mac.tts; - assert!(tts.len() >= 1); - let span = Span { - lo: tts[0].span().lo, - hi: tts[tts.len() - 1].span().hi, - }; - let src = self.sm.source_text(span).unwrap(); - let input = synom::ParseState::new(&src); - let mut class = parsing::class_macro(input).expect(&format!("cpp_class! macro at {}", self.sm.locinfo(span).unwrap())); - class.line = line_directive(span, self.sm); - self.classes.push(class); - } } } diff --git a/test/src/lib.rs b/test/src/lib.rs index e93b8e9..0f6a05f 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -330,3 +330,10 @@ fn rust_submacro_trait() { })}; assert_eq!(i, 123 + 333); } + +#[test] +fn witin_macro() { + assert_eq!(unsafe { cpp!([] -> u32 as "int" { return 12; }) }, 12); + let s = format!("hello{}", unsafe { cpp!([] -> u32 as "int" { return 14; }) } ); + assert_eq!(s, "hello14"); +}