whichever_compiles/
lib.rs1use proc_macro::{Delimiter::Brace, TokenStream, TokenTree::Group};
2use std::{fs::File, io::Read, os::unix::io::FromRawFd};
3
4#[proc_macro]
5pub fn whichever_compiles(input: TokenStream) -> TokenStream {
6 let mut input = input.into_iter();
7 let mut alternatives = Vec::new();
8 while let Some(t) = input.next() {
9 assert_eq!(t.to_string(), "try");
10 match input.next() {
11 Some(Group(g)) if g.delimiter() == Brace => alternatives.push(g.stream()),
12 _ => panic!("{}", "expected `{ .. }` after `try`"),
13 }
14 }
15 let last_alternative = alternatives.pop().expect("missing `try { .. }`");
16 for tokens in alternatives {
17 unsafe {
18 let mut pipe = [-1, -1];
19 assert_eq!(libc::pipe(pipe.as_mut_ptr()), 0);
20 if libc::fork() == 0 {
21 libc::dup2(pipe[1], 1);
22 libc::dup2(pipe[1], 2);
23 libc::close(pipe[0]);
24 libc::close(pipe[1]);
25 return tokens;
26 }
27 libc::close(pipe[1]);
28 let mut out = String::new();
29 File::from_raw_fd(pipe[0]).read_to_string(&mut out).unwrap();
30 if !out.contains("\"error\"") && !out.contains("error:") {
31 libc::_exit(0);
32 }
33 }
34 }
35 last_alternative
36}