summaryrefslogtreecommitdiffstats
path: root/vendor/pest/src/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/pest/src/macros.rs')
-rw-r--r--vendor/pest/src/macros.rs455
1 files changed, 455 insertions, 0 deletions
diff --git a/vendor/pest/src/macros.rs b/vendor/pest/src/macros.rs
new file mode 100644
index 000000000..01f410610
--- /dev/null
+++ b/vendor/pest/src/macros.rs
@@ -0,0 +1,455 @@
+// pest. The Elegant Parser
+// Copyright (c) 2018 DragoČ™ Tiselice
+//
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. All files in the project carrying such notice may not be copied,
+// modified, or distributed except according to those terms.
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! consumes_to {
+ ( $_rules:ident, $tokens:expr, [] ) => ();
+ ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ) ] ) => {
+ let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $start);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::Start { rule, pos } => {
+ let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $start {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+
+ let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $end);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::End { rule, pos } => {
+ let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $end {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+ };
+ ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ),
+ $( $names:ident $calls:tt ),* $(,)* ] ) => {
+
+ let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $start);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::Start { rule, pos } => {
+ let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $start {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+
+ let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $end);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::End { rule, pos } => {
+ let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $end {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+
+ consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
+ };
+ ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
+ [ $( $names:ident $calls:tt ),* $(,)* ] ) ] ) => {
+ let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $start);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::Start { rule, pos } => {
+ let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $start {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+
+ consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
+
+ let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $end);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::End { rule, pos } => {
+ let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $end {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+ };
+ ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
+ [ $( $nested_names:ident $nested_calls:tt ),*
+ $(,)* ] ),
+ $( $names:ident $calls:tt ),* ] ) => {
+
+ let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $start);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::Start { rule, pos } => {
+ let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $start {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+
+ consumes_to!($rules, $tokens, [ $( $nested_names $nested_calls ),* ]);
+
+ let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
+ $rules::$name, $end);
+ match $tokens.next().expect(&format!("{} but found nothing", expected)) {
+ $crate::Token::End { rule, pos } => {
+ let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
+ expected, rule, pos.pos());
+
+ if rule != $rules::$name || pos.pos() != $end {
+ panic!("{}", message);
+ }
+ },
+ token => panic!("{}", format!("{} but found {:?}", expected, token))
+ };
+
+ consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
+ };
+}
+
+/// Testing tool that compares produced tokens.
+///
+/// This macro takes several arguments:
+///
+/// * `parser` - name of the data structure implementing `Parser`
+/// * `input` - input to be tested against
+/// * `rule` - `Rule` which will be run
+/// * `tokens` - token pairs of the form `name(start_pos, end_pos, [nested_child_tokens])`
+///
+/// *Note:* `start_pos` and `end_pos` are byte positions.
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use]
+/// # extern crate pest;
+/// # use pest::Parser;
+/// # use pest::error::Error;
+/// # use pest::iterators::Pairs;
+/// # fn main() {
+/// # #[allow(non_camel_case_types)]
+/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+/// # enum Rule {
+/// # a,
+/// # b,
+/// # c
+/// # }
+/// #
+/// # struct AbcParser;
+/// #
+/// # impl Parser<Rule> for AbcParser {
+/// # fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
+/// # pest::state(input, |state| {
+/// # state.rule(Rule::a, |state| {
+/// # state.skip(1).unwrap().rule(Rule::b, |state| {
+/// # state.skip(1)
+/// # }).unwrap().skip(1)
+/// # }).and_then(|state| {
+/// # state.skip(1).unwrap().rule(Rule::c, |state| {
+/// # state.skip(1)
+/// # })
+/// # })
+/// # })
+/// # }
+/// # }
+/// parses_to! {
+/// parser: AbcParser,
+/// input: "abcde",
+/// rule: Rule::a,
+/// tokens: [
+/// a(0, 3, [
+/// b(1, 2)
+/// ]),
+/// c(4, 5)
+/// ]
+/// };
+/// # }
+/// ```
+#[macro_export]
+macro_rules! parses_to {
+ ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
+ tokens: [ $( $names:ident $calls:tt ),* $(,)* ] ) => {
+
+ #[allow(unused_mut)]
+ {
+ use $crate::Parser;
+
+ let mut tokens = $parser::parse($rules::$rule, $string).unwrap().tokens();
+
+ consumes_to!($rules, &mut tokens, [ $( $names $calls ),* ]);
+
+ let rest: Vec<_> = tokens.collect();
+
+ match rest.len() {
+ 0 => (),
+ 2 => {
+ let (first, second) = (&rest[0], &rest[1]);
+
+ match (first, second) {
+ (
+ &$crate::Token::Start { rule: ref first_rule, .. },
+ &$crate::Token::End { rule: ref second_rule, .. }
+ ) => {
+ assert!(
+ format!("{:?}", first_rule) == "EOI",
+ format!("expected end of input, but found {:?}", rest)
+ );
+ assert!(
+ format!("{:?}", second_rule) == "EOI",
+ format!("expected end of input, but found {:?}", rest)
+ );
+ }
+ _ => panic!("expected end of input, but found {:?}", rest)
+ }
+ }
+ _ => panic!("expected end of input, but found {:?}", rest)
+ };
+ }
+ };
+}
+
+/// Testing tool that compares produced errors.
+///
+/// This macro takes several arguments:
+///
+/// * `parser` - name of the data structure implementing `Parser`
+/// * `input` - input to be tested against
+/// * `rule` - `Rule` which will be run
+/// * `positives` - positive `Rule` attempts that failed
+/// * `negative` - negative `Rule` attempts that failed
+/// * `pos` - byte position of failure
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use]
+/// # extern crate pest;
+/// # use pest::Parser;
+/// # use pest::error::Error;
+/// # use pest::iterators::Pairs;
+/// # fn main() {
+/// # #[allow(non_camel_case_types)]
+/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+/// # enum Rule {
+/// # a,
+/// # b,
+/// # c
+/// # }
+/// #
+/// # struct AbcParser;
+/// #
+/// # impl Parser<Rule> for AbcParser {
+/// # fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
+/// # pest::state(input, |state| {
+/// # state.rule(Rule::a, |state| {
+/// # state.skip(1).unwrap().rule(Rule::b, |s| {
+/// # s.skip(1)
+/// # }).unwrap().skip(1)
+/// # }).and_then(|state| {
+/// # state.skip(1).unwrap().rule(Rule::c, |s| {
+/// # s.match_string("e")
+/// # })
+/// # })
+/// # })
+/// # }
+/// # }
+/// fails_with! {
+/// parser: AbcParser,
+/// input: "abcdf",
+/// rule: Rule::a,
+/// positives: vec![Rule::c],
+/// negatives: vec![],
+/// pos: 4
+/// };
+/// # }
+/// ```
+#[macro_export]
+macro_rules! fails_with {
+ ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
+ positives: $positives:expr, negatives: $negatives:expr, pos: $pos:expr ) => {
+ #[allow(unused_mut)]
+ {
+ use $crate::Parser;
+
+ let error = $parser::parse($rules::$rule, $string).unwrap_err();
+
+ match error.variant {
+ $crate::error::ErrorVariant::ParsingError {
+ positives,
+ negatives,
+ } => {
+ assert_eq!(positives, $positives);
+ assert_eq!(negatives, $negatives);
+ }
+ _ => unreachable!(),
+ };
+
+ match error.location {
+ $crate::error::InputLocation::Pos(pos) => assert_eq!(pos, $pos),
+ _ => unreachable!(),
+ }
+ }
+ };
+}
+
+#[cfg(test)]
+pub mod tests {
+ use super::super::error::Error;
+ use super::super::iterators::Pairs;
+ use super::super::{state, Parser};
+
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ pub enum Rule {
+ a,
+ b,
+ c,
+ }
+
+ pub struct AbcParser;
+
+ impl Parser<Rule> for AbcParser {
+ fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
+ state(input, |state| {
+ state
+ .rule(Rule::a, |s| {
+ s.skip(1)
+ .unwrap()
+ .rule(Rule::b, |s| s.skip(1))
+ .unwrap()
+ .skip(1)
+ })
+ .and_then(|s| s.skip(1).unwrap().rule(Rule::c, |s| s.match_string("e")))
+ })
+ }
+ }
+
+ #[test]
+ fn parses_to() {
+ parses_to! {
+ parser: AbcParser,
+ input: "abcde",
+ rule: Rule::a,
+ tokens: [
+ a(0, 3, [
+ b(1, 2),
+ ]),
+ c(4, 5)
+ ]
+ };
+ }
+
+ #[test]
+ #[should_panic]
+ fn missing_end() {
+ parses_to! {
+ parser: AbcParser,
+ input: "abcde",
+ rule: Rule::a,
+ tokens: [
+ a(0, 3, [
+ b(1, 2)
+ ])
+ ]
+ };
+ }
+
+ #[test]
+ #[should_panic]
+ fn empty() {
+ parses_to! {
+ parser: AbcParser,
+ input: "abcde",
+ rule: Rule::a,
+ tokens: []
+ };
+ }
+
+ #[test]
+ fn fails_with() {
+ fails_with! {
+ parser: AbcParser,
+ input: "abcdf",
+ rule: Rule::a,
+ positives: vec![Rule::c],
+ negatives: vec![],
+ pos: 4
+ };
+ }
+
+ #[test]
+ #[should_panic]
+ fn wrong_positives() {
+ fails_with! {
+ parser: AbcParser,
+ input: "abcdf",
+ rule: Rule::a,
+ positives: vec![Rule::a],
+ negatives: vec![],
+ pos: 4
+ };
+ }
+
+ #[test]
+ #[should_panic]
+ fn wrong_negatives() {
+ fails_with! {
+ parser: AbcParser,
+ input: "abcdf",
+ rule: Rule::a,
+ positives: vec![Rule::c],
+ negatives: vec![Rule::c],
+ pos: 4
+ };
+ }
+
+ #[test]
+ #[should_panic]
+ fn wrong_pos() {
+ fails_with! {
+ parser: AbcParser,
+ input: "abcdf",
+ rule: Rule::a,
+ positives: vec![Rule::c],
+ negatives: vec![],
+ pos: 3
+ };
+ }
+}