Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Vec requirement #392

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 116 additions & 78 deletions peg-macros/grammar.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions peg-macros/grammar.rustpeg
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ rule rust_generic_param()
rule expression() -> SpannedExpr = choice()

rule choice() -> SpannedExpr = sp:sp() s:sequence() ++ "/" {
let s: Vec<_> = s;
if s.len() == 1 {
s.into_iter().next().unwrap()
} else {
Expand Down
30 changes: 18 additions & 12 deletions peg-macros/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
let match_sep = if let Some(sep) = sep {
let sep_inner = compile_expr(context, sep, false);
quote_spanned! { span=>
let __pos = if __repeat_value.is_empty() { __pos } else {
let __pos = if __repeat_count == 0 { __pos } else {
let __sep_res = #sep_inner;
match __sep_res {
::peg::RuleResult::Matched(__newpos, _) => { __newpos },
Expand All @@ -688,23 +688,26 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
quote!(())
};

let (repeat_vec, repeat_step) =
if result_used || min.is_some() || max.is_some() || sep.is_some() {
(
Some(quote_spanned! { span => let mut __repeat_value = vec!(); }),
Some(quote_spanned! { span => __repeat_value.push(__value); }),
)
} else {
(None, None)
};
let (repeat_vec, repeat_step) = if result_used {
(
Some(
quote_spanned! { span => let mut __repeat_value = ::core::default::Default::default(); },
),
Some(
quote_spanned! { span => ::core::iter::Extend::extend(&mut __repeat_value, Some(__value)); },
),
)
} else {
(None, None)
};

let max_check = max.map(|max| {
quote_spanned! { span=> if __repeat_value.len() >= #max { break } }
quote_spanned! { span=> if __repeat_count >= #max { break } }
});

let result_check = if let Some(min) = min {
quote_spanned! { span=>
if __repeat_value.len() >= #min {
if __repeat_count >= #min {
::peg::RuleResult::Matched(__repeat_pos, #result)
} else {
::peg::RuleResult::Failed
Expand All @@ -718,6 +721,7 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
let mut __repeat_pos = __pos;
#repeat_vec

let mut __repeat_count = 0usize;
loop {
let __pos = __repeat_pos;

Expand All @@ -734,6 +738,8 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
break;
}
}

__repeat_count += 1;
}

#result_check
Expand Down
16 changes: 8 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,18 @@
//! ### Repetition
//! * `expression?` - _Optional:_ match zero or one repetitions of `expression`. Returns an
//! `Option`.
//! * `expression*` - _Repeat:_ match zero or more repetitions of `expression` and return the
//! results as a `Vec`.
//! * `expression+` - _One-or-more:_ match one or more repetitions of `expression` and return the
//! results as a `Vec`.
//! * `expression*` - _Repeat:_ match zero or more repetitions of `expression` and stores the
//! results in any collection implementing `Default` and `Extend`.
//! * `expression+` - _One-or-more:_ match one or more repetitions of `expression` and stores the
//! results in any collection implementing `Default` and `Extend`.
//! * `expression*<n,m>` - _Range repeat:_ match between `n` and `m` repetitions of `expression`
//! return the results as a `Vec`. [(details)](#repeat-ranges)
//! store the results in any collection implementing `Default` and `Extend`. [(details)](#repeat-ranges)
//! * `expression ** delim` - _Delimited repeat:_ match zero or more repetitions of `expression`
//! delimited with `delim` and return the results as a `Vec`.
//! delimited with `delim` and stores the results in any collection implementing `Default` and `Extend`.
//! * `expression **<n,m> delim` - _Delimited repeat (range):_ match between `n` and `m` repetitions of `expression`
//! delimited with `delim` and return the results as a `Vec`. [(details)](#repeat-ranges)
//! delimited with `delim` and stores the results in any collection implementing `Default` and `Extend`)
//! * `expression ++ delim` - _Delimited repeat (one or more):_ match one or more repetitions of `expression`
//! delimited with `delim` and return the results as a `Vec`.
//! delimited with `delim` and stores the results in any collection implementing `Default` and `Extend`.
//!
//! ### Special
//! * `$(e)` - _Slice:_ match the expression `e`, and return the slice of the input
Expand Down
25 changes: 24 additions & 1 deletion tests/run-pass/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ peg::parser!{ grammar parser() for str {
pub rule one_letter() = ['a'..='z']

pub rule parse() -> usize
= v:( "a" / "\n" )* { v.len() }
= v:( "a" / "\n" )* {
let counter: ItemCounter = v;
counter.count()
}

pub rule error_pos() = ("a" / "\n" / "\r")*

Expand All @@ -15,6 +18,26 @@ peg::parser!{ grammar parser() for str {
pub rule var(s: &'static str) = expected!(s)
}}

struct ItemCounter {
count: usize,
}
impl Default for ItemCounter {
fn default() -> Self {
Self { count: 0 }
}
}
impl ItemCounter {
pub fn count(&self) -> usize {
self.count
}
}
impl Extend<()> for ItemCounter {
#[inline]
fn extend<T: IntoIterator<Item = ()>>(&mut self, into_iter: T) {
self.count += into_iter.into_iter().count();
}
}

fn main() {
// errors at eof
assert_eq!(parser::one_letter("t"), Ok(()));
Expand Down
4 changes: 1 addition & 3 deletions tests/run-pass/keyval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ peg::parser!( grammar keyval() for str {
= n:$(['0'..='9']+) { n.parse().unwrap() }

pub rule keyvals() -> HashMap<i64, i64>
= kvs:keyval() ++ "\n" {
kvs.iter().cloned().collect::<HashMap<i64, i64>>()
}
= kvs:keyval() ++ "\n" { kvs }

rule keyval() -> (i64, i64)
= k:number() ":" + v:number() { (k, v) }
Expand Down
Loading