diff options
author | David Tolnay <dtolnay@gmail.com> | 2020-08-29 22:05:53 -0700 |
---|---|---|
committer | David Tolnay <dtolnay@gmail.com> | 2020-08-29 22:14:22 -0700 |
commit | 5fc28551e180471b822f47b295a76fa2d02bf649 (patch) | |
tree | b7a43e3586cdb01c7285aeb58ac0201c18a95b73 /gen/src/mod.rs | |
parent | a593d6e867ee66f28a4704257bc15a782df25979 (diff) | |
parent | e1e12220dacb76fe45e79fa74706a3e09bbbe402 (diff) | |
download | cxx-5fc28551e180471b822f47b295a76fa2d02bf649.tar.gz |
Merge pull request 258 from adetaylor/cxx-embedding-lib
Diffstat (limited to 'gen/src/mod.rs')
-rw-r--r-- | gen/src/mod.rs | 72 |
1 files changed, 61 insertions, 11 deletions
diff --git a/gen/src/mod.rs b/gen/src/mod.rs index 68c6f857..a939760b 100644 --- a/gen/src/mod.rs +++ b/gen/src/mod.rs @@ -10,15 +10,19 @@ mod write; #[cfg(test)] mod tests; -use self::error::{format_err, Error, Result}; +use self::error::format_err; +pub use self::error::{Error, Result}; use self::file::File; use crate::syntax::report::Errors; use crate::syntax::{self, check, Types}; +use proc_macro2::TokenStream; +use std::clone::Clone; use std::fs; use std::path::Path; -#[derive(Default)] -pub(super) struct Opt { +/// Options for C++ code generation. +#[derive(Default, Clone)] +pub struct Opt { /// Any additional headers to #include pub include: Vec<String>, /// Whether to set __attribute__((visibility("default"))) @@ -26,6 +30,14 @@ pub(super) struct Opt { pub cxx_impl_annotations: Option<String>, } +/// Results of code generation. +pub struct GeneratedCode { + /// The bytes of a C++ header file. + pub header: Vec<u8>, + /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.) + pub cxx: Vec<u8>, +} + pub(super) fn do_generate_bridge(path: &Path, opt: Opt) -> Vec<u8> { let header = false; generate_from_path(path, opt, header) @@ -36,26 +48,52 @@ pub(super) fn do_generate_header(path: &Path, opt: Opt) -> Vec<u8> { generate_from_path(path, opt, header) } +pub(super) fn do_generate_from_tokens( + tokens: TokenStream, + opt: Opt, +) -> std::result::Result<GeneratedCode, Error> { + let syntax = syn::parse2::<File>(tokens)?; + match generate(syntax, opt, true, true) { + Ok((Some(header), Some(cxx))) => Ok(GeneratedCode { header, cxx }), + Err(err) => Err(err), + _ => panic!("Unexpected generation"), + } +} + fn generate_from_path(path: &Path, opt: Opt, header: bool) -> Vec<u8> { let source = match fs::read_to_string(path) { Ok(source) => source, Err(err) => format_err(path, "", Error::Io(err)), }; - let mut source = source.as_str(); + match generate_from_string(&source, opt, header) { + Ok(out) => out, + Err(err) => format_err(path, &source, err), + } +} + +fn generate_from_string(source: &str, opt: Opt, header: bool) -> Result<Vec<u8>> { + let mut source = source; if source.starts_with("#!") && !source.starts_with("#![") { let shebang_end = source.find('\n').unwrap_or(source.len()); source = &source[shebang_end..]; } - match generate(source, opt, header) { - Ok(out) => out, - Err(err) => format_err(path, source, err), + let syntax: File = syn::parse_str(source)?; + let results = generate(syntax, opt, header, !header)?; + match results { + (Some(hdr), None) => Ok(hdr), + (None, Some(cxx)) => Ok(cxx), + _ => panic!("Unexpected generation"), } } -fn generate(source: &str, opt: Opt, header: bool) -> Result<Vec<u8>> { +fn generate( + syntax: File, + opt: Opt, + gen_header: bool, + gen_cxx: bool, +) -> Result<(Option<Vec<u8>>, Option<Vec<u8>>)> { proc_macro2::fallback::force(); let ref mut errors = Errors::new(); - let syntax: File = syn::parse_str(source)?; let bridge = syntax .modules .into_iter() @@ -68,6 +106,18 @@ fn generate(source: &str, opt: Opt, header: bool) -> Result<Vec<u8>> { errors.propagate()?; check::typecheck(errors, namespace, apis, types); errors.propagate()?; - let out = write::gen(namespace, apis, types, opt, header); - Ok(out.content()) + // Some callers may wish to generate both header and C++ + // from the same token stream to avoid parsing twice. But others + // only need to generate one or the other. + let hdr = if gen_header { + Some(write::gen(namespace, apis, types, opt.clone(), true).content()) + } else { + None + }; + let cxx = if gen_cxx { + Some(write::gen(namespace, apis, types, opt, false).content()) + } else { + None + }; + Ok((hdr, cxx)) } |