212 lines
4.5 KiB
Rust
212 lines
4.5 KiB
Rust
use crate::{
|
|
ast::{well_known, TraceKind},
|
|
expr::UntypedExpr,
|
|
parser::{
|
|
error::{ParseError, Pattern},
|
|
expr::{string, when::clause},
|
|
token::Token,
|
|
},
|
|
};
|
|
use chumsky::prelude::*;
|
|
|
|
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(
|
|
choice((just(Token::Colon), just(Token::Comma)))
|
|
.then(
|
|
choice((string::hybrid(), expression.clone()))
|
|
.separated_by(just(Token::Comma))
|
|
.at_least(1),
|
|
)
|
|
.validate(|(token, arguments), span, emit| {
|
|
if token != Token::Colon {
|
|
emit(ParseError::expected_but_got(
|
|
Pattern::Token(Token::Colon),
|
|
Pattern::Token(token),
|
|
span.map(|start, _end| (start, start + 1)),
|
|
))
|
|
}
|
|
|
|
arguments
|
|
})
|
|
.or_not()
|
|
.map(|opt| opt.unwrap_or_default()),
|
|
)
|
|
.then(sequence.clone().or_not())
|
|
.map_with_span(
|
|
|((label, arguments), continuation), span| UntypedExpr::Trace {
|
|
kind: TraceKind::Trace,
|
|
location: span,
|
|
then: Box::new(continuation.unwrap_or_else(|| UntypedExpr::Var {
|
|
location: span,
|
|
name: well_known::VOID.to_string(),
|
|
})),
|
|
label: Box::new(label),
|
|
arguments,
|
|
},
|
|
),
|
|
))
|
|
}
|
|
|
|
#[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_string() {
|
|
assert_expr!(
|
|
r#"
|
|
trace @"foo"
|
|
a
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trace_bytearray() {
|
|
assert_expr!(
|
|
r#"
|
|
trace "foo"
|
|
a
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trace_expr() {
|
|
assert_expr!(
|
|
r#"
|
|
trace string.join(["foo", "bar"])
|
|
a
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trace_expr_todo() {
|
|
assert_expr!(
|
|
r#"
|
|
trace some_var
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trace_labelled() {
|
|
assert_expr!(
|
|
r#"
|
|
trace foo: "bar"
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trace_variadic() {
|
|
assert_expr!(
|
|
r#"
|
|
trace "foo": @"bar", baz
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trace_dangling_colons() {
|
|
assert_expr!(
|
|
r#"
|
|
let debug = fn() {
|
|
trace "foo":
|
|
}
|
|
"#
|
|
);
|
|
}
|
|
}
|