whichever_compiles/
lib.rs

1use 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}