#![doc = include_str!("../Readme.md")]
use crate::compare::Compare;
use crate::operation::Operation;
use noa_parser::bytes::matchers::match_pattern;
use noa_parser::bytes::primitives::whitespace::OptionalWhitespaces;
use noa_parser::bytes::token::Token;
use noa_parser::errors::{ParseError, ParseResult};
use noa_parser::matcher::{Match, MatchSize};
use noa_parser::peek::{peek, Until, UntilEnd};
use noa_parser::recognizer::recognize;
use noa_parser::scanner::Scanner;
use noa_parser::separated_list::SeparatedList;
use noa_parser::visitor::Visitor;
pub mod compare;
pub mod operation;
pub fn parse(data: &[u8]) -> ParseResult<TxnData> {
TxnData::accept(&mut Scanner::new(data))
}
#[derive(Debug, PartialEq)]
pub struct TxnData<'a> {
pub compares: Vec<Compare<'a>>,
pub success: Vec<Operation<'a>>,
pub failure: Vec<Operation<'a>>,
}
struct LineFeed;
impl<'a> Visitor<'a, u8> for LineFeed {
fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
recognize(Token::Ln, scanner)?;
Ok(LineFeed)
}
}
#[derive(Clone)]
struct SectionEnd;
impl Match<u8> for SectionEnd {
fn matcher(&self, data: &[u8]) -> (bool, usize) {
match_pattern(b"\n\n", data)
}
}
impl MatchSize for SectionEnd {
fn size(&self) -> usize {
2
}
}
impl<'a> Visitor<'a, u8> for TxnData<'a> {
fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
OptionalWhitespaces::accept(scanner)?;
let section_compare =
peek(Until::new(SectionEnd), scanner)?.ok_or(ParseError::UnexpectedToken)?;
let mut section_compare_scanner = Scanner::new(section_compare.data);
let compares =
SeparatedList::<u8, Compare, LineFeed>::accept(&mut section_compare_scanner)?
.into_iter()
.collect();
scanner.bump_by(section_compare.end_slice);
LineFeed::accept(scanner)?;
LineFeed::accept(scanner)?;
let section_success =
peek(Until::new(SectionEnd), scanner)?.ok_or(ParseError::UnexpectedToken)?;
let mut section_success_scanner = Scanner::new(section_success.data);
let success =
SeparatedList::<u8, Operation, LineFeed>::accept(&mut section_success_scanner)?
.into_iter()
.collect();
scanner.bump_by(section_success.end_slice);
LineFeed::accept(scanner)?;
LineFeed::accept(scanner)?;
let section_failure =
peek(UntilEnd::default(), scanner)?.ok_or(ParseError::UnexpectedToken)?;
let mut section_failure_scanner = Scanner::new(section_failure.data);
let failure =
SeparatedList::<u8, Operation, LineFeed>::accept(&mut section_failure_scanner)?
.into_iter()
.collect();
Ok(TxnData {
compares,
success,
failure,
})
}
}