@@ -2,13 +2,13 @@ use crate::tokens::Token;
22use serde:: Serialize ;
33use thiserror:: Error ;
44
5- #[ derive( Clone , Debug , Default , Serialize ) ]
6- pub struct Ast {
5+ #[ derive( Clone , Default , Debug , Serialize ) ]
6+ pub struct NodeList {
77 nodes : Vec < Node > ,
88 line_offsets : LineOffsets ,
99}
1010
11- impl Ast {
11+ impl NodeList {
1212 pub fn nodes ( & self ) -> & Vec < Node > {
1313 & self . nodes
1414 }
@@ -25,7 +25,7 @@ impl Ast {
2525 self . line_offsets = line_offsets
2626 }
2727
28- pub fn finalize ( & mut self ) -> Ast {
28+ pub fn finalize ( & mut self ) -> NodeList {
2929 self . clone ( )
3030 }
3131}
@@ -67,6 +67,28 @@ impl LineOffsets {
6767 }
6868}
6969
70+ #[ derive( Clone , Debug , Serialize ) ]
71+ pub enum Node {
72+ Tag {
73+ name : String ,
74+ bits : Vec < String > ,
75+ span : Span ,
76+ } ,
77+ Comment {
78+ content : String ,
79+ span : Span ,
80+ } ,
81+ Text {
82+ content : String ,
83+ span : Span ,
84+ } ,
85+ Variable {
86+ var : String ,
87+ filters : Vec < String > ,
88+ span : Span ,
89+ } ,
90+ }
91+
7092#[ derive( Clone , Copy , Debug , Eq , PartialEq , Serialize ) ]
7193pub struct Span {
7294 start : u32 ,
@@ -95,127 +117,6 @@ impl From<Token> for Span {
95117 }
96118}
97119
98- #[ derive( Clone , Debug , Serialize ) ]
99- pub enum Node {
100- Block ( Block ) ,
101- Comment {
102- content : String ,
103- span : Span ,
104- } ,
105- Text {
106- content : String ,
107- span : Span ,
108- } ,
109- Variable {
110- bits : Vec < String > ,
111- filters : Vec < DjangoFilter > ,
112- span : Span ,
113- } ,
114- }
115-
116- impl Node {
117- pub fn span ( & self ) -> Option < & Span > {
118- match self {
119- Node :: Block ( block) => Some ( & block. tag ( ) . span ) ,
120- Node :: Comment { span, .. } => Some ( span) ,
121- Node :: Text { span, .. } => Some ( span) ,
122- Node :: Variable { span, .. } => Some ( span) ,
123- }
124- }
125-
126- pub fn children ( & self ) -> Option < & Vec < Node > > {
127- match self {
128- Node :: Block ( block) => block. nodes ( ) ,
129- _ => None ,
130- }
131- }
132- }
133-
134- #[ derive( Debug , Clone , Serialize ) ]
135- pub enum Block {
136- Branch {
137- tag : Tag ,
138- nodes : Vec < Node > ,
139- } ,
140- Closing {
141- tag : Tag ,
142- } ,
143- Container {
144- tag : Tag ,
145- nodes : Vec < Node > ,
146- closing : Option < Box < Block > > ,
147- } ,
148- Inclusion {
149- tag : Tag ,
150- template_name : String ,
151- } ,
152- Single {
153- tag : Tag ,
154- } ,
155- }
156-
157- impl Block {
158- pub fn tag ( & self ) -> & Tag {
159- match self {
160- Self :: Branch { tag, .. }
161- | Self :: Container { tag, .. }
162- | Self :: Closing { tag }
163- | Self :: Inclusion { tag, .. }
164- | Self :: Single { tag } => tag,
165- }
166- }
167-
168- pub fn nodes ( & self ) -> Option < & Vec < Node > > {
169- match self {
170- Block :: Branch { nodes, .. } => Some ( nodes) ,
171- Block :: Container { nodes, .. } => Some ( nodes) ,
172- _ => None ,
173- }
174- }
175-
176- pub fn closing ( & self ) -> Option < & Block > {
177- match self {
178- Block :: Container { closing, .. } => closing. as_deref ( ) ,
179- _ => None ,
180- }
181- }
182-
183- pub fn template_name ( & self ) -> Option < & String > {
184- match self {
185- Block :: Inclusion { template_name, .. } => Some ( template_name) ,
186- _ => None ,
187- }
188- }
189- }
190-
191- #[ derive( Clone , Debug , Serialize ) ]
192- pub struct Tag {
193- pub name : String ,
194- pub bits : Vec < String > ,
195- pub span : Span ,
196- pub tag_span : Span ,
197- pub assignment : Option < String > ,
198- }
199-
200- #[ derive( Clone , Debug , Serialize ) ]
201- pub struct Assignment {
202- pub target : String ,
203- pub value : String ,
204- }
205-
206- #[ derive( Clone , Debug , Serialize ) ]
207- pub struct DjangoFilter {
208- pub name : String ,
209- pub args : Vec < String > ,
210- pub span : Span ,
211- }
212-
213- impl DjangoFilter {
214- pub fn new ( name : String , args : Vec < String > , span : Span ) -> Self {
215- Self { name, args, span }
216- }
217- }
218-
219120#[ derive( Clone , Debug , Error , Serialize ) ]
220121pub enum AstError {
221122 #[ error( "Empty AST" ) ]
@@ -272,28 +173,25 @@ mod tests {
272173
273174 mod spans_and_positions {
274175 use super :: * ;
275- use crate :: tagspecs:: TagSpecs ;
276176
277177 #[ test]
278178 fn test_variable_spans ( ) {
279179 let template = "Hello\n {{ user.name }}\n World" ;
280180 let tokens = Lexer :: new ( template) . tokenize ( ) . unwrap ( ) ;
281- println ! ( "Tokens: {:#?}" , tokens) ; // Add debug print
282- let tags = TagSpecs :: load_builtin_specs ( ) . unwrap ( ) ;
283- let mut parser = Parser :: new ( tokens, tags) ;
284- let ( ast, errors) = parser. parse ( ) . unwrap ( ) ;
181+ let mut parser = Parser :: new ( tokens) ;
182+ let ( nodelist, errors) = parser. parse ( ) . unwrap ( ) ;
285183 assert ! ( errors. is_empty( ) ) ;
286184
287185 // Find the variable node
288- let nodes = ast . nodes ( ) ;
186+ let nodes = nodelist . nodes ( ) ;
289187 let var_node = nodes
290188 . iter ( )
291189 . find ( |n| matches ! ( n, Node :: Variable { .. } ) )
292190 . unwrap ( ) ;
293191
294192 if let Node :: Variable { span, .. } = var_node {
295193 // Variable starts after newline + "{{"
296- let ( line, col) = ast
194+ let ( line, col) = nodelist
297195 . line_offsets ( )
298196 . position_to_line_col ( * span. start ( ) as usize ) ;
299197 assert_eq ! (
@@ -302,84 +200,8 @@ mod tests {
302200 "Variable should start at line 2, col 3"
303201 ) ;
304202
305- // Span should be exactly "user.name"
306203 assert_eq ! ( * span. length( ) , 9 , "Variable span should cover 'user.name'" ) ;
307204 }
308205 }
309-
310- #[ test]
311- fn test_block_spans ( ) {
312- let nodes = vec ! [ Node :: Block ( Block :: Container {
313- tag: Tag {
314- name: "if" . to_string( ) ,
315- bits: vec![ "user.is_authenticated" . to_string( ) ] ,
316- span: Span :: new( 0 , 35 ) ,
317- tag_span: Span :: new( 0 , 35 ) ,
318- assignment: None ,
319- } ,
320- nodes: vec![ ] ,
321- closing: None ,
322- } ) ] ;
323-
324- let ast = Ast {
325- nodes,
326- line_offsets : LineOffsets :: new ( ) ,
327- } ;
328-
329- let node = & ast. nodes ( ) [ 0 ] ;
330- if let Node :: Block ( block) = node {
331- assert_eq ! ( block. tag( ) . span. start( ) , & 0 ) ;
332- assert_eq ! ( block. tag( ) . span. length( ) , & 35 ) ;
333- } else {
334- panic ! ( "Expected Block node" ) ;
335- }
336- }
337-
338- #[ test]
339- fn test_multiline_template ( ) {
340- let template = "{% if user.active %}\n Welcome!\n {% endif %}" ;
341- let tokens = Lexer :: new ( template) . tokenize ( ) . unwrap ( ) ;
342- let tags = TagSpecs :: load_builtin_specs ( ) . unwrap ( ) ;
343- let mut parser = Parser :: new ( tokens, tags) ;
344- let ( ast, errors) = parser. parse ( ) . unwrap ( ) ;
345- assert ! ( errors. is_empty( ) ) ;
346-
347- let nodes = ast. nodes ( ) ;
348- if let Node :: Block ( Block :: Container {
349- tag,
350- nodes,
351- closing,
352- ..
353- } ) = & nodes[ 0 ]
354- {
355- // Check block tag
356- assert_eq ! ( tag. name, "if" ) ;
357- assert_eq ! ( tag. bits, vec![ "if" , "user.active" ] ) ;
358-
359- // Check nodes
360- eprintln ! ( "Nodes: {:?}" , nodes) ;
361- assert_eq ! ( nodes. len( ) , 1 ) ;
362- if let Node :: Text { content, span } = & nodes[ 0 ] {
363- assert_eq ! ( content, "Welcome!" ) ;
364- eprintln ! ( "Line offsets: {:?}" , ast. line_offsets( ) ) ;
365- eprintln ! ( "Span: {:?}" , span) ;
366- let ( line, col) = ast. line_offsets ( ) . position_to_line_col ( span. start as usize ) ;
367- assert_eq ! ( ( line, col) , ( 2 , 2 ) , "Content should be on line 2, col 2" ) ;
368-
369- // Check closing tag
370- if let Block :: Closing { tag } =
371- closing. as_ref ( ) . expect ( "Expected closing tag" ) . as_ref ( )
372- {
373- assert_eq ! ( tag. name, "endif" ) ;
374- } else {
375- panic ! ( "Expected closing block" ) ;
376- }
377- } else {
378- panic ! ( "Expected text node" ) ;
379- }
380- } else {
381- panic ! ( "Expected block node" ) ;
382- }
383- }
384206 }
385207}
0 commit comments