1mod block;
5mod builtin;
6mod cfg;
7mod check;
8pub(super) mod error;
9mod file;
10pub(super) mod fs;
11mod guard;
12mod ifndef;
13pub(super) mod include;
14mod names;
15mod namespace;
16mod nested;
17pub(super) mod out;
18mod pragma;
19mod write;
20
21use self::cfg::UnsupportedCfgEvaluator;
22use self::error::{format_err, Result};
23use self::file::File;
24use self::include::Include;
25use crate::syntax::cfg::CfgExpr;
26use crate::syntax::report::Errors;
27use crate::syntax::{self, attrs, Types};
28use std::collections::BTreeSet as Set;
29use std::path::Path;
30
31pub(super) use self::error::Error;
32
33#[non_exhaustive]
48pub struct Opt {
49 pub include: Vec<Include>,
53 pub cxx_impl_annotations: Option<String>,
59 pub cfg_evaluator: Box<dyn CfgEvaluator>,
61
62 pub(super) gen_header: bool,
63 pub(super) gen_implementation: bool,
64 pub(super) allow_dot_includes: bool,
65 pub(super) doxygen: bool,
66}
67
68pub trait CfgEvaluator {
71 fn eval(&self, name: &str, value: Option<&str>) -> CfgResult;
74}
75
76pub enum CfgResult {
78 True,
80 False,
82 Undetermined {
84 msg: String,
86 },
87}
88
89)]
91pub struct GeneratedCode {
92 pub header: Vec<u8>,
94 pub implementation: Vec<u8>,
96}
97
98impl Default for Opt {
99 fn default() -> Self {
100 Opt {
101 include: Vec::new(),
102 cxx_impl_annotations: None,
103 gen_header: true,
104 gen_implementation: true,
105 allow_dot_includes: true,
106 cfg_evaluator: Box::new(UnsupportedCfgEvaluator),
107 doxygen: false,
108 }
109 }
110}
111
112pub(super) fn generate_from_path(path: &Path, opt: &Opt) -> GeneratedCode {
113 let source = match read_to_string(path) {
114 Ok(source) => source,
115 Err(err) => format_err(path, "", err),
116 };
117 match generate_from_string(&source, opt) {
118 Ok(out) => out,
119 Err(err) => format_err(path, &source, err),
120 }
121}
122
123fn read_to_string(path: &Path) -> Result<String> {
124 let bytes = if path == Path::new("-") {
125 fs::read_stdin()
126 } else {
127 fs::read(path)
128 }?;
129 match String::from_utf8(bytes) {
130 Ok(string) => Ok(string),
131 Err(err) => Err(Error::Utf8(path.to_owned(), err.utf8_error())),
132 }
133}
134
135fn generate_from_string(source: &str, opt: &Opt) -> Result<GeneratedCode> {
136 let mut source = source;
137 if source.starts_with("#!") && !source.starts_with("#![") {
138 let shebang_end = source.find('\n').unwrap_or(source.len());
139 source = &source[shebang_end..];
140 }
141 let syntax: File = syn::parse_str(source)?;
142 generate(syntax, opt)
143}
144
145pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
146 if syntax.modules.is_empty() {
147 return Err(Error::NoBridgeMod);
148 }
149
150 let ref mut apis = Vec::new();
151 let ref mut errors = Errors::new();
152 let ref mut cfg_errors = Set::new();
153 for bridge in syntax.modules {
154 let mut cfg = CfgExpr::Unconditional;
155 let _ = attrs::parse(
156 errors,
157 bridge.attrs,
158 attrs::Parser {
159 cfg: Some(&mut cfg),
160 ignore_unrecognized: true,
161 ..Default::default()
162 },
163 );
164 if cfg::eval(errors, cfg_errors, opt.cfg_evaluator.as_ref(), &cfg) {
165 let ref namespace = bridge.namespace;
166 let trusted = bridge.unsafety.is_some();
167 apis.extend(syntax::parse_items(
168 errors,
169 bridge.content,
170 trusted,
171 namespace,
172 ));
173 }
174 }
175
176 cfg::strip(errors, cfg_errors, opt.cfg_evaluator.as_ref(), apis);
177 errors.propagate()?;
178
179 let ref types = Types::collect(errors, apis);
180 check::precheck(errors, apis, opt);
181 errors.propagate()?;
182
183 let generator = check::Generator::Build;
184 check::typecheck(errors, apis, types, generator);
185 errors.propagate()?;
186
187 let (mut header, mut implementation) = Default::default();
191 if opt.gen_header {
192 header = write::gen(apis, types, opt, true);
193 }
194 if opt.gen_implementation {
195 implementation = write::gen(apis, types, opt, false);
196 }
197 Ok(GeneratedCode {
198 header,
199 implementation,
200 })
201}