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/// A procedure call expression.
7///
8/// ```trilogy
9/// procedure!(args)
10/// ```
11#[derive(Clone, Debug)]
12pub struct CallExpression {
13 pub procedure: Expression,
14 pub bang: Token,
15 pub open_paren: Token,
16 pub arguments: Punctuated<Expression>,
17 pub close_paren: Token,
18 pub span: Span,
19}
20
21impl Spanned for CallExpression {
22 fn span(&self) -> Span {
23 self.span
24 }
25}
26
27impl CallExpression {
28 pub(crate) fn parse(parser: &mut Parser, procedure: Expression) -> SyntaxResult<Self> {
29 let (bang, open_paren) = parser.expect_bang_oparen().unwrap();
30 let mut arguments = Punctuated::new();
31 let close_paren = loop {
32 if let Ok(end) = parser.expect(CParen) {
33 break end;
34 }
35 let expression = Expression::parse_or_pattern(parser)?.map_err(|patt| {
36 let error = SyntaxError::new(
37 patt.span(),
38 "expected an expression in procedure call arguments, but found a pattern",
39 );
40 parser.error(error.clone());
41 error
42 })?;
43 if let Ok(comma) = parser.expect(OpComma) {
44 arguments.push(expression, comma);
45 continue;
46 }
47 arguments.push_last(expression);
48 break parser
49 .expect(CParen)
50 .map_err(|token| parser.expected(token, "expected `,` or `)` in argument list"))?;
51 };
52 Ok(Self {
53 span: procedure.span().union(close_paren.span),
54 procedure,
55 bang,
56 open_paren,
57 arguments,
58 close_paren,
59 })
60 }
61}
62
63#[cfg(test)]
64mod test {
65 use super::*;
66
67 test_parse!(callexpr_empty: "hello!()" => Expression::parse => Expression::Call(CallExpression { .. }));
68 test_parse!(callexpr_params: "hello!(a, b,)" => Expression::parse => Expression::Call(CallExpression { arguments: Punctuated { elements: [_, _], .. }, .. }));
69 test_parse!(callexpr_path: "hello world::inner::hello!(2)" => Expression::parse => Expression::Application(Application { argument: Expression::Call(CallExpression { .. }), .. }));
70 test_parse!(callexpr_expr: "(a |> b |> c)!(1)" => Expression::parse => Expression::Call(CallExpression { .. }));
71 test_parse_error!(callexpr_missing_end: "hello!(1" => Expression::parse => "expected `,` or `)` in argument list");
72}