1#[cfg(feature = "tokenize")]
2mod conversion;
3mod expr;
4mod stmt;
5mod token;
6mod ty;
7
8use std::fmt;
9use std::fs::File;
10use std::io::Write;
11use std::path::Path as Pt;
12
13pub use expr::*;
14pub use stmt::*;
15pub use token::*;
16pub use ty::*;
17
18pub mod traits {
19 pub use crate::{
20 Accessible, AddVisibility, Assignable, Awaitable, BinaryOperable, Callable, Castable,
21 EmptyItem, HasItem, Ident, Indexable, IntoConst, IntoTokens, IntoTryBlock, IntoUnsafe,
22 MaybeIdent, MethodCallable, Returnable, Semicolon, Tryable, UnaryOperable, Yieldable,
23 };
24}
25
26macro_rules! impl_obvious_conversion {
27 ($Enum: ident; $($Variant: ident $(,)?)*) => {
28 $(
29 impl From<$Variant> for $Enum {
30 fn from(item: $Variant) -> Self {
31 Self::$Variant(item)
32 }
33 }
34 )*
35 impl From<$Enum> for $crate::TokenStream {
36 fn from(item: $Enum) -> Self {
37 match item {
38 $($Enum::$Variant(v) => v.into(),)*
39 }
40 }
41 }
42 };
43}
44pub(crate) use impl_obvious_conversion;
45
46macro_rules! impl_display_for_enum {
47 ($Enum: ident; $($Variant: ident $(,)?)*) => {
48 impl std::fmt::Display for $Enum {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 match self {
51 $(
52 Self::$Variant(item) => write!(f, "{item}"),
53 )*
54 }
55 }
56 }
57 };
58}
59pub(crate) use impl_display_for_enum;
60
61macro_rules! impl_hasitem_methods {
62 ($Ty: ident) => {
63 impl $Ty {
64 pub fn with_item(self, item: impl Into<Item>) -> Self {
65 HasItem::with_item(self, item)
66 }
67
68 pub fn add_item(&mut self, item: impl Into<Item>) -> $crate::ItemIndex {
69 HasItem::add_item(self, item)
70 }
71
72 pub fn try_remove_item(&mut self, index: usize) -> Option<Item> {
73 HasItem::try_remove_item(self, index)
74 }
75
76 pub fn remove_item(&mut self, index: $crate::ItemIndex) -> Item {
77 HasItem::remove_item(self, index)
78 }
79
80 pub fn try_remove_item_by_id(&mut self, ident: &str) -> Option<Item> {
81 HasItem::try_remove_item_by_id(self, ident)
82 }
83
84 pub fn get_item(&self, index: usize) -> Option<&Item> {
85 HasItem::get_item(self, index)
86 }
87
88 pub fn get_item_by_id(&self, ident: &str) -> Option<&Item> {
89 HasItem::get_item_by_id(self, ident)
90 }
91 }
92 impl std::ops::Deref for $Ty {
93 type Target = [Item];
94
95 fn deref(&self) -> &Self::Target {
96 self.items()
97 }
98 }
99 impl std::ops::DerefMut for $Ty {
100 fn deref_mut(&mut self) -> &mut Self::Target {
101 self.items_mut()
102 }
103 }
104 impl std::ops::Index<$crate::ItemIndex> for $Ty {
105 type Output = Item;
106
107 fn index(&self, index: $crate::ItemIndex) -> &Self::Output {
108 self.get_item(index.0).expect("index out of bounds")
109 }
110 }
111 impl std::ops::IndexMut<$crate::ItemIndex> for $Ty {
112 fn index_mut(&mut self, index: $crate::ItemIndex) -> &mut Self::Output {
113 self.get_item_mut(index.0).expect("index out of bounds")
114 }
115 }
116 };
117 ($Ty: ident, $Item: ident) => {
118 impl $Ty {
119 pub fn with_item(self, item: impl Into<$Item>) -> Self {
120 HasItem::with_item(self, item)
121 }
122
123 pub fn add_item(&mut self, item: impl Into<$Item>) -> $crate::ItemIndex {
124 HasItem::add_item(self, item)
125 }
126
127 pub fn try_remove_item(&mut self, index: usize) -> Option<$Item> {
128 HasItem::try_remove_item(self, index)
129 }
130
131 pub fn remove_item(&mut self, index: $crate::ItemIndex) -> $Item {
132 HasItem::remove_item(self, index)
133 }
134
135 pub fn try_remove_item_by_id(&mut self, ident: &str) -> Option<$Item> {
136 HasItem::try_remove_item_by_id(self, ident)
137 }
138
139 pub fn get_item(&self, index: usize) -> Option<&$Item> {
140 HasItem::get_item(self, index)
141 }
142
143 pub fn get_item_by_id(&self, ident: &str) -> Option<&$Item> {
144 HasItem::get_item_by_id(self, ident)
145 }
146 }
147 impl std::ops::Deref for $Ty {
148 type Target = [$Item];
149
150 fn deref(&self) -> &Self::Target {
151 self.items()
152 }
153 }
154 impl std::ops::DerefMut for $Ty {
155 fn deref_mut(&mut self) -> &mut Self::Target {
156 self.items_mut()
157 }
158 }
159 impl std::ops::Index<$crate::ItemIndex> for $Ty {
160 type Output = $Item;
161
162 fn index(&self, index: $crate::ItemIndex) -> &Self::Output {
163 self.get_item(index.0).expect("index out of bounds")
164 }
165 }
166 impl std::ops::IndexMut<$crate::ItemIndex> for $Ty {
167 fn index_mut(&mut self, index: $crate::ItemIndex) -> &mut Self::Output {
168 self.get_item_mut(index.0).expect("index out of bounds")
169 }
170 }
171 };
172 ($Ty: ident, $Item: ident, Deref) => {
173 impl std::ops::Deref for $Ty {
174 type Target = [$Item];
175
176 fn deref(&self) -> &Self::Target {
177 self.items()
178 }
179 }
180 impl std::ops::DerefMut for $Ty {
181 fn deref_mut(&mut self) -> &mut Self::Target {
182 self.items_mut()
183 }
184 }
185 };
186}
187pub(crate) use impl_hasitem_methods;
188
189#[cfg_attr(feature = "fuzzing", derive(arbitrary::Arbitrary))]
190#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
191pub struct Crate {
192 pub attrs: Vec<Attribute>,
193 pub items: Vec<Item>,
194}
195
196impl EmptyItem for Crate {
197 type Input = ();
198 fn empty(_: impl Into<()>) -> Self {
199 Self::new()
200 }
201}
202
203impl HasItem for Crate {
204 fn items(&self) -> &[Item] {
205 &self.items
206 }
207 fn items_mut(&mut self) -> &mut Vec<Item> {
208 &mut self.items
209 }
210}
211
212impl_hasitem_methods!(Crate);
213
214impl fmt::Display for Crate {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 for attr in self.attrs.iter() {
217 writeln!(f, "{attr}")?;
218 }
219 writeln!(f)?;
220 for item in self.items.iter() {
221 writeln!(f, "{item}")?;
222 }
223 Ok(())
224 }
225}
226
227impl From<Crate> for TokenStream {
228 fn from(value: Crate) -> Self {
229 let mut ts = TokenStream::new();
230 for attr in value.attrs {
231 ts.extend(TokenStream::from(attr));
232 }
233 for item in value.items {
234 ts.extend(TokenStream::from(item));
235 }
236 ts
237 }
238}
239
240#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
241pub struct CompileOptions {
242 pub allow: Option<String>,
243 pub cap_lints: Option<String>,
244 pub cfg: Option<String>,
245 pub check_cfg: Option<String>,
246 pub crate_name: Option<String>,
247 pub crate_type: Option<String>,
248 pub deny: Option<String>,
249 pub edition: Option<String>,
250 pub emit: Option<String>,
251 pub explain: Option<String>,
252 pub forbid: Option<String>,
253 pub force_warn: Option<String>,
254 pub g: bool,
255 pub o: bool,
256 pub print: Option<String>,
257 pub target: Option<String>,
258 pub test: bool,
259 pub out_dir: Option<String>,
260 pub verbose: bool,
261 pub warn: Option<String>,
262}
263
264impl Crate {
265 pub fn new() -> Self {
266 Self {
267 attrs: Vec::new(),
268 items: Vec::new(),
269 }
270 }
271
272 pub fn dump(self, path: impl AsRef<Pt>) -> Result<(), std::io::Error> {
273 let mut file = File::create(path)?;
274 write!(file, "{self}")?;
275 Ok(())
276 }
277
278 pub fn compile(
279 self,
280 rs_path: impl AsRef<Pt>,
281 options: CompileOptions,
282 ) -> Result<(), std::io::Error> {
283 let rs_path = rs_path.as_ref();
284 let mut file = File::create(rs_path)?;
285 write!(file, "{self}")?;
286 drop(file);
287 let mut cmd = std::process::Command::new("rustc");
288 if let Some(allow) = options.allow {
289 cmd.arg("--allow").arg(allow);
290 }
291 if let Some(cap_lints) = options.cap_lints {
292 cmd.arg("--cap-lints").arg(cap_lints);
293 }
294 if let Some(cfg) = options.cfg {
295 cmd.arg("--cfg").arg(cfg);
296 }
297 if let Some(check_cfg) = options.check_cfg {
298 cmd.arg("--check-cfg").arg(check_cfg);
299 }
300 if let Some(crate_name) = options.crate_name {
301 cmd.arg("--crate-name").arg(crate_name);
302 }
303 if let Some(crate_type) = options.crate_type {
304 cmd.arg("--crate-type").arg(crate_type);
305 }
306 if let Some(deny) = options.deny {
307 cmd.arg("--deny").arg(deny);
308 }
309 if let Some(edition) = options.edition {
310 cmd.arg("--edition").arg(edition);
311 }
312 if let Some(emit) = options.emit {
313 cmd.arg("--emit").arg(emit);
314 }
315 if let Some(explain) = options.explain {
316 cmd.arg("--explain").arg(explain);
317 }
318 if let Some(forbid) = options.forbid {
319 cmd.arg("--forbid").arg(forbid);
320 }
321 if let Some(force_warn) = options.force_warn {
322 cmd.arg("--force-warn").arg(force_warn);
323 }
324 if options.g {
325 cmd.arg("-g");
326 }
327 if options.o {
328 cmd.arg("-O");
329 }
330 if let Some(print) = options.print {
331 cmd.arg("--print").arg(print);
332 }
333 if let Some(target) = options.target {
334 cmd.arg("--target").arg(target);
335 }
336 if options.test {
337 cmd.arg("--test");
338 }
339 if let Some(out_dir) = options.out_dir {
340 cmd.arg("--out-dir").arg(out_dir);
341 }
342 if options.verbose {
343 cmd.arg("--verbose");
344 }
345 if let Some(warn) = options.warn {
346 cmd.arg("--warn").arg(warn);
347 }
348 cmd.arg(rs_path).output()?;
349 Ok(())
350 }
351}
352
353#[cfg(feature = "tokenize")]
354impl_to_tokens!(Crate,);