Skip to content

Commit fcd9026

Browse files
committed
Move to new return type
1 parent aede936 commit fcd9026

32 files changed

+235
-149
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ peg::parser!{
3030
}
3131

3232
pub fn main() {
33-
assert_eq!(list_parser::list("[1,1,2,3,5,8]"), Ok(vec![1, 1, 2, 3, 5, 8]));
33+
assert_eq!(list_parser::list("[1,1,2,3,5,8]").into_result(), Ok(vec![1, 1, 2, 3, 5, 8]));
3434
}
3535
```
3636

37-
[See the tests for more examples](./tests/run-pass/)
37+
[See the tests for more examples](./tests/run-pass/)
3838
[Grammar rule syntax reference in rustdoc](https://docs.rs/peg)
3939

4040
## Comparison with similar parser generators
@@ -60,6 +60,12 @@ pub fn main() {
6060
[annotate-snippets]: https://crates.io/crates/annotate-snippets
6161
[codespan-reporting]: https://crates.io/crates/codespan-reporting
6262
[codemap-diagnostic]: https://crates.io/crates/codemap-diagnostic
63+
64+
## Upgrade guide
65+
66+
The rule return type has changed between 0.8 to 0.9.
67+
To upgrade, add a call to `.into_result()` to convert the new rule return type
68+
to a simple `Result`.
6369
## Development
6470

6571
The `rust-peg` grammar is written in `rust-peg`: `peg-macros/grammar.rustpeg`. To avoid the circular dependency, a precompiled grammar is checked in as `peg-macros/grammar.rs`. To regenerate this, run the `./bootstrap.sh` script.

peg-macros/bin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fn main() {
4242

4343
let source_tokens = source.parse().expect("Error tokenizing input");
4444
let input_tokens = tokens::FlatTokenStream::new(source_tokens);
45-
let grammar = match grammar::peg::peg_grammar(&input_tokens) {
45+
let grammar = match grammar::peg::peg_grammar(&input_tokens).into_result() {
4646
Ok(g) => g,
4747
Err(err) => {
4848
eprintln!("Failed to parse grammar: expected {}", err.expected);

peg-macros/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mod translate;
2020
#[proc_macro]
2121
pub fn parser(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
2222
let tokens = tokens::FlatTokenStream::new(input.into());
23-
let grammar = match grammar::peg::peg_grammar(&tokens) {
23+
let grammar = match grammar::peg::peg_grammar(&tokens).into_result() {
2424
Ok(g) => g,
2525
Err(err) => {
2626
let msg = format!("expected {}", err.expected);

peg-macros/translate.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ fn compile_rule(context: &Context, rule: &Rule) -> TokenStream {
308308
}
309309

310310
/// Compile a rule into the parsing function which will be exported.
311-
/// Returns `Result<T, ParseError>`.
311+
/// Returns `ParseResults<T, L>`.
312312
fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream {
313313
let span = rule.span.resolved_at(Span::mixed_site());
314314

@@ -339,15 +339,15 @@ fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream {
339339

340340
quote_spanned! { span =>
341341
#doc
342-
#visibility fn #name<'input #(, #grammar_lifetime_params)* #(, #ty_params)*>(__input: #input_ty #extra_args_def #(, #rule_params)*) -> ::std::result::Result<#ret_ty, ::peg::error::ParseError<PositionRepr<#(#grammar_lifetime_params),*>>> {
342+
#visibility fn #name<'input #(, #grammar_lifetime_params)* #(, #ty_params)*>(__input: #input_ty #extra_args_def #(, #rule_params)*) -> ::peg::ParseResults<#ret_ty, PositionRepr<#(#grammar_lifetime_params),*>> {
343343
#![allow(non_snake_case, unused)]
344344

345345
let mut __err_state = ::peg::error::ErrorState::new(::peg::Parse::start(__input));
346346
let mut __state = ParseState::new();
347347
match #parse_fn(__input, &mut __state, &mut __err_state, ::peg::Parse::start(__input) #extra_args_call #(, #rule_params_call)*) {
348348
::peg::RuleResult::Matched(__pos, __value) => {
349349
if #eof_check {
350-
return Ok(__value)
350+
return __err_state.into_matched(__value, __input)
351351
} else {
352352
__err_state.mark_failure(__pos, "EOF");
353353
}
@@ -356,7 +356,7 @@ fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream {
356356
}
357357

358358
__state = ParseState::new();
359-
__err_state.reparse_for_error();
359+
__err_state.reparse_for_failure();
360360

361361
match #parse_fn(__input, &mut __state, &mut __err_state, ::peg::Parse::start(__input) #extra_args_call #(, #rule_params_call)*) {
362362
::peg::RuleResult::Matched(__pos, __value) => {
@@ -369,7 +369,7 @@ fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream {
369369
_ => ()
370370
}
371371

372-
Err(__err_state.into_parse_error(__input))
372+
__err_state.into_failure(__input)
373373
}
374374
}
375375
}
@@ -431,7 +431,7 @@ fn compile_expr_continuation(context: &Context, e: &SpannedExpr, result_name: Op
431431
fn compile_literal_expr(s: &Literal, continuation: TokenStream) -> TokenStream {
432432
let span = s.span().resolved_at(Span::mixed_site());
433433
let escaped_str = s.to_string();
434-
quote_spanned! { span =>
434+
quote_spanned! { span =>
435435
match ::peg::ParseLiteral::parse_string_literal(__input, __pos, #s) {
436436
::peg::RuleResult::Matched(__pos, __val) => { #continuation }
437437
::peg::RuleResult::Failed => { __err_state.mark_failure(__pos, #escaped_str); ::peg::RuleResult::Failed }
@@ -456,7 +456,7 @@ fn compile_pattern_expr(pattern_group: &Group, result_name: Ident, success_res:
456456
#pattern => #in_set,
457457
_ => #not_in_set,
458458
}
459-
::peg::RuleResult::Failed => { __err_state.mark_failure(__pos, #pat_str); ::peg::RuleResult::Failed }
459+
::peg::RuleResult::Failed => { __err_state.mark_failure(__pos, #pat_str); ::peg::RuleResult::Failed },
460460
}
461461
}
462462
}
@@ -683,7 +683,7 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
683683
__err_state.suppress_fail -= 1;
684684
match __assert_res {
685685
::peg::RuleResult::Failed => ::peg::RuleResult::Matched(__pos, ()),
686-
::peg::RuleResult::Matched(..) => ::peg::RuleResult::Failed,
686+
::peg::RuleResult::Matched(..) => __err_state.mark_failure(__pos, "mismatch"),
687687
}
688688
}}
689689
}

peg-runtime/error.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Parse error reporting
22
3-
use crate::{Parse, RuleResult};
3+
use crate::{Parse, RuleResult, ParseResults, ParseResult};
44
use std::collections::HashSet;
55
use std::fmt::{self, Debug, Display};
66

@@ -15,6 +15,13 @@ impl ExpectedSet {
1515
pub fn tokens<'a>(&'a self) -> impl Iterator<Item = &'static str> + 'a {
1616
self.expected.iter().map(|x| *x)
1717
}
18+
19+
/// Construct a new singleton set.
20+
pub(crate) fn singleton(error: &'static str) -> Self {
21+
let mut expected = HashSet::new();
22+
expected.insert(error);
23+
ExpectedSet { expected }
24+
}
1825
}
1926

2027
impl Display for ExpectedSet {
@@ -65,6 +72,7 @@ impl<L: Display + Debug> ::std::error::Error for ParseError<L> {
6572
}
6673

6774
#[doc(hidden)]
75+
#[derive(Debug)]
6876
pub struct ErrorState {
6977
/// Furthest failure we've hit so far.
7078
pub max_err_pos: usize,
@@ -75,9 +83,9 @@ pub struct ErrorState {
7583

7684
/// Are we reparsing after a failure? If so, compute and store expected set of all alternative expectations
7785
/// when we are at offset `max_err_pos`.
78-
pub reparsing_on_error: bool,
86+
pub reparsing_on_failure: bool,
7987

80-
/// The set of tokens we expected to find when we hit the failure. Updated when `reparsing_on_error`.
88+
/// The set of tokens we expected to find when we hit the failure. Updated when `reparsing_on_failure`.
8189
pub expected: ExpectedSet,
8290
}
8391

@@ -86,21 +94,21 @@ impl ErrorState {
8694
ErrorState {
8795
max_err_pos: initial_pos,
8896
suppress_fail: 0,
89-
reparsing_on_error: false,
97+
reparsing_on_failure: false,
9098
expected: ExpectedSet {
9199
expected: HashSet::new(),
92100
},
93101
}
94102
}
95103

96104
/// Set up for reparsing to record the details of the furthest failure.
97-
pub fn reparse_for_error(&mut self) {
105+
pub fn reparse_for_failure(&mut self) {
98106
self.suppress_fail = 0;
99-
self.reparsing_on_error = true;
107+
self.reparsing_on_failure = true;
100108
}
101109

102110
#[inline(never)]
103-
pub fn mark_failure_slow_path(&mut self, pos: usize, expected: &'static str) {
111+
fn mark_failure_slow_path(&mut self, pos: usize, expected: &'static str) {
104112
if pos == self.max_err_pos {
105113
self.expected.expected.insert(expected);
106114
}
@@ -110,7 +118,7 @@ impl ErrorState {
110118
#[inline(always)]
111119
pub fn mark_failure(&mut self, pos: usize, expected: &'static str) -> RuleResult<()> {
112120
if self.suppress_fail == 0 {
113-
if self.reparsing_on_error {
121+
if self.reparsing_on_failure {
114122
self.mark_failure_slow_path(pos, expected);
115123
} else if pos > self.max_err_pos {
116124
self.max_err_pos = pos;
@@ -119,10 +127,25 @@ impl ErrorState {
119127
RuleResult::Failed
120128
}
121129

122-
pub fn into_parse_error<I: Parse + ?Sized>(self, input: &I) -> ParseError<I::PositionRepr> {
123-
ParseError {
124-
location: Parse::position_repr(input, self.max_err_pos.into()),
125-
expected: self.expected,
130+
}
131+
}
132+
133+
/// Build `Matched` parse result.
134+
pub fn into_matched<T, I: Parse + ?Sized>(self, v: T, input: &I) -> ParseResults<T, I::PositionRepr> {
135+
ParseResults {
136+
result: ParseResult::Matched(v),
137+
errors: errors_positioned_in(self.errors, input),
138+
}
139+
}
140+
141+
/// Build `Failed` parse result.
142+
pub fn into_failure<T, I: Parse + ?Sized>(self, input: &I) -> ParseResults<T, I::PositionRepr> {
143+
ParseResults {
144+
result: ParseResult::Failed(ParseError {
145+
expected: self.expected,
146+
location: input.position_repr(self.max_err_pos)
147+
}),
148+
errors: errors_positioned_in(self.errors, input),
126149
}
127150
}
128151
}

peg-runtime/lib.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,64 @@ pub mod error;
44
mod slice;
55
pub mod str;
66

7+
8+
/// The public API of a parser: the result of the parse.
9+
#[derive(Clone, PartialEq, Eq, Debug)]
10+
pub struct ParseResults<T, L> {
11+
/// The result of the parse.
12+
pub result: ParseResult<T, L>,
13+
}
14+
15+
impl<T: Display, L: Display> Display for ParseResults<T, L> {
16+
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
17+
write!(fmt, "{}", self.result)
18+
}
19+
}
20+
21+
impl<T, L> ParseResults<T, L> {
22+
/// Convert into a simple `Result`.
23+
pub fn into_result(self) -> Result<T, error::ParseError<L>> {
24+
match self.result {
25+
ParseResult::Matched(v) => Ok(v),
26+
ParseResult::Failed(e) => Err(e),
27+
}
28+
}
29+
}
30+
31+
impl<T, L: Display> ParseResults<T, L> {
32+
/// Return the contained match, or panic on failure.
33+
pub fn unwrap(self) -> T {
34+
match self.result {
35+
ParseResult::Matched(v) => v,
36+
ParseResult::Failed(e) => panic!("parse failed: {}", e),
37+
}
38+
}
39+
}
40+
41+
/// The public result of a parser.
42+
/// A parse may succeed or fail.
43+
#[derive(Clone, PartialEq, Eq, Debug)]
44+
pub enum ParseResult<T, L> {
45+
/// Success
46+
Matched(T),
47+
48+
/// Failure
49+
Failed(error::ParseError<L>),
50+
}
51+
52+
impl<T: Display, L: Display> Display for ParseResult<T, L> {
53+
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
54+
match self {
55+
ParseResult::Matched(v) => write!(fmt, "{}", v),
56+
ParseResult::Failed(e) => write!(fmt, "{}", e),
57+
}
58+
}
59+
}
60+
761
/// The result type used internally in the parser.
862
///
963
/// You'll only need this if implementing the `Parse*` traits for a custom input
10-
/// type. The public API of a parser adapts errors to `std::result::Result`.
64+
/// type.
1165
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
1266
pub enum RuleResult<T> {
1367
/// Success, with final location

src/lib.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@
3333
//!
3434
//! The macro expands to a Rust `mod` containing a function for each rule marked
3535
//! `pub` in the grammar. To parse an input sequence, call one of these
36-
//! functions. The call returns a `Result<T, ParseError>` carrying either the
37-
//! successfully parsed value returned by the rule, or a `ParseError` containing
38-
//! the failure position and the set of tokens expected there.
36+
//! functions. The call returns a `ParseResults<T,L>`, which carries either the
37+
//! successfully parsed value or the furthest failure.
38+
//!
39+
//! * Use `unwrap()` to obtain the successful `T` or panic.
40+
//! * Use `into_result()` to obtain a `Result<T, _>`.
41+
//! * For full details, match on the `result` field.
3942
//!
4043
//! ## Example
4144
//!
@@ -53,7 +56,7 @@
5356
//! }
5457
//!
5558
//! pub fn main() {
56-
//! assert_eq!(list_parser::list("[1,1,2,3,5,8]"), Ok(vec![1, 1, 2, 3, 5, 8]));
59+
//! assert_eq!(list_parser::list("[1,1,2,3,5,8]").into_result(), Ok(vec![1, 1, 2, 3, 5, 8]));
5760
//! }
5861
//! ```
5962
//!

tests/run-pass/arithmetic.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ peg::parser!( grammar arithmetic() for str {
2222
});
2323

2424
fn main() {
25-
assert_eq!(expression("1+1"), Ok(2));
26-
assert_eq!(expression("5*5"), Ok(25));
27-
assert_eq!(expression("222+3333"), Ok(3555));
28-
assert_eq!(expression("2+3*4"), Ok(14));
29-
assert_eq!(expression("(2+2)*3"), Ok(12));
30-
assert!(expression("(22+)+1").is_err());
31-
assert!(expression("1++1").is_err());
32-
assert!(expression("3)+1").is_err());
25+
assert_eq!(expression("1+1").into_result(), Ok(2));
26+
assert_eq!(expression("5*5").into_result(), Ok(25));
27+
assert_eq!(expression("222+3333").into_result(), Ok(3555));
28+
assert_eq!(expression("2+3*4").into_result(), Ok(14));
29+
assert_eq!(expression("(2+2)*3").into_result(), Ok(12));
30+
assert!(expression("(22+)+1").into_result().is_err());
31+
assert!(expression("1++1").into_result().is_err());
32+
assert!(expression("3)+1").into_result().is_err());
3333
}

tests/run-pass/arithmetic_ast.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,29 @@ grammar arithmetic() for str {
3535
}}
3636

3737
fn main() {
38-
assert_eq!(arithmetic::expression("1+1"), Ok(Expression::Sum(
38+
assert_eq!(arithmetic::expression("1+1").into_result(), Ok(Expression::Sum(
3939
Box::new(Expression::Number(1)),
4040
Box::new(Expression::Number(1)))
4141
));
42-
assert_eq!(arithmetic::expression("5*5"), Ok(Expression::Product(
42+
assert_eq!(arithmetic::expression("5*5").into_result(), Ok(Expression::Product(
4343
Box::new(Expression::Number(5)),
4444
Box::new(Expression::Number(5)))
4545
));
46-
assert_eq!(arithmetic::expression("2+3*4"), Ok(Expression::Sum(
46+
assert_eq!(arithmetic::expression("2+3*4").into_result(), Ok(Expression::Sum(
4747
Box::new(Expression::Number(2)),
4848
Box::new(Expression::Product(
4949
Box::new(Expression::Number(3)),
5050
Box::new(Expression::Number(4))
5151
)),
5252
)));
53-
assert_eq!(arithmetic::expression("(2+3) * 4"), Ok(Expression::Product(
53+
assert_eq!(arithmetic::expression("(2+3) * 4").into_result(), Ok(Expression::Product(
5454
Box::new(Expression::Sum(
5555
Box::new(Expression::Number(2)),
5656
Box::new(Expression::Number(3)),
5757
)),
5858
Box::new(Expression::Number(4))
5959
)));
60-
assert!(arithmetic::expression("(22+)+1").is_err());
61-
assert!(arithmetic::expression("1++1").is_err());
62-
assert!(arithmetic::expression("3)+1").is_err());
60+
assert!(arithmetic::expression("(22+)+1").into_result().is_err());
61+
assert!(arithmetic::expression("1++1").into_result().is_err());
62+
assert!(arithmetic::expression("3)+1").into_result().is_err());
6363
}

tests/run-pass/arithmetic_infix.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ peg::parser!( grammar arithmetic() for str {
2222
});
2323

2424
fn main() {
25-
assert_eq!(arithmetic::calculate("3+3*3+3"), Ok(15));
26-
assert_eq!(arithmetic::calculate("2+2^2^2^2/2+2"), Ok(32772));
27-
assert_eq!(arithmetic::calculate("1024/2/2/2+1"), Ok(129));
28-
assert_eq!(arithmetic::calculate("1024/(1+1)/2/2+1"), Ok(129));
29-
assert_eq!(arithmetic::calculate("-1-2*-2"), Ok(3));
30-
assert_eq!(arithmetic::calculate("1+3!+1"), Ok(8));
25+
assert_eq!(arithmetic::calculate("3+3*3+3").into_result(), Ok(15));
26+
assert_eq!(arithmetic::calculate("2+2^2^2^2/2+2").into_result(), Ok(32772));
27+
assert_eq!(arithmetic::calculate("1024/2/2/2+1").into_result(), Ok(129));
28+
assert_eq!(arithmetic::calculate("1024/(1+1)/2/2+1").into_result(), Ok(129));
29+
assert_eq!(arithmetic::calculate("-1-2*-2").into_result(), Ok(3));
30+
assert_eq!(arithmetic::calculate("1+3!+1").into_result(), Ok(8));
3131
}

0 commit comments

Comments
 (0)