mirror of
https://github.com/Noratrieb/mono-fmt.git
synced 2026-01-14 15:25:08 +01:00
wow it works
This commit is contained in:
parent
d43f4577e6
commit
86441cf10b
3 changed files with 109 additions and 11 deletions
|
|
@ -9,5 +9,6 @@ proc-macro = true
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.43"
|
||||
quote = "1.0.21"
|
||||
syn = "1.0.99"
|
||||
syn = { version = "1.0.99", features = ["full"] }
|
||||
|
|
|
|||
|
|
@ -1,31 +1,129 @@
|
|||
use std::{iter::Peekable, str::Chars};
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use proc_macro2::Span;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
Expr, parse_macro_input,
|
||||
parse_macro_input,
|
||||
punctuated::Punctuated,
|
||||
Expr, LitStr, Token,
|
||||
};
|
||||
|
||||
struct Input {
|
||||
format_str: String,
|
||||
items: Vec<Expr>,
|
||||
exprs: Punctuated<Expr, Token![,]>,
|
||||
}
|
||||
|
||||
impl Parse for Input {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let first = input.parse::<syn::LitStr>()?;
|
||||
|
||||
let mut exprs = Punctuated::new();
|
||||
|
||||
if !input.is_empty() {
|
||||
let _ = input.parse::<Token![,]>();
|
||||
}
|
||||
|
||||
while !input.is_empty() {
|
||||
let punct = input.parse()?;
|
||||
exprs.push(punct);
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
let value = input.parse()?;
|
||||
exprs.push(value);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
format_str: first.value(),
|
||||
items: Vec::new(),
|
||||
exprs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enum FmtPart {
|
||||
Literal(String),
|
||||
Debug(Expr),
|
||||
Display(Expr),
|
||||
}
|
||||
|
||||
struct Formatter<'a, I> {
|
||||
string: Peekable<Chars<'a>>,
|
||||
exprs: I,
|
||||
fmt_parts: Vec<FmtPart>,
|
||||
}
|
||||
|
||||
impl<'a, I> Formatter<'a, I>
|
||||
where
|
||||
I: Iterator<Item = Expr>,
|
||||
{
|
||||
fn parse(mut self) -> Vec<FmtPart> {
|
||||
let mut next_string = String::new();
|
||||
while let Some(char) = self.string.next() {
|
||||
match char {
|
||||
'{' => {
|
||||
self.save_string(std::mem::take(&mut next_string));
|
||||
if self.string.next() != Some('}') {
|
||||
panic!("only supports display formatting!");
|
||||
}
|
||||
let expr = self
|
||||
.exprs
|
||||
.next()
|
||||
.expect("missing argument for display formatting");
|
||||
self.fmt_parts.push(FmtPart::Display(expr));
|
||||
}
|
||||
other => {
|
||||
next_string.push(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.save_string(next_string);
|
||||
|
||||
self.fmt_parts
|
||||
}
|
||||
|
||||
fn save_string(&mut self, string: String) {
|
||||
if string.is_empty() {
|
||||
return;
|
||||
}
|
||||
self.fmt_parts.push(FmtPart::Literal(string));
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for FmtPart {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
let own_tokens = match self {
|
||||
FmtPart::Literal(lit) => {
|
||||
let literal = LitStr::new(lit, Span::call_site());
|
||||
quote! { mono_fmt::_private::Str(#literal) }
|
||||
}
|
||||
FmtPart::Display(expr) => {
|
||||
quote! { mono_fmt::_private::DisplayArg(#expr) }
|
||||
}
|
||||
FmtPart::Debug(expr) => {
|
||||
quote! { mono_fmt::_private::DebugArg(#expr) }
|
||||
}
|
||||
};
|
||||
|
||||
tokens.extend(own_tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn format_args(tokens: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(tokens as Input);
|
||||
let str = input.format_str;
|
||||
|
||||
let formatter = Formatter {
|
||||
string: input.format_str.chars().peekable(),
|
||||
exprs: input.exprs.into_iter(),
|
||||
fmt_parts: Vec::new(),
|
||||
};
|
||||
|
||||
let fmt_parts = formatter.parse();
|
||||
|
||||
quote! {
|
||||
(mono_fmt::_private::Str(#str),)
|
||||
(#(#fmt_parts),*,)
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,6 @@ mod tests {
|
|||
// for the macros
|
||||
use crate as mono_fmt;
|
||||
|
||||
use crate::arguments::DebugArg;
|
||||
use crate::format;
|
||||
|
||||
#[test]
|
||||
|
|
@ -149,8 +148,8 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn debug() {
|
||||
let result = format((DebugArg("uwu"),));
|
||||
assert_eq!(result, "\"uwu\"");
|
||||
fn display() {
|
||||
let result = format!("{}", "uwu");
|
||||
assert_eq!(result, "uwu");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue