1
1
// A test of the macro system. Can we do HTML literals?
2
2
3
3
// 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
+ */
5
17
6
18
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
+ )
12
22
}
13
23
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
+ ) ;
19
37
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
+ ) ;
24
49
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
+ ) ;
29
61
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
+ ) ;
34
73
35
- { $builder :expr := } => { }
74
+ { [ ] ; [ : $e : expr] ; } => ( $e ) ;
36
75
}
37
76
38
77
fn main ( ) {
39
-
40
78
let page = html ! {
41
79
<html>
42
80
<head><title>This is the title. </title></head>
@@ -45,24 +83,9 @@ fn main() {
45
83
</body>
46
84
</html>
47
85
} ;
48
-
49
- // When we can do this, we are successful:
50
- //
51
- //let page = tag(~" html", ~[tag(~" head", ~[ ...] ) ] )
52
-
53
86
}
54
87
55
- enum HTMLFragment {
88
+ enum HTMLFragment {
89
+ tag( ~str , ~[ HTMLFragment ] ) ,
90
+ text( ~str ) ,
56
91
}
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