blob: acc766903fe05e95af6c5b386371cc3c96c91a1f [file] [log] [blame]
David Tolnayb4dba232020-05-11 00:55:29 -07001// Functionality that is shared between the cxx_build::bridge entry point and
2// the cxxbridge CLI command.
David Tolnay7db73692019-10-20 14:51:12 -04003
4mod error;
David Tolnay2967b662020-05-11 00:53:06 -07005mod find;
David Tolnay7db73692019-10-20 14:51:12 -04006pub(super) mod include;
7pub(super) mod out;
8mod write;
9
David Tolnay0d47a532020-07-30 19:39:04 -070010#[cfg(test)]
11mod tests;
12
Adrian Taylor9fc08462020-08-14 10:51:00 -070013use self::error::format_err;
14pub use self::error::{Error, Result};
David Tolnay08419302020-04-19 20:38:20 -070015use crate::syntax::namespace::Namespace;
David Tolnay0dd85ff2020-05-03 23:43:33 -070016use crate::syntax::report::Errors;
David Tolnayb6cf3142020-04-19 20:56:09 -070017use crate::syntax::{self, check, Types};
Adrian Taylor9fc08462020-08-14 10:51:00 -070018use proc_macro2::TokenStream;
19use std::clone::Clone;
David Tolnay7db73692019-10-20 14:51:12 -040020use std::fs;
David Tolnay7db73692019-10-20 14:51:12 -040021use std::path::Path;
Adrian Taylor9fc08462020-08-14 10:51:00 -070022use syn::{File, Item};
David Tolnay7db73692019-10-20 14:51:12 -040023
24struct Input {
David Tolnay754e21c2020-03-29 20:58:46 -070025 namespace: Namespace,
David Tolnay7db73692019-10-20 14:51:12 -040026 module: Vec<Item>,
27}
28
Adrian Taylor9fc08462020-08-14 10:51:00 -070029#[derive(Default, Clone)]
David Tolnay33d30292020-03-18 18:02:02 -070030pub(super) struct Opt {
31 /// Any additional headers to #include
32 pub include: Vec<String>,
Adrian Taylor21f0ff02020-07-21 16:21:48 -070033 /// Whether to set __attribute__((visibility("default")))
34 /// or similar annotations on function implementations.
35 pub cxx_impl_annotations: Option<String>,
David Tolnay33d30292020-03-18 18:02:02 -070036}
37
Adrian Taylor9fc08462020-08-14 10:51:00 -070038/// Results of code generation.
39pub struct GeneratedCode {
40 /// The bytes of a C++ header file.
41 pub header: Vec<u8>,
42 /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
43 pub cxx: Vec<u8>,
44}
45
David Tolnay7ece56f2020-03-29 21:21:38 -070046pub(super) fn do_generate_bridge(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040047 let header = false;
Adrian Taylor8205e622020-07-21 21:53:59 -070048 generate_from_path(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040049}
50
David Tolnay7ece56f2020-03-29 21:21:38 -070051pub(super) fn do_generate_header(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040052 let header = true;
Adrian Taylor8205e622020-07-21 21:53:59 -070053 generate_from_path(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040054}
55
Adrian Taylor9fc08462020-08-14 10:51:00 -070056pub(super) fn do_generate_from_tokens(
57 tokens: TokenStream,
58 opt: Opt,
59) -> std::result::Result<GeneratedCode, Error> {
60 let syntax = syn::parse2::<File>(tokens)?;
61 match generate(syntax, opt, true, true) {
62 Ok((Some(header), Some(cxx))) => Ok(GeneratedCode { header, cxx } ),
63 Err(err) => Err(err),
64 _ => panic!("Unexpected generation"),
65 }
66}
67
Adrian Taylor8205e622020-07-21 21:53:59 -070068fn generate_from_path(path: &Path, opt: Opt, header: bool) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040069 let source = match fs::read_to_string(path) {
70 Ok(source) => source,
71 Err(err) => format_err(path, "", Error::Io(err)),
72 };
Adrian Taylor9fc08462020-08-14 10:51:00 -070073 let syntax = match syn::parse_file(&source) {
Adrian Taylor8205e622020-07-21 21:53:59 -070074 Ok(out) => out,
Adrian Taylor9fc08462020-08-14 10:51:00 -070075 Err(err) => format_err(path, "", Error::Syn(err)),
76 };
77 match generate(syntax, opt, header, !header) {
78 Ok((Some(hdr), None)) => hdr,
79 Ok((None, Some(cxx))) => cxx,
David Tolnay7db73692019-10-20 14:51:12 -040080 Err(err) => format_err(path, &source, err),
Adrian Taylor9fc08462020-08-14 10:51:00 -070081 _ => panic!("Unexpected generation"),
David Tolnay7db73692019-10-20 14:51:12 -040082 }
83}
Adrian Taylor8205e622020-07-21 21:53:59 -070084
Adrian Taylor9fc08462020-08-14 10:51:00 -070085fn generate(
86 syntax: File,
87 opt: Opt,
88 gen_header: bool,
89 gen_cxx: bool,
90) -> Result<(Option<Vec<u8>>, Option<Vec<u8>>)> {
Adrian Taylor8205e622020-07-21 21:53:59 -070091 proc_macro2::fallback::force();
92 let ref mut errors = Errors::new();
Adrian Taylor8205e622020-07-21 21:53:59 -070093 let bridge = find::find_bridge_mod(syntax)?;
94 let ref namespace = bridge.namespace;
95 let ref apis = syntax::parse_items(errors, bridge.module);
96 let ref types = Types::collect(errors, apis);
97 errors.propagate()?;
98 check::typecheck(errors, namespace, apis, types);
99 errors.propagate()?;
Adrian Taylor9fc08462020-08-14 10:51:00 -0700100 // Some callers may wish to generate both header and C++
101 // from the same token stream to avoid parsing twice. But others
102 // only need to generate one or the other.
103 let hdr = if gen_header {
104 Some(write::gen(namespace, apis, types, opt.clone(), true).content())
105 } else {
106 None
107 };
108 let cxx = if gen_cxx {
109 Some(write::gen(namespace, apis, types, opt, false).content())
110 } else {
111 None
112 };
113 Ok((hdr, cxx))
Adrian Taylor8205e622020-07-21 21:53:59 -0700114}