617 lines
10 KiB
Rust
617 lines
10 KiB
Rust
use snapbox::prelude::*;
|
|
use snapbox::str;
|
|
|
|
use crate::ascii::dec_uint;
|
|
use crate::ascii::digit0;
|
|
use crate::combinator::dispatch;
|
|
use crate::combinator::empty;
|
|
use crate::combinator::fail;
|
|
use crate::combinator::seq;
|
|
use crate::prelude::*;
|
|
use crate::token::any;
|
|
|
|
#[test]
|
|
fn dispatch_basics() {
|
|
fn escape_seq_char<'i>(input: &mut &'i str) -> TestResult<&'i str, char> {
|
|
dispatch! {any;
|
|
'b' => empty.value('\u{8}'),
|
|
'f' => empty.value('\u{c}'),
|
|
'n' => empty.value('\n'),
|
|
'r' => empty.value('\r'),
|
|
't' => empty.value('\t'),
|
|
'\\' => empty.value('\\'),
|
|
'"' => empty.value('"'),
|
|
_ => fail::<_, char, _>,
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
assert_parse!(
|
|
escape_seq_char.parse_peek("b123"),
|
|
str![[r#"
|
|
Ok(
|
|
(
|
|
"123",
|
|
'\u{8}',
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
escape_seq_char.parse_peek("error"),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: "rror",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
escape_seq_char.parse_peek(""),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: "",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn seq_struct_basics() {
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point {
|
|
x: u32,
|
|
y: u32,
|
|
}
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point {
|
|
x: dec_uint,
|
|
_: ',',
|
|
y: dec_uint,
|
|
}
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
assert_parse!(
|
|
parser.parse_peek("123,4 remaining"),
|
|
str![[r#"
|
|
Ok(
|
|
(
|
|
" remaining",
|
|
Point {
|
|
x: 123,
|
|
y: 4,
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek("123, remaining"),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: " remaining",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek(""),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: "",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn seq_struct_default_init() {
|
|
#[derive(Debug, PartialEq, Default)]
|
|
struct Point {
|
|
x: u32,
|
|
y: u32,
|
|
z: u32,
|
|
}
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point {
|
|
x: dec_uint,
|
|
_: ',',
|
|
y: dec_uint,
|
|
..Default::default()
|
|
}
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
assert_parse!(
|
|
parser.parse_peek("123,4 remaining"),
|
|
str![[r#"
|
|
Ok(
|
|
(
|
|
" remaining",
|
|
Point {
|
|
x: 123,
|
|
y: 4,
|
|
z: 0,
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek("123, remaining"),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: " remaining",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek(""),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: "",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn seq_struct_trailing_comma_elided() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point {
|
|
x: u32,
|
|
y: u32,
|
|
}
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point {
|
|
x: dec_uint,
|
|
_: ',',
|
|
y: dec_uint,
|
|
_: empty,
|
|
}
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_struct_no_trailing_comma() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point {
|
|
x: u32,
|
|
y: u32,
|
|
}
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point {
|
|
x: dec_uint,
|
|
_: ',',
|
|
y: dec_uint
|
|
}
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_struct_no_trailing_comma_elided() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point {
|
|
x: u32,
|
|
y: u32,
|
|
}
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point {
|
|
x: dec_uint,
|
|
_: ',',
|
|
y: dec_uint,
|
|
_: empty
|
|
}
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_enum_struct_variant() {
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
enum Expr {
|
|
Add { lhs: u32, rhs: u32 },
|
|
Mul(u32, u32),
|
|
}
|
|
|
|
fn add<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
|
|
seq! {Expr::Add {
|
|
lhs: dec_uint::<_, u32, _>,
|
|
_: b" + ",
|
|
rhs: dec_uint::<_, u32, _>,
|
|
}}
|
|
.parse_next(input)
|
|
}
|
|
|
|
fn mul<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
|
|
seq!(Expr::Mul(
|
|
dec_uint::<_, u32, _>,
|
|
_: b" * ",
|
|
dec_uint::<_, u32, _>,
|
|
))
|
|
.parse_next(input)
|
|
}
|
|
|
|
assert_parse!(
|
|
add.parse_peek(&b"1 + 2"[..]),
|
|
str![[r#"
|
|
Ok(
|
|
(
|
|
[],
|
|
Add {
|
|
lhs: 1,
|
|
rhs: 2,
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
|
|
assert_parse!(
|
|
mul.parse_peek(&b"3 * 4"[..]),
|
|
str![[r#"
|
|
Ok(
|
|
(
|
|
[],
|
|
Mul(
|
|
3,
|
|
4,
|
|
),
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn seq_struct_borrow() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point {
|
|
x: u32,
|
|
y: u32,
|
|
}
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
let mut dec_uint = digit0.parse_to();
|
|
seq! {
|
|
Point {
|
|
x: dec_uint,
|
|
_: ',',
|
|
y: dec_uint,
|
|
_: empty
|
|
}
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_struct_basics() {
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point(u32, u32);
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
assert_parse!(
|
|
parser.parse_peek("123,4 remaining"),
|
|
str![[r#"
|
|
Ok(
|
|
(
|
|
" remaining",
|
|
Point(
|
|
123,
|
|
4,
|
|
),
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek("123, remaining"),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: " remaining",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek(""),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: "",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_struct_trailing_comma_elided() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point(u32, u32);
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
_: empty,
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_struct_no_trailing_comma() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point(u32, u32);
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_struct_no_trailing_comma_elided() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point(u32, u32);
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
seq! {
|
|
Point(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
_: empty
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_basics() {
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
|
|
seq! {
|
|
(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
assert_parse!(
|
|
parser.parse_peek("123,4 remaining"),
|
|
str![[r#"
|
|
Ok(
|
|
(
|
|
" remaining",
|
|
(
|
|
123,
|
|
4,
|
|
),
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek("123, remaining"),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: " remaining",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
assert_parse!(
|
|
parser.parse_peek(""),
|
|
str![[r#"
|
|
Err(
|
|
Backtrack(
|
|
InputError {
|
|
input: "",
|
|
},
|
|
),
|
|
)
|
|
|
|
"#]]
|
|
.raw()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_trailing_comma_elided() {
|
|
#![allow(dead_code)]
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
|
|
seq! {
|
|
(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
_: empty,
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_no_trailing_comma() {
|
|
#![allow(dead_code)]
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
|
|
seq! {
|
|
(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_no_trailing_comma_elided() {
|
|
#![allow(dead_code)]
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
|
|
seq! {
|
|
(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
_: empty
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_no_parens() {
|
|
#![allow(dead_code)]
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
|
|
seq! (
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
)
|
|
.parse_next(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn seq_tuple_borrow() {
|
|
#![allow(dead_code)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct Point(u32, u32);
|
|
|
|
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
|
|
let mut dec_uint = digit0.parse_to();
|
|
seq! {
|
|
Point(
|
|
dec_uint,
|
|
_: ',',
|
|
dec_uint,
|
|
_: empty
|
|
)
|
|
}
|
|
.parse_next(input)
|
|
}
|
|
}
|