spade_parser/
expression.rs

1use num::ToPrimitive;
2use spade_ast::{ArgumentList, BinaryOperator, CallKind, Expression, IntLiteral, UnaryOperator};
3use spade_common::location_info::{Loc, WithLocation};
4use spade_diagnostics::Diagnostic;
5use spade_macros::trace_parser;
6
7use crate::error::{ExpectedArgumentList, Result, UnexpectedToken};
8use crate::{lexer::TokenKind, ParseStackEntry, Parser};
9
10#[derive(PartialEq, PartialOrd, Eq, Ord)]
11enum OpBindingPower {
12    None,
13    LogicalOr,
14    LogicalAnd,
15    LogicalXor,
16    Equality,
17    RelationalCmp,
18    BitwiseOr,
19    BitwiseXor,
20    BitwiseAnd,
21    Shift,
22    AddLike,
23    MulLike,
24    // Unary operator appearing before the expression it applies to such as
25    // - and !
26    PrefixUnary,
27}
28
29fn binop_binding_power(op: &BinaryOperator) -> OpBindingPower {
30    match op {
31        BinaryOperator::Add => OpBindingPower::AddLike,
32        BinaryOperator::Sub => OpBindingPower::AddLike,
33        BinaryOperator::Mul => OpBindingPower::MulLike,
34        BinaryOperator::Div => OpBindingPower::MulLike,
35        BinaryOperator::Mod => OpBindingPower::MulLike,
36        BinaryOperator::Equals => OpBindingPower::Equality,
37        BinaryOperator::NotEquals => OpBindingPower::Equality,
38        BinaryOperator::Lt => OpBindingPower::RelationalCmp,
39        BinaryOperator::Gt => OpBindingPower::RelationalCmp,
40        BinaryOperator::Le => OpBindingPower::RelationalCmp,
41        BinaryOperator::Ge => OpBindingPower::RelationalCmp,
42        BinaryOperator::LogicalAnd => OpBindingPower::LogicalAnd,
43        BinaryOperator::LogicalOr => OpBindingPower::LogicalOr,
44        BinaryOperator::LogicalXor => OpBindingPower::LogicalXor,
45        BinaryOperator::LeftShift => OpBindingPower::Shift,
46        BinaryOperator::RightShift => OpBindingPower::Shift,
47        BinaryOperator::ArithmeticRightShift => OpBindingPower::Shift,
48        BinaryOperator::BitwiseAnd => OpBindingPower::BitwiseAnd,
49        BinaryOperator::BitwiseOr => OpBindingPower::BitwiseOr,
50        BinaryOperator::BitwiseXor => OpBindingPower::BitwiseXor,
51    }
52}
53
54fn unop_binding_power(op: &UnaryOperator) -> OpBindingPower {
55    match op {
56        UnaryOperator::Sub => OpBindingPower::PrefixUnary,
57        UnaryOperator::Not => OpBindingPower::PrefixUnary,
58        UnaryOperator::BitwiseNot => OpBindingPower::PrefixUnary,
59        UnaryOperator::Dereference => OpBindingPower::PrefixUnary,
60        UnaryOperator::Reference => OpBindingPower::PrefixUnary,
61    }
62}
63
64impl<'a> Parser<'a> {
65    fn binop_from_kind(kind: &TokenKind) -> Option<BinaryOperator> {
66        match kind {
67            TokenKind::Plus => Some(BinaryOperator::Add),
68            TokenKind::Minus => Some(BinaryOperator::Sub),
69            TokenKind::Asterisk => Some(BinaryOperator::Mul),
70            TokenKind::Slash => Some(BinaryOperator::Div),
71            TokenKind::Percentage => Some(BinaryOperator::Mod),
72            TokenKind::Equals => Some(BinaryOperator::Equals),
73            TokenKind::NotEquals => Some(BinaryOperator::NotEquals),
74            // We have to handle left and right shifts separately because otherwise
75            // their parsing interferes with generic arguments
76            TokenKind::Lt => Some(BinaryOperator::Lt),
77            TokenKind::Gt => Some(BinaryOperator::Gt),
78            TokenKind::Le => Some(BinaryOperator::Le),
79            TokenKind::Ge => Some(BinaryOperator::Ge),
80            TokenKind::RightShift => Some(BinaryOperator::RightShift),
81            TokenKind::ArithmeticRightShift => Some(BinaryOperator::ArithmeticRightShift),
82            TokenKind::LeftShift => Some(BinaryOperator::LeftShift),
83            TokenKind::LogicalOr => Some(BinaryOperator::LogicalOr),
84            TokenKind::LogicalAnd => Some(BinaryOperator::LogicalAnd),
85            TokenKind::LogicalXor => Some(BinaryOperator::LogicalXor),
86            TokenKind::Ampersand => Some(BinaryOperator::BitwiseAnd),
87            TokenKind::BitwiseOr => Some(BinaryOperator::BitwiseOr),
88            TokenKind::BitwiseXor => Some(BinaryOperator::BitwiseXor),
89            _ => None,
90        }
91    }
92
93    fn unop_from_kind(kind: &TokenKind) -> Option<UnaryOperator> {
94        match kind {
95            TokenKind::Minus => Some(UnaryOperator::Sub),
96            TokenKind::Not => Some(UnaryOperator::Not),
97            TokenKind::Tilde => Some(UnaryOperator::BitwiseNot),
98            TokenKind::Ampersand => Some(UnaryOperator::Reference),
99            TokenKind::Asterisk => Some(UnaryOperator::Dereference),
100            _ => None,
101        }
102    }
103
104    #[tracing::instrument(skip(self))]
105    pub fn expression(&mut self) -> Result<Loc<Expression>> {
106        self.non_comptime_expression()
107    }
108
109    /// We need a function like this in order to not run into parser conflicts when
110    /// parsing blocks, since both statements and expressions can start with $if.
111    #[tracing::instrument(skip(self))]
112    pub fn non_comptime_expression(&mut self) -> Result<Loc<Expression>> {
113        self.custom_infix_operator()
114    }
115
116    fn custom_infix_operator(&mut self) -> Result<Loc<Expression>> {
117        let lhs_val = self.expr_bp(OpBindingPower::None)?;
118
119        if self.peek_kind(&TokenKind::InfixOperatorSeparator)? {
120            let (Some((callee, turbofish)), _) = self.surrounded(
121                &TokenKind::InfixOperatorSeparator,
122                Self::path_with_turbofish,
123                &TokenKind::InfixOperatorSeparator,
124            )?
125            else {
126                return Err(Diagnostic::from(UnexpectedToken {
127                    got: self.peek()?,
128                    expected: vec!["Identifier"],
129                }));
130            };
131
132            let rhs_val = self.custom_infix_operator()?;
133
134            Ok(Expression::Call {
135                kind: CallKind::Function,
136                callee,
137                args: ArgumentList::Positional(vec![lhs_val.clone(), rhs_val.clone()]).between(
138                    self.file_id,
139                    &lhs_val,
140                    &rhs_val,
141                ),
142                turbofish,
143            }
144            .between(self.file_id, &lhs_val, &rhs_val))
145        } else {
146            Ok(lhs_val)
147        }
148    }
149
150    /// If `op` is a subtraction, and `rhs` is an integer literal, construct a negative integer literal instead.
151    fn inline_negative_literal(
152        &self,
153        op: Loc<UnaryOperator>,
154        rhs: Loc<Expression>,
155    ) -> Result<Loc<Expression>> {
156        let (op, op_loc) = op.split_loc();
157        let (rhs, rhs_loc) = rhs.split_loc();
158        let expr_loc = ().between_locs(&op_loc, &rhs_loc);
159        let expr: Result<Expression> = match (op, rhs) {
160            (UnaryOperator::Sub, Expression::IntLiteral(int)) => {
161                let int = match int {
162                    IntLiteral::Unsized(val) => Ok(IntLiteral::Unsized(-val)),
163                    IntLiteral::Signed { val, size } => Ok(IntLiteral::Signed { val: -val, size }),
164                    IntLiteral::Unsigned { val, size } => Err(Diagnostic::error(
165                        expr_loc,
166                        "Cannot apply unary minus to unsigned integer literal",
167                    )
168                    .help("Only signed integers can have negative values")
169                    .span_suggest_replace(
170                        "Try making the integer signed",
171                        expr_loc,
172                        format!("-{val}i{size}"),
173                    )),
174                }?;
175                Ok(Expression::IntLiteral(int))
176            }
177            (op, rhs) => Ok(Expression::UnaryOperator(
178                op.at_loc(&op_loc),
179                Box::new(rhs.at_loc(&rhs_loc)),
180            )),
181        };
182        Ok(expr?.at_loc(&expr_loc))
183    }
184
185    // Based on matklads blog post on pratt parsing:
186    // https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
187    fn expr_bp(&mut self, min_power: OpBindingPower) -> Result<Loc<Expression>> {
188        let next_tok = self.peek()?;
189        let mut lhs = if let Some((tok, op)) =
190            Self::unop_from_kind(&next_tok.kind).map(|op| (next_tok, op))
191        {
192            self.eat_unconditional()?;
193            let op_power = unop_binding_power(&op);
194            let rhs = self.expr_bp(op_power)?;
195            self.inline_negative_literal(op.at_loc(&tok.loc()), rhs)?
196        } else {
197            self.base_expression()?
198        };
199
200        while let Some(op) = Self::binop_from_kind(&self.peek()?.kind) {
201            let op_power = binop_binding_power(&op);
202
203            if op_power <= min_power {
204                break;
205            }
206
207            let op_tok = self.eat_unconditional()?;
208
209            let rhs = self.expr_bp(op_power)?;
210            lhs = Expression::BinaryOperator(
211                Box::new(lhs.clone()),
212                op.at(self.file_id, &op_tok),
213                Box::new(rhs.clone()),
214            )
215            .between(self.file_id, &lhs, &rhs)
216        }
217
218        Ok(lhs)
219    }
220
221    // Expression parsing
222
223    #[trace_parser]
224    fn base_expression(&mut self) -> Result<Loc<Expression>> {
225        let expr = if let Some(tuple) = self.tuple_literal()? {
226            Ok(tuple)
227        } else if let Some(array) = self.array_literal()? {
228            Ok(array)
229        } else if let Some(instance) = self.entity_instance()? {
230            Ok(instance)
231        } else if let Some(val) = self.bool_literal()? {
232            Ok(val.map(Expression::BoolLiteral))
233        } else if let Some(val) = self.bit_literal()? {
234            Ok(val.map(Expression::BitLiteral))
235        } else if let Some(val) = self.int_literal()? {
236            Ok(Expression::IntLiteral(val.inner.clone())).map(|v| v.at_loc(&val))
237        } else if let Some(block) = self.block(false)? {
238            Ok(block.map(Box::new).map(Expression::Block))
239        } else if let Some(if_expr) = self.if_expression(false)? {
240            Ok(if_expr)
241        } else if let Some(if_expr) = self.type_level_if()? {
242            Ok(if_expr)
243        } else if let Some(match_expr) = self.match_expression()? {
244            Ok(match_expr)
245        } else if let Some(stageref) = self.pipeline_reference()? {
246            Ok(stageref)
247        } else if let Some(create_ports) = self.peek_and_eat(&TokenKind::Port)? {
248            Ok(Expression::CreatePorts.at(self.file_id, &create_ports))
249        } else if let Some((path, turbofish)) = self.path_with_turbofish()? {
250            let span = path.span;
251            match (turbofish, self.argument_list()?) {
252                (None, None) => Ok(Expression::Identifier(path).at(self.file_id, &span)),
253                (Some(tf), None) => {
254                    return Err(Diagnostic::error(self.peek()?, "Expected argument list")
255                        .primary_label("Expected argument list")
256                        .secondary_label(
257                            tf,
258                            "Type parameters can only be specified on function calls",
259                        ))
260                }
261                (tf, Some(args)) => {
262                    // Doing this avoids cloning result and args
263                    let span = ().between(self.file_id, &path, &args);
264
265                    Ok(Expression::Call {
266                        kind: CallKind::Function,
267                        callee: path,
268                        args,
269                        turbofish: tf,
270                    }
271                    .at_loc(&span))
272                }
273            }
274        } else {
275            let got = self.peek()?;
276            Err(Diagnostic::error(
277                got.loc(),
278                format!("Unexpected `{}`, expected expression", got.kind.as_str()),
279            )
280            .primary_label("expected expression here"))
281        }?;
282
283        self.expression_suffix(expr)
284    }
285
286    #[trace_parser]
287    fn expression_suffix(&mut self, expr: Loc<Expression>) -> Result<Loc<Expression>> {
288        let base = if let Some(hash) = self.peek_and_eat(&TokenKind::Hash)? {
289            if let Some(index) = self.int_literal()? {
290                let index = index
291                    .try_map_ref(|idx| -> Result<u128> {
292                        let as_u128 = idx
293                            .clone()
294                            .as_unsigned()
295                            .ok_or_else(|| {
296                                Diagnostic::error(&index, "Tuple indices must be non-negative")
297                                    .primary_label("Negative tuple index")
298                            })?
299                            .to_u128()
300                            .ok_or_else(|| {
301                                Diagnostic::bug(&index, "Tuple index too large")
302                                    .primary_label("Tuple index too large")
303                                    .note(format!("Tuple index can be at most {}", u128::MAX))
304                            })?;
305
306                        Ok(as_u128)
307                    })?
308                    .between(self.file_id, &hash, &index);
309                Ok(
310                    Expression::TupleIndex(Box::new(expr.clone()), index).between(
311                        self.file_id,
312                        &expr,
313                        &index,
314                    ),
315                )
316            } else {
317                Err(
318                    Diagnostic::error(self.peek()?.loc(), "expected an index after #")
319                        .primary_label("expected index here"),
320                )
321            }
322        } else if self.peek_and_eat(&TokenKind::Dot)?.is_some() {
323            let inst = self.peek_and_eat(&TokenKind::Instance)?;
324
325            let field = self.identifier()?;
326
327            let turbofish = self.turbofish()?;
328
329            if let Some(args) = self.argument_list()? {
330                Ok(Expression::MethodCall {
331                    target: Box::new(expr.clone()),
332                    name: field.clone(),
333                    args: args.clone(),
334                    kind: inst
335                        .map(|i| CallKind::Entity(().at(self.file_id, &i)))
336                        .unwrap_or(CallKind::Function),
337                    turbofish,
338                }
339                .between(self.file_id, &expr, &args))
340            } else if let Some(inst_keyword) = inst {
341                let base_loc = ().between(self.file_id, &inst_keyword, &field);
342                let base_expr = if let Some(turbofish) = turbofish {
343                    ().between_locs(&base_loc, &turbofish)
344                } else {
345                    base_loc
346                };
347                Err(ExpectedArgumentList {
348                    next_token: self.peek()?,
349                    base_expr,
350                }
351                .with_suggestions())
352            } else if let Some(turbofish) = turbofish {
353                Err(ExpectedArgumentList {
354                    next_token: self.peek()?,
355                    base_expr: ().between(self.file_id, &turbofish, &field),
356                }
357                .with_suggestions())
358            } else {
359                Ok(
360                    Expression::FieldAccess(Box::new(expr.clone()), field.clone()).between(
361                        self.file_id,
362                        &expr,
363                        &field,
364                    ),
365                )
366            }
367        } else if self.peek_kind(&TokenKind::OpenBracket)? {
368            let (inner_expr, loc) = self.surrounded(
369                &TokenKind::OpenBracket,
370                |s| {
371                    // `start` is parsed as an expression since at this point we are parsing either
372                    //
373                    // - an array index (`a[2]`) which allows an expression (`a[2+offset]`)
374                    // - a range index (`a[1:2]`) which does not allow an expression
375                    let start = s.expression()?;
376
377                    if let Some(_) = s.peek_and_eat(&TokenKind::Colon)? {
378                        // colon => range index: `[1:2]`
379                        let end = s.expression()?;
380                        Ok(Expression::RangeIndex {
381                            target: Box::new(expr.clone()),
382                            start: Box::new(start),
383                            end: Box::new(end),
384                        })
385                    } else {
386                        Ok(Expression::Index(Box::new(expr.clone()), Box::new(start)))
387                    }
388                },
389                &TokenKind::CloseBracket,
390            )?;
391
392            Ok(inner_expr.between_locs(&expr, &loc))
393        } else {
394            return Ok(expr);
395        }?;
396
397        self.expression_suffix(base)
398    }
399}
400
401#[cfg(test)]
402mod test {
403    use spade_ast::testutil::{ast_ident, ast_path};
404    use spade_ast::*;
405
406    use super::*;
407    use crate::lexer::TokenKind;
408    use crate::{check_parse, format_parse_stack};
409
410    use colored::Colorize;
411    use logos::Logos;
412
413    use spade_common::location_info::WithLocation;
414
415    #[test]
416    fn addition_operatoins_are_expressions() {
417        let expected_value = Expression::BinaryOperator(
418            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
419            BinaryOperator::Add.nowhere(),
420            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
421        )
422        .nowhere();
423
424        check_parse!("a + b", expression, Ok(expected_value));
425    }
426
427    #[test]
428    fn unary_suptraction_works() {
429        let expected_value = Expression::UnaryOperator(
430            UnaryOperator::Sub.nowhere(),
431            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
432        )
433        .nowhere();
434
435        check_parse!("- b", expression, Ok(expected_value));
436    }
437
438    #[test]
439    fn not_operator_works() {
440        let expected_value = Expression::UnaryOperator(
441            UnaryOperator::Not.nowhere(),
442            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
443        )
444        .nowhere();
445
446        check_parse!("!b", expression, Ok(expected_value));
447    }
448
449    #[test]
450    fn bitwise_and_operatoins_are_expressions() {
451        let expected_value = Expression::BinaryOperator(
452            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
453            BinaryOperator::BitwiseAnd.nowhere(),
454            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
455        )
456        .nowhere();
457
458        check_parse!("a & b", expression, Ok(expected_value));
459    }
460
461    #[test]
462    fn bitwise_or_operatoins_are_expressions() {
463        let expected_value = Expression::BinaryOperator(
464            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
465            BinaryOperator::BitwiseOr.nowhere(),
466            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
467        )
468        .nowhere();
469
470        check_parse!("a | b", expression, Ok(expected_value));
471    }
472
473    #[test]
474    fn multiplications_are_expressions() {
475        let expected_value = Expression::BinaryOperator(
476            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
477            BinaryOperator::Mul.nowhere(),
478            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
479        )
480        .nowhere();
481
482        check_parse!("a * b", expression, Ok(expected_value));
483    }
484
485    #[test]
486    fn multiplication_before_addition() {
487        let expected_value = Expression::BinaryOperator(
488            Box::new(
489                Expression::BinaryOperator(
490                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
491                    BinaryOperator::Mul.nowhere(),
492                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
493                )
494                .nowhere(),
495            ),
496            BinaryOperator::Add.nowhere(),
497            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
498        )
499        .nowhere();
500
501        check_parse!("a*b + c", expression, Ok(expected_value));
502    }
503
504    #[test]
505    fn equals_after_addition() {
506        let expected_value = Expression::BinaryOperator(
507            Box::new(
508                Expression::BinaryOperator(
509                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
510                    BinaryOperator::Add.nowhere(),
511                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
512                )
513                .nowhere(),
514            ),
515            BinaryOperator::Equals.nowhere(),
516            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
517        )
518        .nowhere();
519
520        check_parse!("a+b == c", expression, Ok(expected_value));
521    }
522
523    #[test]
524    fn and_after_equals() {
525        {
526            let expected_value = Expression::BinaryOperator(
527                Box::new(
528                    Expression::BinaryOperator(
529                        Box::new(Expression::Identifier(ast_path("a")).nowhere()),
530                        BinaryOperator::Equals.nowhere(),
531                        Box::new(Expression::Identifier(ast_path("b")).nowhere()),
532                    )
533                    .nowhere(),
534                ),
535                BinaryOperator::LogicalAnd.nowhere(),
536                Box::new(Expression::Identifier(ast_path("c")).nowhere()),
537            )
538            .nowhere();
539
540            check_parse!("a == b && c", expression, Ok(expected_value));
541        }
542        {
543            let expected_value = Expression::BinaryOperator(
544                Box::new(Expression::Identifier(ast_path("a")).nowhere()),
545                BinaryOperator::LogicalAnd.nowhere(),
546                Box::new(
547                    Expression::BinaryOperator(
548                        Box::new(Expression::Identifier(ast_path("b")).nowhere()),
549                        BinaryOperator::Equals.nowhere(),
550                        Box::new(Expression::Identifier(ast_path("c")).nowhere()),
551                    )
552                    .nowhere(),
553                ),
554            )
555            .nowhere();
556
557            check_parse!("a && b == c", expression, Ok(expected_value));
558        }
559    }
560
561    #[test]
562    fn bracketed_expressions_are_expressions() {
563        let expected_value = Expression::BinaryOperator(
564            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
565            BinaryOperator::Add.nowhere(),
566            Box::new(
567                Expression::BinaryOperator(
568                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
569                    BinaryOperator::Add.nowhere(),
570                    Box::new(Expression::Identifier(ast_path("c")).nowhere()),
571                )
572                .nowhere(),
573            ),
574        )
575        .nowhere();
576
577        check_parse!("a + (b + c)", expression, Ok(expected_value));
578    }
579
580    #[test]
581    fn repeated_bracketed_expressions_work() {
582        let expected_value = Expression::BinaryOperator(
583            Box::new(
584                Expression::BinaryOperator(
585                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
586                    BinaryOperator::Add.nowhere(),
587                    Box::new(Expression::Identifier(ast_path("c")).nowhere()),
588                )
589                .nowhere(),
590            ),
591            BinaryOperator::Add.nowhere(),
592            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
593        )
594        .nowhere();
595
596        check_parse!("((b + c) + a)", expression, Ok(expected_value));
597    }
598
599    #[test]
600    fn functions_work() {
601        let code = "test(1, 2)";
602
603        let expected = Expression::Call {
604            kind: CallKind::Function,
605            callee: ast_path("test"),
606            args: ArgumentList::Positional(vec![
607                Expression::int_literal_signed(1).nowhere(),
608                Expression::int_literal_signed(2).nowhere(),
609            ])
610            .nowhere(),
611            turbofish: None,
612        }
613        .nowhere();
614
615        check_parse!(code, expression, Ok(expected));
616    }
617
618    #[test]
619    fn functions_with_named_arguments_work() {
620        let code = "test$(a, b)";
621
622        let expected = Expression::Call {
623            kind: CallKind::Function,
624            callee: ast_path("test"),
625            args: ArgumentList::Named(vec![
626                NamedArgument::Short(ast_ident("a")),
627                NamedArgument::Short(ast_ident("b")),
628            ])
629            .nowhere(),
630            turbofish: None,
631        }
632        .nowhere();
633
634        check_parse!(code, expression, Ok(expected));
635    }
636
637    #[test]
638    fn tuple_literals_parse() {
639        let code = "(1, true)";
640
641        let expected = Expression::TupleLiteral(vec![
642            Expression::int_literal_signed(1).nowhere(),
643            Expression::BoolLiteral(true).nowhere(),
644        ])
645        .nowhere();
646
647        check_parse!(code, expression, Ok(expected));
648    }
649
650    #[test]
651    fn array_literals_parse() {
652        let code = "[1, 2, 3]";
653
654        let expected = Expression::ArrayLiteral(vec![
655            Expression::int_literal_signed(1).nowhere(),
656            Expression::int_literal_signed(2).nowhere(),
657            Expression::int_literal_signed(3).nowhere(),
658        ])
659        .nowhere();
660
661        check_parse!(code, expression, Ok(expected));
662    }
663
664    #[test]
665    fn array_indexing_works() {
666        let code = "a[0]";
667
668        let expected = Expression::Index(
669            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
670            Box::new(Expression::int_literal_signed(0).nowhere()),
671        )
672        .nowhere();
673
674        check_parse!(code, expression, Ok(expected));
675    }
676
677    #[test]
678    fn tuple_indexing_parsese() {
679        let code = "a#0";
680
681        let expected = Expression::TupleIndex(
682            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
683            Loc::new(0, ().nowhere().span, 0),
684        )
685        .nowhere();
686
687        check_parse!(code, expression, Ok(expected));
688    }
689
690    #[test]
691    fn field_access_parses() {
692        let code = "a.b";
693        let expected = Expression::FieldAccess(
694            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
695            ast_ident("b"),
696        )
697        .nowhere();
698
699        check_parse!(code, expression, Ok(expected));
700    }
701
702    #[test]
703    fn method_call_parses() {
704        let code = "a.b(x)";
705
706        let expected = Expression::MethodCall {
707            target: Box::new(Expression::Identifier(ast_path("a")).nowhere()),
708            name: ast_ident("b"),
709            args: ArgumentList::Positional(vec![Expression::Identifier(ast_path("x")).nowhere()])
710                .nowhere(),
711            kind: CallKind::Function,
712            turbofish: None,
713        }
714        .nowhere();
715
716        check_parse!(code, expression, Ok(expected));
717    }
718
719    #[test]
720    fn inst_method_call_parses() {
721        let code = "a.inst b(x)";
722
723        let expected = Expression::MethodCall {
724            target: Box::new(Expression::Identifier(ast_path("a")).nowhere()),
725            name: ast_ident("b"),
726            args: ArgumentList::Positional(vec![Expression::Identifier(ast_path("x")).nowhere()])
727                .nowhere(),
728            kind: CallKind::Entity(().nowhere()),
729            turbofish: None,
730        }
731        .nowhere();
732
733        check_parse!(code, expression, Ok(expected));
734    }
735
736    #[test]
737    fn method_call_with_named_args_works() {
738        let code = "a.b$(x: y)";
739
740        let expected = Expression::MethodCall {
741            target: Box::new(Expression::Identifier(ast_path("a")).nowhere()),
742            name: ast_ident("b"),
743            args: ArgumentList::Named(vec![NamedArgument::Full(
744                ast_ident("x"),
745                Expression::Identifier(ast_path("y")).nowhere(),
746            )])
747            .nowhere(),
748            kind: CallKind::Function,
749            turbofish: None,
750        }
751        .nowhere();
752
753        check_parse!(code, expression, Ok(expected));
754    }
755
756    #[test]
757    fn if_expressions_work() {
758        let code = r#"
759        if a {b} else {c}
760        "#;
761
762        let expected = Expression::If(
763            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
764            Box::new(
765                Expression::Block(Box::new(Block {
766                    statements: vec![],
767                    result: Some(Expression::Identifier(ast_path("b")).nowhere()),
768                }))
769                .nowhere(),
770            ),
771            Box::new(
772                Expression::Block(Box::new(Block {
773                    statements: vec![],
774                    result: Some(Expression::Identifier(ast_path("c")).nowhere()),
775                }))
776                .nowhere(),
777            ),
778        )
779        .nowhere();
780
781        check_parse!(code, expression, Ok(expected));
782    }
783
784    #[test]
785    fn match_expressions_work() {
786        let code = r#"
787        match x {
788            (0, y) => y,
789            (x, y) => x,
790        }
791        "#;
792
793        let expected = Expression::Match(
794            Box::new(Expression::Identifier(ast_path("x")).nowhere()),
795            vec![
796                (
797                    Pattern::Tuple(vec![Pattern::integer(0).nowhere(), Pattern::name("y")])
798                        .nowhere(),
799                    Expression::Identifier(ast_path("y")).nowhere(),
800                ),
801                (
802                    Pattern::Tuple(vec![Pattern::name("x"), Pattern::name("y")]).nowhere(),
803                    Expression::Identifier(ast_path("x")).nowhere(),
804                ),
805            ]
806            .nowhere(),
807        )
808        .nowhere();
809
810        check_parse!(code, expression, Ok(expected));
811    }
812
813    #[test]
814    fn blocks_work() {
815        let code = r#"
816            {
817                let a = 0;
818                1
819            }
820            "#;
821
822        let expected = Block {
823            statements: vec![Statement::binding(
824                Pattern::name("a"),
825                None,
826                Expression::int_literal_signed(0).nowhere(),
827            )
828            .nowhere()],
829            result: Some(Expression::int_literal_signed(1).nowhere()),
830        }
831        .nowhere();
832
833        check_parse!(code, block(false), Ok(Some(expected)));
834    }
835
836    #[test]
837    fn blocks_are_expressions() {
838        let code = r#"
839            {
840                let a = 0;
841                1
842            }
843            "#;
844
845        let expected = Expression::Block(Box::new(Block {
846            statements: vec![Statement::binding(
847                Pattern::name("a"),
848                None,
849                Expression::int_literal_signed(0).nowhere(),
850            )
851            .nowhere()],
852            result: Some(Expression::int_literal_signed(1).nowhere()),
853        }))
854        .nowhere();
855
856        check_parse!(code, expression, Ok(expected));
857    }
858
859    #[test]
860    fn infix_operators_work() {
861        let code = r#"
862            1 `infix` 2
863            "#;
864
865        let expected = Expression::Call {
866            kind: CallKind::Function,
867            callee: ast_path("infix"),
868            args: ArgumentList::Positional(vec![
869                Expression::int_literal_signed(1).nowhere(),
870                Expression::int_literal_signed(2).nowhere(),
871            ])
872            .nowhere(),
873            turbofish: None,
874        }
875        .nowhere();
876
877        check_parse!(code, expression, Ok(expected));
878    }
879
880    #[test]
881    fn infix_operator_precedence_is_unchanged() {
882        // NOTE: the exact ordering here is somewhat unimportant, in general one
883        // should probably put parentheses around infix operators anyway. The main
884        // purpose of this test is to prevent accidental changes to the order in the future
885        let code = r#"
886            0 || 1 `infix` 2 `infix` 3
887            "#;
888
889        let expected = Expression::Call {
890            kind: CallKind::Function,
891            callee: ast_path("infix"),
892            args: ArgumentList::Positional(vec![
893                Expression::BinaryOperator(
894                    Box::new(Expression::int_literal_signed(0).nowhere()),
895                    BinaryOperator::LogicalOr.nowhere(),
896                    Box::new(Expression::int_literal_signed(1).nowhere()),
897                )
898                .nowhere(),
899                Expression::Call {
900                    kind: CallKind::Function,
901                    callee: ast_path("infix"),
902                    args: ArgumentList::Positional(vec![
903                        Expression::int_literal_signed(2).nowhere(),
904                        Expression::int_literal_signed(3).nowhere(),
905                    ])
906                    .nowhere(),
907                    turbofish: None,
908                }
909                .nowhere(),
910            ])
911            .nowhere(),
912            turbofish: None,
913        }
914        .nowhere();
915
916        check_parse!(code, expression, Ok(expected));
917    }
918
919    #[test]
920    fn field_access_operator_does_not_require_parens() {
921        let code = r#"x.y.z"#;
922
923        let expected = Expression::FieldAccess(
924            Box::new(
925                Expression::FieldAccess(
926                    Box::new(Expression::Identifier(ast_path("x")).nowhere()),
927                    ast_ident("y"),
928                )
929                .nowhere(),
930            ),
931            ast_ident("z"),
932        )
933        .nowhere();
934
935        check_parse!(code, expression, Ok(expected));
936    }
937
938    #[test]
939    fn array_index_operator_precedence_is_correct() {
940        let code = r#"x && y[z]"#;
941
942        let expected = Expression::BinaryOperator(
943            Box::new(Expression::Identifier(ast_path("x")).nowhere()),
944            BinaryOperator::LogicalAnd.nowhere(),
945            Box::new(
946                Expression::Index(
947                    Box::new(Expression::Identifier(ast_path("y")).nowhere()),
948                    Box::new(Expression::Identifier(ast_path("z")).nowhere()),
949                )
950                .nowhere(),
951            ),
952        )
953        .nowhere();
954
955        check_parse!(code, expression, Ok(expected));
956    }
957
958    #[test]
959    fn tuple_index_operator_precedence_is_correct() {
960        let code = r#"y#1#2"#;
961
962        let expected = Expression::TupleIndex(
963            Box::new(
964                Expression::TupleIndex(
965                    Box::new(Expression::Identifier(ast_path("y")).nowhere()),
966                    1u128.nowhere(),
967                )
968                .nowhere(),
969            ),
970            2.nowhere(),
971        )
972        .nowhere();
973
974        check_parse!(code, expression, Ok(expected));
975    }
976
977    // Precedence related tests
978    #[test]
979    fn subtraction_occurs_in_correct_order() {
980        let expected_value = Expression::BinaryOperator(
981            Box::new(
982                Expression::BinaryOperator(
983                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
984                    BinaryOperator::Sub.nowhere(),
985                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
986                )
987                .nowhere(),
988            ),
989            BinaryOperator::Sub.nowhere(),
990            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
991        )
992        .nowhere();
993
994        check_parse!("a - b - c", expression, Ok(expected_value));
995    }
996
997    #[test]
998    fn not_function_call_does_not_invert_function() {
999        let expected_value = Expression::UnaryOperator(
1000            UnaryOperator::Not.nowhere(),
1001            Box::new(
1002                Expression::Call {
1003                    kind: CallKind::Function,
1004                    callee: ast_path("a"),
1005                    args: ArgumentList::Positional(vec![]).nowhere(),
1006                    turbofish: None,
1007                }
1008                .nowhere(),
1009            ),
1010        )
1011        .nowhere();
1012
1013        check_parse!("!a()", expression, Ok(expected_value));
1014    }
1015
1016    #[test]
1017    fn chained_array_indexing_is_left_to_right() {
1018        let expected_value = Expression::Index(
1019            Box::new(
1020                Expression::Index(
1021                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1022                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1023                )
1024                .nowhere(),
1025            ),
1026            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
1027        )
1028        .nowhere();
1029
1030        check_parse!("a[b][c]", expression, Ok(expected_value));
1031    }
1032
1033    #[test]
1034    fn not_index_result_inverts_whole_result() {
1035        let expected_value = Expression::UnaryOperator(
1036            UnaryOperator::Not.nowhere(),
1037            Box::new(
1038                Expression::Index(
1039                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1040                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1041                )
1042                .nowhere(),
1043            ),
1044        )
1045        .nowhere();
1046
1047        check_parse!("!a[b]", expression, Ok(expected_value));
1048    }
1049
1050    #[test]
1051    fn unary_sub_binds_correctly() {
1052        let expected_value = Expression::BinaryOperator(
1053            Box::new(
1054                Expression::UnaryOperator(
1055                    UnaryOperator::Sub.nowhere(),
1056                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1057                )
1058                .nowhere(),
1059            ),
1060            BinaryOperator::Add.nowhere(),
1061            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1062        )
1063        .nowhere();
1064
1065        check_parse!("-a + b", expression, Ok(expected_value));
1066    }
1067
1068    #[test]
1069    fn unary_sub_binds_correctly_without_spaces() {
1070        let expected_value = Expression::BinaryOperator(
1071            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1072            BinaryOperator::Add.nowhere(),
1073            Box::new(
1074                Expression::UnaryOperator(
1075                    UnaryOperator::Sub.nowhere(),
1076                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1077                )
1078                .nowhere(),
1079            ),
1080        )
1081        .nowhere();
1082
1083        check_parse!("b+-a", expression, Ok(expected_value));
1084    }
1085
1086    #[test]
1087    fn binary_sub_binds_correctly_without_spaces() {
1088        let expected_value = Expression::BinaryOperator(
1089            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1090            BinaryOperator::Sub.nowhere(),
1091            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1092        )
1093        .nowhere();
1094
1095        check_parse!("b-a", expression, Ok(expected_value));
1096    }
1097
1098    #[test]
1099    fn deref_operator_works() {
1100        let expected = Expression::UnaryOperator(
1101            UnaryOperator::Dereference.nowhere(),
1102            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1103        )
1104        .nowhere();
1105
1106        check_parse!("*a", expression, Ok(expected));
1107    }
1108
1109    #[test]
1110    fn deref_operator_precedence() {
1111        let expected = Expression::BinaryOperator(
1112            Box::new(
1113                Expression::UnaryOperator(
1114                    UnaryOperator::Dereference.nowhere(),
1115                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1116                )
1117                .nowhere(),
1118            ),
1119            BinaryOperator::Add.nowhere(),
1120            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1121        )
1122        .nowhere();
1123
1124        check_parse!("*a + b", expression, Ok(expected));
1125    }
1126
1127    #[test]
1128    fn ref_operator_works() {
1129        let expected = Expression::UnaryOperator(
1130            UnaryOperator::Reference.nowhere(),
1131            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1132        )
1133        .nowhere();
1134
1135        check_parse!("&a", expression, Ok(expected));
1136    }
1137}