@@ -2,7 +2,10 @@ use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream, TokenTree};
22use quote:: quote;
33use std:: iter:: Peekable ;
44use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
5- use syn:: Lifetime ;
5+ use syn:: {
6+ Expr , Lifetime , Token ,
7+ parse:: { Parse , ParseStream } ,
8+ } ;
69
710type Tokens = Peekable < proc_macro2:: token_stream:: IntoIter > ;
811type Result < T > = std:: result:: Result < T , syn:: Error > ;
@@ -332,28 +335,10 @@ fn parse_query_list(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
332335
333336const IMPLICIT_CTX : & str = "ctx" ;
334337
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`.
338+ /// Parse `tree!((template))` — returns single `Id`.
354339pub fn parse_tree_top ( input : TokenStream ) -> Result < TokenStream > {
355340 let mut tokens = input. into_iter ( ) . peekable ( ) ;
356- let ctx = parse_ctx_or_implicit ( & mut tokens ) ;
341+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
357342
358343 let first = parse_direct_node ( & mut tokens, & ctx, None ) ?;
359344
@@ -368,10 +353,10 @@ pub fn parse_tree_top(input: TokenStream) -> Result<TokenStream> {
368353 Ok ( quote ! { { #first } } )
369354}
370355
371- /// Parse `trees!(ctx, ...)` or `trees!( ...)` — returns `Vec<Id>`.
356+ /// Parse `trees!(...)` — returns `Vec<Id>`.
372357pub fn parse_trees_top ( input : TokenStream ) -> Result < TokenStream > {
373358 let mut tokens = input. into_iter ( ) . peekable ( ) ;
374- let ctx = parse_ctx_or_implicit ( & mut tokens ) ;
359+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
375360 let items = parse_direct_list ( & mut tokens, & ctx) ?;
376361 if let Some ( tok) = tokens. next ( ) {
377362 return Err ( syn:: Error :: new_spanned (
@@ -388,6 +373,76 @@ pub fn parse_trees_top(input: TokenStream) -> Result<TokenStream> {
388373 } )
389374}
390375
376+ pub fn parse_tree_at_top ( input : TokenStream ) -> Result < TokenStream > {
377+ let LocatedTreeInput {
378+ source,
379+ template,
380+ } = syn:: parse2 ( input) ?;
381+ let mut tokens = template. into_iter ( ) . peekable ( ) ;
382+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
383+ let node = parse_direct_node ( & mut tokens, & ctx, None ) ?;
384+ if let Some ( tok) = tokens. next ( ) {
385+ return Err ( syn:: Error :: new_spanned (
386+ tok,
387+ "unexpected token after tree_at! template" ,
388+ ) ) ;
389+ }
390+
391+ Ok ( quote ! {
392+ {
393+ let __yeast_source: yeast:: Id = { #source } ;
394+ let __yeast_source_range = #ctx
395+ . ast
396+ . get_node( __yeast_source)
397+ . and_then( |node| node. source_range( ) ) ;
398+ let __yeast_node: yeast:: Id = #node;
399+ #ctx. set_node_source_range( __yeast_node, __yeast_source_range)
400+ }
401+ } )
402+ }
403+
404+ pub fn parse_tree_spanning_top ( input : TokenStream ) -> Result < TokenStream > {
405+ let LocatedTreeInput {
406+ source : sources,
407+ template,
408+ } = syn:: parse2 ( input) ?;
409+ let mut tokens = template. into_iter ( ) . peekable ( ) ;
410+ let ctx = Ident :: new ( IMPLICIT_CTX , Span :: call_site ( ) ) ;
411+ let node = parse_direct_node ( & mut tokens, & ctx, None ) ?;
412+ if let Some ( tok) = tokens. next ( ) {
413+ return Err ( syn:: Error :: new_spanned (
414+ tok,
415+ "unexpected token after tree_spanning! template" ,
416+ ) ) ;
417+ }
418+
419+ Ok ( quote ! {
420+ {
421+ let __yeast_source_range = :: std:: iter:: IntoIterator :: into_iter( { #sources } )
422+ . filter_map( |source: yeast:: Id | {
423+ #ctx. ast. get_node( source) . and_then( |node| node. source_range( ) )
424+ } )
425+ . reduce( yeast:: Range :: union ) ;
426+ let __yeast_node: yeast:: Id = #node;
427+ #ctx. set_node_source_range( __yeast_node, __yeast_source_range)
428+ }
429+ } )
430+ }
431+
432+ struct LocatedTreeInput {
433+ source : Expr ,
434+ template : TokenStream ,
435+ }
436+
437+ impl Parse for LocatedTreeInput {
438+ fn parse ( input : ParseStream < ' _ > ) -> syn:: Result < Self > {
439+ let source = input. parse ( ) ?;
440+ input. parse :: < Token ! [ , ] > ( ) ?;
441+ let template = input. parse ( ) ?;
442+ Ok ( Self { source, template } )
443+ }
444+ }
445+
391446/// Parse a single node template and generate code that returns an `Id`.
392447/// Handles: `(kind fields... children...)` and `{expr}`.
393448///
0 commit comments