@@ -332,28 +332,10 @@ fn parse_query_list(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
332332
333333const IMPLICIT_CTX : & str = "ctx" ;
334334
335- /// Determine the context identifier: either explicit `ctx,` or the implicit
336- /// `ctx` from an enclosing `rule!`.
337- fn parse_ctx_or_implicit ( tokens : & mut Tokens ) -> Ident {
338- // Check if first token is an ident followed by a comma
339- let mut lookahead = tokens. clone ( ) ;
340- let is_explicit = matches ! ( lookahead. next( ) , Some ( TokenTree :: Ident ( _) ) )
341- && matches ! ( lookahead. next( ) , Some ( TokenTree :: Punct ( p) ) if p. as_char( ) == ',' ) ;
342-
343- if is_explicit {
344- let ctx = expect_ident ( tokens, "unreachable: ident was just peeked" )
345- . expect ( "unreachable: ident was just peeked" ) ;
346- let _ = tokens. next ( ) ; // consume comma
347- ctx
348- } else {
349- Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) )
350- }
351- }
352-
353- /// Parse `tree!(ctx, (template))` or `tree!((template))` — returns single `Id`.
335+ /// Parse `tree!((template))` — returns single `Id`.
354336pub fn parse_tree_top ( input : TokenStream ) -> Result < TokenStream > {
355337 let mut tokens = input. into_iter ( ) . peekable ( ) ;
356- let ctx = parse_ctx_or_implicit ( & mut tokens ) ;
338+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
357339
358340 let first = parse_direct_node ( & mut tokens, & ctx, None ) ?;
359341
@@ -368,10 +350,10 @@ pub fn parse_tree_top(input: TokenStream) -> Result<TokenStream> {
368350 Ok ( quote ! { { #first } } )
369351}
370352
371- /// Parse `trees!(ctx, ...)` or `trees!( ...)` — returns `Vec<Id>`.
353+ /// Parse `trees!(...)` — returns `Vec<Id>`.
372354pub fn parse_trees_top ( input : TokenStream ) -> Result < TokenStream > {
373355 let mut tokens = input. into_iter ( ) . peekable ( ) ;
374- let ctx = parse_ctx_or_implicit ( & mut tokens ) ;
356+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
375357 let items = parse_direct_list ( & mut tokens, & ctx) ?;
376358 if let Some ( tok) = tokens. next ( ) {
377359 return Err ( syn:: Error :: new_spanned (
@@ -388,6 +370,70 @@ pub fn parse_trees_top(input: TokenStream) -> Result<TokenStream> {
388370 } )
389371}
390372
373+ pub fn parse_tree_at_top ( input : TokenStream ) -> Result < TokenStream > {
374+ let mut tokens = input. into_iter ( ) . peekable ( ) ;
375+ let source = parse_argument ( & mut tokens, "expected `,` after source node" ) ?;
376+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
377+ let node = parse_direct_node ( & mut tokens, & ctx, None ) ?;
378+ if let Some ( tok) = tokens. next ( ) {
379+ return Err ( syn:: Error :: new_spanned (
380+ tok,
381+ "unexpected token after tree_at! template" ,
382+ ) ) ;
383+ }
384+
385+ Ok ( quote ! {
386+ {
387+ let __yeast_source: yeast:: Id = { #source } ;
388+ let __yeast_source_range = #ctx
389+ . ast
390+ . get_node( __yeast_source)
391+ . and_then( |node| node. source_range( ) ) ;
392+ let __yeast_node: yeast:: Id = #node;
393+ #ctx. set_node_source_range( __yeast_node, __yeast_source_range)
394+ }
395+ } )
396+ }
397+
398+ pub fn parse_tree_spanning_top ( input : TokenStream ) -> Result < TokenStream > {
399+ let mut tokens = input. into_iter ( ) . peekable ( ) ;
400+ let sources = parse_argument ( & mut tokens, "expected `,` after source nodes" ) ?;
401+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
402+ let node = parse_direct_node ( & mut tokens, & ctx, None ) ?;
403+ if let Some ( tok) = tokens. next ( ) {
404+ return Err ( syn:: Error :: new_spanned (
405+ tok,
406+ "unexpected token after tree_spanning! template" ,
407+ ) ) ;
408+ }
409+
410+ Ok ( quote ! {
411+ {
412+ let __yeast_source_range = :: std:: iter:: IntoIterator :: into_iter( { #sources } )
413+ . filter_map( |source: yeast:: Id | {
414+ #ctx. ast. get_node( source) . and_then( |node| node. source_range( ) )
415+ } )
416+ . reduce( yeast:: Range :: union ) ;
417+ let __yeast_node: yeast:: Id = #node;
418+ #ctx. set_node_source_range( __yeast_node, __yeast_source_range)
419+ }
420+ } )
421+ }
422+
423+ fn parse_argument ( tokens : & mut Tokens , missing_comma : & str ) -> Result < TokenStream > {
424+ let mut argument = TokenStream :: new ( ) ;
425+ while let Some ( token) = tokens. next ( ) {
426+ if matches ! ( & token, TokenTree :: Punct ( p) if p. as_char( ) == ',' ) {
427+ if argument. is_empty ( ) {
428+ return Err ( syn:: Error :: new_spanned ( token, "expected expression" ) ) ;
429+ }
430+ return Ok ( argument) ;
431+ }
432+ argument. extend ( [ token] ) ;
433+ }
434+ Err ( syn:: Error :: new ( Span :: call_site ( ) , missing_comma) )
435+ }
436+
391437/// Parse a single node template and generate code that returns an `Id`.
392438/// Handles: `(kind fields... children...)` and `{expr}`.
393439///
0 commit comments