mamba/parse/
call.rs

1use crate::parse::ast::AST;
2use crate::parse::ast::Node;
3use crate::parse::definition::parse_fun_arg;
4use crate::parse::expression::parse_inner_expression;
5use crate::parse::iterator::LexIterator;
6use crate::parse::lex::token::Token;
7use crate::parse::operation::parse_expression;
8use crate::parse::result::{expected_one_of, ParseResult};
9
10pub fn parse_anon_fun(it: &mut LexIterator) -> ParseResult {
11    let start = it.start_pos("anonymous function")?;
12    it.eat(&Token::BSlash, "anonymous function")?;
13
14    let mut args: Vec<AST> = vec![];
15    it.peek_while_not_token(&Token::BTo, &mut |it, _| {
16        args.push(*it.parse(&parse_fun_arg, "anonymous function", start)?);
17        it.eat_if(&Token::Comma);
18        Ok(())
19    })?;
20
21    it.eat(&Token::BTo, "anonymous function")?;
22
23    let body = it.parse(&parse_expression, "anonymous function", start)?;
24    let node = Node::AnonFun { args, body: body.clone() };
25    Ok(Box::from(AST::new(start.union(body.pos), node)))
26}
27
28pub fn parse_call(pre: &AST, it: &mut LexIterator) -> ParseResult {
29    it.peek_or_err(
30        &|it, ast| match ast.token {
31            Token::Point => {
32                it.eat(&Token::Point, "call")?;
33                let property = it.parse(&parse_inner_expression, "call", pre.pos)?;
34                let node = Node::PropertyCall {
35                    instance: Box::from(pre.clone()),
36                    property: property.clone(),
37                };
38                Ok(Box::from(AST::new(pre.pos.union(property.pos), node)))
39            }
40            Token::LRBrack => {
41                it.eat(&Token::LRBrack, "direct call")?;
42                let args = it.parse_vec(&parse_arguments, "direct call", pre.pos)?;
43                let end = it.eat(&Token::RRBrack, "direct call")?;
44                let node = Node::FunctionCall { name: Box::from(pre.clone()), args };
45                Ok(Box::from(AST::new(pre.pos.union(end), node)))
46            }
47            _ => Err(Box::from(expected_one_of(&[Token::Point, Token::LRBrack], ast, "function call"))),
48        },
49        &[Token::Point, Token::LRBrack],
50        "function call",
51    )
52}
53
54fn parse_arguments(it: &mut LexIterator) -> ParseResult<Vec<AST>> {
55    let start = it.start_pos("arguments")?;
56    let mut arguments = vec![];
57    it.peek_while_not_token(&Token::RRBrack, &mut |it, _| {
58        arguments.push(*it.parse(&parse_expression, "arguments", start)?);
59        it.eat_if(&Token::Comma);
60        Ok(())
61    })?;
62    Ok(arguments)
63}
64
65#[cfg(test)]
66mod test {
67    use crate::parse::{parse, parse_direct};
68    use crate::parse::ast::{AST, Node};
69    use crate::parse::ast::node_op::NodeOp;
70
71    #[test]
72    fn op_assign() {
73        let source = String::from("a:=1\nb+=2\nc-=3\nd*=4\ne/=5\nf^=6\ng<<=7\nh>>=8\n");
74        let statements = parse_direct(&source).unwrap();
75
76        let ops: Vec<NodeOp> = statements
77            .iter()
78            .map(|ast| match &ast.node {
79                Node::Reassign { op, .. } => op.clone(),
80                other => panic!("Expected reassign {:?}", other)
81            })
82            .collect();
83
84        assert_eq!(ops[0], NodeOp::Assign);
85        assert_eq!(ops[1], NodeOp::Add);
86        assert_eq!(ops[2], NodeOp::Sub);
87        assert_eq!(ops[3], NodeOp::Mul);
88        assert_eq!(ops[4], NodeOp::Div);
89        assert_eq!(ops[5], NodeOp::Pow);
90        assert_eq!(ops[6], NodeOp::BLShift);
91        assert_eq!(ops[7], NodeOp::BRShift);
92    }
93
94    #[test]
95    fn anon_fun_no_args_verify() {
96        let source = String::from("\\ => c");
97        let statements = parse_direct(&source).unwrap();
98
99        let Node::AnonFun { args, body } = &statements.first().expect("script empty.").node else {
100            panic!("first element script was anon fun.")
101        };
102
103        assert_eq!(args.len(), 0);
104        assert_eq!(body.node, Node::Id { lit: String::from("c") });
105    }
106
107    #[test]
108    fn anon_fun_verify() {
109        let source = String::from("\\a,b => c");
110        let statements = parse_direct(&source).unwrap();
111
112        let Node::AnonFun { args, body } = &statements.first().expect("script empty.").node else {
113            panic!("first element script was anon fun.")
114        };
115
116        assert_eq!(args.len(), 2);
117        let (id1, id2) = match (&args[0], &args[1]) {
118            (
119                AST { node: Node::FunArg { var: id1, ty: None, mutable: true, .. }, .. },
120                AST { node: Node::FunArg { var: id2, ty: None, mutable: true, .. }, .. },
121            ) => (id1.clone(), id2.clone()),
122            other => panic!("Id's of anon fun not expression type: {:?}", other),
123        };
124
125        assert_eq!(id1.node, Node::Id { lit: String::from("a") });
126        assert_eq!(id2.node, Node::Id { lit: String::from("b") });
127
128        assert_eq!(body.node, Node::Id { lit: String::from("c") });
129    }
130
131    #[test]
132    fn direct_call_verify() {
133        let source = String::from("a(b, c)");
134        let statements = parse_direct(&source).unwrap();
135
136        let Node::FunctionCall { name, args } = &statements.first().expect("script empty.").node else {
137            panic!("first element script was anon fun.")
138        };
139
140        assert_eq!(name.node, Node::Id { lit: String::from("a") });
141        assert_eq!(args.len(), 2);
142        assert_eq!(args[0].node, Node::Id { lit: String::from("b") });
143        assert_eq!(args[1].node, Node::Id { lit: String::from("c") });
144    }
145
146    #[test]
147    fn method_call_verify() {
148        let source = String::from("instance.a(b, c)");
149        let statements = parse_direct(&source).unwrap();
150
151        let (instance, name, args) = match &statements.first().expect("script empty.").node {
152            Node::PropertyCall { instance, property } => match &property.node {
153                Node::FunctionCall { name, args } => (instance.clone(), name.clone(), args.clone()),
154                other => panic!("not function call in property call {:?}", other),
155            },
156            other => panic!("first element script was property call {:?}", other),
157        };
158
159        assert_eq!(instance.node, Node::Id { lit: String::from("instance") });
160        assert_eq!(name.node, Node::Id { lit: String::from("a") });
161
162        assert_eq!(args.len(), 2);
163        assert_eq!(args[0].node, Node::Id { lit: String::from("b") });
164        assert_eq!(args[1].node, Node::Id { lit: String::from("c") });
165    }
166
167    #[test]
168    fn direct_call_missing_closing_bracket() {
169        let source = String::from("a(b");
170        parse(&source).unwrap_err();
171    }
172
173    #[test]
174    fn regular_call_missing_closing_bracket() {
175        let source = String::from("instance.a(b");
176        parse(&source).unwrap_err();
177    }
178}