mirror of
https://github.com/Noratrieb/mono-fmt.git
synced 2026-01-17 08:45:05 +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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
proc-macro2 = "1.0.43"
|
||||||
quote = "1.0.21"
|
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 proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use proc_macro2::Span;
|
||||||
|
use quote::{quote, ToTokens};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
Expr, parse_macro_input,
|
parse_macro_input,
|
||||||
|
punctuated::Punctuated,
|
||||||
|
Expr, LitStr, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Input {
|
struct Input {
|
||||||
format_str: String,
|
format_str: String,
|
||||||
items: Vec<Expr>,
|
exprs: Punctuated<Expr, Token![,]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Input {
|
impl Parse for Input {
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
let first = input.parse::<syn::LitStr>()?;
|
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 {
|
Ok(Self {
|
||||||
format_str: first.value(),
|
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]
|
#[proc_macro]
|
||||||
pub fn format_args(tokens: TokenStream) -> TokenStream {
|
pub fn format_args(tokens: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(tokens as Input);
|
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! {
|
quote! {
|
||||||
(mono_fmt::_private::Str(#str),)
|
(#(#fmt_parts),*,)
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,6 @@ mod tests {
|
||||||
// for the macros
|
// for the macros
|
||||||
use crate as mono_fmt;
|
use crate as mono_fmt;
|
||||||
|
|
||||||
use crate::arguments::DebugArg;
|
|
||||||
use crate::format;
|
use crate::format;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -149,8 +148,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn debug() {
|
fn display() {
|
||||||
let result = format((DebugArg("uwu"),));
|
let result = format!("{}", "uwu");
|
||||||
assert_eq!(result, "\"uwu\"");
|
assert_eq!(result, "uwu");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue