@@ -3,7 +3,7 @@ use quote::quote;
33use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
44use syn:: Lifetime ;
55
6- use crate :: ast:: { Content , Field , Node , Template } ;
6+ use crate :: ast:: { Cardinality , Content , Field , Node , Pattern , Replacement , Rule , Template } ;
77
88struct LoweringContext < ' a > {
99 /// Enclosing optional-field label to exit when a computed value is absent.
@@ -16,6 +16,256 @@ fn fresh_fallible_label() -> Lifetime {
1616 Lifetime :: new ( & format ! ( "'__yeast_field_{n}" ) , Span :: call_site ( ) )
1717}
1818
19+ #[ derive( Clone ) ]
20+ struct CaptureBinding {
21+ name : Ident ,
22+ raw : bool ,
23+ cardinality : Cardinality ,
24+ }
25+
26+ impl Rule {
27+ pub ( crate ) fn lower ( & self ) -> TokenStream {
28+ let query = self . pattern . lower ( ) ;
29+ let captures = self . pattern . captures ( ) ;
30+ let ( raw_captures, translated_captures) : ( Vec < _ > , Vec < _ > ) =
31+ captures. iter ( ) . partition ( |capture| capture. raw ) ;
32+ let raw_capture_names = raw_captures
33+ . iter ( )
34+ . map ( |capture| capture. name . to_string ( ) )
35+ . collect :: < Vec < _ > > ( ) ;
36+ let raw_bindings = capture_bindings ( raw_captures. into_iter ( ) ) ;
37+ let translated_bindings = capture_bindings ( translated_captures. into_iter ( ) ) ;
38+ let replacement = self . replacement . lower ( ) ;
39+ let guard = self
40+ . guard
41+ . clone ( )
42+ . unwrap_or_else ( || syn:: parse_quote!( true ) ) ;
43+ let ctx = Ident :: new ( "ctx" , Span :: call_site ( ) ) ;
44+
45+ quote ! {
46+ {
47+ let __query = #query;
48+ yeast:: Rule :: guarded(
49+ __query,
50+ Box :: new( |__ast: & yeast:: Ast , __captures: & yeast:: captures:: Captures , __user_ctx: & mut _| {
51+ #( #raw_bindings) *
52+ #( #translated_bindings) *
53+ let ast = __ast;
54+ let #ctx = __user_ctx;
55+ Ok ( #guard)
56+ } ) ,
57+ Box :: new( |__ast: & mut yeast:: Ast , mut __captures: yeast:: captures:: Captures , __source_range: Option <yeast:: Range >, __user_ctx: & mut _, __translator: yeast:: TranslatorHandle <' _, _>| {
58+ let __skip: & [ & str ] = & [ #( #raw_capture_names) , * ] ;
59+ __translator. auto_translate_captures( & mut __captures, __ast, __user_ctx, __skip) ?;
60+ #( #raw_bindings) *
61+ #( #translated_bindings) *
62+ let mut #ctx = yeast:: build:: BuildCtx :: with_translator( __ast, & __captures, __source_range, __user_ctx, __translator) ;
63+ let __result: Vec <yeast:: Id > = { #replacement } ;
64+ let __result = #ctx. finish_rule( __result) ;
65+ Ok ( __result)
66+ } ) ,
67+ )
68+ }
69+ }
70+ }
71+ }
72+
73+ impl Replacement {
74+ fn lower ( & self ) -> TokenStream {
75+ match self {
76+ Replacement :: Templates ( templates) => Template :: lower_list ( templates) ,
77+ Replacement :: Rust { body, .. } => {
78+ let body = rust_block ( body) ;
79+ quote ! {
80+ let __value = #body;
81+ let mut __ids: Vec <yeast:: Id > = Vec :: new( ) ;
82+ yeast:: IntoFieldIds :: extend_into( __value, & mut __ids) ;
83+ __ids
84+ }
85+ }
86+ }
87+ }
88+ }
89+
90+ impl Pattern {
91+ pub ( crate ) fn lower ( & self ) -> TokenStream {
92+ match self {
93+ Pattern :: Any { match_unnamed } => {
94+ quote ! { yeast:: query:: QueryNode :: Any { match_unnamed: #match_unnamed } }
95+ }
96+ Pattern :: Node { kind, fields } => {
97+ let fields = fields. iter ( ) . map ( |( name, pattern) | {
98+ let elements = pattern. lower_list ( ) ;
99+ quote ! { ( #name, vec![ #( #elements) , * ] ) }
100+ } ) ;
101+ quote ! {
102+ yeast:: query:: QueryNode :: Node {
103+ kind: #kind,
104+ children: vec![ #( #fields) , * ] ,
105+ }
106+ }
107+ }
108+ Pattern :: Unnamed ( kind) => {
109+ quote ! { yeast:: query:: QueryNode :: UnnamedNode { kind: #kind } }
110+ }
111+ Pattern :: Capture {
112+ name,
113+ pattern,
114+ cardinality,
115+ ..
116+ } => {
117+ debug_assert_eq ! ( * cardinality, Cardinality :: SINGLE ) ;
118+ let name = name. to_string ( ) ;
119+ let pattern = pattern. lower ( ) ;
120+ quote ! {
121+ yeast:: query:: QueryNode :: Capture {
122+ capture: #name,
123+ node: Box :: new( #pattern) ,
124+ }
125+ }
126+ }
127+ Pattern :: Sequence ( _) | Pattern :: Repeated { .. } => {
128+ unreachable ! ( "sequence and repeated patterns cannot match a single node" )
129+ }
130+ }
131+ }
132+
133+ fn lower_list ( & self ) -> Vec < TokenStream > {
134+ match self {
135+ Pattern :: Sequence ( patterns) => patterns. iter ( ) . flat_map ( Pattern :: lower_list) . collect ( ) ,
136+ Pattern :: Capture {
137+ name,
138+ pattern,
139+ cardinality,
140+ ..
141+ } => {
142+ let capture = name. to_string ( ) ;
143+ let pattern = pattern. lower ( ) ;
144+ let captured = quote ! {
145+ yeast:: query:: QueryListElem :: SingleNode (
146+ yeast:: query:: QueryNode :: Capture {
147+ capture: #capture,
148+ node: Box :: new( #pattern) ,
149+ }
150+ )
151+ } ;
152+ if * cardinality == Cardinality :: SINGLE {
153+ vec ! [ captured]
154+ } else {
155+ let repetition = match ( cardinality. multiple , cardinality. required ) {
156+ ( true , false ) => quote ! { yeast:: query:: Rep :: ZeroOrMore } ,
157+ ( true , true ) => quote ! { yeast:: query:: Rep :: OneOrMore } ,
158+ ( false , false ) => quote ! { yeast:: query:: Rep :: ZeroOrOne } ,
159+ ( false , true ) => unreachable ! ( "single cardinality handled above" ) ,
160+ } ;
161+ vec ! [ quote! {
162+ yeast:: query:: QueryListElem :: Repeated {
163+ children: vec![ #captured] ,
164+ rep: #repetition,
165+ }
166+ } ]
167+ }
168+ }
169+ Pattern :: Repeated {
170+ pattern,
171+ cardinality,
172+ } => {
173+ let children = pattern. lower_list ( ) ;
174+ let repetition = match ( cardinality. multiple , cardinality. required ) {
175+ ( true , false ) => quote ! { yeast:: query:: Rep :: ZeroOrMore } ,
176+ ( true , true ) => quote ! { yeast:: query:: Rep :: OneOrMore } ,
177+ ( false , false ) => quote ! { yeast:: query:: Rep :: ZeroOrOne } ,
178+ ( false , true ) => unreachable ! ( "single patterns are not wrapped as repeated" ) ,
179+ } ;
180+ vec ! [ quote! {
181+ yeast:: query:: QueryListElem :: Repeated {
182+ children: vec![ #( #children) , * ] ,
183+ rep: #repetition,
184+ }
185+ } ]
186+ }
187+ pattern => {
188+ let pattern = pattern. lower ( ) ;
189+ vec ! [ quote! { yeast:: query:: QueryListElem :: SingleNode ( #pattern) } ]
190+ }
191+ }
192+ }
193+ fn captures ( & self ) -> Vec < CaptureBinding > {
194+ let mut captures = Vec :: new ( ) ;
195+ self . collect_captures ( Cardinality :: SINGLE , & mut captures) ;
196+ captures
197+ }
198+
199+ fn collect_captures ( & self , cardinality : Cardinality , captures : & mut Vec < CaptureBinding > ) {
200+ match self {
201+ Pattern :: Any { .. } | Pattern :: Unnamed ( _) => { }
202+ Pattern :: Node { fields, .. } => {
203+ for ( _, pattern) in fields {
204+ pattern. collect_captures ( cardinality, captures) ;
205+ }
206+ }
207+ Pattern :: Capture {
208+ name,
209+ raw,
210+ pattern,
211+ cardinality : captured,
212+ } => {
213+ let cardinality = combine_cardinality ( cardinality, * captured) ;
214+ pattern. collect_captures ( cardinality, captures) ;
215+ captures. push ( CaptureBinding {
216+ name : name. clone ( ) ,
217+ raw : * raw,
218+ cardinality,
219+ } ) ;
220+ }
221+ Pattern :: Sequence ( patterns) => {
222+ for pattern in patterns {
223+ pattern. collect_captures ( cardinality, captures) ;
224+ }
225+ }
226+ Pattern :: Repeated {
227+ pattern,
228+ cardinality : repeated,
229+ } => {
230+ pattern. collect_captures ( combine_cardinality ( cardinality, * repeated) , captures) ;
231+ }
232+ }
233+ }
234+ }
235+
236+ fn combine_cardinality ( parent : Cardinality , child : Cardinality ) -> Cardinality {
237+ Cardinality {
238+ multiple : parent. multiple || child. multiple ,
239+ required : parent. required && child. required ,
240+ }
241+ }
242+
243+ fn capture_bindings < ' a > ( captures : impl Iterator < Item = & ' a CaptureBinding > ) -> Vec < TokenStream > {
244+ captures
245+ . map ( |capture| {
246+ let name_string = capture. name . to_string ( ) ;
247+ let name = Ident :: new ( & name_string, Span :: call_site ( ) ) ;
248+ match ( capture. cardinality . multiple , capture. cardinality . required ) {
249+ ( true , _) => {
250+ quote ! {
251+ let #name: Vec <yeast:: Id > = __captures. get_all( #name_string) ;
252+ }
253+ }
254+ ( false , false ) => {
255+ quote ! {
256+ let #name: Option <yeast:: Id > = __captures. get_opt( #name_string) ;
257+ }
258+ }
259+ ( false , true ) => {
260+ quote ! {
261+ let #name: yeast:: Id = __captures. get_var( #name_string) . unwrap( ) ;
262+ }
263+ }
264+ }
265+ } )
266+ . collect ( )
267+ }
268+
19269impl Template {
20270 pub ( crate ) fn lower_root ( & self ) -> TokenStream {
21271 self . lower ( & LoweringContext {
0 commit comments