@@ -6,6 +6,7 @@ use grammer::{proc_macro, scannerless};
6
6
7
7
use indexmap:: { indexmap, IndexMap , IndexSet } ;
8
8
use std:: borrow:: Cow ;
9
+ use std:: collections:: BTreeSet ;
9
10
use std:: fmt:: { self , Write as _} ;
10
11
use std:: hash:: Hash ;
11
12
use std:: ops:: Add ;
@@ -90,6 +91,18 @@ struct RustField {
90
91
refutable : bool ,
91
92
}
92
93
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
+
93
106
type RustFields = IndexMap < IStr , RustField > ;
94
107
95
108
enum RustVariant {
@@ -106,13 +119,13 @@ enum RustAdt {
106
119
}
107
120
108
121
trait 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 ;
111
124
fn traverse_shape ( self , cx : & Context < Pat > , rust_fields : & RustFields ) -> Src ;
112
125
}
113
126
114
127
impl < 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 {
116
129
let children = match & cx[ self . fields ] {
117
130
Fields :: Leaf ( None ) => return indexmap ! { } ,
118
131
Fields :: Leaf ( Some ( field) ) => {
@@ -121,29 +134,73 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
121
134
fields : field. sub ,
122
135
} ;
123
136
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 ,
126
141
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
+ } ;
132
157
133
158
let repeat = match cx[ sub. rule ] {
134
159
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
+ }
137
177
}
138
178
_ => false ,
139
179
} ;
140
180
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 ! ( ( ) ) ,
145
203
}
146
- _ => quote ! ( ( ) ) ,
147
204
} ;
148
205
149
206
return indexmap ! {
@@ -155,15 +212,15 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
155
212
}
156
213
Fields :: Aggregate ( children) => children,
157
214
} ;
158
- let child_fields = |rule, i| {
215
+ let mut child_fields = |rule, i| {
159
216
let child = RuleWithFields {
160
217
rule,
161
218
fields : children
162
219
. get ( i)
163
220
. cloned ( )
164
221
. unwrap_or_else ( || cx. intern ( Fields :: Leaf ( None ) ) ) ,
165
222
} ;
166
- child. rust_fields ( cx)
223
+ child. rust_fields ( cx, records )
167
224
} ;
168
225
169
226
match cx[ self . rule ] {
@@ -181,7 +238,7 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
181
238
fields
182
239
}
183
240
Rule :: Or ( ref cases) => {
184
- let child_fields = |i| {
241
+ let mut child_fields = |i| {
185
242
let mut fields = child_fields ( cases[ i] , i) ;
186
243
for field in fields. values_mut ( ) {
187
244
field. refutable = true ;
@@ -221,7 +278,7 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
221
278
}
222
279
}
223
280
224
- fn rust_adt ( self , cx : & Context < Pat > ) -> RustAdt {
281
+ fn rust_adt ( self , cx : & Context < Pat > , records : & mut BTreeSet < Vec < String > > ) -> RustAdt {
225
282
match ( & cx[ self . rule ] , & cx[ self . fields ] ) {
226
283
( Rule :: Or ( cases) , Fields :: Aggregate ( children) ) => {
227
284
let variants: Option < IndexMap < _ , _ > > = cases
@@ -233,13 +290,13 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
233
290
rule,
234
291
fields : field. sub ,
235
292
} ;
236
- let subfields = child. rust_fields ( cx) ;
293
+ let subfields = child. rust_fields ( cx, records ) ;
237
294
let variant = if subfields. is_empty ( ) {
238
295
let variant = RuleWithFields {
239
296
rule,
240
297
fields : children[ i] ,
241
298
} ;
242
- let variant_fields = variant. rust_fields ( cx) ;
299
+ let variant_fields = variant. rust_fields ( cx, records ) ;
243
300
assert_eq ! ( variant_fields. len( ) , 1 ) ;
244
301
RustVariant :: Newtype ( variant_fields. into_iter ( ) . next ( ) . unwrap ( ) . 1 )
245
302
} else {
@@ -261,7 +318,7 @@ impl<Pat: RustInputPat> RuleWithFieldsMethods<Pat> for RuleWithFields {
261
318
_ => { }
262
319
}
263
320
264
- RustAdt :: Struct ( self . rust_fields ( cx) )
321
+ RustAdt :: Struct ( self . rust_fields ( cx, records ) )
265
322
}
266
323
267
324
fn traverse_shape ( self , cx : & Context < Pat > , rust_fields : & RustFields ) -> Src {
@@ -430,10 +487,71 @@ impl<Pat: MatchesEmpty + RustInputPat> GrammarGenerateMethods<Pat> for grammer::
430
487
. parse :: < Src > ( )
431
488
. unwrap ( ) ;
432
489
490
+ let mut records = BTreeSet :: new ( ) ;
491
+
433
492
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) ;
435
495
}
436
496
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
+
437
555
let mut code_labels = IndexMap :: new ( ) ;
438
556
out += define_parse_fn ( cx, & mut rules, & mut code_labels) ;
439
557
@@ -970,39 +1088,29 @@ where
970
1088
fn declare_rule < Pat > (
971
1089
name : IStr ,
972
1090
rule : RuleWithFields ,
1091
+ rust_adt : & RustAdt ,
973
1092
cx : & Context < Pat > ,
974
1093
rules : & mut RuleMap < ' _ > ,
975
1094
) -> Src
976
1095
where
977
1096
Pat : RustInputPat ,
978
1097
{
979
1098
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
- } ;
991
1099
992
- let rule_ty_def = match & rust_adt {
1100
+ let rule_ty_def = match rust_adt {
993
1101
RustAdt :: Enum ( variants) => {
994
1102
let variants = variants. iter ( ) . map ( |( & v_name, ( _, variant) ) | {
995
1103
let variant_ident = Src :: ident ( & cx[ v_name] ) ;
996
1104
match variant {
997
1105
RustVariant :: Newtype ( field) => {
998
- let field_ty = field_handle_ty ( field) ;
1106
+ let field_ty = field. handle_ty ( ) ;
999
1107
quote ! ( #variant_ident( #field_ty) )
1000
1108
}
1001
1109
RustVariant :: StructLike ( v_fields) => {
1002
1110
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 ( ) ) ;
1004
1112
quote ! ( #variant_ident {
1005
- #( #fields_ident: #fields_ty ) , *
1113
+ #( #fields_ident: #fields_handle_ty ) , *
1006
1114
} )
1007
1115
}
1008
1116
}
@@ -1016,7 +1124,7 @@ where
1016
1124
}
1017
1125
RustAdt :: Struct ( fields) => {
1018
1126
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 ( ) ) ;
1020
1128
let marker_field = if fields. is_empty ( ) {
1021
1129
Some ( quote ! ( _marker: PhantomData <( & ' a ( ) , & ' i ( ) , I ) >, ) )
1022
1130
} else {
@@ -1025,15 +1133,15 @@ where
1025
1133
quote ! (
1026
1134
#[ allow( non_camel_case_types) ]
1027
1135
pub struct #ident<' a, ' i, I : gll:: grammer:: input:: Input > {
1028
- #( pub #fields_ident: #fields_ty ) , *
1136
+ #( pub #fields_ident: #fields_handle_ty ) , *
1029
1137
#marker_field
1030
1138
}
1031
1139
)
1032
1140
}
1033
1141
} ;
1034
1142
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)
1037
1145
}
1038
1146
1039
1147
fn impl_rule_traverse_impl < Pat > (
0 commit comments