#![feature(proc_macro_span)]
use std::path::Path;
use std::fs;
use proc_macro::{ Span, TokenStream };
use proc_macro_error::{
proc_macro_error,
abort,
};
use quote::{quote, format_ident};
use python_ast::{parse, PythonOptions, CodeGen, CodeGenContext};
#[proc_macro]
#[proc_macro_error]
pub fn python_module(input: TokenStream) -> TokenStream {
let mod_name = input.to_string();
let mod_path = match Span::mixed_site().parent() {
Some(p) => p,
_ => abort!("unable to determine parent of module for {}", mod_name)
}.source_file().path();
let mod_name_dir = format!("src/{}/__init__.py", &mod_name);
let mod_name_file = format!("src/{}.py", &mod_name);
let python_str_result = if Path::new(&mod_name_dir).exists() {
fs::read_to_string(mod_name_dir)
} else if Path::new(&mod_name_file).exists() {
fs::read_to_string(mod_name_file)
} else {
abort!(mod_name, "Module not found {} in {:?}", mod_name, mod_path)
};
let python_str = match python_str_result {
Ok(s) => s,
Err(e) => abort!("1: {:?}", e)
};
let py_mod = match parse(&python_str, &mod_name) {
Ok(p) => p,
Err(e) => abort!("parse error: {:?}", e)
};
let options = PythonOptions::default();
let output = match py_mod.to_rust(CodeGenContext::Module, options) {
Ok(o) => o,
Err(e) => abort!("transpiler error: {:?}", e)
};
let new_mod_name = format_ident!("{}", mod_name);
let result = quote!(mod #new_mod_name {
#output
});
println!("result: {}", result);
result.into()
}
#[proc_macro]
#[proc_macro_error]
pub fn python_inline_string(input: TokenStream) -> TokenStream {
let mut tokens = input.into_iter();
let mod_name = format_ident!("{}", tokens.next().unwrap().to_string());
for token in tokens {
let py_string = token.to_string();
println!("{} tokens: {:?}, {}", mod_name, token, py_string);
}
quote!("").into()
}