use crate::ast::Spanned;
use crate::lexer::Token;
use chumsky::input::MappedInput;
use chumsky::prelude::*;
pub type Span = SimpleSpan<usize>;
pub type SpannedToken<'src> = (Token<'src>, Span);
pub type ParserInput<'tokens, 'src> =
MappedInput<'tokens, Token<'src>, Span, &'tokens [SpannedToken<'src>]>;
pub fn to_ast_span(span: Span) -> std::ops::Range<usize> {
span.start..span.end
}
pub fn ident<'tokens, 'src: 'tokens>() -> impl Parser<
'tokens,
ParserInput<'tokens, 'src>,
&'src str,
extra::Err<Rich<'tokens, Token<'src>, Span>>,
> + Clone {
select! {
Token::Ident(s) => s,
}
}
pub fn spanned_ident<'tokens, 'src: 'tokens>() -> impl Parser<
'tokens,
ParserInput<'tokens, 'src>,
Spanned<String>,
extra::Err<Rich<'tokens, Token<'src>, Span>>,
> + Clone {
ident().map_with(|s, e| Spanned::new(s.to_string(), to_ast_span(e.span())))
}
pub fn string_lit<'tokens, 'src: 'tokens>() -> impl Parser<
'tokens,
ParserInput<'tokens, 'src>,
&'src str,
extra::Err<Rich<'tokens, Token<'src>, Span>>,
> + Clone {
select! {
Token::StringLit(s) => s,
}
}
pub fn spanned_string<'tokens, 'src: 'tokens>() -> impl Parser<
'tokens,
ParserInput<'tokens, 'src>,
Spanned<String>,
extra::Err<Rich<'tokens, Token<'src>, Span>>,
> + Clone {
string_lit().map_with(|s, e| Spanned::new(s.to_string(), to_ast_span(e.span())))
}
pub fn number_lit<'tokens, 'src: 'tokens>() -> impl Parser<
'tokens,
ParserInput<'tokens, 'src>,
f64,
extra::Err<Rich<'tokens, Token<'src>, Span>>,
> + Clone {
select! {
Token::NumberLit(n) => n,
}
}
pub fn newline<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
just(Token::Newline).ignored()
}
#[allow(dead_code)]
pub fn skip_newlines<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
newline().repeated().ignored()
}
pub fn indent<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
just(Token::Indent).ignored()
}
pub fn dedent<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
just(Token::Dedent).ignored()
}
#[allow(dead_code)]
pub fn skip_noise<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
choice((newline(), indent(), dedent(), select! { Token::Comment(_) => () }))
.repeated()
.ignored()
}
pub fn skip_block_noise<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
choice((newline(), select! { Token::Comment(_) => () }))
.repeated()
.ignored()
}
pub fn skip_toplevel_noise<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
choice((newline(), dedent(), select! { Token::Comment(_) => () }))
.repeated()
.ignored()
}
#[allow(dead_code)]
pub fn skip_comments<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
+ Clone {
select! { Token::Comment(_) => () }.repeated().ignored()
}
pub fn description_entry<'tokens, 'src: 'tokens>() -> impl Parser<
'tokens,
ParserInput<'tokens, 'src>,
Spanned<String>,
extra::Err<Rich<'tokens, Token<'src>, Span>>,
> + Clone {
just(Token::Description)
.ignore_then(just(Token::Colon))
.ignore_then(spanned_string())
}