| //@ 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),*]; | |
| </$tag:ident> $($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! ( | |
| <html> | |
| <head><title>This is the title.</title></head> | |
| <body> | |
| <p>This is some text</p> | |
| </body> | |
| </html> | |
| ); | |
| } | |
| #[allow(dead_code)] | |
| enum HTMLFragment { | |
| tag(String, Vec<HTMLFragment> ), | |
| text(String), | |
| } |