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
use proc_macro::{Delimiter::Brace, TokenStream, TokenTree::Group};
use std::{fs::File, io::Read, os::unix::io::FromRawFd};

#[proc_macro]
pub fn whichever_compiles(input: TokenStream) -> TokenStream {
    let mut input = input.into_iter();
    let mut alternatives = Vec::new();
    while let Some(t) = input.next() {
        assert_eq!(t.to_string(), "try");
        match input.next() {
            Some(Group(g)) if g.delimiter() == Brace => alternatives.push(g.stream()),
            _ => panic!("{}", "expected `{ .. }` after `try`"),
        }
    }
    let last_alternative = alternatives.pop().expect("missing `try { .. }`");
    for tokens in alternatives {
        unsafe {
            let mut pipe = [-1, -1];
            assert_eq!(libc::pipe(pipe.as_mut_ptr()), 0);
            if libc::fork() == 0 {
                libc::dup2(pipe[1], 1);
                libc::dup2(pipe[1], 2);
                libc::close(pipe[0]);
                libc::close(pipe[1]);
                return tokens;
            }
            libc::close(pipe[1]);
            let mut out = String::new();
            File::from_raw_fd(pipe[0]).read_to_string(&mut out).unwrap();
            if !out.contains("\"error\"") && !out.contains("error:") {
                libc::_exit(0);
            }
        }
    }
    last_alternative
}