@@ -6,11 +6,16 @@ use thiserror::Error;
66pub struct Parser {
77 tokens : TokenStream ,
88 current : usize ,
9+ ast : Ast ,
910}
1011
1112impl Parser {
1213 pub fn new ( tokens : TokenStream ) -> Self {
13- Parser { tokens, current : 0 }
14+ Parser {
15+ tokens,
16+ current : 0 ,
17+ ast : Ast :: default ( ) ,
18+ }
1419 }
1520
1621 pub fn parse ( & mut self ) -> Result < Ast , ParserError > {
@@ -26,19 +31,19 @@ impl Parser {
2631 }
2732 Err ( err) => {
2833 match err {
29- ParserError :: NodeWithError { node, error } => {
30- ast. add_error ( error) ;
34+ ParserError :: Ast ( err, Some ( node) ) => {
3135 ast. add_node ( node) ;
36+ ast. add_error ( err) ;
3237 }
33- ParserError :: Ast ( err) => {
38+ ParserError :: Ast ( err, None ) => {
3439 ast. add_error ( err) ;
3540 }
3641 _ => return Err ( err) ,
3742 }
3843
3944 if let Err ( e) = self . synchronize ( ) {
4045 match e {
41- ParserError :: Ast ( AstError :: StreamError ( ref kind) )
46+ ParserError :: Ast ( AstError :: StreamError ( ref kind) , _ )
4247 if kind == "AtEnd" =>
4348 {
4449 break
@@ -57,7 +62,10 @@ impl Parser {
5762
5863 fn next_node ( & mut self ) -> Result < Node , ParserError > {
5964 if self . is_at_end ( ) {
60- return Err ( ParserError :: Ast ( AstError :: StreamError ( "AtEnd" . to_string ( ) ) ) ) ;
65+ return Err ( ParserError :: Ast (
66+ AstError :: StreamError ( "AtEnd" . to_string ( ) ) ,
67+ None ,
68+ ) ) ;
6169 }
6270
6371 let token = self . peek ( ) ?;
@@ -84,7 +92,10 @@ impl Parser {
8492 | TokenType :: ScriptTagClose ( _)
8593 | TokenType :: StyleTagOpen ( _)
8694 | TokenType :: StyleTagClose ( _) => self . parse_text ( ) ,
87- TokenType :: Eof => Err ( ParserError :: Ast ( AstError :: StreamError ( "AtEnd" . to_string ( ) ) ) ) ,
95+ TokenType :: Eof => Err ( ParserError :: Ast (
96+ AstError :: StreamError ( "AtEnd" . to_string ( ) ) ,
97+ None ,
98+ ) ) ,
8899 } ?;
89100 Ok ( node)
90101 }
@@ -142,7 +153,7 @@ impl Parser {
142153 Err ( ParserError :: ErrorSignal ( Signal :: SpecialTag ( tag) ) ) => {
143154 if let Some ( spec) = & tag_spec {
144155 // Check if closing tag
145- if Some ( & tag ) == spec . closing . as_ref ( ) {
156+ if spec . closing . as_ref ( ) . map ( |s| s . as_str ( ) ) == Some ( & tag ) {
146157 // If we have a current branch, add it to children
147158 if let Some ( ( name, bits, branch_children) ) = current_branch {
148159 children. push ( Node :: Django ( DjangoNode :: Tag ( TagNode :: Branch {
@@ -187,19 +198,15 @@ impl Parser {
187198 }
188199 }
189200 }
190- // If we get here, it's an unexpected tag - return what we have
191- // but signal that we hit an error
201+ // If we get here, it's an unexpected tag
192202 let node = Node :: Django ( DjangoNode :: Tag ( TagNode :: Block {
193- name : tag_name,
194- bits,
195- children,
203+ name : tag_name. clone ( ) ,
204+ bits : bits . clone ( ) ,
205+ children : children . clone ( ) ,
196206 } ) ) ;
197- return Err ( ParserError :: NodeWithError {
198- node,
199- error : AstError :: UnexpectedTag ( tag) ,
200- } ) ;
207+ return Err ( ParserError :: Ast ( AstError :: UnexpectedTag ( tag) , Some ( node) ) ) ;
201208 }
202- Err ( ParserError :: Ast ( AstError :: StreamError ( kind) ) ) if kind == "AtEnd" => {
209+ Err ( ParserError :: Ast ( AstError :: StreamError ( kind) , _ ) ) if kind == "AtEnd" => {
203210 break ;
204211 }
205212 Err ( e) => return Err ( e) ,
@@ -213,11 +220,10 @@ impl Parser {
213220 } ) ) ;
214221
215222 if !found_closing_tag {
216- // Return the node with an unclosed tag error
217- return Err ( ParserError :: NodeWithError {
218- node,
219- error : AstError :: UnclosedTag ( tag_name) ,
220- } ) ;
223+ return Err ( ParserError :: Ast (
224+ AstError :: UnclosedTag ( tag_name) ,
225+ Some ( node) ,
226+ ) ) ;
221227 }
222228
223229 Ok ( node)
@@ -329,22 +335,32 @@ impl Parser {
329335 }
330336
331337 fn synchronize ( & mut self ) -> Result < ( ) , ParserError > {
332- let sync_types = [
333- TokenType :: DjangoBlock ( String :: new ( ) ) ,
334- TokenType :: DjangoVariable ( String :: new ( ) ) ,
335- TokenType :: Comment ( String :: new ( ) , String :: from ( "{#" ) , Some ( String :: from ( "#}" ) ) ) ,
336- TokenType :: Eof ,
337- ] ;
338+ let mut depth = 0 ;
339+ let mut found_django_token = false ;
338340
339341 while !self . is_at_end ( ) {
340- let current = self . peek ( ) ?;
341-
342- for sync_type in & sync_types {
343- if current. token_type ( ) == sync_type {
344- return Ok ( ( ) ) ;
342+ if let TokenType :: DjangoBlock ( content) = & self . tokens [ self . current ] . token_type ( ) {
343+ let tag = content. split_whitespace ( ) . next ( ) . unwrap_or ( "" ) ;
344+ if let Some ( spec) = TagSpec :: load_builtin_specs ( ) . unwrap_or_default ( ) . get ( tag) {
345+ if spec. closing . as_deref ( ) == Some ( tag) {
346+ depth -= 1 ;
347+ if depth <= 0 {
348+ found_django_token = true ;
349+ break ;
350+ }
351+ } else {
352+ depth += 1 ;
353+ }
345354 }
346355 }
347- self . consume ( ) ?;
356+ self . current += 1 ;
357+ }
358+
359+ if !found_django_token {
360+ return Err ( ParserError :: Ast (
361+ AstError :: StreamError ( "AtEnd" . into ( ) ) ,
362+ None ,
363+ ) ) ;
348364 }
349365
350366 Ok ( ( ) )
@@ -362,47 +378,48 @@ pub enum Signal {
362378
363379#[ derive( Error , Debug ) ]
364380pub enum ParserError {
365- #[ error( transparent) ]
366- Ast ( #[ from] AstError ) ,
367- #[ error( "multi-line comment outside of script or style context" ) ]
368- InvalidMultiLineComment ,
381+ #[ error( "ast error: {0}" ) ]
382+ Ast ( AstError , Option < Node > ) ,
369383 #[ error( "internal signal: {0:?}" ) ]
370384 ErrorSignal ( Signal ) ,
371- #[ error( "node with error: {node:?}, error: {error}" ) ]
372- NodeWithError { node : Node , error : AstError } ,
385+ }
386+
387+ impl From < AstError > for ParserError {
388+ fn from ( err : AstError ) -> Self {
389+ ParserError :: Ast ( err, None )
390+ }
373391}
374392
375393impl ParserError {
376394 pub fn unclosed_tag ( tag : impl Into < String > ) -> Self {
377- Self :: Ast ( AstError :: UnclosedTag ( tag. into ( ) ) )
395+ Self :: Ast ( AstError :: UnclosedTag ( tag. into ( ) ) , None )
378396 }
379397
380398 pub fn unexpected_tag ( tag : impl Into < String > ) -> Self {
381- Self :: Ast ( AstError :: UnexpectedTag ( tag. into ( ) ) )
399+ Self :: Ast ( AstError :: UnexpectedTag ( tag. into ( ) ) , None )
382400 }
383401
384402 pub fn invalid_tag ( kind : impl Into < String > ) -> Self {
385- Self :: Ast ( AstError :: InvalidTag ( kind. into ( ) ) )
403+ Self :: Ast ( AstError :: InvalidTag ( kind. into ( ) ) , None )
386404 }
387405
388406 pub fn block_error ( kind : impl Into < String > , name : impl Into < String > ) -> Self {
389- Self :: Ast ( AstError :: BlockError ( kind. into ( ) , name. into ( ) ) )
407+ Self :: Ast ( AstError :: BlockError ( kind. into ( ) , name. into ( ) ) , None )
390408 }
391409
392410 pub fn stream_error ( kind : impl Into < String > ) -> Self {
393- Self :: Ast ( AstError :: StreamError ( kind. into ( ) ) )
411+ Self :: Ast ( AstError :: StreamError ( kind. into ( ) ) , None )
394412 }
395413
396414 pub fn token_error ( expected : impl Into < String > , actual : Token ) -> Self {
397- Self :: Ast ( AstError :: TokenError ( format ! (
398- "expected {}, got {:?}" ,
399- expected. into( ) ,
400- actual
401- ) ) )
415+ Self :: Ast (
416+ AstError :: TokenError ( format ! ( "expected {}, got {:?}" , expected. into( ) , actual) ) ,
417+ None ,
418+ )
402419 }
403420
404421 pub fn argument_error ( kind : impl Into < String > , details : impl Into < String > ) -> Self {
405- Self :: Ast ( AstError :: ArgumentError ( kind. into ( ) , details. into ( ) ) )
422+ Self :: Ast ( AstError :: ArgumentError ( kind. into ( ) , details. into ( ) ) , None )
406423 }
407424}
408425
0 commit comments