@@ -319,8 +319,8 @@ impl Node {
319319 let ctx = Ident :: new ( "ctx" , Span :: call_site ( ) ) ;
320320 let kind_str = self . kind . to_string ( ) ;
321321
322- if let Some ( content) = & self . content {
323- return match content {
322+ let node_init = if let Some ( content) = & self . content {
323+ let node = match content {
324324 Content :: Static ( lit) => quote ! { #ctx. literal( #kind_str, #lit) } ,
325325 Content :: Computed ( block) => {
326326 let block = rust_block ( block) ;
@@ -362,74 +362,105 @@ impl Node {
362362 }
363363 }
364364 } ;
365- }
365+ quote ! { let __node: yeast:: Id = #node; }
366+ } else {
367+ TokenStream :: new ( )
368+ } ;
366369
367370 let mut stmts = Vec :: new ( ) ;
368371 let mut field_args = Vec :: new ( ) ;
369372
370373 for ( field_counter, field) in self . fields . iter ( ) . enumerate ( ) {
371- let Field :: Named {
372- name,
373- value,
374- optional,
375- } = field;
376- let field_name = name. to_string ( ) ;
377- let field_str = field_name
378- . strip_prefix ( "r#" )
379- . unwrap_or ( & field_name)
380- . to_string ( ) ;
381- let temp = Ident :: new (
382- & format ! ( "__field_{field_str}_{field_counter}" ) ,
383- Span :: call_site ( ) ,
384- ) ;
385-
386- match value {
387- Template :: Splice ( block) => {
388- debug_assert ! ( !optional) ;
374+ match field {
375+ Field :: Location { block } => {
389376 let block = rust_block ( block) ;
390377 stmts. push ( quote ! {
391- let mut #temp: Vec <yeast:: Id > = Vec :: new( ) ;
392- yeast:: IntoFieldIds :: extend_into( #block, & mut #temp) ;
393- } ) ;
394- field_args. push ( quote ! {
395- if !#temp. is_empty( ) {
396- __fields. push( ( #field_str, #temp) ) ;
397- }
378+ yeast:: IntoFieldIds :: extend_into( #block, & mut __location_ids) ;
398379 } ) ;
399380 }
400- Template :: Node ( child) if * optional => {
401- let label = fresh_fallible_label ( ) ;
402- let value = child. lower ( & LoweringContext {
403- fallible_scope : Some ( & label) ,
404- } ) ;
405- stmts. push ( quote ! {
406- #[ allow( unused_labels) ]
407- let #temp: :: std:: option:: Option <yeast:: Id > = #label: {
408- :: std:: option:: Option :: Some ( #value)
409- } ;
410- } ) ;
411- field_args. push ( quote ! {
412- if let :: std:: option:: Option :: Some ( __id) = #temp {
413- __fields. push( ( #field_str, vec![ __id] ) ) ;
381+ Field :: Named {
382+ name,
383+ value,
384+ optional,
385+ } => {
386+ let field_name = name. to_string ( ) ;
387+ let field_str = field_name
388+ . strip_prefix ( "r#" )
389+ . unwrap_or ( & field_name)
390+ . to_string ( ) ;
391+ let temp = Ident :: new (
392+ & format ! ( "__field_{field_str}_{field_counter}" ) ,
393+ Span :: call_site ( ) ,
394+ ) ;
395+
396+ match value {
397+ Template :: Splice ( block) => {
398+ debug_assert ! ( !optional) ;
399+ let block = rust_block ( block) ;
400+ stmts. push ( quote ! {
401+ let mut #temp: Vec <yeast:: Id > = Vec :: new( ) ;
402+ yeast:: IntoFieldIds :: extend_into( #block, & mut #temp) ;
403+ } ) ;
404+ field_args. push ( quote ! {
405+ if !#temp. is_empty( ) {
406+ __fields. push( ( #field_str, #temp) ) ;
407+ }
408+ } ) ;
414409 }
415- } ) ;
416- }
417- Template :: Node ( child) => {
418- let value = child. lower ( context) ;
419- stmts. push ( quote ! { let #temp: yeast:: Id = #value; } ) ;
420- field_args. push ( quote ! {
421- __fields. push( ( #field_str, vec![ #temp] ) ) ;
422- } ) ;
410+ Template :: Node ( child) if * optional => {
411+ let label = fresh_fallible_label ( ) ;
412+ let value = child. lower ( & LoweringContext {
413+ fallible_scope : Some ( & label) ,
414+ } ) ;
415+ stmts. push ( quote ! {
416+ #[ allow( unused_labels) ]
417+ let #temp: :: std:: option:: Option <yeast:: Id > = #label: {
418+ :: std:: option:: Option :: Some ( #value)
419+ } ;
420+ } ) ;
421+ field_args. push ( quote ! {
422+ if let :: std:: option:: Option :: Some ( __id) = #temp {
423+ __fields. push( ( #field_str, vec![ __id] ) ) ;
424+ }
425+ } ) ;
426+ }
427+ Template :: Node ( child) => {
428+ let value = child. lower ( context) ;
429+ stmts. push ( quote ! { let #temp: yeast:: Id = #value; } ) ;
430+ field_args. push ( quote ! {
431+ __fields. push( ( #field_str, vec![ #temp] ) ) ;
432+ } ) ;
433+ }
434+ }
423435 }
424436 }
425437 }
426438
439+ let build_node = if self . content . is_none ( ) {
440+ quote ! {
441+ let mut __fields: Vec <( & str , Vec <yeast:: Id >) > = Vec :: new( ) ;
442+ #( #field_args) *
443+ let __node: yeast:: Id = #ctx. node( #kind_str, __fields) ;
444+ }
445+ } else {
446+ TokenStream :: new ( )
447+ } ;
448+
427449 quote ! {
428450 {
451+ let mut __location_ids: Vec <yeast:: Id > = Vec :: new( ) ;
452+ #node_init
429453 #( #stmts) *
430- let mut __fields: Vec <( & str , Vec <yeast:: Id >) > = Vec :: new( ) ;
431- #( #field_args) *
432- #ctx. node( #kind_str, __fields)
454+ #build_node
455+ let __source_range = __location_ids
456+ . into_iter( )
457+ . filter_map( |__source| {
458+ #ctx. ast
459+ . get_node( __source)
460+ . and_then( |__node| __node. source_range( ) )
461+ } )
462+ . reduce( yeast:: Range :: union ) ;
463+ #ctx. set_node_source_range( __node, __source_range)
433464 }
434465 }
435466 }
0 commit comments