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}