use chumsky::prelude::*;
use crate::{
ast::TraceKind,
expr::UntypedExpr,
parser::{
error::ParseError,
expr::{string, when::clause},
token::Token,
},
};
pub fn parser<'a>(
expression: Recursive<'a, Token, UntypedExpr, ParseError>,
sequence: Recursive<'a, Token, UntypedExpr, ParseError>,
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + 'a {
let message = choice((
clause(expression.clone()).ignored().rewind().to(None),
choice((string::hybrid(), expression.clone())).or_not(),
))
.boxed();
choice((
just(Token::Todo)
.ignore_then(message.clone())
.map_with_span(UntypedExpr::todo),
just(Token::Fail)
.ignore_then(message)
.map_with_span(UntypedExpr::fail),
just(Token::Trace)
.ignore_then(choice((string::hybrid(), expression.clone())))
.then(sequence.clone().or_not())
.map_with_span(|(text, then_), span| UntypedExpr::Trace {
kind: TraceKind::Trace,
location: span,
then: Box::new(then_.unwrap_or_else(|| UntypedExpr::todo(None, span))),
text: Box::new(text),
}),
))
}
#[cfg(test)]
mod tests {
use crate::assert_expr;
#[test]
fn error_basic() {
assert_expr!(
r#"
fail @"foo"
"#
);
}
#[test]
fn error_sugar() {
assert_expr!(
r#"
fail "foo"
"#
);
}
#[test]
fn todo_basic() {
assert_expr!(
r#"
todo @"foo"
"#
);
}
#[test]
fn todo_sugar() {
assert_expr!(
r#"
todo "foo"
"#
);
}
#[test]
fn todo_empty() {
assert_expr!(
r#"
todo
"#
);
}
#[test]
fn todo_expr() {
assert_expr!(
r#"
todo string.join(["foo", "bar"])
"#
);
}
#[test]
fn fail_expr() {
assert_expr!(
r#"
fail str.join([@"Some string ", some_params, @" some string"], @"")
"#
);
}
#[test]
fn fail_empty() {
assert_expr!(
r#"
fail
"#
);
}
#[test]
fn trace_expr() {
assert_expr!(
r#"
trace string.join(["foo", "bar"])
a
"#
);
}
#[test]
fn trace_expr_todo() {
assert_expr!(
r#"
trace some_var
"#
);
}
}