1#![cfg_attr(feature = "nightly", feature(proc_macro_tracked_path))]
2
3use std::path::PathBuf;
4
5use proc_macro::Span;
6use syn::parse::Parse;
7use syn::{Expr, ExprArray, LitStr, Token};
8use quote::ToTokens;
9
10use ppx_impl as ppx;
11
12struct Args {
13 file_path: String,
14 base_path: String,
15 params: Vec<String>,
16}
17
18impl Parse for Args {
19 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
20 let file_path: LitStr = input.parse()?;
21 input.parse::<Token![,]>()?;
22
23 let mut params: Option<ExprArray> = None;
24 let base_path: LitStr = input.parse()?;
25 if input.peek(Token![,]) {
26 input.parse::<Token![,]>()?;
27 if !input.is_empty() {
28 params = Some(input.parse()?);
29 }
30 }
31
32 let params = params
33 .map(|params| {
34 params.elems
35 .into_iter()
36 .map(|elem| match elem {
37 Expr::Lit(lit) => match &lit.lit {
38 syn::Lit::Str(s) => s.value(),
39 _ => panic!("Expected string literal in params"),
40 },
41 _ => panic!("Expected string literal in params")
42 }).collect::<Vec<_>>()
43 })
44 .unwrap_or(Vec::new());
45
46 Ok(Args {
47 file_path: file_path.value(),
48 base_path: base_path.value(),
49 params: params
50 })
51 }
52}
53
54#[cfg(feature = "nightly")]
62#[proc_macro]
63pub fn include_ppx(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
64 let args = syn::parse_macro_input!(input as Args);
65
66 let source_path = PathBuf::from(Span::call_site().file());
67 let base_path = source_path.parent().unwrap();
68
69 let file_path = base_path.join(args.file_path);
70 proc_macro::tracked::path(file_path.to_str().expect("File path was not UTF-8 encoded"));
71 let base_path = base_path.join(args.base_path);
72
73 let output = ppx::parse(file_path, base_path, args.params.iter().map(|s| s.as_str())).unwrap();
74 let output = LitStr::new(&output, Span::call_site().into());
75
76 return output.to_token_stream().into();
77}
78
79#[proc_macro]
91pub fn include_ppx_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
92 let args = syn::parse_macro_input!(input as Args);
93
94 let source_path = PathBuf::from(Span::call_site().file());
95 let base_path = source_path.parent().unwrap();
96
97 let contents = args.file_path;
98 let base_path = base_path.join(args.base_path);
99
100 let output = ppx::parse_string(&contents, base_path, args.params.iter().map(|s| s.as_str())).unwrap();
101 let output = LitStr::new(&output, Span::call_site().into());
102
103 return output.to_token_stream().into();
104}