#![allow(dead_code)] use crate::ExCode::*; use kparse::combinators::track; use kparse::prelude::*; use kparse::token_error::TokenizerError; use kparse::{ParserError, ParserResult, TokenizerResult}; use nom::bytes::complete::tag; use nom::character::complete::digit1; use nom::combinator::consumed; use nom::multi::many0; use nom::sequence::{terminated, tuple}; use nom::{AsChar, InputTakeAtPosition, Parser}; use std::env; use std::fmt::{Display, Formatter}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExCode { ExNomError, ExTagA, ExTagB, ExNumber, ExAthenB, ExAoptB, ExAstarB, ExABstar, ExAorB, ExABNum, } impl Display for ExCode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, "{}", match self { ExNomError => "nom", ExTagA => "a", ExTagB => "b", ExNumber => "number", ExAthenB => "A B", ExAoptB => "A? B", ExAstarB => "A* B", ExABstar => "(A | B)*", ExAorB => "A | B", ExABNum => "A B Number", } ) } } impl Code for ExCode { const NOM_ERROR: Self = Self::ExNomError; } define_span!(ExSpan = ExCode, str); pub type ExParserResult<'s, O> = ParserResult, O>; pub type ExTokenizerResult<'s, O> = TokenizerResult, O>; pub type ExParserError<'s> = ParserError>; pub type ExTokenizerError<'s> = TokenizerError>; #[derive(Debug)] struct AstA<'s> { pub span: ExSpan<'s>, } #[derive(Debug)] struct AstB<'s> { pub span: ExSpan<'s>, } #[derive(Debug)] struct AstAthenB<'s> { pub a: AstA<'s>, pub b: AstB<'s>, } #[derive(Debug)] struct AstAoptB<'s> { pub a: Option>, pub b: AstB<'s>, } #[derive(Debug)] struct AstAstarB<'s> { pub a: Vec>, pub b: AstB<'s>, } #[derive(Debug)] struct AstABstar<'s> { pub a: Vec>, pub b: Vec>, } #[derive(Debug)] struct AstAorB<'s> { pub a: Option>, pub b: Option>, } #[derive(Debug)] struct AstABNum<'s> { pub a: Option>, pub b: Option>, pub num: AstNumber<'s>, } #[derive(Debug)] struct AstNumber<'s> { pub number: u32, pub span: ExSpan<'s>, } fn nom_parse_a(i: ExSpan<'_>) -> ExTokenizerResult<'_, ExSpan<'_>> { tag("a").with_code(ExTagA).parse(i) } fn nom_parse_b(i: ExSpan<'_>) -> ExTokenizerResult<'_, ExSpan<'_>> { tag("b").with_code(ExTagB).parse(i) } fn nom_digits(i: ExSpan<'_>) -> ExTokenizerResult<'_, ExSpan<'_>> { digit1(i) } fn nom_ws(i: ExSpan<'_>) -> ExTokenizerResult<'_, ExSpan<'_>> { i.split_at_position_complete(|item| { let c = item.as_char(); !(c == ' ' || c == '\t') }) } fn nom_number(i: ExSpan<'_>) -> ExParserResult<'_, (ExSpan<'_>, u32)> { consumed(terminated(digit1, nom_ws).parse_from_str::<_, u32>(ExNumber)) // .err_into() .parse(i) } fn token_number(i: ExSpan<'_>) -> ExParserResult<'_, AstNumber<'_>> { nom_number .map(|(span, number)| AstNumber { number, span }) .parse(i) } fn parse_a(input: ExSpan<'_>) -> ExParserResult<'_, AstA> { Track.enter(ExTagA, input); let (rest, tok) = nom_parse_a.parse(input).err_into().track()?; Track.ok(rest, tok, AstA { span: tok }) } fn parse_b(input: ExSpan<'_>) -> ExParserResult<'_, AstB> { track( ExTagB, // nom_parse_b.map(|span| AstB { span }), ) .err_into() .parse(input) } // := a b fn parse_ab(input: ExSpan<'_>) -> ExParserResult<'_, AstAthenB> { Track.enter(ExAthenB, input); let rest = input; let (rest, a) = parse_a(rest).track()?; let (rest, b) = parse_b(rest).track()?; let span = input.span_union(&a.span, &b.span); Track.ok(rest, span, AstAthenB { a, b }) } // := a b fn parse_ab_v2(input: ExSpan<'_>) -> ExParserResult<'_, AstAthenB> { Track.enter(ExAthenB, input); let (rest, (span, (a, b))) = consumed(tuple((parse_a, parse_b)))(input).track()?; Track.ok(rest, span, AstAthenB { a, b }) } // := a? b fn parse_a_opt_b(input: ExSpan<'_>) -> ExParserResult<'_, AstAoptB> { track( ExAoptB, tuple((parse_a.opt(), parse_b)) // .map(|(a, b)| AstAoptB { a, b }), ) .err_into() .parse(input) } // := a* b fn parse_a_star_b(input: ExSpan<'_>) -> ExParserResult<'_, AstAstarB> { track( ExAstarB, tuple((many0(parse_a), parse_b)) // .map(|(a, b)| AstAstarB { a, b }), ) .err_into() .parse(input) } // := ( a | b )* fn parse_a_b_star(input: ExSpan<'_>) -> ExParserResult<'_, AstABstar> { Track.enter(ExABstar, input); let mut loop_rest = input; let mut res = AstABstar { a: vec![], b: vec![], }; let mut err = None; loop { let rest2 = loop_rest; let rest2 = match parse_a(rest2) { Ok((rest3, a)) => { res.a.push(a); rest3 } Err(e) => match parse_b(rest2) { Ok((rest3, b)) => { res.b.push(b); rest3 } Err(e2) => { err.append(e)?; err.append(e2)?; rest2 } }, }; if let Some(err) = err { return Track.err(err); } if rest2.is_empty() { break; } loop_rest = rest2; } Track.ok(loop_rest, input, res) } fn parse_a_or_b(input: ExSpan<'_>) -> ExParserResult<'_, AstAorB> { track( ExAorB, parse_a .or_else(parse_b) // .map(|(a, b)| AstAorB { a, b }), ) .err_into() .parse(input) } fn parse_a_b_num(input: ExSpan<'_>) -> ExParserResult<'_, AstABNum> { track( ExABNum, tuple(( // parse_a.opt(), parse_b.opt(), token_number, )) .map(|(a, b, num)| AstABNum { a, b, num }), ) .err_into() .parse(input) } fn main() { for txt in env::args() { let trk = Track::new_tracker::(); let span = Track::new_span(&trk, txt.as_str()); match parse_a_b_star(span) { Ok((_rest, val)) => { dbg!(val); } Err(e) => { println!("{:?}", trk.results()); println!("{:?}", e); } } } } #[cfg(test)] mod tests { use crate::*; use kparse::test::{str_parse, Timing}; #[test] fn test_1() { str_parse(&mut None, "", parse_ab).err_any().q(Timing(1)); str_parse(&mut None, "ab", parse_ab).ok_any().q(Timing(1)); str_parse(&mut None, "aba", parse_ab).rest("a").q(Timing(1)); } #[test] fn test_2() { str_parse(&mut None, "ab", parse_a_or_b) .ok_any() .q(Timing(1)); str_parse(&mut None, "a", parse_a_or_b) .ok_any() .q(Timing(1)); str_parse(&mut None, "b", parse_a_or_b) .ok_any() .q(Timing(1)); str_parse(&mut None, "", parse_a_opt_b) .err_any() .q(Timing(1)); str_parse(&mut None, "b", parse_a_opt_b) .ok_any() .rest("") .q(Timing(1)); str_parse(&mut None, "ab", parse_a_opt_b) .ok_any() .rest("") .q(Timing(1)); str_parse(&mut None, "bb", parse_a_opt_b) .ok_any() .rest("b") .q(Timing(1)); str_parse(&mut None, "aab", parse_a_opt_b) .err_any() .q(Timing(1)); str_parse(&mut None, "aab", parse_a_opt_b) .err_any() .q(Timing(1)); str_parse(&mut None, "aab", parse_a_star_b) .ok_any() .q(Timing(1)); str_parse(&mut None, "aab", parse_a_b_star) .ok_any() .q(Timing(1)); str_parse(&mut None, "aabc", parse_a_b_star) .err_any() .q(Timing(1)); } }