aiken/crates/aiken-lang/src/parser/expr/fail_todo_trace.rs

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":
}
"#
);
}
}