mirror of
https://github.com/Noratrieb/mono-fmt.git
synced 2026-01-17 00:35:05 +01:00
wow cool $crate hack thank you nemo
This commit is contained in:
parent
20befd0a8f
commit
5b22878e81
3 changed files with 49 additions and 29 deletions
|
|
@ -9,12 +9,13 @@ use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
parse_macro_input,
|
parse_macro_input,
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
Expr, LitStr, Token,
|
Expr, Ident, LitStr, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
struct Input {
|
struct Input {
|
||||||
|
crate_ident: Ident,
|
||||||
format_str: String,
|
format_str: String,
|
||||||
str_span: Span,
|
str_span: Span,
|
||||||
exprs: Punctuated<Expr, Token![,]>,
|
exprs: Punctuated<Expr, Token![,]>,
|
||||||
|
|
@ -22,6 +23,7 @@ struct Input {
|
||||||
|
|
||||||
impl Parse for Input {
|
impl Parse for Input {
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let crate_ident = input.parse()?;
|
||||||
let first = input.parse::<syn::LitStr>()?;
|
let first = input.parse::<syn::LitStr>()?;
|
||||||
|
|
||||||
let mut exprs = Punctuated::new();
|
let mut exprs = Punctuated::new();
|
||||||
|
|
@ -41,6 +43,7 @@ impl Parse for Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
crate_ident,
|
||||||
format_str: first.value(),
|
format_str: first.value(),
|
||||||
str_span: first.span(),
|
str_span: first.span(),
|
||||||
exprs,
|
exprs,
|
||||||
|
|
@ -49,15 +52,15 @@ impl Parse for Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FmtPart {
|
enum FmtPart {
|
||||||
Literal(String),
|
Literal(Ident, String),
|
||||||
Spec(FmtSpec, Expr),
|
Spec(Ident, FmtSpec, Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for FmtPart {
|
impl std::fmt::Debug for FmtPart {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Literal(arg0) => f.debug_tuple("Literal").field(arg0).finish(),
|
Self::Literal(_, arg0) => f.debug_tuple("Literal").field(arg0).finish(),
|
||||||
Self::Spec(spec, _) => f.debug_tuple("Spec").field(spec).finish(),
|
Self::Spec(_, spec, _) => f.debug_tuple("Spec").field(spec).finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,8 +68,8 @@ impl std::fmt::Debug for FmtPart {
|
||||||
impl PartialEq for FmtPart {
|
impl PartialEq for FmtPart {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Self::Literal(a), Self::Literal(b)) => a == b,
|
(Self::Literal(_, a), Self::Literal(_, b)) => a == b,
|
||||||
(Self::Spec(a, _), Self::Spec(b, _)) => a == b,
|
(Self::Spec(_ ,a, _), Self::Spec(_, b, _)) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +77,7 @@ impl PartialEq for FmtPart {
|
||||||
|
|
||||||
struct Formatter<'a, I> {
|
struct Formatter<'a, I> {
|
||||||
string: PeekMoreIterator<Chars<'a>>,
|
string: PeekMoreIterator<Chars<'a>>,
|
||||||
|
crate_ident: Ident,
|
||||||
exprs: I,
|
exprs: I,
|
||||||
fmt_parts: Vec<FmtPart>,
|
fmt_parts: Vec<FmtPart>,
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +100,8 @@ where
|
||||||
self.save_string(std::mem::take(&mut next_string));
|
self.save_string(std::mem::take(&mut next_string));
|
||||||
let argument = self.fmt_spec()?;
|
let argument = self.fmt_spec()?;
|
||||||
let expr = self.expect_expr();
|
let expr = self.expect_expr();
|
||||||
self.fmt_parts.push(FmtPart::Spec(argument, expr));
|
self.fmt_parts
|
||||||
|
.push(FmtPart::Spec(self.crate_ident.clone(), argument, expr));
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
next_string.push(other);
|
next_string.push(other);
|
||||||
|
|
@ -117,7 +122,8 @@ where
|
||||||
if string.is_empty() {
|
if string.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.fmt_parts.push(FmtPart::Literal(string));
|
self.fmt_parts
|
||||||
|
.push(FmtPart::Literal(self.crate_ident.clone(), string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,25 +140,25 @@ impl ToTokens for Alignment {
|
||||||
impl ToTokens for FmtPart {
|
impl ToTokens for FmtPart {
|
||||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||||
let own_tokens = match self {
|
let own_tokens = match self {
|
||||||
FmtPart::Literal(lit) => {
|
FmtPart::Literal(crate_ident, lit) => {
|
||||||
let literal = LitStr::new(lit, Span::call_site());
|
let literal = LitStr::new(lit, Span::call_site());
|
||||||
quote! { ::mono_fmt::_private::Str(#literal) }
|
quote! { #crate_ident::_private::Str(#literal) }
|
||||||
}
|
}
|
||||||
FmtPart::Spec(spec, expr) => {
|
FmtPart::Spec(crate_ident, spec, expr) => {
|
||||||
let mut tokens = expr.to_token_stream();
|
let mut opt_toks = quote! { () };
|
||||||
|
|
||||||
// FIXME: Wait no we want `DebugArg::<WithUwu<WithOwo<()>>>(expr)`
|
// FIXME: Wait no we want `DebugArg::<WithUwu<WithOwo<()>>>(expr)`
|
||||||
|
|
||||||
if let Some(align) = &spec.align {
|
if let Some(align) = &spec.align {
|
||||||
if let Some(fill) = align.fill {
|
if let Some(fill) = align.fill {
|
||||||
tokens = quote! { ::mono_fmt::_private::WithFill::<_, #fill>(#tokens) };
|
opt_toks = quote! { #crate_ident::_private::WithFill<#opt_toks, #fill> };
|
||||||
}
|
}
|
||||||
let alignment = align.kind;
|
let alignment = align.kind;
|
||||||
tokens = quote! { ::mono_fmt::_private::#alignment(#tokens) };
|
opt_toks = quote! { #crate_ident::_private::#alignment<#opt_toks> };
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.alternate {
|
if spec.alternate {
|
||||||
tokens = quote! { ::mono_fmt::_private::WithAlternate(#tokens) };
|
opt_toks = quote! { #crate_ident::_private::WithAlternate<_, #opt_toks };
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.zero {
|
if spec.zero {
|
||||||
|
|
@ -169,10 +175,10 @@ impl ToTokens for FmtPart {
|
||||||
|
|
||||||
match spec.kind {
|
match spec.kind {
|
||||||
FmtType::Default => quote! {
|
FmtType::Default => quote! {
|
||||||
::mono_fmt::_private::DisplayArg(#tokens)
|
#crate_ident::_private::DisplayArg::<_, #opt_toks>(#expr, ::std::marker::PhantomData)
|
||||||
},
|
},
|
||||||
FmtType::Debug => quote! {
|
FmtType::Debug => quote! {
|
||||||
::mono_fmt::_private::DebugArg(#tokens)
|
#crate_ident::_private::DebugArg::<_, #opt_toks>(#expr, ::std::marker::PhantomData)
|
||||||
},
|
},
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
|
|
@ -184,11 +190,12 @@ impl ToTokens for FmtPart {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 formatter = Formatter {
|
let formatter = Formatter {
|
||||||
string: input.format_str.chars().peekmore(),
|
string: input.format_str.chars().peekmore(),
|
||||||
|
crate_ident: input.crate_ident,
|
||||||
exprs: input.exprs.into_iter(),
|
exprs: input.exprs.into_iter(),
|
||||||
fmt_parts: Vec::new(),
|
fmt_parts: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
@ -211,6 +218,7 @@ pub fn format_args(tokens: TokenStream) -> TokenStream {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use peekmore::PeekMore;
|
use peekmore::PeekMore;
|
||||||
|
use proc_macro2::{Ident, Span};
|
||||||
use syn::Expr;
|
use syn::Expr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -226,9 +234,14 @@ mod tests {
|
||||||
vec![fake_expr(); count]
|
vec![fake_expr(); count]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn crate_ident() -> Ident {
|
||||||
|
Ident::new("mono_fmt", Span::call_site())
|
||||||
|
}
|
||||||
|
|
||||||
fn run_test(string: &str, expr_count: usize) -> Vec<FmtPart> {
|
fn run_test(string: &str, expr_count: usize) -> Vec<FmtPart> {
|
||||||
let fmt = super::Formatter {
|
let fmt = super::Formatter {
|
||||||
string: string.chars().peekmore(),
|
string: string.chars().peekmore(),
|
||||||
|
crate_ident: crate_ident(),
|
||||||
exprs: fake_exprs(expr_count).into_iter(),
|
exprs: fake_exprs(expr_count).into_iter(),
|
||||||
fmt_parts: Vec::new(),
|
fmt_parts: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
@ -241,6 +254,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parts,
|
parts,
|
||||||
vec![FmtPart::Spec(
|
vec![FmtPart::Spec(
|
||||||
|
crate_ident(),
|
||||||
FmtSpec {
|
FmtSpec {
|
||||||
..FmtSpec::default()
|
..FmtSpec::default()
|
||||||
},
|
},
|
||||||
|
|
@ -255,6 +269,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parts,
|
parts,
|
||||||
vec![FmtPart::Spec(
|
vec![FmtPart::Spec(
|
||||||
|
crate_ident(),
|
||||||
FmtSpec {
|
FmtSpec {
|
||||||
kind: FmtType::Debug,
|
kind: FmtType::Debug,
|
||||||
..FmtSpec::default()
|
..FmtSpec::default()
|
||||||
|
|
@ -270,6 +285,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parts,
|
parts,
|
||||||
vec![FmtPart::Spec(
|
vec![FmtPart::Spec(
|
||||||
|
crate_ident(),
|
||||||
FmtSpec {
|
FmtSpec {
|
||||||
arg: Argument::Keyword("uwu".to_string()),
|
arg: Argument::Keyword("uwu".to_string()),
|
||||||
align: Some(Align {
|
align: Some(Align {
|
||||||
|
|
|
||||||
|
|
@ -50,17 +50,17 @@ impl Arguments for Str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DebugArg<T>(pub T);
|
pub struct DebugArg<T, O>(pub T, pub PhantomData<O>);
|
||||||
|
|
||||||
impl<T: Debug> Arguments for DebugArg<T> {
|
impl<T: Debug, OutOpt> Arguments for DebugArg<T, OutOpt> {
|
||||||
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
|
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
|
||||||
Debug::fmt(&self.0, f)
|
Debug::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DisplayArg<T>(pub T);
|
pub struct DisplayArg<T, O>(pub T, pub PhantomData<O>);
|
||||||
|
|
||||||
impl<T: Display> Arguments for DisplayArg<T> {
|
impl<T: Display, OutOpt> Arguments for DisplayArg<T, OutOpt> {
|
||||||
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
|
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
|
||||||
Display::fmt(&self.0, f)
|
Display::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/lib.rs
14
src/lib.rs
|
|
@ -1,13 +1,18 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
// for the test macro expansion
|
|
||||||
extern crate self as mono_fmt;
|
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
mod opts;
|
mod opts;
|
||||||
mod write;
|
mod write;
|
||||||
|
|
||||||
pub use mono_fmt_macro::format_args;
|
#[doc(hidden)]
|
||||||
|
pub use mono_fmt_macro::__format_args;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! format_args {
|
||||||
|
($($tt:tt)*) => {
|
||||||
|
$crate::__format_args!($crate $($tt)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub use crate::args::Arguments;
|
pub use crate::args::Arguments;
|
||||||
pub use crate::opts::FmtOpts;
|
pub use crate::opts::FmtOpts;
|
||||||
|
|
@ -137,7 +142,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn f() {
|
fn f() {
|
||||||
crate::format!("uwu, {f:_<?}", "what");
|
crate::format!("uwu, {f:_<?}", "what");
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue