#[macro_export]
macro_rules! xfmt {
(move $($tt:tt)*) => {
$crate::fmt(move |_f| {
$crate::__xfmt!{_f concat() $($tt)*}
Ok(())
})
};
($($tt:tt)*) => {
$crate::fmt(|_f| {
$crate::__xfmt!{_f concat() $($tt)*}
Ok(())
})
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt {
($f:ident concat($($texts:expr,)*) </ @ident($tag:expr) > $($tail:tt)*) => {
$crate::__xfmt!{$f concat($($texts,)* "</", $tag, ">",) $($tail)*}
};
($f:ident concat($($texts:expr,)*) </ $($tail:tt)*) => {
$crate::__xfmt_ident!{__xfmt! [$f concat($($texts,)*) </] $($tail)*}
};
($f:ident concat($($texts:expr,)*) <!-- $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)* "<!-- ",)}
$crate::__xfmt_comment!{$f () $($tail)*}
};
($f:ident concat($($texts:expr,)*) <![CDATA[ $($tt:tt)* ]]> $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)* "<![CDATA[",)}
{
let _f = $crate::EscapeCharData::wrap($f);
$crate::__fmt!{_f $($tt)*}
}
$crate::__xfmt!{$f concat("]]>",) $($tail)*}
};
($f:ident concat($($texts:expr,)*) <! @ident($tag:expr) $($tail:tt)*) => {
$crate::__xfmt_attrs!{__xfmt_close_tag! $f concat($($texts,)* "<!", $tag,) $($tail)*}
};
($f:ident concat($($texts:expr,)*) <! $($tail:tt)*) => {
$crate::__xfmt_ident!{__xfmt! [$f concat($($texts,)*) <!] $($tail)*}
};
($f:ident concat($($texts:expr,)*) <? @ident($tag:expr) $($tail:tt)*) => {
$crate::__xfmt_attrs!{__xfmt_close_decl! $f concat($($texts,)* "<?", $tag,) $($tail)*}
};
($f:ident concat($($texts:expr,)*) <? $($tail:tt)*) => {
$crate::__xfmt_ident!{__xfmt! [$f concat($($texts,)*) <?] $($tail)*}
};
($f:ident concat($($texts:expr,)*) < @ident($tag:expr) $($tail:tt)*) => {
$crate::__xfmt_attrs!{__xfmt_close_tag! $f concat($($texts,)* "<", $tag,) $($tail)*}
};
($f:ident concat($($texts:expr,)*) < $($tail:tt)*) => {
$crate::__xfmt_ident!{__xfmt! [$f concat($($texts,)*) <] $($tail)*}
};
($f:ident concat($($texts:expr,)*) $text1:literal $text2:literal $($tail:tt)*) => {
$crate::__xfmt!{$f concat($($texts,)* $text1, $text2,) $($tail)*}
};
($f:ident concat($($texts:expr,)*) $text:literal $($tail:tt)*) => {
$crate::__xfmt!{$f concat($($texts,)* $text,) $($tail)*}
};
($f:ident concat($($texts:expr,)*) {$($e:tt)*} $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)*)}
::core::fmt::write($crate::EscapeText::wrap($f), $crate::__xfmt_format!([] $($e)*))?;
$crate::__xfmt!{$f concat() $($tail)*}
};
($f:ident concat($($texts:expr,)*) |$ff:pat_param| $block:block $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)*)}
let $ff = &mut *$f;
$block
$crate::__xfmt!{$f concat() $($tail)*}
};
($f:ident concat($($texts:expr,)*) |$ff:pat_param| $stmt:stmt; $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)*)}
let $ff = &mut *$f;
$stmt
$crate::__xfmt!{$f concat() $($tail)*}
};
($f:ident concat($($texts:expr,)*) let $p:pat = $e:expr; $($tail:tt)*) => {
let $p = $e;
$crate::__xfmt!{$f concat($($texts,)*) $($tail)*}
};
($f:ident concat($($texts:expr,)*) if $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)*)}
$crate::__xfmt_if!{$f [] if $($tail)*}
};
($f:ident concat($($texts:expr,)*) match ($e:expr) { $($body:tt)* } $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)*)}
$crate::__xfmt_match!{$f match ($e) {} $($body)*}
$crate::__xfmt!{$f concat() $($tail)*}
};
($f:ident concat($($texts:expr,)*) match $($tail:tt)*) => {
$crate::__with_parens!{__xfmt! [$f concat($($texts:expr,)*) match] [] $($tail)*}
};
($f:ident concat($($texts:expr,)*) for $p:pat in ($e:expr) { $($body:tt)*} $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)*)}
for $p in $e {
$crate::__xfmt!{$f concat() $($body)*}
}
$crate::__xfmt!{$f concat() $($tail)*}
};
($f:ident concat($($texts:expr,)*) for $p:pat in $($tail:tt)*) => {
$crate::__with_parens!{__xfmt! [$f concat($($texts,)*) for $p in] [] $($tail)*}
};
($f:ident concat($($texts:expr,)*) ($($tt:tt)*) $($tail:tt)*) => {
$crate::__xfmt!{$f concat($($texts,)*) $($tt)*}
$crate::__xfmt!{$f concat() $($tail)*}
};
($f:ident concat()) => {};
($f:ident concat($($texts:expr,)*)) => {
$crate::__write_str!{$f concat($($texts,)*)}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt_close_tag {
($f:ident concat($($texts:expr,)*) > $($tail:tt)*) => {
$crate::__xfmt!{$f concat($($texts,)* ">",) $($tail)*}
};
($f:ident concat($($texts:expr,)*) /> $($tail:tt)*) => {
$crate::__xfmt!{$f concat($($texts,)* " />",) $($tail)*}
};
($f:ident concat($($texts:expr,)*)) => {
$crate::__xfmt!{$f concat($($texts,)* ">",)}
compile_error!("missing closing `>`");
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt_close_decl {
($f:ident concat($($texts:expr,)*) ?> $($tail:tt)*) => {
$crate::__xfmt!{$f concat($($texts,)* "?>",) $($tail)*}
};
($f:ident concat($($texts:expr,)*)) => {
$crate::__xfmt!{$f concat($($texts,)* "?>",)}
compile_error!("missing closing `?>`");
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt_attrs {
($term:ident! $f:ident concat($($texts:expr,)*) @ident($key:expr) = $($tail:tt)*) => {
$crate::__xfmt_attrvalue!{$term! $f concat($($texts,)* " ", $key, "=",) $($tail)*}
};
($term:ident! $f:ident concat($($texts:expr,)*) @ident($key:expr) $($tail:tt)*) => {
$crate::__xfmt_attrs!{$term! $f concat($($texts,)* " ", $key,) $($tail)*}
};
($term:ident! $f:ident concat($($texts:expr,)*) $key:ident $($tail:tt)*) => {
$crate::__xfmt_ident!{__xfmt_attrs! [$term! $f concat($($texts,)*) ] $key $($tail)*}
};
($term:ident! $f:ident concat($($texts:expr,)*) $key:literal = $($tail:tt)*) => {
$crate::__xfmt_attrvalue!{$term! $f concat($($texts,)* " ", $key, "=",) $($tail)*}
};
($term:ident! $f:ident concat($($texts:expr,)*) $($tail:tt)*) => {
$crate::$term!{$f concat($($texts,)*) $($tail)*}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt_attrvalue {
($term:ident! $f:ident concat($($texts:expr,)*) $text:literal $($tail:tt)*) => {
$crate::__xfmt_attrs!{$term! $f concat($($texts,)* "\"", $text, "\"",) $($tail)*}
};
($term:ident! $f:ident concat($($texts:expr,)*) {$($e:tt)*} $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)* "\"",)}
::core::fmt::write($crate::EscapeAttrValue::wrap($f), $crate::__xfmt_format!([] $($e)*))?;
$crate::__xfmt_attrs!{$term! $f concat("\"",) $($tail)*}
};
($term:ident! $f:ident concat($($texts:expr,)*) |$ff:pat_param| $block:block $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)* "\"",)}
let $ff = &mut *$f;
$block
$crate::__xfmt_attrs!{$term! $f concat("\"",) $($tail)*}
};
($term:ident! $f:ident concat($($texts:expr,)*) |$ff:pat_param| $stmt:stmt; $($tail:tt)*) => {
$crate::__write_str!{$f concat($($texts,)* "\"",)}
let $ff = &mut *$f;
$stmt
$crate::__xfmt_attrs!{$term! $f concat("\"",) $($tail)*}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt_ident {
($next:ident! [$($prefix:tt)*] $name:literal $($tail:tt)*) => {
$crate::$next!{$($prefix)* @ident(concat!($name)) $($tail)*}
};
($next:ident! [$($prefix:tt)*] $frag:ident: $($tail:tt)*) => {
$crate::__xfmt_ident_cont!{$next! [$($prefix)*] [stringify!($frag), ":",] $($tail)*}
};
($next:ident! [$($prefix:tt)*] $frag:ident- $($tail:tt)*) => {
$crate::__xfmt_ident_cont!{$next! [$($prefix)*] [stringify!($frag), "-",] $($tail)*}
};
($next:ident! [$($prefix:tt)*] $frag:ident. $($tail:tt)*) => {
$crate::__xfmt_ident_cont!{$next! [$($prefix)*] [stringify!($frag), ".",] $($tail)*}
};
($next:ident! [$($prefix:tt)*] $frag:ident $($tail:tt)*) => {
$crate::$next!{$($prefix)* @ident(stringify!($frag)) $($tail)*}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt_ident_cont {
($next:ident! [$($prefix:tt)*] [$($tt:expr,)*] $frag:ident- $($tail:tt)*) => {
$crate::__xfmt_ident_cont!{$next! [$($prefix)*] [$($tt,)* stringify!($frag), "-",] $($tail)*}
};
($next:ident! [$($prefix:tt)*] [$($tt:expr,)*] $frag:ident. $($tail:tt)*) => {
$crate::__xfmt_ident_cont!{$next! [$($prefix)*] [$($tt,)* stringify!($frag), ".",] $($tail)*}
};
($next:ident! [$($prefix:tt)*] [$($tt:expr,)*] $frag:ident $($tail:tt)*) => {
$crate::$next!{$($prefix)* @ident(concat!($($tt,)* stringify!($frag))) $($tail)*}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __xfmt_comment {
($f:ident ($($tt:tt)*) --> $($tail:tt)*) => {
{
let _f = $crate::EscapeComment::wrap($f);
$crate::__fmt!{_f $($tt)*}
}
$crate::__xfmt!{$f concat(" -->",) $($tail)*}
};
($f:ident ($($tt:tt)*) $nom:tt $($tail:tt)*) => {
$crate::__xfmt_comment!{$f ($($tt)* $nom) $($tail)*}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __xfmt_format {
([$($e:tt)*] : $($tail:tt)*) => {
$crate::__xfmt_format_expr!([$($e)*] : $($tail)*)
};
([$($e:tt)*] ; $($tail:tt)*) => {
$crate::__xfmt_format_expr!([$($e)*] : $($tail)*)
};
([$($e:tt)*] $nom:tt $($tail:tt)*) => {
$crate::__xfmt_format!([$($e)* $nom] $($tail)*)
};
([$($e:tt)*]) => {
$crate::__xfmt_format_expr!([$($e)*])
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __xfmt_format_expr {
([$e:expr]) => {
::core::format_args!("{}", $e)
};
([$e:expr $(, $w:expr)?] $($s:tt)*) => {
::core::format_args!(concat!("{", $(stringify!($s),)* "}"), $e $(,$w)?)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __write_str {
($f:ident concat()) => {};
($f:ident concat($($texts:expr,)+)) => {
$f.write_str($crate::obfstr!(concat!($($texts),+)))?;
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __xfmt_if {
($f:ident [$($c:tt)*] if let $p:pat = ($e:expr) { $($body:tt)* } $($tail:tt)*) => {
$crate::__xfmt_if!{$f [$($c)* if let $p = $e { $crate::__xfmt!{$f concat() $($body)*} }] $($tail)*}
};
($f:ident [$($c:tt)*] if let $p:pat = $($tail:tt)*) => {
$crate::__with_parens!{__xfmt_if! [$f [$($c)*] if let $p =] [] $($tail)*}
};
($f:ident [$($c:tt)*] if ($e:expr) { $($body:tt)* } $($tail:tt)*) => {
$crate::__xfmt_if!{$f [$($c)* if $e { $crate::__xfmt!{$f concat() $($body)*} }] $($tail)*}
};
($f:ident [$($c:tt)*] if $($tail:tt)*) => {
$crate::__with_parens!{__xfmt_if! [$f [$($c)*] if] [] $($tail)*}
};
($f:ident [$($c:tt)*] else if let $p:pat = ($e:expr) { $($body:tt)* } $($tail:tt)*) => {
$crate::__xfmt_if!{$f [$($c)* else if let $p = $e { $crate::__xfmt!{$f concat() $($body)*} }] $($tail)*}
};
($f:ident [$($c:tt)*] else if let $p:pat = $($tail:tt)*) => {
$crate::__with_parens!{__xfmt_if! [$f [$($c)*] else if let $p =] [] $($tail)*}
};
($f:ident [$($c:tt)*] else if ($e:expr) { $($body:tt)* } $($tail:tt)*) => {
$crate::__xfmt_if!{$f [$($c)* else if $e { $crate::__xfmt!{$f concat() $($body)*} }] $($tail)*}
};
($f:ident [$($c:tt)*] else if $($tail:tt)*) => {
$crate::__with_parens!{__xfmt_if! [$f [$($c)*] else if] [] $($tail)*}
};
($f:ident [$($c:tt)*] else { $($body:tt)* } $($tail:tt)*) => {
$($c)*
else {
$crate::__xfmt!{$f concat() $($body)*}
}
$crate::__xfmt!{$f concat() $($tail)*}
};
($f:ident [$($c:tt)*] $($tail:tt)*) => {
$($c)*
$crate::__xfmt!{$f concat() $($tail)*}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __xfmt_match {
($f:ident match ($e:expr) {$($arms:tt)*} $p:pat $(if $guard:expr)? => { $($body:tt)* }, $($tail:tt)*) => {
$crate::__xfmt_match!{$f match ($e) {$($arms)* $p $(if $guard)? => { $crate::__xfmt!{$f concat() $($body)*} }} $($tail)*}
};
($f:ident match ($e:expr) {$($arms:tt)*} $p:pat $(if $guard:expr)? => { $($body:tt)* } $($tail:tt)*) => {
$crate::__xfmt_match!{$f match ($e) {$($arms)* $p $(if $guard)? => { $crate::__xfmt!{$f concat() $($body)*} }} $($tail)*}
};
($f:ident match ($e:expr) {$($arms:tt)*} $p:pat $(if $guard:expr)? => $($tail:tt)*) => {
$crate::__until_comma!{__xfmt_match! [$f match ($e) {$($arms)*} $p $(if $guard)? =>] {} $($tail)*}
};
($f:ident match ($e:expr) {$($pat:pat $(if $guard:expr)? => $block:block)*}) => {
match $e {
$($pat $(if $guard)? => $block)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __with_parens {
($next:ident! [$($prefix:tt)*] [$($tt:tt)*] { $($body:tt)* } $($tail:tt)*) => {
$crate::$next!{$($prefix)* ($($tt)*) { $($body)* } $($tail)*}
};
($next:ident! [$($prefix:tt)*] [$($tt:tt)*] $nom:tt $($tail:tt)*) => {
$crate::__with_parens!{$next! [$($prefix)*] [$($tt)* $nom] $($tail)*}
};
($next:ident! [$($prefix:tt)*] [$($tt:tt)*]) => {
$crate::$next!{$($prefix)* ($($tt)*) {}}
compile_error!(concat!("missing block after expression: ", stringify!($($tt)*)));
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __until_comma {
($next:ident! [$($prefix:tt)*] {$($tt:tt)*} , $($tail:tt)*) => {
$crate::$next!{$($prefix)* {$($tt)*}, $($tail)*}
};
($next:ident! [$($prefix:tt)*] {$($tt:tt)*} $nom:tt $($tail:tt)*) => {
$crate::__until_comma!{$next! [$($prefix)*] {$($tt)* $nom} $($tail)*}
};
($next:ident! [$($prefix:tt)*] {$($tt:tt)*}) => {
$crate::$next!{$($prefix)* {$($tt)*}}
};
}
#[test]
fn test_syntax() {
let c = 5i32;
let _ = xfmt! {
(<a> <a-b> <"a-0"> <a.b> <"a.0"> <"0">)
(<xmlns:a> <xmlns:a-b> <xmlns:a.b>)
(</a> </a-b> </"a-0"> </a.b> </"a.0"> </"0">)
(<tag a="hello" a-b='a' "a-0"=0 a.b="a.b">)
<self-closing />
<?open?>"{}"
<!-- --><!-- "asd" --><!-- 0 '1' "2" 0.3 -->
<![CDATA[if c.is_positive() { "Hello world!" }]]>
{42}
};
let _ = xfmt!{if true {}};
let _ = xfmt!{for _ in 0..4 {}};
let _ = xfmt!{match true { false => "false", true => "true"}};
}