Skip to content

Commit 1627835

Browse files
authored
Merge pull request #554 from ratmice/grmtools_section_cleanup
First take at removing `HeaderError` from `YaccParser` internals
2 parents 04ae392 + e5e3b65 commit 1627835

23 files changed

Lines changed: 521 additions & 560 deletions

File tree

cfgrammar/src/lib/header.rs

Lines changed: 120 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::{
22
markmap::{Entry, MarkMap},
3-
yacc::{ParserError, YaccKind, YaccOriginalActionKind},
3+
yacc::{
4+
parser::SpansKind, YaccGrammarError, YaccGrammarErrorKind, YaccKind, YaccOriginalActionKind,
5+
},
46
Location, Span,
57
};
68
use lazy_static::lazy_static;
@@ -14,21 +16,37 @@ use std::{error::Error, fmt};
1416
/// * An error during parsing the section.
1517
/// * An error resulting from a value in the section having an invalid value.
1618
#[derive(Debug, Clone)]
17-
pub struct HeaderError {
19+
#[doc(hidden)]
20+
pub struct HeaderError<T> {
1821
pub kind: HeaderErrorKind,
19-
pub locations: Vec<Location>,
22+
pub locations: Vec<T>,
2023
}
2124

22-
impl Error for HeaderError {}
23-
impl fmt::Display for HeaderError {
25+
impl<T: fmt::Debug> Error for HeaderError<T> {}
26+
impl<T> fmt::Display for HeaderError<T> {
2427
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2528
write!(f, "{}", self.kind)
2629
}
2730
}
2831

29-
impl From<HeaderError> for ParserError {
30-
fn from(e: HeaderError) -> ParserError {
31-
ParserError::HeaderError(e)
32+
impl From<HeaderError<Span>> for YaccGrammarError {
33+
fn from(e: HeaderError<Span>) -> YaccGrammarError {
34+
YaccGrammarError {
35+
kind: YaccGrammarErrorKind::Header(e.kind, e.spanskind()),
36+
spans: e.locations,
37+
}
38+
}
39+
}
40+
41+
// This is essentially a tuple that needs a newtype so we can implement `From` for it.
42+
// Thus we aren't worried about it being `pub`.
43+
#[derive(Debug, PartialEq)]
44+
#[doc(hidden)]
45+
pub struct HeaderValue<T>(pub T, pub Value<T>);
46+
47+
impl From<HeaderValue<Span>> for HeaderValue<Location> {
48+
fn from(hv: HeaderValue<Span>) -> HeaderValue<Location> {
49+
HeaderValue(hv.0.into(), hv.1.into())
3250
}
3351
}
3452

@@ -60,6 +78,16 @@ impl fmt::Display for HeaderErrorKind {
6078
}
6179
}
6280

81+
impl<T> HeaderError<T> {
82+
/// Returns the [SpansKind] associated with this error.
83+
pub fn spanskind(&self) -> SpansKind {
84+
match self.kind {
85+
HeaderErrorKind::DuplicateEntry => SpansKind::DuplicationError,
86+
_ => SpansKind::Error,
87+
}
88+
}
89+
}
90+
6391
/// Indicates a value prefixed by an optional namespace.
6492
/// `Foo::Bar` with optional `Foo` specified being
6593
/// ```rust,ignore
@@ -78,24 +106,24 @@ impl fmt::Display for HeaderErrorKind {
78106
/// ```
79107
#[derive(Debug, Eq, PartialEq)]
80108
#[doc(hidden)]
81-
pub struct Namespaced {
82-
pub namespace: Option<(String, Location)>,
83-
pub member: (String, Location),
109+
pub struct Namespaced<T> {
110+
pub namespace: Option<(String, T)>,
111+
pub member: (String, T),
84112
}
85113

86114
#[derive(Debug, Eq, PartialEq)]
87115
#[doc(hidden)]
88-
pub enum Setting {
116+
pub enum Setting<T> {
89117
/// A value like `YaccKind::Grmtools`
90-
Unitary(Namespaced),
118+
Unitary(Namespaced<T>),
91119
/// A value like `YaccKind::Original(UserActions)`.
92120
/// In that example the field ctor would be: `Namespaced { namespace: "YaccKind", member: "Original" }`.
93121
/// The field would be `Namespaced{ None, UserActions }`.
94122
Constructor {
95-
ctor: Namespaced,
96-
arg: Namespaced,
123+
ctor: Namespaced<T>,
124+
arg: Namespaced<T>,
97125
},
98-
Num(u64, Location),
126+
Num(u64, T),
99127
}
100128

101129
/// Parser for the `%grmtools` section
@@ -111,9 +139,48 @@ pub struct GrmtoolsSectionParser<'input> {
111139
/// like booleans, numeric types, and string values.
112140
#[derive(Debug, Eq, PartialEq)]
113141
#[doc(hidden)]
114-
pub enum Value {
115-
Flag(bool, Location),
116-
Setting(Setting),
142+
pub enum Value<T> {
143+
Flag(bool, T),
144+
Setting(Setting<T>),
145+
}
146+
147+
impl From<Value<Span>> for Value<Location> {
148+
fn from(v: Value<Span>) -> Value<Location> {
149+
match v {
150+
Value::Flag(flag, u) => Value::Flag(flag, u.into()),
151+
Value::Setting(s) => Value::Setting(match s {
152+
Setting::Unitary(Namespaced {
153+
namespace,
154+
member: (m, ml),
155+
}) => Setting::Unitary(Namespaced {
156+
namespace: namespace.map(|(n, nl)| (n, nl.into())),
157+
member: (m, ml.into()),
158+
}),
159+
Setting::Constructor {
160+
ctor:
161+
Namespaced {
162+
namespace: ctor_ns,
163+
member: (ctor_m, ctor_ml),
164+
},
165+
arg:
166+
Namespaced {
167+
namespace: arg_ns,
168+
member: (arg_m, arg_ml),
169+
},
170+
} => Setting::Constructor {
171+
ctor: Namespaced {
172+
namespace: ctor_ns.map(|(ns, ns_l)| (ns, ns_l.into())),
173+
member: (ctor_m, ctor_ml.into()),
174+
},
175+
arg: Namespaced {
176+
namespace: arg_ns.map(|(ns, ns_l)| (ns, ns_l.into())),
177+
member: (arg_m, arg_ml.into()),
178+
},
179+
},
180+
Setting::Num(num, num_loc) => Setting::Num(num, num_loc.into()),
181+
}),
182+
}
183+
}
117184
}
118185

119186
lazy_static! {
@@ -127,11 +194,11 @@ lazy_static! {
127194

128195
const MAGIC: &str = "%grmtools";
129196

130-
fn add_duplicate_occurrence(
131-
errs: &mut Vec<HeaderError>,
197+
fn add_duplicate_occurrence<T: Eq + PartialEq + Clone>(
198+
errs: &mut Vec<HeaderError<T>>,
132199
kind: HeaderErrorKind,
133-
orig_loc: Location,
134-
dup_loc: Location,
200+
orig_loc: T,
201+
dup_loc: T,
135202
) {
136203
if !errs.iter_mut().any(|e| {
137204
if e.kind == kind && e.locations[0] == orig_loc {
@@ -152,18 +219,18 @@ impl<'input> GrmtoolsSectionParser<'input> {
152219
pub fn parse_value(
153220
&'_ self,
154221
mut i: usize,
155-
) -> Result<(String, Location, Value, usize), HeaderError> {
222+
) -> Result<(String, Span, Value<Span>, usize), HeaderError<Span>> {
156223
if let Some(j) = self.lookahead_is("!", i) {
157224
let (flag_name, k) = self.parse_name(j)?;
158225
Ok((
159226
flag_name,
160-
Location::Span(Span::new(j, k)),
161-
Value::Flag(false, Location::Span(Span::new(i, k))),
227+
Span::new(j, k),
228+
Value::Flag(false, Span::new(i, k)),
162229
self.parse_ws(k),
163230
))
164231
} else {
165232
let (key_name, j) = self.parse_name(i)?;
166-
let key_span = Location::Span(Span::new(i, j));
233+
let key_span = Span::new(i, j);
167234
i = self.parse_ws(j);
168235
if let Some(j) = self.lookahead_is(":", i) {
169236
i = self.parse_ws(j);
@@ -173,7 +240,7 @@ impl<'input> GrmtoolsSectionParser<'input> {
173240
let num_str = &self.src[num_span.start()..num_span.end()];
174241
// If the above regex matches we expect this to succeed.
175242
let num = str::parse::<u64>(num_str).unwrap();
176-
let val = Setting::Num(num, Location::Span(num_span));
243+
let val = Setting::Num(num, num_span);
177244
i = self.parse_ws(num_span.end());
178245
Ok((key_name, key_span, Value::Setting(val), i))
179246
}
@@ -197,7 +264,7 @@ impl<'input> GrmtoolsSectionParser<'input> {
197264
} else {
198265
Err(HeaderError {
199266
kind: HeaderErrorKind::ExpectedToken(')'),
200-
locations: vec![Location::Span(Span::new(i, i))],
267+
locations: vec![Span::new(i, i)],
201268
})
202269
}
203270
} else {
@@ -211,20 +278,23 @@ impl<'input> GrmtoolsSectionParser<'input> {
211278
}
212279
}
213280
} else {
214-
Ok((key_name, key_span.clone(), Value::Flag(true, key_span), i))
281+
Ok((key_name, key_span, Value::Flag(true, key_span), i))
215282
}
216283
}
217284
}
218285

219-
fn parse_namespaced(&self, mut i: usize) -> Result<(Namespaced, usize), HeaderError> {
286+
fn parse_namespaced(
287+
&self,
288+
mut i: usize,
289+
) -> Result<(Namespaced<Span>, usize), HeaderError<Span>> {
220290
// Either a name alone, or a namespace which will be followed by a member.
221291
let (name, j) = self.parse_name(i)?;
222-
let name_span = Location::Span(Span::new(i, j));
292+
let name_span = Span::new(i, j);
223293
i = self.parse_ws(j);
224294
if let Some(j) = self.lookahead_is("::", i) {
225295
i = self.parse_ws(j);
226296
let (member_val, j) = self.parse_name(i)?;
227-
let member_val_span = Location::Span(Span::new(i, j));
297+
let member_val_span = Span::new(i, j);
228298
i = self.parse_ws(j);
229299
Ok((
230300
Namespaced {
@@ -258,7 +328,7 @@ impl<'input> GrmtoolsSectionParser<'input> {
258328
}
259329

260330
#[allow(clippy::type_complexity)]
261-
pub fn parse(&'_ self) -> Result<(Header, usize), Vec<HeaderError>> {
331+
pub fn parse(&'_ self) -> Result<(Header<Span>, usize), Vec<HeaderError<Span>>> {
262332
let mut errs = Vec::new();
263333
if let Some(mut i) = self.lookahead_is(MAGIC, self.parse_ws(0)) {
264334
let mut ret = Header::new();
@@ -276,16 +346,16 @@ impl<'input> GrmtoolsSectionParser<'input> {
276346
};
277347
match ret.entry(key) {
278348
Entry::Occupied(orig) => {
279-
let (orig_loc, _): &(Location, Value) = orig.get();
349+
let HeaderValue(orig_loc, _): &HeaderValue<Span> = orig.get();
280350
add_duplicate_occurrence(
281351
&mut errs,
282352
HeaderErrorKind::DuplicateEntry,
283-
orig_loc.clone(),
353+
*orig_loc,
284354
key_loc,
285355
)
286356
}
287357
Entry::Vacant(entry) => {
288-
entry.insert((key_loc, val));
358+
entry.insert(HeaderValue(key_loc, val));
289359
}
290360
}
291361
if let Some(j) = self.lookahead_is(",", j) {
@@ -305,32 +375,29 @@ impl<'input> GrmtoolsSectionParser<'input> {
305375
} else {
306376
errs.push(HeaderError {
307377
kind: HeaderErrorKind::ExpectedToken('}'),
308-
locations: vec![Location::Span(Span::new(
309-
section_start_pos,
310-
self.src.len(),
311-
))],
378+
locations: vec![Span::new(section_start_pos, self.src.len())],
312379
});
313380
Err(errs)
314381
}
315382
} else {
316383
errs.push(HeaderError {
317384
kind: HeaderErrorKind::ExpectedToken('{'),
318-
locations: vec![Location::Span(Span::new(i, i))],
385+
locations: vec![Span::new(i, i)],
319386
});
320387
Err(errs)
321388
}
322389
} else if self.required {
323390
errs.push(HeaderError {
324391
kind: HeaderErrorKind::MissingGrmtoolsSection,
325-
locations: vec![Location::Span(Span::new(0, 0))],
392+
locations: vec![Span::new(0, 0)],
326393
});
327394
Err(errs)
328395
} else {
329396
Ok((Header::new(), 0))
330397
}
331398
}
332399

333-
fn parse_name(&self, i: usize) -> Result<(String, usize), HeaderError> {
400+
fn parse_name(&self, i: usize) -> Result<(String, usize), HeaderError<Span>> {
334401
match RE_NAME.find(&self.src[i..]) {
335402
Some(m) => {
336403
assert_eq!(m.start(), 0);
@@ -341,7 +408,7 @@ impl<'input> GrmtoolsSectionParser<'input> {
341408
}
342409
None => Err(HeaderError {
343410
kind: HeaderErrorKind::IllegalName,
344-
locations: vec![Location::Span(Span::new(i, i))],
411+
locations: vec![Span::new(i, i)],
345412
}),
346413
}
347414
}
@@ -363,11 +430,12 @@ impl<'input> GrmtoolsSectionParser<'input> {
363430
}
364431

365432
/// A data structure representation of the %grmtools section.
366-
pub type Header = MarkMap<String, (Location, Value)>;
433+
#[doc(hidden)]
434+
pub type Header<T> = MarkMap<String, HeaderValue<T>>;
367435

368-
impl TryFrom<YaccKind> for Value {
369-
type Error = HeaderError;
370-
fn try_from(kind: YaccKind) -> Result<Value, HeaderError> {
436+
impl TryFrom<YaccKind> for Value<Location> {
437+
type Error = HeaderError<Location>;
438+
fn try_from(kind: YaccKind) -> Result<Value<Location>, HeaderError<Location>> {
371439
let from_loc = Location::Other("From<YaccKind>".to_string());
372440
Ok(match kind {
373441
YaccKind::Grmtools => Value::Setting(Setting::Unitary(Namespaced {
@@ -402,9 +470,9 @@ impl TryFrom<YaccKind> for Value {
402470
}
403471
}
404472

405-
impl TryFrom<&Value> for YaccKind {
406-
type Error = HeaderError;
407-
fn try_from(value: &Value) -> Result<YaccKind, HeaderError> {
473+
impl<T: Clone> TryFrom<&Value<T>> for YaccKind {
474+
type Error = HeaderError<T>;
475+
fn try_from(value: &Value<T>) -> Result<YaccKind, HeaderError<T>> {
408476
let mut err_locs = Vec::new();
409477
match value {
410478
Value::Flag(_, loc) => Err(HeaderError {

0 commit comments

Comments
 (0)