1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
mod error;
mod file;
pub(super) mod include;
pub(super) mod out;
mod write;
#[cfg(test)]
mod tests;
pub(super) use self::error::Error;
use self::error::{format_err, Result};
use self::file::File;
use crate::syntax::report::Errors;
use crate::syntax::{self, check, Types};
use std::fs;
use std::path::Path;
#[non_exhaustive]
pub struct Opt {
pub include: Vec<String>,
pub cxx_impl_annotations: Option<String>,
pub(super) gen_header: bool,
pub(super) gen_implementation: bool,
}
pub struct GeneratedCode {
pub header: Vec<u8>,
pub implementation: Vec<u8>,
}
impl Default for Opt {
fn default() -> Self {
Opt {
include: Vec::new(),
cxx_impl_annotations: None,
gen_header: true,
gen_implementation: true,
}
}
}
pub(super) fn generate_from_path(path: &Path, opt: &Opt) -> GeneratedCode {
let source = match fs::read_to_string(path) {
Ok(source) => source,
Err(err) => format_err(path, "", Error::Io(err)),
};
match generate_from_string(&source, opt) {
Ok(out) => out,
Err(err) => format_err(path, &source, err),
}
}
fn generate_from_string(source: &str, opt: &Opt) -> Result<GeneratedCode> {
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..];
}
let syntax: File = syn::parse_str(source)?;
generate(syntax, opt)
}
pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
proc_macro2::fallback::force();
let ref mut errors = Errors::new();
let bridge = syntax
.modules
.into_iter()
.next()
.ok_or(Error::NoBridgeMod)?;
let ref namespace = bridge.namespace;
let trusted = bridge.unsafety.is_some();
let ref apis = syntax::parse_items(errors, bridge.content, trusted);
let ref types = Types::collect(errors, apis);
errors.propagate()?;
check::typecheck(errors, namespace, apis, types);
errors.propagate()?;
Ok(GeneratedCode {
header: if opt.gen_header {
write::gen(namespace, apis, types, opt, true).content()
} else {
Vec::new()
},
implementation: if opt.gen_implementation {
write::gen(namespace, apis, types, opt, false).content()
} else {
Vec::new()
},
})
}