some fixes of my macros
Dieser Commit ist enthalten in:
Ursprung
efa52f4f5b
Commit
587ef24505
2 geänderte Dateien mit 108 neuen und 89 gelöschten Zeilen
|
@ -8,5 +8,8 @@ proc-macro = true
|
|||
|
||||
[dependencies]
|
||||
quote = "1.0.*"
|
||||
syn = "2.0.*"
|
||||
proc-macro2 = {version = "*", features = ["span-locations"]}
|
||||
proc-macro2 = {version = "*", features = ["span-locations"]}
|
||||
|
||||
[dependencies.syn]
|
||||
version = ">=2.0.90"
|
||||
features = ["full"]
|
|
@ -1,113 +1,107 @@
|
|||
use std::fs;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
buffer::Cursor,
|
||||
parse::{Parse, ParseStream, StepCursor},
|
||||
Error, LitStr,
|
||||
spanned::Spanned,
|
||||
Error, Ident, Lit, LitInt,
|
||||
};
|
||||
use syn::{parse, LitInt, Result};
|
||||
use syn::{parse, Result};
|
||||
|
||||
const DATA_DIR: &str = "data";
|
||||
const EXAMPLE_DIR: &str = "examples";
|
||||
const VAR_NAME: &str = "DATA";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct IncludeData {
|
||||
var: String,
|
||||
year: String,
|
||||
day: String,
|
||||
year: Option<String>,
|
||||
day: Option<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,
|
||||
impl Default for IncludeData {
|
||||
fn default() -> Self {
|
||||
IncludeData {
|
||||
var: VAR_NAME.into(),
|
||||
year: None,
|
||||
day: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_text<T: Spanned>(item: T) -> Result<String> {
|
||||
let span = item.span();
|
||||
match span.source_text() {
|
||||
Some(text) => Ok(text),
|
||||
None => {
|
||||
let start = span.start();
|
||||
let end = span.end();
|
||||
return Err(Error::new(
|
||||
Err(Error::new(
|
||||
span,
|
||||
format!(
|
||||
"Failed to get sourcetext for {}:{}-{}:{}",
|
||||
start.line, start.column, end.line, end.column,
|
||||
),
|
||||
));
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_literal<'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 text = get_text(lit)?;
|
||||
Ok((text, c))
|
||||
}
|
||||
|
||||
fn get_ident<'a, 'b>(cursor: StepCursor<'a, 'b>) -> Result<(String, Cursor<'a>)> {
|
||||
let (lit, c) = match cursor.ident() {
|
||||
Some(literal) => literal,
|
||||
None => return Err(Error::new(cursor.span(), "Failed to get literal")),
|
||||
};
|
||||
let text = get_text(lit)?;
|
||||
Ok((text, c))
|
||||
}
|
||||
|
||||
impl Parse for IncludeData {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut data = IncludeData {
|
||||
var: "".into(),
|
||||
year: "".into(),
|
||||
day: "".into(),
|
||||
};
|
||||
let mut look = input.lookahead1();
|
||||
if !look.peek(LitStr) {
|
||||
let s = input.span();
|
||||
return Err(Error::new(
|
||||
s,
|
||||
format!("{} is not an valid Token", s.source_text().unwrap()),
|
||||
));
|
||||
let mut data = IncludeData::default();
|
||||
if input.peek(Ident) && !input.peek(LitInt) {
|
||||
data.var = get_text(input.parse::<Ident>().unwrap())?;
|
||||
}
|
||||
data.var = input.step(get_string).expect("Wanted a string");
|
||||
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");
|
||||
data.year = Some(get_text(input.parse::<LitInt>()?)?);
|
||||
data.day = Some(get_text(input.parse::<Lit>()?)?);
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
fn canonicalize(dir: &str, input: Result<IncludeData>) -> Option<String> {
|
||||
let pathname = match input {
|
||||
Ok(id) => Some(format!("{}/{}/{}.txt", dir, id.year, id.day)),
|
||||
Err(_) => None,
|
||||
};
|
||||
if let Some(p) = pathname {
|
||||
match fs::canonicalize(p.clone()) {
|
||||
Ok(canon) => {
|
||||
if canon.is_file() {
|
||||
Some(canon.to_str().unwrap().to_string())
|
||||
} else {
|
||||
println!("ERROR: {:?} is not a file", canon);
|
||||
None
|
||||
fn canonicalize(dir: &str, input: IncludeData) -> Option<String> {
|
||||
let pathname = format!("{}/{}/{}.txt", dir, input.year.unwrap(), input.day.unwrap());
|
||||
match fs::canonicalize(pathname) {
|
||||
Ok(canon) => {
|
||||
if canon.is_file() {
|
||||
match canon.to_str() {
|
||||
Some(c) => Some(c.to_string()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("ERROR: {} does not exist: {}", p, err);
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// includes Data from Advent of code
|
||||
/// ```ignore (cannot-doctest-external-file-dependency)
|
||||
/// include_data!(DATA 2015 01)
|
||||
/// // or
|
||||
/// include_data!(2015 01)
|
||||
///
|
||||
/// fn main() {
|
||||
/// print!("{DATA}");
|
||||
|
@ -119,37 +113,59 @@ fn canonicalize(dir: &str, input: Result<IncludeData>) -> Option<String> {
|
|||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn include_data(data: TokenStream) -> TokenStream {
|
||||
let input = parse::<IncludeData>(data);
|
||||
let name = match input.clone() {
|
||||
Ok(d) => d.var,
|
||||
Err(_)=>"DATA".into(),
|
||||
let input = match parse::<IncludeData>(data) {
|
||||
Ok(include) => include,
|
||||
Err(error) => return error.into_compile_error().into(),
|
||||
};
|
||||
let mut path = canonicalize(DATA_DIR, input.clone());
|
||||
if path.is_none() {
|
||||
path = canonicalize(EXAMPLE_DIR, input)
|
||||
}
|
||||
match path {
|
||||
Some(p) => quote! {
|
||||
static #name: &str = include_str!(#p);
|
||||
let ident = format_ident!("{}", input.var);
|
||||
let mut comment: String;
|
||||
if input.day.is_some() && input.year.is_some() {
|
||||
comment = "Data from the data dir".into();
|
||||
let mut path = canonicalize(DATA_DIR, input.clone());
|
||||
if path.is_none() {
|
||||
comment = "Data from the examples".into();
|
||||
path = canonicalize(EXAMPLE_DIR, input)
|
||||
}
|
||||
.into(),
|
||||
None => quote! {
|
||||
static #name: &str = "";
|
||||
match path {
|
||||
Some(p) => {
|
||||
return quote! {
|
||||
#[doc = #comment]
|
||||
static #ident: &str = include_str!(#p);
|
||||
}
|
||||
.into()
|
||||
}
|
||||
None => comment = "failed to get data from the paths".into(),
|
||||
}
|
||||
.into(),
|
||||
} else {
|
||||
comment = format!(
|
||||
"Failed to get the year({:?}) or day({:?})",
|
||||
input.year, input.day
|
||||
);
|
||||
}
|
||||
quote! {
|
||||
#[doc = #comment]
|
||||
static #ident: &str = "";
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn include_example(data: TokenStream) -> TokenStream {
|
||||
match canonicalize(EXAMPLE_DIR, parse::<IncludeData>(data)) {
|
||||
Some(p) => quote! {
|
||||
static DATA: &str = include_str!(#p);
|
||||
let input = parse::<IncludeData>(data).unwrap_or_default();
|
||||
let ident = format_ident!("{}", input.var);
|
||||
if input.day.is_some() && input.year.is_some() {
|
||||
match canonicalize(EXAMPLE_DIR, input.clone()) {
|
||||
Some(p) => {
|
||||
return quote! {
|
||||
static #ident: &str = include_str!(#p);
|
||||
}
|
||||
.into()
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
.into(),
|
||||
None => quote! {
|
||||
static DATA: &str = "";
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
quote! {
|
||||
static #ident: &str = "";
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren