//@ run-pass #![allow(non_camel_case_types)] // A test of the macro system. Can we do HTML literals? /* This is an HTML parser written as a macro. It's all CPS, and we have to carry around a bunch of state. The arguments to macros all look like this: { tag_stack* # expr* # tokens } The stack keeps track of where we are in the tree. The expr is a list of children of the current node. The tokens are everything that's left. */ use HTMLFragment::{tag, text}; macro_rules! html { ( $($body:tt)* ) => ( parse_node!( []; []; $($body)* ) ) } macro_rules! parse_node { ( [:$head:ident ($(:$head_nodes:expr),*) $(:$tags:ident ($(:$tag_nodes:expr),*))*]; [$(:$nodes:expr),*]; $($rest:tt)* ) => ( parse_node!( [$(: $tags ($(:$tag_nodes),*))*]; [$(:$head_nodes,)* :tag(stringify!($head).to_string(), vec![$($nodes),*])]; $($rest)* ) ); ( [$(:$tags:ident ($(:$tag_nodes:expr),*) )*]; [$(:$nodes:expr),*]; <$tag:ident> $($rest:tt)* ) => ( parse_node!( [:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*]; []; $($rest)* ) ); ( [$(:$tags:ident ($(:$tag_nodes:expr),*) )*]; [$(:$nodes:expr),*]; . $($rest:tt)* ) => ( parse_node!( [$(: $tags ($(:$tag_nodes),*))*]; [$(:$nodes,)* :text(".".to_string())]; $($rest)* ) ); ( [$(:$tags:ident ($(:$tag_nodes:expr),*) )*]; [$(:$nodes:expr),*]; $word:ident $($rest:tt)* ) => ( parse_node!( [$(: $tags ($(:$tag_nodes),*))*]; [$(:$nodes,)* :text(stringify!($word).to_string())]; $($rest)* ) ); ( []; [:$e:expr]; ) => ( $e ); } pub fn main() { let _page = html! ( This is the title.

This is some text

); } #[allow(dead_code)] enum HTMLFragment { tag(String, Vec ), text(String), }