Skip to content

Commit af41c9a

Browse files
committed
refactor Parser API to use multi_variant
This will make it easier to support fixed point parsing.
1 parent 1dc3bda commit af41c9a

File tree

3 files changed

+113
-108
lines changed

3 files changed

+113
-108
lines changed

crates/formality-core/src/parse/parser.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,23 @@ where
7373
nonterminal_name: &'static str,
7474
op: impl FnOnce(&mut ActiveVariant<'s, 't, L>) -> Result<T, Set<ParseError<'t>>>,
7575
) -> ParseResult<'t, T> {
76-
let mut result = Parser::new(scope, text, nonterminal_name);
77-
result.parse_variant(nonterminal_name, 0, op);
78-
result.finish()
76+
Parser::multi_variant(scope, text, nonterminal_name, |parser| {
77+
parser.parse_variant(nonterminal_name, 0, op);
78+
})
7979
}
8080

81-
/// Creates a new parser. You should then invoke `parse_variant` 0 or more times for
82-
/// each of the possibilities and finally invoke `finish`.
81+
/// Creates a new parser that can accommodate multiple variants.
82+
///
83+
/// Invokes `op` to do the parsing; `op` should call `parse_variant` 0 or more times for
84+
/// each of the possibilities. The best result (if any) will then be returned.
8385
///
8486
/// The method [`single_variant`] is more convenient if you have exactly one variant.
85-
pub fn new(scope: &'s Scope<L>, text: &'t str, nonterminal_name: &'static str) -> Self {
87+
pub fn multi_variant(
88+
scope: &'s Scope<L>,
89+
text: &'t str,
90+
nonterminal_name: &'static str,
91+
op: impl FnOnce(&mut Self),
92+
) -> ParseResult<'t, T> {
8693
let tracing_span = tracing::span!(
8794
tracing::Level::TRACE,
8895
"nonterminal",
@@ -92,14 +99,18 @@ where
9299
)
93100
.entered();
94101

95-
Self {
102+
let mut parser = Self {
96103
scope,
97104
start_text: text,
98105
nonterminal_name,
99106
tracing_span,
100107
successes: vec![],
101108
failures: set![],
102-
}
109+
};
110+
111+
op(&mut parser);
112+
113+
parser.finish()
103114
}
104115

105116
/// Shorthand for `parse_variant` where the parsing operation is to
@@ -173,7 +184,7 @@ where
173184
}
174185
}
175186

176-
pub fn finish(self) -> ParseResult<'t, T> {
187+
fn finish(self) -> ParseResult<'t, T> {
177188
// If we did not parse anything successfully, then return an error.
178189
// There are two possibilities: some of our variants may have made
179190
// progress but ultimately failed. If so, self.failures will be non-empty,

crates/formality-macros/src/parse.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ pub(crate) fn derive_parse_with_spec(
5555
gen impl parse::CoreParse<crate::FormalityLang> for @Self {
5656
fn parse<'t>(scope: &parse::Scope<crate::FormalityLang>, text: &'t str) -> parse::ParseResult<'t, Self>
5757
{
58-
let mut __parser = parse::Parser::new(scope, text, #type_name);
59-
#parse_variants;
60-
__parser.finish()
58+
parse::Parser::multi_variant(scope, text, #type_name, |__parser| {
59+
#parse_variants;
60+
})
6161
}
6262
}
6363
}))

crates/formality-types/src/grammar/ty/parse_impls.rs

Lines changed: 90 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -16,94 +16,90 @@ use crate::rust::FormalityLang as Rust;
1616
// Implement custom parsing for rigid types.
1717
impl CoreParse<Rust> for RigidTy {
1818
fn parse<'t>(scope: &Scope<Rust>, text: &'t str) -> ParseResult<'t, Self> {
19-
let mut parser: Parser<'_, '_, RigidTy, Rust> = Parser::new(scope, text, "AliasTy");
20-
21-
// Parse a `ScalarId` (and upcast it to `RigidTy`) with the highest
22-
// precedence. If someone writes `u8`, we always interpret it as a
23-
// scalar-id.
24-
parser.parse_variant_cast::<ScalarId>(1);
25-
26-
// Parse something like `Id<...>` as an ADT.
27-
parser.parse_variant("Adt", 0, |p| {
28-
let name: AdtId = p.nonterminal()?;
29-
let parameters: Vec<Parameter> = parse_parameters(p)?;
30-
Ok(RigidTy {
31-
name: name.upcast(),
32-
parameters,
33-
})
34-
});
35-
36-
// Parse `&`
37-
parser.parse_variant("Ref", 0, |p| {
38-
p.expect_char('&')?;
39-
let lt: Lt = p.nonterminal()?;
40-
let ty: Ty = p.nonterminal()?;
41-
Ok(RigidTy {
42-
name: RigidName::Ref(RefKind::Shared),
43-
parameters: seq![lt.upcast(), ty.upcast()],
44-
}
45-
.upcast())
46-
});
47-
48-
parser.parse_variant("RefMut", 0, |p| {
49-
p.expect_char('&')?;
50-
p.expect_keyword("mut")?;
51-
let lt: Lt = p.nonterminal()?;
52-
let ty: Ty = p.nonterminal()?;
53-
Ok(RigidTy {
54-
name: RigidName::Ref(RefKind::Mut),
55-
parameters: seq![lt.upcast(), ty.upcast()],
56-
})
57-
});
58-
59-
parser.parse_variant("Tuple", 0, |p| {
60-
p.expect_char('(')?;
61-
p.reject_custom_keywords(&["alias", "rigid", "predicate"])?;
62-
let types: Vec<Ty> = p.comma_nonterminal()?;
63-
p.expect_char(')')?;
64-
let name = RigidName::Tuple(types.len());
65-
Ok(RigidTy {
66-
name,
67-
parameters: types.upcast(),
68-
})
69-
});
70-
71-
parser.finish()
19+
Parser::multi_variant(scope, text, "AliasTy", |parser| {
20+
// Parse a `ScalarId` (and upcast it to `RigidTy`) with the highest
21+
// precedence. If someone writes `u8`, we always interpret it as a
22+
// scalar-id.
23+
parser.parse_variant_cast::<ScalarId>(1);
24+
25+
// Parse something like `Id<...>` as an ADT.
26+
parser.parse_variant("Adt", 0, |p| {
27+
let name: AdtId = p.nonterminal()?;
28+
let parameters: Vec<Parameter> = parse_parameters(p)?;
29+
Ok(RigidTy {
30+
name: name.upcast(),
31+
parameters,
32+
})
33+
});
34+
35+
// Parse `&`
36+
parser.parse_variant("Ref", 0, |p| {
37+
p.expect_char('&')?;
38+
let lt: Lt = p.nonterminal()?;
39+
let ty: Ty = p.nonterminal()?;
40+
Ok(RigidTy {
41+
name: RigidName::Ref(RefKind::Shared),
42+
parameters: seq![lt.upcast(), ty.upcast()],
43+
}
44+
.upcast())
45+
});
46+
47+
parser.parse_variant("RefMut", 0, |p| {
48+
p.expect_char('&')?;
49+
p.expect_keyword("mut")?;
50+
let lt: Lt = p.nonterminal()?;
51+
let ty: Ty = p.nonterminal()?;
52+
Ok(RigidTy {
53+
name: RigidName::Ref(RefKind::Mut),
54+
parameters: seq![lt.upcast(), ty.upcast()],
55+
})
56+
});
57+
58+
parser.parse_variant("Tuple", 0, |p| {
59+
p.expect_char('(')?;
60+
p.reject_custom_keywords(&["alias", "rigid", "predicate"])?;
61+
let types: Vec<Ty> = p.comma_nonterminal()?;
62+
p.expect_char(')')?;
63+
let name = RigidName::Tuple(types.len());
64+
Ok(RigidTy {
65+
name,
66+
parameters: types.upcast(),
67+
})
68+
});
69+
})
7270
}
7371
}
7472
// ANCHOR_END: RigidTy_impl
7573

7674
impl CoreParse<Rust> for AliasTy {
7775
fn parse<'t>(scope: &Scope<Rust>, text: &'t str) -> ParseResult<'t, Self> {
78-
let mut parser: Parser<'_, '_, AliasTy, Rust> = Parser::new(scope, text, "AliasTy");
79-
80-
parser.parse_variant("associated type", 0, |p| {
81-
p.expect_char('<')?;
82-
let ty0: Ty = p.nonterminal()?;
83-
let () = p.expect_keyword("as")?;
84-
let trait_id: TraitId = p.nonterminal()?;
85-
let trait_parameters1 = parse_parameters(p)?;
86-
p.expect_char('>')?;
87-
p.expect_char(':')?;
88-
p.expect_char(':')?;
89-
let item_id: AssociatedItemId = p.nonterminal()?;
90-
let item_parameters = parse_parameters(p)?;
91-
let name = AssociatedTyName {
92-
trait_id,
93-
item_id,
94-
item_arity: item_parameters.len(),
95-
};
96-
let parameters: Vec<Parameter> = std::iter::once(ty0.upcast())
97-
.chain(trait_parameters1)
98-
.chain(item_parameters)
99-
.collect();
100-
Ok(AliasTy {
101-
name: name.upcast(),
102-
parameters,
103-
})
104-
});
105-
106-
parser.finish()
76+
Parser::multi_variant(scope, text, "AliasTy", |parser| {
77+
parser.parse_variant("associated type", 0, |p| {
78+
p.expect_char('<')?;
79+
let ty0: Ty = p.nonterminal()?;
80+
let () = p.expect_keyword("as")?;
81+
let trait_id: TraitId = p.nonterminal()?;
82+
let trait_parameters1 = parse_parameters(p)?;
83+
p.expect_char('>')?;
84+
p.expect_char(':')?;
85+
p.expect_char(':')?;
86+
let item_id: AssociatedItemId = p.nonterminal()?;
87+
let item_parameters = parse_parameters(p)?;
88+
let name = AssociatedTyName {
89+
trait_id,
90+
item_id,
91+
item_arity: item_parameters.len(),
92+
};
93+
let parameters: Vec<Parameter> = std::iter::once(ty0.upcast())
94+
.chain(trait_parameters1)
95+
.chain(item_parameters)
96+
.collect();
97+
Ok(AliasTy {
98+
name: name.upcast(),
99+
parameters,
100+
})
101+
});
102+
})
107103
}
108104
}
109105

@@ -122,19 +118,17 @@ fn parse_parameters<'t>(
122118
// writing tests so much more pleasant.
123119
impl CoreParse<Rust> for ConstData {
124120
fn parse<'t>(scope: &Scope<Rust>, text: &'t str) -> ParseResult<'t, Self> {
125-
let mut parser: Parser<'_, '_, ConstData, Rust> = Parser::new(scope, text, "Ty");
126-
127-
parser.parse_variant("Variable", 1, |p| p.variable());
128-
129-
parser.parse_variant_cast::<Bool>(1);
130-
131-
parser.parse_variant("Int", 0, |p| {
132-
let n: u128 = p.number()?;
133-
p.expect_char('_')?;
134-
let ty: Ty = p.nonterminal()?;
135-
Ok(ConstData::Value(Scalar::new(n).upcast(), ty))
136-
});
137-
138-
parser.finish()
121+
Parser::multi_variant(scope, text, "ConstData", |parser| {
122+
parser.parse_variant("Variable", 1, |p| p.variable());
123+
124+
parser.parse_variant_cast::<Bool>(1);
125+
126+
parser.parse_variant("Int", 0, |p| {
127+
let n: u128 = p.number()?;
128+
p.expect_char('_')?;
129+
let ty: Ty = p.nonterminal()?;
130+
Ok(ConstData::Value(Scalar::new(n).upcast(), ty))
131+
});
132+
})
139133
}
140134
}

0 commit comments

Comments
 (0)