1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![cfg_attr(feature = "nightly", feature(proc_macro_tracked_path))]
3
4use std::path::PathBuf;
5
6use proc_macro::Span;
7use syn::parse::Parse;
8use syn::{Expr, ExprArray, LitStr, Token};
9use quote::ToTokens;
10
11use ppx_impl as ppx;
12
13struct Args {
14 file_path: String,
15 base_path: String,
16 params: Vec<String>,
17}
18
19impl Parse for Args {
20 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
21 let file_path: LitStr = input.parse()?;
22 input.parse::<Token![,]>()?;
23
24 let mut params: Option<ExprArray> = None;
25 let base_path: LitStr = input.parse()?;
26 if input.peek(Token![,]) {
27 input.parse::<Token![,]>()?;
28 if !input.is_empty() {
29 params = Some(input.parse()?);
30 }
31 }
32
33 let params = params
34 .map(|params| {
35 params.elems
36 .into_iter()
37 .map(|elem| match elem {
38 Expr::Lit(lit) => match &lit.lit {
39 syn::Lit::Str(s) => s.value(),
40 _ => panic!("Expected string literal in params"),
41 },
42 _ => panic!("Expected string literal in params")
43 }).collect::<Vec<_>>()
44 })
45 .unwrap_or(Vec::new());
46
47 if !input.is_empty() {
48 if input.peek(Token![,]) {
49 _ = input.parse::<Token![,]>()?;
50 if !input.is_empty() {
51 panic!("Unexpected token(s) in input {:?}", input);
52 }
53 } else {
54 panic!("Unexpected token(s) in input {:?}", input);
55 }
56 }
57
58 Ok(Args {
59 file_path: file_path.value(),
60 base_path: base_path.value(),
61 params: params
62 })
63 }
64}
65
66#[cfg(feature = "nightly")]
74#[proc_macro]
75pub fn include_ppx(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
76 let args = syn::parse_macro_input!(input as Args);
77
78 let source_path = PathBuf::from(Span::call_site().file());
79 let base_path = source_path.parent().unwrap();
80
81 let file_path = base_path.join(args.file_path);
82 proc_macro::tracked::path(file_path.to_str().expect("File path was not UTF-8 encoded"));
83 let base_path = base_path.join(args.base_path);
84
85 let output = ppx::parse(file_path, base_path, args.params.iter().map(|s| s.as_str())).unwrap();
86 let output = LitStr::new(&output, Span::call_site().into());
87
88 return output.to_token_stream().into();
89}
90
91#[proc_macro]
103pub fn include_ppx_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
104 let args = syn::parse_macro_input!(input as Args);
105
106 let source_path = PathBuf::from(Span::call_site().file());
107 let base_path = source_path.parent().unwrap();
108
109 let contents = args.file_path;
110 let base_path = base_path.join(args.base_path);
111
112 let output = ppx::parse_string(&contents, base_path, args.params.iter().map(|s| s.as_str())).unwrap();
113 let output = LitStr::new(&output, Span::call_site().into());
114
115 return output.to_token_stream().into();
116}