@@ -13,7 +13,7 @@ use crate::ast::TextNode;
1313use crate :: ast:: VariableName ;
1414use crate :: ast:: VariableNode ;
1515use crate :: db:: Db as TemplateDb ;
16- use crate :: lexer :: LexerError ;
16+
1717use crate :: tokens:: Token ;
1818use crate :: tokens:: TokenStream ;
1919use crate :: tokens:: TokenType ;
@@ -75,29 +75,18 @@ impl<'db> Parser<'db> {
7575 let token = self . consume ( ) ?;
7676
7777 match token. token_type ( ) {
78- TokenType :: Comment ( _, open , _ ) => self . parse_comment ( open ) ,
78+ TokenType :: Comment ( _) => self . parse_comment ( ) ,
7979 TokenType :: Eof => Err ( ParserError :: stream_error ( StreamError :: AtEnd ) ) ,
8080 TokenType :: Block ( _) => self . parse_django_block ( ) ,
8181 TokenType :: Variable ( _) => self . parse_django_variable ( ) ,
82- TokenType :: HtmlTagClose ( _)
83- | TokenType :: HtmlTagOpen ( _)
84- | TokenType :: HtmlTagVoid ( _)
85- | TokenType :: Newline
86- | TokenType :: ScriptTagClose ( _)
87- | TokenType :: ScriptTagOpen ( _)
88- | TokenType :: StyleTagClose ( _)
89- | TokenType :: StyleTagOpen ( _)
82+ TokenType :: Error ( _) => self . parse_error ( ) ,
83+ TokenType :: Newline
9084 | TokenType :: Text ( _)
9185 | TokenType :: Whitespace ( _) => self . parse_text ( ) ,
9286 }
9387 }
9488
95- fn parse_comment ( & mut self , open : & str ) -> Result < Node < ' db > , ParserError > {
96- // Only treat Django comments as Comment nodes
97- if open != "{#" {
98- return self . parse_text ( ) ;
99- }
100-
89+ fn parse_comment ( & mut self ) -> Result < Node < ' db > , ParserError > {
10190 let token = self . peek_previous ( ) ?;
10291
10392 Ok ( Node :: Comment ( CommentNode {
@@ -106,6 +95,23 @@ impl<'db> Parser<'db> {
10695 } ) )
10796 }
10897
98+ fn parse_error ( & mut self ) -> Result < Node < ' db > , ParserError > {
99+ let token = self . peek_previous ( ) ?;
100+
101+ if let TokenType :: Error ( content) = token. token_type ( ) {
102+ let position = token. start ( ) . unwrap_or ( 0 ) as usize ;
103+
104+ Err ( ParserError :: MalformedConstruct {
105+ position,
106+ content : content. clone ( ) ,
107+ } )
108+ } else {
109+ Err ( ParserError :: InvalidSyntax {
110+ context : "Expected Error token" . to_string ( ) ,
111+ } )
112+ }
113+ }
114+
109115 pub fn parse_django_block ( & mut self ) -> Result < Node < ' db > , ParserError > {
110116 let token = self . peek_previous ( ) ?;
111117
@@ -144,41 +150,60 @@ impl<'db> Parser<'db> {
144150 }
145151
146152 fn parse_text ( & mut self ) -> Result < Node < ' db > , ParserError > {
147- let token = self . peek_previous ( ) ?;
148-
149- if token. token_type ( ) == & TokenType :: Newline {
150- return self . next_node ( ) ;
151- }
152-
153- let mut text = token. lexeme ( ) ;
154-
155- while let Ok ( token) = self . peek ( ) {
156- match token. token_type ( ) {
157- TokenType :: Block ( _)
158- | TokenType :: Variable ( _)
159- | TokenType :: Comment ( _, _, _)
160- | TokenType :: Newline
161- | TokenType :: Eof => break ,
162- _ => {
163- let token_text = token. lexeme ( ) ;
164- text. push_str ( & token_text) ;
153+ // Keep looping until we find non-empty text or hit a significant token
154+ loop {
155+ let token = self . peek_previous ( ) ?;
156+
157+ // Skip newlines directly without recursion
158+ if token. token_type ( ) == & TokenType :: Newline {
159+ if !self . is_at_end ( ) {
165160 self . consume ( ) ?;
161+ continue ;
162+ } else {
163+ return Err ( ParserError :: stream_error ( StreamError :: AtEnd ) ) ;
166164 }
167165 }
168- }
169166
170- let content = match text. trim ( ) {
171- "" => return self . next_node ( ) ,
172- trimmed => trimmed. to_string ( ) ,
173- } ;
167+ let mut text = token. lexeme ( ) ;
168+
169+ while let Ok ( token) = self . peek ( ) {
170+ match token. token_type ( ) {
171+ TokenType :: Block ( _)
172+ | TokenType :: Variable ( _)
173+ | TokenType :: Comment ( _)
174+ | TokenType :: Error ( _)
175+ | TokenType :: Newline
176+ | TokenType :: Eof => break ,
177+ _ => {
178+ let token_text = token. lexeme ( ) ;
179+ text. push_str ( & token_text) ;
180+ self . consume ( ) ?;
181+ }
182+ }
183+ }
174184
175- let start = token. start ( ) . unwrap_or ( 0 ) ;
176- let offset = u32:: try_from ( text. find ( content. as_str ( ) ) . unwrap_or ( 0 ) )
177- . expect ( "Offset should fit in u32" ) ;
178- let length = u32:: try_from ( content. len ( ) ) . expect ( "Content length should fit in u32" ) ;
179- let span = Span :: new ( start + offset, length) ;
185+ let content = match text. trim ( ) {
186+ "" => {
187+ // Instead of recursing, continue the loop
188+ if !self . is_at_end ( ) {
189+ self . consume ( ) ?;
190+ continue ;
191+ } else {
192+ return Err ( ParserError :: stream_error ( StreamError :: AtEnd ) ) ;
193+ }
194+ }
195+ trimmed => trimmed. to_string ( ) ,
196+ } ;
197+
198+ // We have non-empty content, create the text node
199+ let start = token. start ( ) . unwrap_or ( 0 ) ;
200+ let offset = u32:: try_from ( text. find ( content. as_str ( ) ) . unwrap_or ( 0 ) )
201+ . expect ( "Offset should fit in u32" ) ;
202+ let length = u32:: try_from ( content. len ( ) ) . expect ( "Content length should fit in u32" ) ;
203+ let span = Span :: new ( start + offset, length) ;
180204
181- Ok ( Node :: Text ( TextNode { content, span } ) )
205+ return Ok ( Node :: Text ( TextNode { content, span } ) ) ;
206+ }
182207 }
183208
184209 fn peek ( & self ) -> Result < Token , ParserError > {
@@ -255,7 +280,7 @@ impl<'db> Parser<'db> {
255280 let sync_types = & [
256281 TokenType :: Block ( String :: new ( ) ) ,
257282 TokenType :: Variable ( String :: new ( ) ) ,
258- TokenType :: Comment ( String :: new ( ) , String :: from ( "{#" ) , Some ( String :: from ( "#}" ) ) ) ,
283+ TokenType :: Comment ( String :: new ( ) ) ,
259284 TokenType :: Eof ,
260285 ] ;
261286
@@ -314,8 +339,8 @@ pub enum ParseError {
314339 #[ error( "Empty tag" ) ]
315340 EmptyTag ,
316341
317- #[ error( "Lexer error : {0 }" ) ]
318- Lexer ( # [ from ] LexerError ) ,
342+ #[ error( "Malformed Django construct at position {position} : {content }" ) ]
343+ MalformedConstruct { position : usize , content : String } ,
319344
320345 #[ error( "Stream error: {kind:?}" ) ]
321346 StreamError { kind : StreamError } ,
@@ -392,7 +417,7 @@ mod tests {
392417 #[ salsa:: tracked]
393418 fn parse_test_template ( db : & dyn TemplateDb , template : TestTemplate ) -> NodeList < ' _ > {
394419 let source = template. source ( db) ;
395- let tokens = Lexer :: new ( source) . tokenize ( ) . unwrap ( ) ;
420+ let tokens = Lexer :: new ( source) . tokenize ( ) ;
396421 let token_stream = TokenStream :: new ( db, tokens) ;
397422 let mut parser = Parser :: new ( db, token_stream) ;
398423 let ( ast, _) = parser. parse ( ) . unwrap ( ) ;
0 commit comments