@@ -20,39 +20,40 @@ fn parse_element<I>(chars: &mut std::iter::Peekable<I>) -> JSXNode
2020where
2121 I : Iterator < Item = char > ,
2222{
23- consume_whitespace ( chars) ;
24- assert_eq ! ( chars. next ( ) , Some ( '<' ) ) ;
23+ skip_ws ( chars) ;
24+ expect ( chars, '<' ) ;
2525
26- let tag = parse_identifier ( chars) ;
27- let attrs = parse_attributes ( chars) ;
26+ let tag = parse_ident ( chars) ;
27+ let attrs = parse_attrs ( chars) ;
2828
29- let is_self_closing = if let Some ( '/' ) = chars. peek ( ) {
30- chars. next ( ) ;
31- assert_eq ! ( chars. next( ) , Some ( '>' ) ) ;
32- true
33- } else {
34- assert_eq ! ( chars. next( ) , Some ( '>' ) ) ;
35- false
29+ let self_closing = match chars. peek ( ) {
30+ Some ( '/' ) => {
31+ chars. next ( ) ;
32+ expect ( chars, '>' ) ;
33+ true
34+ }
35+ Some ( '>' ) => {
36+ chars. next ( ) ;
37+ false
38+ }
39+ _ => panic ! ( "Invalid JSX format" ) ,
3640 } ;
3741
3842 let mut children = vec ! [ ] ;
3943
40- if !is_self_closing {
44+ if !self_closing {
4145 loop {
42- consume_whitespace ( chars) ;
43-
46+ skip_ws ( chars) ;
4447 match chars. peek ( ) {
45- Some ( '<' ) => {
46- if lookahead ( chars, "</" ) {
47- consume_until ( chars, '>' ) ;
48- chars. next ( ) ; // consume '>'
49- break ;
50- } else {
51- children. push ( parse_element ( chars) ) ;
52- }
48+ Some ( '<' ) if peek_match ( chars, "</" ) => {
49+ consume ( chars, "</" ) ;
50+ parse_ident ( chars) ;
51+ expect ( chars, '>' ) ;
52+ break ;
5353 }
54+ Some ( '<' ) => children. push ( parse_element ( chars) ) ,
5455 Some ( '{' ) => {
55- chars. next ( ) ; // {
56+ chars. next ( ) ; // consume {
5657 let expr = consume_until ( chars, '}' ) ;
5758 chars. next ( ) ; // }
5859 children. push ( JSXNode :: Expression ( expr. trim ( ) . to_string ( ) ) ) ;
@@ -68,14 +69,10 @@ where
6869 }
6970 }
7071
71- JSXNode :: Element {
72- tag,
73- attrs,
74- children,
75- }
72+ JSXNode :: Element { tag, attrs, children }
7673}
7774
78- fn parse_identifier < I > ( chars : & mut std:: iter:: Peekable < I > ) -> String
75+ fn parse_ident < I > ( chars : & mut std:: iter:: Peekable < I > ) -> String
7976where
8077 I : Iterator < Item = char > ,
8178{
@@ -91,20 +88,20 @@ where
9188 ident
9289}
9390
94- fn parse_attributes < I > ( chars : & mut std:: iter:: Peekable < I > ) -> HashMap < String , String >
91+ fn parse_attrs < I > ( chars : & mut std:: iter:: Peekable < I > ) -> HashMap < String , String >
9592where
9693 I : Iterator < Item = char > ,
9794{
9895 let mut attrs = HashMap :: new ( ) ;
9996 loop {
100- consume_whitespace ( chars) ;
97+ skip_ws ( chars) ;
10198 match chars. peek ( ) {
10299 Some ( '>' ) | Some ( '/' ) => break ,
103100 Some ( _) => {
104- let name = parse_identifier ( chars) ;
105- consume_whitespace ( chars) ;
106- assert_eq ! ( chars. next ( ) , Some ( '=' ) ) ;
107- consume_whitespace ( chars) ;
101+ let name = parse_ident ( chars) ;
102+ skip_ws ( chars) ;
103+ expect ( chars, '=' ) ;
104+ skip_ws ( chars) ;
108105 let quote = chars. next ( ) . unwrap ( ) ;
109106 assert ! ( quote == '"' || quote == '\'' ) ;
110107 let value = consume_until ( chars, quote) ;
@@ -117,49 +114,37 @@ where
117114 attrs
118115}
119116
120- fn consume_whitespace < I > ( chars : & mut std:: iter:: Peekable < I > )
121- where
122- I : Iterator < Item = char > ,
123- {
117+ fn skip_ws < I : Iterator < Item = char > > ( chars : & mut std:: iter:: Peekable < I > ) {
124118 while matches ! ( chars. peek( ) , Some ( c) if c. is_whitespace( ) ) {
125119 chars. next ( ) ;
126120 }
127121}
128122
129- fn consume_until < I > ( chars : & mut std:: iter:: Peekable < I > , end : char ) -> String
130- where
131- I : Iterator < Item = char > ,
132- {
133- let mut result = String :: new ( ) ;
134- while let Some ( & ch) = chars. peek ( ) {
135- if ch == end {
123+ fn consume_until < I : Iterator < Item = char > > ( chars : & mut std:: iter:: Peekable < I > , end : char ) -> String {
124+ let mut out = String :: new ( ) ;
125+ while let Some ( & c) = chars. peek ( ) {
126+ if c == end {
136127 break ;
137128 }
138- result . push ( ch ) ;
129+ out . push ( c ) ;
139130 chars. next ( ) ;
140131 }
141- result
132+ out
142133}
143134
144- fn consume_text < I > ( chars : & mut std:: iter:: Peekable < I > ) -> String
145- where
146- I : Iterator < Item = char > ,
147- {
148- let mut result = String :: new ( ) ;
135+ fn consume_text < I : Iterator < Item = char > > ( chars : & mut std:: iter:: Peekable < I > ) -> String {
136+ let mut out = String :: new ( ) ;
149137 while let Some ( & ch) = chars. peek ( ) {
150138 if ch == '<' || ch == '{' {
151139 break ;
152140 }
153- result . push ( ch) ;
141+ out . push ( ch) ;
154142 chars. next ( ) ;
155143 }
156- result
144+ out
157145}
158146
159- fn lookahead < I > ( chars : & mut std:: iter:: Peekable < I > , pat : & str ) -> bool
160- where
161- I : Iterator < Item = char > + Clone ,
162- {
147+ fn peek_match < I : Iterator < Item = char > + Clone > ( chars : & std:: iter:: Peekable < I > , pat : & str ) -> bool {
163148 let mut clone = chars. clone ( ) ;
164149 for c in pat. chars ( ) {
165150 if clone. next ( ) != Some ( c) {
@@ -168,3 +153,16 @@ where
168153 }
169154 true
170155}
156+
157+ fn consume < I : Iterator < Item = char > > ( chars : & mut std:: iter:: Peekable < I > , pat : & str ) {
158+ for expected in pat. chars ( ) {
159+ assert_eq ! ( chars. next( ) , Some ( expected) ) ;
160+ }
161+ }
162+
163+ fn expect < I : Iterator < Item = char > > ( chars : & mut std:: iter:: Peekable < I > , expected : char ) {
164+ match chars. next ( ) {
165+ Some ( c) if c == expected => { }
166+ _ => panic ! ( "Expected '{}'" , expected) ,
167+ }
168+ }
0 commit comments