Actually just three programming languages in a trenchcoat
at main 72 lines 2.5 kB view raw
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}