mod check;
mod instantiate;
mod normalize;
mod parse;
use std::path::PathBuf;
use instantiate::Instantiate;
use proc_macro as pm;
use proc_macro2::{self as pm2, Span};
use parse::{MacroInput, MultipleMacroInput};
use quote::{quote, ToTokens};
use syn::parse_macro_input;
use crate::{instantiate::ConstIdentDef, normalize::TomlValue};
const MAP_FIELD: &str = "__map__";
#[proc_macro]
pub fn toml_const(input: pm::TokenStream) -> pm::TokenStream {
let input: MultipleMacroInput = parse_macro_input!(input);
let manifest_path =
std::env::var("CARGO_MANIFEST_DIR").expect("manifest dir variable must exist");
let manifest_path = PathBuf::from(manifest_path);
assert!(manifest_path.is_dir());
let abs_manifest_path = manifest_path
.canonicalize()
.expect("path must canonicalize");
let const_defs = input
.0
.iter()
.map(|i| i.to_const_defs(&abs_manifest_path))
.collect::<pm2::TokenStream>();
let inner_calls = input
.0
.iter()
.map(|i| {
let absolute = i.to_abs_path(&abs_manifest_path);
quote! {
toml_const::toml_const_inner! {
#absolute
}
}
})
.collect::<pm2::TokenStream>();
quote! {
#const_defs
#inner_calls
}
.into()
}
#[proc_macro]
pub fn toml_const_ws(input: pm::TokenStream) -> pm::TokenStream {
let input: MultipleMacroInput = parse_macro_input!(input);
let ws_dir = std::env::current_dir()
.expect("current directory must exist")
.to_string_lossy()
.to_string();
let ws_path = PathBuf::from(ws_dir);
assert!(ws_path.is_dir());
let abs_ws_path = ws_path.canonicalize().expect("path must canonicalize");
let const_defs = input
.0
.iter()
.map(|i| i.to_const_defs(&abs_ws_path))
.collect::<pm2::TokenStream>();
let inner_calls = input
.0
.iter()
.map(|i| {
let absolute = i.to_abs_path(&abs_ws_path);
quote! {
toml_const::toml_const_inner! {
#absolute
}
}
})
.collect::<pm2::TokenStream>();
quote! {
#const_defs
#inner_calls
}
.into()
}
#[proc_macro_attribute]
pub fn unwrap_datetime(_attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream {
let syn::ItemMacro {
attrs,
ident,
mac,
semi_token,
} = parse_macro_input!(item);
syn::ItemMacro {
attrs,
ident,
mac,
semi_token,
}
.to_token_stream()
.into()
}
#[doc(hidden)]
#[proc_macro]
pub fn toml_const_inner(input: pm::TokenStream) -> pm::TokenStream {
let input: MacroInput = parse_macro_input!(input);
let toml_table = match input.generate_toml_table() {
Ok(tt) => tt,
Err(e) => return e.into(),
};
match check::check_unauthorized_keys(&toml_table) {
Ok(_) => (),
Err(e) => return e.into(),
}
let toml_val_table = TomlValue::from(toml_table.clone());
let toml_val_table = match toml_val_table.normalize() {
Ok(n) => n,
Err(e) => {
return syn::Error::new(Span::call_site(), e.to_string())
.to_compile_error()
.into()
}
};
let toml_val_table = toml_val_table.reduce();
let mut toml_table_val = toml::Value::Table(toml_table);
toml_val_table.normalize_toml(&mut toml_table_val);
let toml_table = toml_table_val
.as_table()
.expect("conversion back to table must not fail");
let definition_attrs = match input.definition_attrs() {
Ok(def) => def,
Err(e) => return e.to_compile_error().into(),
};
let table_definitions =
toml_val_table.definition(&input.item_ident.to_string(), &definition_attrs);
let instantiation =
toml_table.instantiate(&input.item_ident.to_string(), &toml_val_table, vec![]);
let pub_token = if input.is_pub {
quote! {pub}
} else {
quote! {}
};
let static_const_token = match input.static_const {
true => quote! {const},
false => quote! {static},
};
let item_ident = &input.item_ident;
let item_ty = input.item_ident.to_string().to_type_ident();
let instance_attrs = match input.instantiation_attrs() {
Ok(instance) => instance
.into_iter()
.map(|a| a.to_token_stream())
.collect::<pm2::TokenStream>(),
Err(e) => return e.to_compile_error().into(),
};
quote! {
#table_definitions
#instance_attrs
#pub_token #static_const_token #item_ident: #item_ty = #instantiation;
}
.into()
}