mod annotation;
pub mod ast;
mod block;
mod effect;
pub mod error;
mod expr;
mod fn_def;
mod ident;
mod import;
mod interpolation;
mod module;
mod need;
mod operator;
mod overlay;
mod prefix;
mod punctuation;
mod stmt;
mod test_def;
mod timeout;
mod token;
mod ws;
pub use ast::*;
pub use error::ParseError;
use chumsky::error::RichPattern;
use chumsky::error::RichReason;
use chumsky::input::Input as _;
use chumsky::input::MappedInput;
use chumsky::prelude::*;
use crate::dsl::lexer::Token;
pub type Span = crate::Span;
pub type ParserInput<'a> = MappedInput<'a, Token<'a>, SimpleSpan, &'a [(Token<'a>, SimpleSpan)]>;
pub(crate) fn lex_to_pairs(source: &str) -> Vec<(Token<'_>, SimpleSpan)> {
crate::dsl::lexer::lex(source)
.into_iter()
.map(Into::into)
.collect()
}
pub(crate) fn make_input<'a>(
tokens: &'a [(Token<'a>, SimpleSpan)],
source_len: usize,
) -> ParserInput<'a> {
let eoi = SimpleSpan::from(source_len..source_len);
tokens.split_token_span(eoi)
}
fn format_rich_error(e: &Rich<'_, Token<'_>>) -> String {
match e.reason() {
RichReason::ExpectedFound { expected, found } => {
let expected: Vec<_> = expected
.iter()
.filter(|p| !matches!(p, RichPattern::SomethingElse))
.collect();
let found_str = match found {
Some(tok) => format!("found '{}'", &**tok),
None => "found end of input".to_string(),
};
if expected.is_empty() {
format!("{found_str} expected something else")
} else {
let mut parts: Vec<String> = expected.iter().map(|p| format!("{p}")).collect();
parts.sort();
parts.dedup();
let expected_str = match &parts[..] {
[one] => one.clone(),
_ => {
let last = parts.last().unwrap().clone();
let rest = &parts[..parts.len() - 1];
format!("{}, or {last}", rest.join(", "))
}
};
format!("{found_str} expected {expected_str}")
}
}
RichReason::Custom(msg) => msg.clone(),
}
}
pub fn parse(source: &str) -> Result<AstModule, ParseError> {
let pairs = lex_to_pairs(source);
let input = make_input(&pairs, source.len());
module::module()
.then_ignore(end())
.parse(input)
.into_result()
.map_err(|errs| {
let msgs: Vec<String> = errs.iter().map(format_rich_error).collect();
ParseError::Multiple(msgs.join("; "))
})
}