@@ -122,10 +122,41 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
122122
123123 expect_punct ( tokens, ':' , "expected `:` after field name" ) ?;
124124
125- let child = parse_query_node ( tokens) ?;
126- fields. push ( quote ! {
127- ( #field_str, vec![ yeast:: query:: QueryListElem :: SingleNode ( #child) ] )
128- } ) ;
125+ // Parse the field's pattern. To support repetition like
126+ // `field: (kind)* @cap`, parse the atom first, then check for
127+ // a quantifier, and lastly handle a trailing `@capture`.
128+ let atom = parse_query_atom ( tokens) ?;
129+ if peek_is_repetition ( tokens) {
130+ let rep = expect_repetition ( tokens) ?;
131+ let elem = quote ! {
132+ yeast:: query:: QueryListElem :: Repeated {
133+ children: vec![ yeast:: query:: QueryListElem :: SingleNode ( #atom) ] ,
134+ rep: #rep,
135+ }
136+ } ;
137+ let elem = maybe_wrap_list_capture ( tokens, elem) ?;
138+ fields. push ( quote ! {
139+ ( #field_str, vec![ #elem] )
140+ } ) ;
141+ } else {
142+ let child = if peek_is_at ( tokens) {
143+ tokens. next ( ) ;
144+ let capture_name =
145+ expect_ident ( tokens, "expected capture name after @" ) ?;
146+ let name_str = capture_name. to_string ( ) ;
147+ quote ! {
148+ yeast:: query:: QueryNode :: Capture {
149+ capture: #name_str,
150+ node: Box :: new( #atom) ,
151+ }
152+ }
153+ } else {
154+ atom
155+ } ;
156+ fields. push ( quote ! {
157+ ( #field_str, vec![ yeast:: query:: QueryListElem :: SingleNode ( #child) ] )
158+ } ) ;
159+ }
129160 } else {
130161 // Bare patterns — accumulate into the implicit `child` field.
131162 // We don't break here, so we can interleave with named fields.
0 commit comments