Skip to content

Commit 54ad119

Browse files
committed
generate: support nested records.
1 parent ab3101c commit 54ad119

File tree

3 files changed

+208
-47
lines changed

3 files changed

+208
-47
lines changed

macros/tests/basic.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,46 @@ testcases![
209209
} | A::Baz {
210210
baz: 1:1-1:3,
211211
}";
212+
213+
nested_records {
214+
A = "a" nested:{ b:"b" c:"c"* d:"d"? } list:{ e:"e"? "f" }* "g";
215+
}:
216+
A("abg") => "\
217+
1:1-1:4 => A {
218+
nested: 1:2-1:3 => {
219+
b: 1:2-1:3,
220+
c: 1:3-1:3 => [],
221+
d: None,
222+
},
223+
list: 1:3-1:3 => [],
224+
}",
225+
A("abcccdeffefg") => "\
226+
1:1-1:13 => A {
227+
nested: 1:2-1:7 => {
228+
b: 1:2-1:3,
229+
c: 1:3-1:6 => [
230+
1:3-1:4,
231+
1:4-1:5,
232+
1:5-1:6,
233+
],
234+
d: Some(
235+
1:6-1:7,
236+
),
237+
},
238+
list: 1:7-1:12 => [
239+
1:7-1:9 => {
240+
e: Some(
241+
1:7-1:8,
242+
),
243+
},
244+
1:9-1:10 => {
245+
e: None,
246+
},
247+
1:10-1:12 => {
248+
e: Some(
249+
1:10-1:11,
250+
),
251+
},
252+
],
253+
}";
212254
];

src/generate/rust.rs

Lines changed: 152 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use grammer::{proc_macro, scannerless};
66

77
use indexmap::{indexmap, IndexMap, IndexSet};
88
use std::borrow::Cow;
9+
use std::collections::BTreeSet;
910
use std::fmt::{self, Write as _};
1011
use std::hash::Hash;
1112
use 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+
93106
type RustFields = IndexMap<IStr, RustField>;
94107

95108
enum RustVariant {
@@ -106,13 +119,13 @@ enum RustAdt {
106119
}
107120

108121
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;
111124
fn traverse_shape(self, cx: &Context<Pat>, rust_fields: &RustFields) -> Src;
112125
}
113126

114127
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 {
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
9701088
fn declare_rule<Pat>(
9711089
name: IStr,
9721090
rule: RuleWithFields,
1091+
rust_adt: &RustAdt,
9731092
cx: &Context<Pat>,
9741093
rules: &mut RuleMap<'_>,
9751094
) -> Src
9761095
where
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

10391147
fn impl_rule_traverse_impl<Pat>(

0 commit comments

Comments
 (0)