qroc/
lib.rs

1use proc_macro::TokenStream;
2use std::env;
3use std::fs::{create_dir_all, File};
4use std::io::Read;
5use std::path::Path;
6
7use std::process::Command;
8
9#[proc_macro_attribute]
10pub fn perl(attr: TokenStream, item: TokenStream) -> TokenStream {
11    let out_path = format!("/tmp/{}/outputs", env!("CARGO_PKG_NAME"));
12    if !Path::new(&out_path).exists() {
13        create_dir_all(Path::new(&out_path)).expect("Couldn't create temp directory");
14    }
15
16    let pl = attr.to_string();
17    let body = item.to_string();
18
19    let filestub = format!("{:x}", md5::compute(format!("{}+{}", pl, body)));
20
21    let header_pl = format!(
22        "$_ = @ARGV[0]; {}; open (FH, '>', '{}/{}'); print FH $_;",
23        pl, out_path, filestub
24    );
25
26    let output = Command::new("perl")
27        .args(["-e", &header_pl, &body])
28        .output()
29        .expect("Failed to invoke perl");
30
31    if !output.stderr.is_empty() {
32        let err = String::from_utf8(output.stderr).expect("Couldn't decode UTF-8");
33        panic!("stderr(perl): {}", err)
34    } else {
35        if !output.stdout.is_empty() {
36            let stdout = String::from_utf8(output.stdout).expect("Couldn't decode UTF-8");
37            println!("stdout(perl): {}", stdout);
38        }
39
40        let mut outfile = File::open(Path::new(&format!("{}/{}", out_path, filestub)))
41            .expect("Couldn't open output file");
42        let mut tokens = String::new();
43        outfile
44            .read_to_string(&mut tokens)
45            .expect("Couldn't read output file");
46        tokens.parse().expect("Couldn't form token stream")
47    }
48}