Actually just three programming languages in a trenchcoat
1use super::*;
2use crate::{Parser, Spanned};
3use source_span::Span;
4use trilogy_scanner::{Token, TokenType::*};
5
6#[derive(Clone, Debug, PrettyPrintSExpr)]
7pub struct HandledExpression {
8 pub with: Token,
9 pub expression: Expression,
10 pub handlers: Vec<Handler>,
11 span: Span,
12}
13
14impl Spanned for HandledExpression {
15 fn span(&self) -> Span {
16 self.span
17 }
18}
19
20impl HandledExpression {
21 pub(crate) fn parse(parser: &mut Parser) -> SyntaxResult<Self> {
22 let with = parser
23 .expect(KwWith)
24 .map_err(|token| parser.expected(token, "expected `with`"))?;
25
26 let expression = Expression::parse(parser)?;
27
28 let mut handlers = vec![];
29 loop {
30 if let Err(token) = parser.check([KwWhen, KwElse]) {
31 let error = SyntaxError::new(
32 token.span,
33 "expected `when`, or `else` to with an effect handler",
34 );
35 parser.error(error.clone());
36 return Err(error);
37 }
38 let handler = Handler::parse(parser)?;
39 let end = matches!(handler, Handler::Else(..));
40 handlers.push(handler);
41 if end {
42 return Ok(Self {
43 span: with.span.union(handlers.last().unwrap().span()),
44 with,
45 expression,
46 handlers,
47 });
48 }
49 }
50 }
51}
52
53#[cfg(test)]
54mod test {
55 use super::*;
56
57 test_parse!(handled_expr_else_yield: "with 3 else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::Else _)])");
58 test_parse!(handled_expr_else_resume: "with 3 else resume 3" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::Else _)])");
59 test_parse!(handled_expr_else_cancel: "with 3 else cancel 3" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::Else _)])");
60 test_parse!(handled_expr_yield: "with 3 when 'x yield else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::Else _)])");
61 test_parse_error!(handled_expr_resume_block: "with 3 when 'x resume {} else yield" => HandledExpression::parse);
62 test_parse_error!(handled_expr_cancel_block: "with 3 when 'x cancel {} else yield" => HandledExpression::parse);
63 test_parse!(handled_expr_resume_expr: "with 3 when 'x resume 3 else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::Else _)])");
64 test_parse!(handled_expr_cancel_expr: "with 3 when 'x cancel 3 else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::Else _)])");
65 test_parse!(handled_expr_multiple_yield: "with 3 when 'x yield when 'y yield else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::When _) (Handler::Else _)])");
66 test_parse_error!(handled_expr_block: "with {} else yield" => HandledExpression::parse);
67}