adventofcode/macros/src/lib.rs

102 Zeilen
Kein EOL
2,8 KiB
Rust

use proc_macro::TokenStream;
use quote::quote;
use syn::{
buffer::Cursor,
parse::{Parse, ParseStream, StepCursor},
Error,
};
use syn::{parse, LitInt, Result};
struct IncludeData {
year: String,
day: String,
}
fn get_string<'a, 'b>(cursor: StepCursor<'a, 'b>) -> Result<(String, Cursor<'a>)> {
let (lit, c) = match cursor.literal() {
Some(literal) => literal,
None => return Err(Error::new(cursor.span(), "Failed to get literal")),
};
let span = lit.span();
let text = match span.source_text() {
Some(text) => text,
None => {
let start = span.start();
let end = span.end();
return Err(Error::new(
span,
format!(
"Failed to get sourcetext for {}:{}-{}:{}",
start.line, start.column, end.line, end.column,
),
));
}
};
Ok((text, c))
}
impl Parse for IncludeData {
fn parse(input: ParseStream) -> Result<Self> {
let mut data = IncludeData {
year: "".into(),
day: "".into(),
};
let mut look = input.lookahead1();
if !look.peek(LitInt) {
let s = input.span();
return Err(Error::new(
s,
format!("{} is not an valid Year", s.source_text().unwrap()),
));
}
data.year = input.step(get_string).expect("Wanted an string");
look = input.lookahead1();
if !look.peek(LitInt) {
let s = input.span();
return Err(Error::new(
s,
format!("{} is not an valid Day", s.source_text().unwrap()),
));
}
data.day = input.step(get_string).expect("Wanted an string");
Ok(data)
}
}
fn get_stream(dir: &str, data: Result<IncludeData>) -> TokenStream {
match data {
Ok(id) => {
let path = format!("../../../{}/{}/{}.txt", dir, id.year, id.day);
quote! {
static DATA: &str = include_str!(#path);
}
}
Err(_)=> {
quote! {
static DATA: &str = "";
}
}
}.into()
}
/// includes Data from Advent of code
/// ```ignore (cannot-doctest-external-file-dependency)
/// include_data!(2015 01)
///
/// fn main() {
/// print!("{DATA}");
/// }
/// ```
/// The Equivalent is
/// ```ignore (cannot-doctest-external-file-dependency)
/// static DATA: &str = include_str!("../../../data/2015/01.txt");
/// ```
#[proc_macro]
pub fn include_data(data: TokenStream) -> TokenStream {
get_stream("data", parse::<IncludeData>(data))
}
#[proc_macro]
pub fn include_example(data: TokenStream)->TokenStream {
get_stream("examples", parse::<IncludeData>(data))
}