use std::fmt::Debug;
use nom::bytes::complete::{take, take_while};
use nom::Err::Error;
use nom::IResult;
use nom::multi::{separated_list0, separated_list1};
use nom::Parser;
use nom::sequence::tuple;
use nom_supreme::error::BaseErrorKind;
use nom_supreme::ParserExt;
use crate::common::VerboseEnclosed;
use crate::lexer::Token;
use crate::lexer::traits::ToRepresentation;
use crate::nom::parser::{ParseError, ParseResult};
use crate::nom::parser::macros::match_any_token;
use crate::nom::TokenVerificationError;
use crate::token_match::TokenMatch;
use crate::token_stream::TokenStream;
#[inline]
pub fn any_not_ignored_token(input: TokenStream) -> ParseResult<TokenMatch> {
take_while(|it: TokenMatch| matches!(it.token, Token::Ignore(_)))
.precedes(take(1usize))
.map(|it: TokenStream| {
it.into_token_match()
.expect("Token stream with 1 element can be coerced to lexer match")
})
.parse(input)
}
#[inline]
pub fn any_token(input: TokenStream) -> ParseResult<TokenMatch> {
take(1usize)
.map(|it: TokenStream| {
it.into_token_match()
.expect("Token stream with 1 element can be coerced to lexer match")
})
.parse(input)
}
#[inline]
pub fn match_token<'t, T>(example: T) -> impl FnMut(TokenStream<'t>) -> ParseResult<TokenMatch<'t>>
where
T: Into<Token<'t>> + Clone + ToRepresentation,
{
let repr = example.representation();
move |input| {
let example = example.clone();
let i = input;
let (input, output) = any_not_ignored_token(input)?;
if output.token == example.into() {
Ok((input, output))
} else {
let error = ParseError::Base {
location: i,
kind: BaseErrorKind::External(TokenVerificationError::new(repr)),
};
Err(Error(error))
}
}
}
#[inline]
#[allow(unused)]
pub fn inspect_input<I: Debug, O, E, P>(mut parser: P) -> impl FnMut(I) -> IResult<I, O, E>
where
P: Parser<I, O, E>,
{
move |input| parser.parse(dbg!(input))
}
#[inline]
#[allow(unused)]
pub fn inspect<I: Debug, O: Debug, E: Debug, P>(mut parser: P) -> impl FnMut(I) -> IResult<I, O, E>
where
P: Parser<I, O, E>,
{
move |input| {
let (rest, result) = parser.parse(input)?;
dbg!(&result);
Ok((rest, result))
}
}
#[inline]
pub fn paren_enclosed<'t, T, P: Parser<TokenStream<'t>, T, ParseError<'t>>>(
items_parser: P,
) -> impl Parser<TokenStream<'t>, VerboseEnclosed<T>, ParseError<'t>> {
use crate::lexer::Symbol::*;
tuple((
match_token(LParen),
items_parser.cut(),
match_token(RParen).cut(),
))
.map(|it| it.into())
}
#[inline]
pub fn brace_enclosed<'t, T, P: Parser<TokenStream<'t>, T, ParseError<'t>>>(
items_parser: P,
) -> impl Parser<TokenStream<'t>, VerboseEnclosed<T>, ParseError<'t>> {
use crate::lexer::Symbol::*;
tuple((
match_token(LBrace),
items_parser.cut(),
match_token(RBrace).cut(),
))
.map(|it| it.into())
}
#[allow(unused_parens)]
#[inline]
pub fn newline_separated<'t, T, P: Parser<TokenStream<'t>, T, ParseError<'t>>>(
items_parser: P,
) -> impl Parser<TokenStream<'t>, Vec<T>, ParseError<'t>> {
use crate::lexer::{Ignore::*, Symbol::*};
separated_list0(
match_any_token!((Token::Ignore(Newline | Whitespace) | Token::Symbol(Semicolon))),
items_parser,
)
}
#[inline]
pub fn comma_separated0<'t, T, P: Parser<TokenStream<'t>, T, ParseError<'t>>>(
items_parser: P,
) -> impl Parser<TokenStream<'t>, Vec<T>, ParseError<'t>> {
use crate::lexer::Symbol::*;
separated_list0(match_token(Comma), items_parser).terminated(match_token(Comma).opt())
}
#[inline]
pub fn comma_separated1<'t, T, P: Parser<TokenStream<'t>, T, ParseError<'t>>>(
items_parser: P,
) -> impl Parser<TokenStream<'t>, Vec<T>, ParseError<'t>> {
use crate::lexer::Symbol::*;
separated_list1(match_token(Comma), items_parser).terminated(match_token(Comma).opt())
}