@@ -6,17 +6,21 @@ use thiserror::Error;
66pub struct Parser {
77 tokens : TokenStream ,
88 current : usize ,
9+ errors : Vec < ParserError > ,
910}
1011
1112impl Parser {
1213 pub fn new ( tokens : TokenStream ) -> Self {
13- Self { tokens, current : 0 }
14+ Self {
15+ tokens,
16+ current : 0 ,
17+ errors : Vec :: new ( ) ,
18+ }
1419 }
1520
16- pub fn parse ( & mut self ) -> Result < ( Ast , Vec < AstError > ) , ParserError > {
21+ pub fn parse ( & mut self ) -> Result < ( Ast , Vec < ParserError > ) , ParserError > {
1722 let mut ast = Ast :: default ( ) ;
1823 let mut line_offsets = LineOffsets :: new ( ) ;
19- let mut all_errors = Vec :: new ( ) ;
2024
2125 // First pass: collect line offsets
2226 for token in self . tokens . tokens ( ) {
@@ -33,23 +37,21 @@ impl Parser {
3337 // Second pass: parse nodes
3438 while !self . is_at_end ( ) {
3539 match self . next_node ( ) {
36- Ok ( ( node, errors ) ) => {
40+ Ok ( node) => {
3741 ast. add_node ( node) ;
38- all_errors. extend ( errors) ;
3942 }
4043 Err ( _) => self . synchronize ( ) ?,
4144 }
4245 }
4346
4447 ast. set_line_offsets ( line_offsets) ;
45- Ok ( ( ast, all_errors ) )
48+ Ok ( ( ast, std :: mem :: take ( & mut self . errors ) ) )
4649 }
4750
48- fn next_node ( & mut self ) -> Result < ( Node , Vec < AstError > ) , ParserError > {
51+ fn next_node ( & mut self ) -> Result < Node , ParserError > {
4952 if self . is_at_end ( ) {
5053 return Err ( ParserError :: Ast ( AstError :: StreamError ( "AtEnd" . to_string ( ) ) ) ) ;
5154 }
52-
5355 let token = self . peek ( ) ?;
5456 match token. token_type ( ) {
5557 TokenType :: DjangoBlock ( content) => {
@@ -58,7 +60,7 @@ impl Parser {
5860 }
5961 TokenType :: DjangoVariable ( content) => {
6062 self . consume ( ) ?;
61- Ok ( ( self . parse_django_variable ( content) ? , vec ! [ ] ) )
63+ self . parse_django_variable ( content)
6264 }
6365 TokenType :: Text ( _)
6466 | TokenType :: Whitespace ( _)
@@ -69,7 +71,7 @@ impl Parser {
6971 | TokenType :: ScriptTagOpen ( _)
7072 | TokenType :: ScriptTagClose ( _)
7173 | TokenType :: StyleTagOpen ( _)
72- | TokenType :: StyleTagClose ( _) => Ok ( ( self . parse_text ( ) ? , vec ! [ ] ) ) ,
74+ | TokenType :: StyleTagClose ( _) => self . parse_text ( ) ,
7375 TokenType :: Comment ( content, start, end) => {
7476 self . consume ( ) ?;
7577 self . parse_comment ( content, start, end. as_deref ( ) )
@@ -78,7 +80,7 @@ impl Parser {
7880 }
7981 }
8082
81- fn parse_django_block ( & mut self , content : & str ) -> Result < ( Node , Vec < AstError > ) , ParserError > {
83+ fn parse_django_block ( & mut self , content : & str ) -> Result < Node , ParserError > {
8284 let token = self . peek_previous ( ) ?;
8385 let start_pos = token. start ( ) . unwrap_or ( 0 ) ;
8486 let total_length = token. length ( ) . unwrap_or ( 0 ) ;
@@ -110,63 +112,54 @@ impl Parser {
110112
111113 // Check if this is a closing tag
112114 if tag_name. starts_with ( "end" ) {
113- return Ok ( ( Node :: Block ( Block :: Closing { tag } ) , vec ! [ ] ) ) ;
115+ return Ok ( Node :: Block ( Block :: Closing { tag } ) ) ;
114116 }
115117
116118 // Load tag specs
117119 let specs = TagSpec :: load_builtin_specs ( ) ?;
118120 let spec = match specs. get ( & tag_name) {
119121 Some ( spec) => spec,
120- None => return Ok ( ( Node :: Block ( Block :: Tag { tag } ) , vec ! [ ] ) ) ,
122+ None => return Ok ( Node :: Block ( Block :: Tag { tag } ) ) ,
121123 } ;
122124
123125 match spec. tag_type {
124126 TagType :: Block => {
125127 let mut nodes = Vec :: new ( ) ;
126- let mut all_errors = Vec :: new ( ) ;
127128
128129 // Parse child nodes until we find the closing tag
129- while let Ok ( ( node, errors ) ) = self . next_node ( ) {
130+ while let Ok ( node) = self . next_node ( ) {
130131 if let Node :: Block ( Block :: Closing { tag : closing_tag } ) = & node {
131132 if let Some ( expected_closing) = & spec. closing {
132133 if closing_tag. name == * expected_closing {
133- return Ok ( (
134- Node :: Block ( Block :: Block {
135- tag,
136- nodes,
137- closing : Some ( Box :: new ( Block :: Closing {
138- tag : closing_tag. clone ( ) ,
139- } ) ) ,
140- assignments : Some ( assignments) ,
141- } ) ,
142- all_errors,
143- ) ) ;
134+ return Ok ( Node :: Block ( Block :: Block {
135+ tag,
136+ nodes,
137+ closing : Some ( Box :: new ( Block :: Closing {
138+ tag : closing_tag. clone ( ) ,
139+ } ) ) ,
140+ assignments : Some ( assignments) ,
141+ } ) ) ;
144142 }
145143 }
146144 }
147145 nodes. push ( node) ;
148- all_errors. extend ( errors) ;
149146 }
150147
151148 // Add error for unclosed tag
152- all_errors. push ( AstError :: UnclosedTag ( tag_name. clone ( ) ) ) ;
153-
154- // Return the partial block with the error
155- Ok ( (
156- Node :: Block ( Block :: Block {
157- tag,
158- nodes,
159- closing : None ,
160- assignments : Some ( assignments) ,
161- } ) ,
162- all_errors,
163- ) )
149+ self . errors . push ( ParserError :: Ast ( AstError :: UnclosedTag ( tag_name. clone ( ) ) ) ) ;
150+
151+ Ok ( Node :: Block ( Block :: Block {
152+ tag,
153+ nodes,
154+ closing : None ,
155+ assignments : Some ( assignments) ,
156+ } ) )
164157 }
165- TagType :: Tag => Ok ( ( Node :: Block ( Block :: Tag { tag } ) , vec ! [ ] ) ) ,
166- TagType :: Variable => Ok ( ( Node :: Block ( Block :: Variable { tag } ) , vec ! [ ] ) ) ,
158+ TagType :: Tag => Ok ( Node :: Block ( Block :: Tag { tag } ) ) ,
159+ TagType :: Variable => Ok ( Node :: Block ( Block :: Variable { tag } ) ) ,
167160 TagType :: Inclusion => {
168161 let template_name = bits_vec. get ( 1 ) . cloned ( ) . unwrap_or_default ( ) ;
169- Ok ( ( Node :: Block ( Block :: Inclusion { tag, template_name } ) , vec ! [ ] ) )
162+ Ok ( Node :: Block ( Block :: Inclusion { tag, template_name } ) )
170163 }
171164 }
172165 }
@@ -213,14 +206,14 @@ impl Parser {
213206 let start_token = self . peek ( ) ?;
214207 let start_pos = start_token. start ( ) . unwrap_or ( 0 ) ;
215208 let mut total_length = start_token. length ( ) . unwrap_or ( 0 ) ;
216-
209+
217210 // Handle newlines by returning next node
218211 if matches ! ( start_token. token_type( ) , TokenType :: Newline ) {
219212 self . consume ( ) ?;
220- let ( next_node , _ ) = self . next_node ( ) ?;
221- return Ok ( next_node ) ;
213+ let node = self . next_node ( ) ?;
214+ return Ok ( node ) ;
222215 }
223-
216+
224217 let mut content = match start_token. token_type ( ) {
225218 TokenType :: Text ( text) => text. to_string ( ) ,
226219 TokenType :: Whitespace ( count) => " " . repeat ( * count) ,
@@ -257,8 +250,8 @@ impl Parser {
257250
258251 // Skip empty text nodes
259252 if content. trim ( ) . is_empty ( ) {
260- let ( next_node , _ ) = self . next_node ( ) ?;
261- Ok ( next_node )
253+ let node = self . next_node ( ) ?;
254+ Ok ( node )
262255 } else {
263256 Ok ( Node :: Text {
264257 content,
@@ -272,18 +265,15 @@ impl Parser {
272265 content : & str ,
273266 start : & str ,
274267 end : Option < & str > ,
275- ) -> Result < ( Node , Vec < AstError > ) , ParserError > {
268+ ) -> Result < Node , ParserError > {
276269 let start_token = self . peek_previous ( ) ?;
277270 let start_pos = start_token. start ( ) . unwrap_or ( 0 ) ;
278271 let total_length = ( content. len ( ) + start. len ( ) + end. map_or ( 0 , |e| e. len ( ) ) ) as u32 ;
279272 let span = Span :: new ( start_pos, total_length) ;
280- Ok ( (
281- Node :: Comment {
282- content : content. to_string ( ) ,
283- span,
284- } ,
285- vec ! [ ] ,
286- ) )
273+ Ok ( Node :: Comment {
274+ content : content. to_string ( ) ,
275+ span,
276+ } )
287277 }
288278
289279 fn peek ( & self ) -> Result < Token , ParserError > {
@@ -554,7 +544,7 @@ mod tests {
554544 let ( ast, errors) = parser. parse ( ) . unwrap ( ) ;
555545 insta:: assert_yaml_snapshot!( ast) ;
556546 assert_eq ! ( errors. len( ) , 1 ) ;
557- assert ! ( matches!( & errors[ 0 ] , AstError :: UnclosedTag ( tag) if tag == "if" ) ) ;
547+ assert ! ( matches!( & errors[ 0 ] , ParserError :: Ast ( AstError :: UnclosedTag ( tag) ) if tag == "if" ) ) ;
558548 }
559549 #[ test]
560550 fn test_parse_unclosed_django_for ( ) {
@@ -564,7 +554,7 @@ mod tests {
564554 let ( ast, errors) = parser. parse ( ) . unwrap ( ) ;
565555 insta:: assert_yaml_snapshot!( ast) ;
566556 assert_eq ! ( errors. len( ) , 1 ) ;
567- assert ! ( matches!( & errors[ 0 ] , AstError :: UnclosedTag ( tag) if tag == "for" ) ) ;
557+ assert ! ( matches!( & errors[ 0 ] , ParserError :: Ast ( AstError :: UnclosedTag ( tag) ) if tag == "for" ) ) ;
568558 }
569559 #[ test]
570560 fn test_parse_unclosed_script ( ) {
@@ -603,7 +593,7 @@ mod tests {
603593 let ( ast, errors) = parser. parse ( ) . unwrap ( ) ;
604594 insta:: assert_yaml_snapshot!( ast) ;
605595 assert_eq ! ( errors. len( ) , 1 ) ;
606- assert ! ( matches!( & errors[ 0 ] , AstError :: UnclosedTag ( tag) if tag == "if" ) ) ;
596+ assert ! ( matches!( & errors[ 0 ] , ParserError :: Ast ( AstError :: UnclosedTag ( tag) ) if tag == "if" ) ) ;
607597 }
608598 }
609599
0 commit comments