Skip to content

Commit c03e14a

Browse files
committed
generate: rely on traverse! shapes entirely for decoding enum variants.
1 parent 48f7346 commit c03e14a

File tree

3 files changed

+96
-129
lines changed

3 files changed

+96
-129
lines changed

src/generate/rust.rs

Lines changed: 77 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ impl<Pat: RustInputPat> RuleWithFieldsGenerateMethods<Pat> for RuleWithFields {
902902
.collect::<Vec<_>>();
903903
let cases_node_kind = cases.iter().map(|rule| rule.node_kind(cx, rules));
904904
let cases_node_kind_src = cases_node_kind.map(|kind| kind.to_src());
905-
quote!({ _P; #(#cases_node_kind_src => #cases_shape,)* })
905+
quote!({ _P; _ @ #(#cases_node_kind_src => #cases_shape,)* })
906906
}
907907
Rule::Opt(rule) => {
908908
let shape = child(rule, 0).generate_traverse_shape(cx, rules, rust_fields);
@@ -1026,11 +1026,16 @@ where
10261026
};
10271027
rule_ty_def
10281028
+ rule_debug_impls(cx, name, &rust_adt)
1029-
+ impl_rule_from_forest(name, &rust_adt, cx)
1029+
+ impl_rule_from_forest(name, &rust_adt, cx, rules)
10301030
+ impl_rule_one_and_all(name, rule, &rust_adt, cx, rules)
10311031
}
10321032

1033-
fn impl_rule_from_forest<Pat>(name: IStr, rust_adt: &RustAdt, cx: &Context<Pat>) -> Src
1033+
fn impl_rule_from_forest<Pat>(
1034+
name: IStr,
1035+
rust_adt: &RustAdt,
1036+
cx: &Context<Pat>,
1037+
rules: &mut RuleMap<'_>,
1038+
) -> Src
10341039
where
10351040
Pat: RustInputPat,
10361041
{
@@ -1051,20 +1056,30 @@ where
10511056
}
10521057
};
10531058

1054-
let methods = match rust_adt {
1059+
let method = match rust_adt {
10551060
RustAdt::Enum(variants) => {
1056-
let variants_fields_len = variants.values().map(|(_, variant)| match variant {
1057-
RustVariant::Newtype(_) => 0,
1058-
RustVariant::StructLike(v_fields) => v_fields.len(),
1059-
});
1060-
let variants_from_forest_ident = variants
1061-
.keys()
1062-
.map(|&v_name| Src::ident(format!("{}_from_forest", &cx[v_name])));
1063-
let variants_body = variants.iter().map(|(&v_name, (_, variant))| {
1061+
let max_fields_len = variants
1062+
.values()
1063+
.map(|(_, variant)| match variant {
1064+
RustVariant::Newtype(_) => 0,
1065+
RustVariant::StructLike(v_fields) => v_fields.len(),
1066+
})
1067+
.max()
1068+
.unwrap_or(0);
1069+
// HACK(eddyb) only collected to a `Vec` to avoid `rules` borrow conflicts.
1070+
let variants_kind = variants
1071+
.values()
1072+
.map(|(v_rule, _)| v_rule.rule.node_kind(cx, rules))
1073+
.collect::<Vec<_>>();
1074+
let variants_kind_src = variants_kind
1075+
.iter()
1076+
.map(|kind| kind.to_src())
1077+
.collect::<Vec<_>>();
1078+
let variants_expr = variants.iter().map(|(&v_name, (_, variant))| {
10641079
let variant_ident = Src::ident(&cx[v_name]);
10651080
match variant {
10661081
RustVariant::Newtype(_) => quote!(#ident::#variant_ident(Handle {
1067-
node: _node,
1082+
node: _r[#max_fields_len].unwrap(),
10681083
forest,
10691084
_marker: PhantomData,
10701085
})),
@@ -1078,16 +1093,17 @@ where
10781093
}
10791094
});
10801095

1081-
quote!(#(
1082-
#[allow(non_snake_case)]
1083-
fn #variants_from_forest_ident(
1084-
forest: &'a gll::grammer::forest::ParseForest<'i, _G, I>,
1085-
_node: Node<'i, _G>,
1086-
_r: [Option<Node<'i, _G>>; #variants_fields_len],
1087-
) -> Self {
1088-
#variants_body
1089-
}
1090-
)*)
1096+
quote!(
1097+
fn from_forest(
1098+
forest: &'a gll::grammer::forest::ParseForest<'i, _G, I>,
1099+
_r: [Option<Node<'i, _G>>; #max_fields_len + 1],
1100+
) -> Self {
1101+
match _r[#max_fields_len].unwrap().kind {
1102+
#(#variants_kind_src => #variants_expr,)*
1103+
_ => unreachable!(),
1104+
}
1105+
}
1106+
)
10911107
}
10921108
RustAdt::Struct(fields) => {
10931109
let fields_len = fields.len();
@@ -1101,7 +1117,6 @@ where
11011117
quote!(
11021118
fn from_forest(
11031119
forest: &'a gll::grammer::forest::ParseForest<'i, _G, I>,
1104-
_node: Node<'i, _G>,
11051120
_r: [Option<Node<'i, _G>>; #fields_len],
11061121
) -> Self {
11071122
#ident {
@@ -1114,7 +1129,7 @@ where
11141129
};
11151130

11161131
quote!(impl<'a, 'i, I: gll::grammer::input::Input> #ident<'a, 'i, I> {
1117-
#methods
1132+
#method
11181133
})
11191134
}
11201135

@@ -1129,21 +1144,17 @@ where
11291144
Pat: RustInputPat,
11301145
{
11311146
let ident = Src::ident(&cx[name]);
1132-
let (consts, one, all) = match rust_adt {
1147+
let (total_fields, shape) = match rust_adt {
11331148
RustAdt::Enum(variants) => {
1134-
let variants_fields_len = variants.values().map(|(_, variant)| match variant {
1135-
RustVariant::Newtype(_) => 0,
1136-
RustVariant::StructLike(v_fields) => v_fields.len(),
1137-
});
1138-
// FIXME(eddyb) figure out a more efficient way to reuse
1139-
// iterators with `quote!(...)` than `.collect::<Vec<_>>()`.
1140-
let i_ident = (0..variants.len())
1141-
.map(|i| Src::ident(format!("_{}", i)))
1142-
.collect::<Vec<_>>();
1143-
let variants_from_forest_ident = variants
1144-
.keys()
1145-
.map(|&v_name| Src::ident(format!("{}_from_forest", &cx[v_name])))
1146-
.collect::<Vec<_>>();
1149+
let max_fields_len = variants
1150+
.values()
1151+
.map(|(_, variant)| match variant {
1152+
RustVariant::Newtype(_) => 0,
1153+
RustVariant::StructLike(v_fields) => v_fields.len(),
1154+
})
1155+
.max()
1156+
.unwrap_or(0);
1157+
// HACK(eddyb) only collected to a `Vec` to avoid `rules` borrow conflicts.
11471158
let variants_kind = variants
11481159
.values()
11491160
.map(|(v_rule, _)| v_rule.rule.node_kind(cx, rules))
@@ -1152,10 +1163,6 @@ where
11521163
.iter()
11531164
.map(|kind| kind.to_src())
11541165
.collect::<Vec<_>>();
1155-
let variants_shape_ident = variants
1156-
.keys()
1157-
.map(|&v_name| Src::ident(format!("{}_SHAPE", &cx[v_name])))
1158-
.collect::<Vec<_>>();
11591166
let variants_shape = variants
11601167
.values()
11611168
.map(|(v_rule, variant)| match variant {
@@ -1167,100 +1174,51 @@ where
11671174
.collect::<Vec<_>>();
11681175

11691176
(
1170-
quote!(#(
1171-
#[allow(non_upper_case_globals)]
1172-
const #variants_shape_ident: traverse::ty!(#variants_shape) = traverse::new!(#variants_shape);
1173-
)*),
1174-
quote!(
1175-
forest.one_choice(node).and_then(|node| match node.kind {
1176-
#(#variants_kind_src => {
1177-
let mut r = [None; #variants_fields_len];
1178-
#ident::<I>::#variants_shape_ident
1179-
.one(forest, node, &mut r)
1180-
.map(|()| {
1181-
#ident::#variants_from_forest_ident(self.forest, node, r)
1182-
})
1183-
})*
1184-
_ => unreachable!()
1185-
})
1186-
),
1187-
quote!(
1188-
#[derive(Clone)]
1189-
enum Iter<#(#i_ident),*> {
1190-
#(#i_ident(#i_ident)),*
1191-
}
1192-
impl<T #(, #i_ident: Iterator<Item = T>)*> Iterator for Iter<#(#i_ident),*>
1193-
{
1194-
type Item = T;
1195-
fn next(&mut self) -> Option<T> {
1196-
match self {
1197-
#(Iter::#i_ident(iter) => iter.next()),*
1198-
}
1199-
}
1200-
}
1201-
1202-
forest.all_choices(node).flat_map(move |node| {
1203-
match node.kind {
1204-
#(#variants_kind_src => Iter::#i_ident({
1205-
#ident::<I>::#variants_shape_ident
1206-
.all(forest, node)
1207-
.into_iter()
1208-
.map(move |r| {
1209-
#ident::#variants_from_forest_ident(self.forest, node, r)
1210-
})
1211-
}),)*
1212-
_ => unreachable!(),
1213-
}
1214-
})
1215-
),
1216-
)
1217-
}
1218-
RustAdt::Struct(fields) => {
1219-
let fields_len = fields.len();
1220-
let shape = rule.generate_traverse_shape(cx, rules, fields);
1221-
(
1222-
quote!(
1223-
#[allow(non_upper_case_globals)]
1224-
const SHAPE: traverse::ty!(#shape) = traverse::new!(#shape);
1225-
),
1226-
quote!(
1227-
let mut r = [None; #fields_len];
1228-
#ident::<I>::SHAPE
1229-
.one(forest, node, &mut r)
1230-
.map(|()| #ident::from_forest(self.forest, node, r))
1231-
),
1232-
quote!(
1233-
#ident::<I>::SHAPE
1234-
.all(forest, node)
1235-
.into_iter()
1236-
.map(move |r| {
1237-
#ident::from_forest(self.forest, node, r)
1238-
})
1239-
),
1177+
max_fields_len + 1,
1178+
quote!({ _P; #max_fields_len @ #(#variants_kind_src => #variants_shape,)* }),
12401179
)
12411180
}
1181+
RustAdt::Struct(fields) => (
1182+
fields.len(),
1183+
rule.generate_traverse_shape(cx, rules, fields),
1184+
),
12421185
};
12431186

12441187
quote!(
12451188
impl<'a, 'i, I: gll::grammer::input::Input> #ident<'a, 'i, I> {
1246-
#consts
1189+
const SHAPE: traverse::ty!(#shape) = traverse::new!(#shape);
12471190
}
12481191

12491192
impl<'a, 'i, I> Handle<'a, 'i, I, #ident<'a, 'i, I>>
12501193
where I: gll::grammer::input::Input,
12511194
{
1252-
#consts
1253-
12541195
pub fn one(self) -> Result<#ident<'a, 'i, I>, Ambiguity<Self>> {
12551196
let forest = self.forest;
12561197
let node = forest.unpack_alias(self.node);
1257-
#one.map_err(|gll::grammer::forest::MoreThanOne| Ambiguity(self))
1198+
1199+
let mut r = [None; #total_fields];
1200+
#ident::<I>::SHAPE
1201+
.one(forest, node, &mut r)
1202+
.map_err(|gll::grammer::forest::MoreThanOne| Ambiguity(self))?;
1203+
1204+
Ok(#ident::from_forest(forest, r))
12581205
}
12591206

1260-
pub fn all(self) -> impl Iterator<Item = #ident<'a, 'i, I>> {
1207+
pub fn all(self) -> ::std::iter::Map<
1208+
cursor::IntoIter<
1209+
<traverse::ty!(#shape) as traverse::Shape<'a, 'i, _G>>::All,
1210+
[Option<Node<'i, _G>>; #total_fields],
1211+
[Option<Node<'i, _G>>],
1212+
>,
1213+
impl FnMut([Option<Node<'i, _G>>; #total_fields]) -> #ident<'a, 'i, I>,
1214+
> {
12611215
let forest = self.forest;
12621216
let node = forest.unpack_alias(self.node);
1263-
#all
1217+
1218+
#ident::<I>::SHAPE
1219+
.all(forest, node)
1220+
.into_iter()
1221+
.map(move |r| #ident::from_forest(forest, r))
12641222
}
12651223
}
12661224
)

src/generate/templates/imports.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use gll::grammer::forest::{GrammarReflector as _, Node, NodeShape};
22
use gll::runtime::{
3-
cursor::Cursor as _,
3+
cursor::{self, Cursor as _},
44
traverse::{self, Shape as _},
55
};
66
use std::any;

src/runtime.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -658,13 +658,16 @@ pub mod traverse {
658658
}
659659

660660
#[derive(Copy, Clone)]
661-
pub struct Choice<M>(pub M);
661+
pub struct Choice<A, M>(pub A, pub M);
662662

663-
impl<'a, 'i, G: GrammarReflector, M> Shape<'a, 'i, G> for Choice<M>
663+
impl<'a, 'i, G: GrammarReflector, A, M> Shape<'a, 'i, G> for Choice<A, M>
664664
where
665+
A: Shape<'a, 'i, G>,
666+
A::All: Clone,
665667
M: Shape<'a, 'i, G>,
666668

667669
// HACK(eddyb) these are only because of dynamic dispatch / boxing:
670+
A: 'a,
668671
M: 'a,
669672
G: 'a,
670673
{
@@ -675,17 +678,21 @@ pub mod traverse {
675678
out: &mut [Option<Node<'i, G>>],
676679
) -> Result<(), MoreThanOne> {
677680
let node = forest.one_choice(node)?;
681+
self.1.one(forest, node, out)?;
678682
self.0.one(forest, node, out)
679683
}
680684

681-
type All = FlattenIter<Box<dyn IteratorCloneHack<'a, Item = M::All>>>;
685+
// HACK(eddyb) `A` is after `M` because `Product<X, Y>` keeps two copies
686+
// of `Y` (so that it can reset the `Y` when `X` advances), and we don't
687+
// want two copies of `M` (a dedicated reset mechanism might be better?).
688+
type All = FlattenIter<Box<dyn IteratorCloneHack<'a, Item = Product<M::All, A::All>>>>;
682689
fn all<I: Input>(self, forest: &'a ParseForest<'i, G, I>, node: Node<'i, G>) -> Self::All {
683690
FlattenIter::new(Box::new(
684-
forest
685-
.all_choices(node)
686-
.map(move |node| self.0.all(forest, node)),
691+
forest.all_choices(node).map(move |node| {
692+
Product::new(self.1.all(forest, node), self.0.all(forest, node))
693+
}),
687694
)
688-
as Box<dyn IteratorCloneHack<'_, Item = M::All>>)
695+
as Box<dyn IteratorCloneHack<'_, Item = Product<M::All, A::All>>>)
689696
}
690697
}
691698

@@ -793,8 +800,9 @@ pub mod traverse {
793800
$crate::runtime::traverse::ty!($r_shape),
794801
>
795802
};
796-
({ $kind_ty:ty; $($kind:expr => $shape:tt,)* }) => {
803+
({ $kind_ty:ty; $at_shape:tt @ $($kind:expr => $shape:tt,)* }) => {
797804
$crate::runtime::traverse::Choice<
805+
$crate::runtime::traverse::ty!($at_shape),
798806
$crate::runtime::traverse::ty!(match($kind_ty) { $($shape,)* }),
799807
>
800808
};
@@ -830,8 +838,9 @@ pub mod traverse {
830838
$crate::runtime::traverse::new!($r_shape),
831839
)
832840
};
833-
({ $kind_ty:ty; $($kind:expr => $shape:tt,)* }) => {
841+
({ $kind_ty:ty; $at_shape:tt @ $($kind:expr => $shape:tt,)* }) => {
834842
$crate::runtime::traverse::Choice(
843+
$crate::runtime::traverse::new!($at_shape),
835844
$crate::runtime::traverse::new!(match { $($kind => $shape,)* }),
836845
)
837846
};

0 commit comments

Comments
 (0)