@@ -6,6 +6,7 @@ use grammer::{proc_macro, scannerless};
66
77use indexmap:: { indexmap, IndexMap , IndexSet } ;
88use std:: borrow:: Cow ;
9+ use std:: collections:: BTreeSet ;
910use std:: fmt:: { self , Write as _} ;
1011use std:: hash:: Hash ;
1112use std:: ops:: Add ;
@@ -90,6 +91,18 @@ struct RustField {
9091 refutable : bool ,
9192}
9293
94+ impl RustField {
95+ fn handle_ty ( & self ) -> Src {
96+ let ty = & self . ty ;
97+ let handle_ty = quote ! ( Handle <' a, ' i, I , #ty>) ;
98+ if self . refutable {
99+ quote ! ( Option <#handle_ty>)
100+ } else {
101+ handle_ty
102+ }
103+ }
104+ }
105+
93106type RustFields = IndexMap < IStr , RustField > ;
94107
95108enum RustVariant {
@@ -106,13 +119,13 @@ enum RustAdt {
106119}
107120
108121trait RuleWithFieldsMethods < Pat > {
109- fn rust_fields ( self , cx : & Context < Pat > ) -> RustFields ;
110- fn rust_adt ( self , cx : & Context < Pat > ) -> RustAdt ;
122+ fn rust_fields ( self , cx : & Context < Pat > , records : & mut BTreeSet < Vec < String > > ) -> RustFields ;
123+ fn rust_adt ( self , cx : & Context < Pat > , records : & mut BTreeSet < Vec < String > > ) -> RustAdt ;
111124 fn traverse_shape ( self , cx : & Context < Pat > , rust_fields : & RustFields ) -> Src ;
112125}
113126
114127impl < Pat : RustInputPat > RuleWithFieldsMethods < Pat > for RuleWithFields {
115- fn rust_fields ( self , cx : & Context < Pat > ) -> RustFields {
128+ fn rust_fields ( self , cx : & Context < Pat > , records : & mut BTreeSet < Vec < String > > ) -> RustFields {
116129 let children = match & cx[ self . fields ] {
117130 Fields :: Leaf ( None ) => return indexmap ! { } ,
118131 Fields :: Leaf ( Some ( field) ) => {
@@ -121,29 +134,73 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
121134 fields : field. sub ,
122135 } ;
123136
124- // FIXME(eddyb) support this properly (see issue #128).
125- assert_eq ! ( cx[ sub. fields] , Fields :: Leaf ( None ) ) ;
137+ let refutable = match cx[ sub. rule ] {
138+ Rule :: Opt ( child) => match & cx[ sub. fields ] {
139+ // `x:{ y:Y? }`
140+ Fields :: Leaf ( Some ( _) ) => false ,
126141
127- let mut refutable = false ;
128- while let Rule :: Opt ( child) = cx[ sub. rule ] {
129- refutable = true ;
130- sub. rule = child;
131- }
142+ // `x:X?`
143+ Fields :: Leaf ( None ) => {
144+ sub. rule = child;
145+ true
146+ }
147+
148+ // `x:{ y:Y z:Z }?`
149+ Fields :: Aggregate ( children) => {
150+ sub. rule = child;
151+ sub. fields = children[ 0 ] ;
152+ true
153+ }
154+ } ,
155+ _ => false ,
156+ } ;
132157
133158 let repeat = match cx[ sub. rule ] {
134159 Rule :: RepeatMany ( elem, _) | Rule :: RepeatMore ( elem, _) => {
135- sub. rule = elem;
136- true
160+ match & cx[ sub. fields ] {
161+ // `xs:{ ys:Y* }`
162+ Fields :: Leaf ( Some ( _) ) => false ,
163+
164+ // `xs:X*`
165+ Fields :: Leaf ( None ) => {
166+ sub. rule = elem;
167+ true
168+ }
169+
170+ // `xs:{ y:Y z:Z }*`
171+ Fields :: Aggregate ( children) => {
172+ sub. rule = elem;
173+ sub. fields = children[ 0 ] ;
174+ true
175+ }
176+ }
137177 }
138178 _ => false ,
139179 } ;
140180
141- let ty = match cx[ sub. rule ] {
142- Rule :: Call ( r) => {
143- let ident = Src :: ident ( & cx[ r] ) ;
144- quote ! ( #ident<' a, ' i, I >)
181+ let subfields = sub. rust_fields ( cx, records) ;
182+ let ty = if !subfields. is_empty ( ) {
183+ let rec_fields_name: Vec < _ > =
184+ subfields. keys ( ) . map ( |& name| cx[ name] . to_string ( ) ) . collect ( ) ;
185+ let rec_ident = Src :: ident ( & ( rec_fields_name. join ( "__" ) + "__" ) ) ;
186+ let rec_fields_handle_ty = subfields. values ( ) . map ( |field| field. handle_ty ( ) ) ;
187+ let shape = sub. traverse_shape ( cx, & subfields) ;
188+
189+ records. insert ( rec_fields_name) ;
190+
191+ quote ! ( _forest:: typed:: WithShape <
192+ _rec:: #rec_ident<#( #rec_fields_handle_ty) , * >,
193+ _forest:: typed:: shape!( #shape) ,
194+ [ usize ; <_forest:: typed:: shape!( #shape) as _forest:: typed:: Shape >:: STATE_LEN ] ,
195+ >)
196+ } else {
197+ match cx[ sub. rule ] {
198+ Rule :: Call ( r) => {
199+ let ident = Src :: ident ( & cx[ r] ) ;
200+ quote ! ( #ident<' a, ' i, I >)
201+ }
202+ _ => quote ! ( ( ) ) ,
145203 }
146- _ => quote ! ( ( ) ) ,
147204 } ;
148205
149206 return indexmap ! {
@@ -155,15 +212,15 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
155212 }
156213 Fields :: Aggregate ( children) => children,
157214 } ;
158- let child_fields = |rule, i| {
215+ let mut child_fields = |rule, i| {
159216 let child = RuleWithFields {
160217 rule,
161218 fields : children
162219 . get ( i)
163220 . cloned ( )
164221 . unwrap_or_else ( || cx. intern ( Fields :: Leaf ( None ) ) ) ,
165222 } ;
166- child. rust_fields ( cx)
223+ child. rust_fields ( cx, records )
167224 } ;
168225
169226 match cx[ self . rule ] {
@@ -181,7 +238,7 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
181238 fields
182239 }
183240 Rule :: Or ( ref cases) => {
184- let child_fields = |i| {
241+ let mut child_fields = |i| {
185242 let mut fields = child_fields ( cases[ i] , i) ;
186243 for field in fields. values_mut ( ) {
187244 field. refutable = true ;
@@ -221,7 +278,7 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
221278 }
222279 }
223280
224- fn rust_adt ( self , cx : & Context < Pat > ) -> RustAdt {
281+ fn rust_adt ( self , cx : & Context < Pat > , records : & mut BTreeSet < Vec < String > > ) -> RustAdt {
225282 match ( & cx[ self . rule ] , & cx[ self . fields ] ) {
226283 ( Rule :: Or ( cases) , Fields :: Aggregate ( children) ) => {
227284 let variants: Option < IndexMap < _ , _ > > = cases
@@ -233,13 +290,13 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
233290 rule,
234291 fields : field. sub ,
235292 } ;
236- let subfields = child. rust_fields ( cx) ;
293+ let subfields = child. rust_fields ( cx, records ) ;
237294 let variant = if subfields. is_empty ( ) {
238295 let variant = RuleWithFields {
239296 rule,
240297 fields : children[ i] ,
241298 } ;
242- let variant_fields = variant. rust_fields ( cx) ;
299+ let variant_fields = variant. rust_fields ( cx, records ) ;
243300 assert_eq ! ( variant_fields. len( ) , 1 ) ;
244301 RustVariant :: Newtype ( variant_fields. into_iter ( ) . next ( ) . unwrap ( ) . 1 )
245302 } else {
@@ -261,7 +318,7 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
261318 _ => { }
262319 }
263320
264- RustAdt :: Struct ( self . rust_fields ( cx) )
321+ RustAdt :: Struct ( self . rust_fields ( cx, records ) )
265322 }
266323
267324 fn traverse_shape ( self , cx : & Context < Pat > , rust_fields : & RustFields ) -> Src {
@@ -430,10 +487,71 @@ impl<Pat: MatchesEmpty + RustInputPat> GrammarGenerateMethods<Pat> for grammer::
430487 . parse :: < Src > ( )
431488 . unwrap ( ) ;
432489
490+ let mut records = BTreeSet :: new ( ) ;
491+
433492 for ( & name, & rule) in rules. named {
434- out += declare_rule ( name, rule, cx, & mut rules) + impl_parse_with ( cx, name) ;
493+ let rust_adt = rule. rust_adt ( cx, & mut records) ;
494+ out += declare_rule ( name, rule, & rust_adt, cx, & mut rules) + impl_parse_with ( cx, name) ;
435495 }
436496
497+ let records = records. into_iter ( ) . map ( |fields| {
498+ let ident = Src :: ident ( & ( fields. join ( "__" ) + "__" ) ) ;
499+ // FIXME(eddyb) figure out a more efficient way to reuse
500+ // iterators with `quote!(...)` than `.collect::<Vec<_>>()`.
501+ let f_ident = fields. iter ( ) . map ( Src :: ident) . collect :: < Vec < _ > > ( ) ;
502+ let f_len = fields. len ( ) ;
503+
504+ quote ! (
505+ #[ derive( Copy , Clone ) ]
506+ pub struct #ident<#( #f_ident) , * > {
507+ #( pub #f_ident: #f_ident) , *
508+ }
509+
510+ impl <#( #f_ident) , * > fmt:: Debug for #ident<#( #f_ident) , * >
511+ where
512+ #( #f_ident: fmt:: Debug ) , *
513+ {
514+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
515+ f. debug_map( )
516+ #( . entry( & FieldName ( stringify!( #f_ident) ) , & self . #f_ident) ) *
517+ . finish( )
518+ }
519+ }
520+
521+ impl <' a, ' i, I , #( #f_ident) , * > _forest:: typed:: FromShapeFields <' a, ' i, _G, I > for #ident<#( #f_ident) , * >
522+ where
523+ I : gll:: grammer:: input:: Input ,
524+ #( #f_ident: _forest:: typed:: FromShapeFields <' a, ' i, _G, I , Fields = [ Option <Node <' i, _G>>; 1 ] >) , *
525+ {
526+ type Output = #ident<#( #f_ident:: Output ) , * >;
527+ type Fields = [ Option <Node <' i, _G>>; #f_len] ;
528+
529+ fn from_shape_fields(
530+ forest: & ' a _forest:: ParseForest <' i, _G, I >,
531+ [ #( #f_ident) , * ] : Self :: Fields ,
532+ ) -> Self :: Output {
533+ #ident {
534+ #( #f_ident: #f_ident:: from_shape_fields( forest, [ #f_ident] ) ) , *
535+ }
536+ }
537+ }
538+ )
539+ } ) ;
540+ out += quote ! ( pub mod _rec {
541+ use super :: { _forest, _G, Node } ;
542+ use std:: fmt;
543+
544+ // FIXME(eddyb) move this somewhere else.
545+ struct FieldName <' a>( & ' a str ) ;
546+ impl fmt:: Debug for FieldName <' _> {
547+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
548+ f. write_str( self . 0 )
549+ }
550+ }
551+
552+ #( #records) *
553+ } ) ;
554+
437555 let mut code_labels = IndexMap :: new ( ) ;
438556 out += define_parse_fn ( cx, & mut rules, & mut code_labels) ;
439557
@@ -970,39 +1088,29 @@ where
9701088fn declare_rule < Pat > (
9711089 name : IStr ,
9721090 rule : RuleWithFields ,
1091+ rust_adt : & RustAdt ,
9731092 cx : & Context < Pat > ,
9741093 rules : & mut RuleMap < ' _ > ,
9751094) -> Src
9761095where
9771096 Pat : RustInputPat ,
9781097{
9791098 let ident = Src :: ident ( & cx[ name] ) ;
980- let rust_adt = rule. rust_adt ( cx) ;
981-
982- let field_handle_ty = |field : & RustField | {
983- let ty = & field. ty ;
984- let handle_ty = quote ! ( Handle <' a, ' i, I , #ty>) ;
985- if field. refutable {
986- quote ! ( Option <#handle_ty>)
987- } else {
988- handle_ty
989- }
990- } ;
9911099
992- let rule_ty_def = match & rust_adt {
1100+ let rule_ty_def = match rust_adt {
9931101 RustAdt :: Enum ( variants) => {
9941102 let variants = variants. iter ( ) . map ( |( & v_name, ( _, variant) ) | {
9951103 let variant_ident = Src :: ident ( & cx[ v_name] ) ;
9961104 match variant {
9971105 RustVariant :: Newtype ( field) => {
998- let field_ty = field_handle_ty ( field) ;
1106+ let field_ty = field. handle_ty ( ) ;
9991107 quote ! ( #variant_ident( #field_ty) )
10001108 }
10011109 RustVariant :: StructLike ( v_fields) => {
10021110 let fields_ident = v_fields. keys ( ) . map ( |& name| Src :: ident ( & cx[ name] ) ) ;
1003- let fields_ty = v_fields. values ( ) . map ( field_handle_ty ) ;
1111+ let fields_handle_ty = v_fields. values ( ) . map ( |field| field . handle_ty ( ) ) ;
10041112 quote ! ( #variant_ident {
1005- #( #fields_ident: #fields_ty ) , *
1113+ #( #fields_ident: #fields_handle_ty ) , *
10061114 } )
10071115 }
10081116 }
@@ -1016,7 +1124,7 @@ where
10161124 }
10171125 RustAdt :: Struct ( fields) => {
10181126 let fields_ident = fields. keys ( ) . map ( |& name| Src :: ident ( & cx[ name] ) ) ;
1019- let fields_ty = fields. values ( ) . map ( field_handle_ty ) ;
1127+ let fields_handle_ty = fields. values ( ) . map ( |field| field . handle_ty ( ) ) ;
10201128 let marker_field = if fields. is_empty ( ) {
10211129 Some ( quote ! ( _marker: PhantomData <( & ' a ( ) , & ' i ( ) , I ) >, ) )
10221130 } else {
@@ -1025,15 +1133,15 @@ where
10251133 quote ! (
10261134 #[ allow( non_camel_case_types) ]
10271135 pub struct #ident<' a, ' i, I : gll:: grammer:: input:: Input > {
1028- #( pub #fields_ident: #fields_ty ) , *
1136+ #( pub #fields_ident: #fields_handle_ty ) , *
10291137 #marker_field
10301138 }
10311139 )
10321140 }
10331141 } ;
10341142 rule_ty_def
1035- + rule_debug_impl ( cx, name, & rust_adt)
1036- + impl_rule_traverse_impl ( name, rule, & rust_adt, cx, rules)
1143+ + rule_debug_impl ( cx, name, rust_adt)
1144+ + impl_rule_traverse_impl ( name, rule, rust_adt, cx, rules)
10371145}
10381146
10391147fn impl_rule_traverse_impl < Pat > (
0 commit comments