1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
// 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(unused_tuple_struct_fields)]
enum HTMLFragment {
tag(String, Vec<HTMLFragment> ),
text(String),
}
|