@@ -159,6 +159,14 @@ impl Pattern {
159159 }
160160 }
161161 }
162+ Pattern :: Choice { alternatives } => {
163+ let alternatives = alternatives. iter ( ) . map ( Pattern :: lower) ;
164+ quote ! {
165+ yeast:: query:: QueryNode :: Choice {
166+ alternatives: vec![ #( #alternatives) , * ] ,
167+ }
168+ }
169+ }
162170 Pattern :: Sequence ( _) | Pattern :: Repeated { .. } => {
163171 unreachable ! ( "sequence and repeated patterns cannot match a single node" )
164172 }
@@ -168,6 +176,9 @@ impl Pattern {
168176 fn lower_list ( & self ) -> Vec < TokenStream > {
169177 match self {
170178 Pattern :: Sequence ( patterns) => patterns. iter ( ) . flat_map ( Pattern :: lower_list) . collect ( ) ,
179+ Pattern :: Choice { .. } if !self . matches_single_node ( ) => {
180+ vec ! [ self . lower_list_choice( ) ]
181+ }
171182 Pattern :: Capture {
172183 name,
173184 pattern,
@@ -226,6 +237,21 @@ impl Pattern {
226237 }
227238 }
228239
240+ fn lower_list_choice ( & self ) -> TokenStream {
241+ let Pattern :: Choice { alternatives } = self else {
242+ unreachable ! ( "expected query choice pattern" ) ;
243+ } ;
244+ let alternatives = alternatives. iter ( ) . map ( |alternative| {
245+ let children = alternative. lower_list ( ) ;
246+ quote ! { vec![ #( #children) , * ] }
247+ } ) ;
248+ quote ! {
249+ yeast:: query:: QueryListElem :: Choice {
250+ alternatives: vec![ #( #alternatives) , * ] ,
251+ }
252+ }
253+ }
254+
229255 fn captures ( & self ) -> Vec < CaptureBinding > {
230256 let mut captures = Vec :: new ( ) ;
231257 self . collect_captures ( Cardinality :: SINGLE , & mut captures) ;
@@ -254,6 +280,9 @@ impl Pattern {
254280 cardinality,
255281 } ) ;
256282 }
283+ Pattern :: Choice { alternatives } => {
284+ captures. extend ( unify_choice_captures ( alternatives, cardinality) ) ;
285+ }
257286 Pattern :: Sequence ( patterns) => {
258287 for pattern in patterns {
259288 pattern. collect_captures ( cardinality, captures) ;
@@ -269,6 +298,41 @@ impl Pattern {
269298 }
270299}
271300
301+ fn unify_choice_captures (
302+ alternatives : & [ Pattern ] ,
303+ parent : Cardinality ,
304+ ) -> Vec < CaptureBinding > {
305+ let alternative_count = alternatives. len ( ) ;
306+ let mut order = Vec :: new ( ) ;
307+ let mut by_name = std:: collections:: BTreeMap :: < String , Vec < CaptureBinding > > :: new ( ) ;
308+
309+ for alternative in alternatives {
310+ for capture in alternative. captures ( ) {
311+ let name = capture. name . to_string ( ) ;
312+ if !by_name. contains_key ( & name) {
313+ order. push ( name. clone ( ) ) ;
314+ }
315+ by_name. entry ( name) . or_default ( ) . push ( capture) ;
316+ }
317+ }
318+
319+ order
320+ . into_iter ( )
321+ . map ( |name| {
322+ let captures = by_name. remove ( & name) . unwrap ( ) ;
323+ let present_in_every_alternative = captures. len ( ) == alternative_count;
324+ let mut capture = captures[ 0 ] . clone ( ) ;
325+ for other in captures. iter ( ) . skip ( 1 ) {
326+ capture. cardinality . multiple |= other. cardinality . multiple ;
327+ capture. cardinality . required &= other. cardinality . required ;
328+ }
329+ capture. cardinality . required &= present_in_every_alternative;
330+ capture. cardinality = combine_cardinality ( parent, capture. cardinality ) ;
331+ capture
332+ } )
333+ . collect ( )
334+ }
335+
272336fn combine_cardinality ( parent : Cardinality , child : Cardinality ) -> Cardinality {
273337 Cardinality {
274338 multiple : parent. multiple || child. multiple ,
0 commit comments