Skip to content

Commit 27749a0

Browse files
committed
fix: Allow empty scanner on separated list
1 parent 2c5a607 commit 27749a0

5 files changed

Lines changed: 92 additions & 4 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "noa-parser"
3-
version = "0.7.3"
3+
version = "0.7.4"
44
edition = "2024"
55
homepage = "https://github.com/Akanoa/noa-parser"
66
repository = "https://github.com/Akanoa/noa-parser"

Readme.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,4 +589,49 @@ fn main() {
589589
}
590590
```
591591

592-
An example of the peeking usage is available in the [expression](examples/expression.rs) example.
592+
An example of the peeking usage is available in the [expression](examples/expression.rs) example.
593+
594+
## Separated List
595+
596+
The `SeparatedList` component is used to parse a list of elements separated by a separator.
597+
598+
If you have this expression: "1 + 2 + 3 + 4", you want to get all the numbers.
599+
600+
The data are separated by the ` + ` pattern.
601+
602+
The `SeparatedList` takes two `Visitor` as type parameters:
603+
604+
- The element visitor : the one that will be used to parse each element of the list
605+
- The separator visitor : the one that will be used to parse the separator between each element of the list
606+
607+
Once one of parsers fails, the `SeparatedList` will stop parsing the list and return the result.
608+
609+
```rust
610+
use noa_parser::bytes::primitives::number::Number;
611+
use noa_parser::bytes::token::Token;
612+
use noa_parser::errors::ParseResult;
613+
use noa_parser::recognizer::recognize;
614+
use noa_parser::scanner::Scanner;
615+
use noa_parser::separated_list::SeparatedList;
616+
use noa_parser::visitor::Visitor;
617+
618+
#[derive(Debug)]
619+
struct Separator;
620+
621+
impl<'a> Visitor<'a, u8> for Separator {
622+
fn accept(scanner: &mut noa_parser::scanner::Scanner<u8>) -> ParseResult<Self> {
623+
recognize(Token::Tilde, scanner)?;
624+
recognize(Token::Tilde, scanner)?;
625+
recognize(Token::Tilde, scanner)?;
626+
Ok(Separator)
627+
}
628+
}
629+
630+
fn main() {
631+
let data = b"1~~~2~~~3~~~4";
632+
let mut scanner = Scanner::new(data);
633+
let result =
634+
SeparatedList::<u8, Number<usize>, Separator>::accept(&mut scanner).map(|x| x.data);
635+
println!("{:?}", result); // Ok([Number(1), Number(2), Number(3), Number(4)])
636+
}
637+
```

examples/separated_list.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use noa_parser::bytes::primitives::number::Number;
2+
use noa_parser::bytes::token::Token;
3+
use noa_parser::errors::ParseResult;
4+
use noa_parser::recognizer::recognize;
5+
use noa_parser::scanner::Scanner;
6+
use noa_parser::separated_list::SeparatedList;
7+
use noa_parser::visitor::Visitor;
8+
9+
#[derive(Debug)]
10+
struct Separator;
11+
12+
impl<'a> Visitor<'a, u8> for Separator {
13+
fn accept(scanner: &mut noa_parser::scanner::Scanner<u8>) -> ParseResult<Self> {
14+
recognize(Token::Tilde, scanner)?;
15+
recognize(Token::Tilde, scanner)?;
16+
recognize(Token::Tilde, scanner)?;
17+
Ok(Separator)
18+
}
19+
}
20+
21+
fn main() {
22+
let data = b"1~~~2~~~3~~~4";
23+
let mut scanner = Scanner::new(data);
24+
let result =
25+
SeparatedList::<u8, Number<usize>, Separator>::accept(&mut scanner).map(|x| x.data);
26+
println!("{:?}", result); // Ok([Number(1), Number(2), Number(3), Number(4)])
27+
}

src/separated_list.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use crate::scanner::Scanner;
33
use crate::visitor::Visitor;
44
use std::marker::PhantomData;
55

6+
#[derive(Debug)]
67
pub struct SeparatedList<T, V, S> {
7-
pub(crate) data: Vec<V>,
8+
pub data: Vec<V>,
89
separator: PhantomData<(S, T)>,
910
}
1011

@@ -92,6 +93,14 @@ where
9293
let mut elements = vec![];
9394
let cursor = scanner.current_position();
9495

96+
// if the scanner is empty, return an empty list
97+
if scanner.remaining().is_empty() {
98+
return Ok(SeparatedList {
99+
data: elements,
100+
separator: PhantomData,
101+
});
102+
}
103+
95104
loop {
96105
if let Ok(result) = yield_element::<T, V, S>(scanner) {
97106
let element: YieldResult<V> = result;
@@ -154,5 +163,12 @@ mod tests {
154163
vec![Number(12), Number(4), Number(78), Number(22)]
155164
);
156165
assert_eq!(scanner.current_position(), 10);
166+
167+
let data = b"";
168+
let mut scanner = Scanner::new(data);
169+
let result = scanner
170+
.visit::<SeparatedList<u8, Number<usize>, SeparatorComma>>()
171+
.expect("failed to parse");
172+
assert_eq!(result.data, vec![]);
157173
}
158174
}

0 commit comments

Comments
 (0)