Skip to content

Commit 9a1a258

Browse files
committed
A better HTML parser.
1 parent b354fe2 commit 9a1a258

File tree

1 file changed

+66
-43
lines changed

1 file changed

+66
-43
lines changed

src/test/run-pass/html-literals.rs

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,80 @@
11
// A test of the macro system. Can we do HTML literals?
22

33
// xfail-pretty
4-
// xfail-test
4+
5+
/*
6+
7+
This is an HTML parser written as a macro. It's all CPS, and we have
8+
to carry around a bunch of state. The arguments to macros all look like this:
9+
10+
{ tag_stack* # expr* # tokens }
11+
12+
The stack keeps track of where we are in the tree. The expr is a list
13+
of children of the current node. The tokens are everything that's
14+
left.
15+
16+
*/
517

618
macro_rules! html {
7-
{ $($body:tt)* } => {
8-
let builder = HTMLBuilder();
9-
build_html!{builder := $($body)*};
10-
builder.getDoc()
11-
}
19+
{ $($body:tt)* } => (
20+
parse_node!( []; []; $($body)* )
21+
)
1222
}
1323

14-
macro_rules! build_html {
15-
{ $builder:expr := </$tag:ident> $($rest:tt)* } => {
16-
$builder.endTag(stringify!($tag));
17-
build_html!{ $builder := $($rest)* };
18-
};
24+
macro_rules! parse_node {
25+
{
26+
[:$head:ident ($(:$head_nodes:expr),*)
27+
$(:$tags:ident ($(:$tag_nodes:expr),*))*];
28+
[$(:$nodes:expr),*];
29+
</$tag:ident> $($rest:tt)*
30+
} => (
31+
parse_node!(
32+
[$(: $tags ($(:$tag_nodes),*))*];
33+
[$(:$head_nodes,)* :tag(stringify!($head), ~[$($nodes),*])];
34+
$($rest)*
35+
)
36+
);
1937

20-
{ $builder:expr := <$tag:ident> $($rest:tt)* } => {
21-
$builder.beginTag(stringify!($tag));
22-
build_html!{ $builder := $($rest)* };
23-
};
38+
{
39+
[$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
40+
[$(:$nodes:expr),*];
41+
<$tag:ident> $($rest:tt)*
42+
} => (
43+
parse_node!(
44+
[:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*];
45+
[];
46+
$($rest)*
47+
)
48+
);
2449

25-
{ $builder:expr := . $($rest:tt)* } => {
26-
$builder.addText(~".");
27-
build_html!{ $builder := $($rest)* };
28-
};
50+
{
51+
[$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
52+
[$(:$nodes:expr),*];
53+
. $($rest:tt)*
54+
} => (
55+
parse_node!(
56+
[$(: $tags ($(:$tag_nodes),*))*];
57+
[$(:$nodes,)* :text(~".")];
58+
$($rest)*
59+
)
60+
);
2961

30-
{ $builder:expr := $word:ident $($rest:tt)* } => {
31-
$builder.addText(stringify!($word));
32-
build_html!{ $builder := $($rest)* };
33-
};
62+
{
63+
[$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
64+
[$(:$nodes:expr),*];
65+
$word:ident $($rest:tt)*
66+
} => (
67+
parse_node!(
68+
[$(: $tags ($(:$tag_nodes),*))*];
69+
[$(:$nodes,)* :text(stringify!($word))];
70+
$($rest)*
71+
)
72+
);
3473

35-
{ $builder:expr := } => { }
74+
{ []; [:$e:expr]; } => ( $e );
3675
}
3776

3877
fn main() {
39-
4078
let page = html! {
4179
<html>
4280
<head><title>This is the title.</title></head>
@@ -45,24 +83,9 @@ fn main() {
4583
</body>
4684
</html>
4785
};
48-
49-
// When we can do this, we are successful:
50-
//
51-
//let page = tag(~"html", ~[tag(~"head", ~[...])])
52-
5386
}
5487

55-
enum HTMLFragment {
88+
enum HTMLFragment {
89+
tag(~str, ~[HTMLFragment]),
90+
text(~str),
5691
}
57-
58-
struct HTMLBuilder {
59-
bar: ();
60-
fn getDoc() -> HTMLFragment { fail }
61-
fn beginTag(tag: ~str) { }
62-
fn endTag(tag: ~str) { }
63-
fn addText(test: ~str) { }
64-
}
65-
66-
fn HTMLBuilder() -> HTMLBuilder {
67-
HTMLBuilder { bar: () }
68-
}

0 commit comments

Comments
 (0)