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::{CSErrorTransformations, 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(lambda) = self.lambda()? {
228            Ok(lambda)
229        } else if let Some(array) = self.array_literal()? {
230            Ok(array)
231        } else if let Some(instance) = self.entity_instance()? {
232            Ok(instance)
233        } else if let Some(val) = self.bool_literal()? {
234            Ok(val.map(Expression::BoolLiteral))
235        } else if let Some(val) = self.bit_literal()? {
236            Ok(val.map(Expression::BitLiteral))
237        } else if let Some(val) = self.int_literal()? {
238            Ok(Expression::IntLiteral(val.inner.clone())).map(|v| v.at_loc(&val))
239        } else if let Some(block) = self.block(false)? {
240            Ok(block.map(Box::new).map(Expression::Block))
241        } else if let Some(if_expr) = self.if_expression(false)? {
242            Ok(if_expr)
243        } else if let Some(if_expr) = self.type_level_if()? {
244            Ok(if_expr)
245        } else if let Some(match_expr) = self.match_expression()? {
246            Ok(match_expr)
247        } else if let Some(stageref) = self.pipeline_reference()? {
248            Ok(stageref)
249        } else if let Some(create_ports) = self.peek_and_eat(&TokenKind::Port)? {
250            Ok(Expression::CreatePorts.at(self.file_id, &create_ports))
251        } else if let Some((path, turbofish)) = self.path_with_turbofish()? {
252            let span = path.span;
253            match (turbofish, self.argument_list()?) {
254                (None, None) => Ok(Expression::Identifier(path).at(self.file_id, &span)),
255                (Some(tf), None) => {
256                    return Err(Diagnostic::error(self.peek()?, "Expected argument list")
257                        .primary_label("Expected argument list")
258                        .secondary_label(
259                            tf,
260                            "Type parameters can only be specified on function calls",
261                        ))
262                }
263                (tf, Some(args)) => {
264                    // Doing this avoids cloning result and args
265                    let span = ().between(self.file_id, &path, &args);
266
267                    Ok(Expression::Call {
268                        kind: CallKind::Function,
269                        callee: path,
270                        args,
271                        turbofish: tf,
272                    }
273                    .at_loc(&span))
274                }
275            }
276        } else {
277            let got = self.peek()?;
278            Err(Diagnostic::error(
279                got.loc(),
280                format!("Unexpected `{}`, expected expression", got.kind.as_str()),
281            )
282            .primary_label("expected expression here"))
283        }?;
284
285        self.expression_suffix(expr)
286    }
287
288    #[trace_parser]
289    fn lambda(&mut self) -> Result<Option<Loc<Expression>>> {
290        let start_token = self.peek()?;
291        let Some(unit_kind) = self.unit_kind(&start_token)? else {
292            return Ok(None);
293        };
294
295        let (args, args_loc) = self.surrounded(
296            &TokenKind::OpenParen,
297            |s| {
298                let args = s
299                    .comma_separated(|s| s.pattern(), &TokenKind::CloseParen)
300                    .no_context()?;
301
302                Ok(args)
303            },
304            &TokenKind::CloseParen,
305        )?;
306        let args = args.at_loc(&args_loc);
307
308        let Some(body) = self.block(false)? else {
309            let loc = self.peek()?;
310            return Err(Diagnostic::error(&loc.loc(), "Expected lambda body")
311                .primary_label("Expected body")
312                .span_suggest_replace("Consider adding a body", loc, "{ /*..*/ }"));
313        };
314
315        let loc = ().between(self.file_id, &start_token, &body);
316
317        Ok(Some(
318            Expression::Lambda {
319                unit_kind,
320                args,
321                body: Box::new(body),
322            }
323            .at_loc(&loc),
324        ))
325    }
326
327    #[trace_parser]
328    fn expression_suffix(&mut self, expr: Loc<Expression>) -> Result<Loc<Expression>> {
329        let base = if let Some(hash) = self.peek_and_eat(&TokenKind::Hash)? {
330            if let Some(index) = self.int_literal()? {
331                let index = index
332                    .try_map_ref(|idx| -> Result<u128> {
333                        let as_u128 = idx
334                            .clone()
335                            .as_unsigned()
336                            .ok_or_else(|| {
337                                Diagnostic::error(&index, "Tuple indices must be non-negative")
338                                    .primary_label("Negative tuple index")
339                            })?
340                            .to_u128()
341                            .ok_or_else(|| {
342                                Diagnostic::bug(&index, "Tuple index too large")
343                                    .primary_label("Tuple index too large")
344                                    .note(format!("Tuple index can be at most {}", u128::MAX))
345                            })?;
346
347                        Ok(as_u128)
348                    })?
349                    .between(self.file_id, &hash, &index);
350                Ok(
351                    Expression::TupleIndex(Box::new(expr.clone()), index).between(
352                        self.file_id,
353                        &expr,
354                        &index,
355                    ),
356                )
357            } else {
358                Err(
359                    Diagnostic::error(self.peek()?.loc(), "expected an index after #")
360                        .primary_label("expected index here"),
361                )
362            }
363        } else if self.peek_and_eat(&TokenKind::Dot)?.is_some() {
364            let inst = self.peek_and_eat(&TokenKind::Instance)?;
365
366            let field = self.identifier()?;
367
368            let turbofish = self.turbofish()?;
369
370            if let Some(args) = self.argument_list()? {
371                Ok(Expression::MethodCall {
372                    target: Box::new(expr.clone()),
373                    name: field.clone(),
374                    args: args.clone(),
375                    kind: inst
376                        .map(|i| CallKind::Entity(().at(self.file_id, &i)))
377                        .unwrap_or(CallKind::Function),
378                    turbofish,
379                }
380                .between(self.file_id, &expr, &args))
381            } else if let Some(inst_keyword) = inst {
382                let base_loc = ().between(self.file_id, &inst_keyword, &field);
383                let base_expr = if let Some(turbofish) = turbofish {
384                    ().between_locs(&base_loc, &turbofish)
385                } else {
386                    base_loc
387                };
388                Err(ExpectedArgumentList {
389                    next_token: self.peek()?,
390                    base_expr,
391                }
392                .with_suggestions())
393            } else if let Some(turbofish) = turbofish {
394                Err(ExpectedArgumentList {
395                    next_token: self.peek()?,
396                    base_expr: ().between(self.file_id, &turbofish, &field),
397                }
398                .with_suggestions())
399            } else {
400                Ok(
401                    Expression::FieldAccess(Box::new(expr.clone()), field.clone()).between(
402                        self.file_id,
403                        &expr,
404                        &field,
405                    ),
406                )
407            }
408        } else if self.peek_kind(&TokenKind::OpenBracket)? {
409            let (inner_expr, loc) = self.surrounded(
410                &TokenKind::OpenBracket,
411                |s| {
412                    // `start` is parsed as an expression since at this point we are parsing either
413                    //
414                    // - an array index (`a[2]`) which allows an expression (`a[2+offset]`)
415                    // - a range index (`a[1..2]`) which does not allow an expression
416                    let start = s.expression()?;
417
418                    if let Some(_) = s.peek_and_eat(&TokenKind::DotDot)? {
419                        // double dot => range index: `[1..2]`
420                        let end = s.expression()?;
421                        Ok(Expression::RangeIndex {
422                            target: Box::new(expr.clone()),
423                            start: Box::new(start),
424                            end: Box::new(end),
425                        })
426                    } else {
427                        Ok(Expression::Index(Box::new(expr.clone()), Box::new(start)))
428                    }
429                },
430                &TokenKind::CloseBracket,
431            )?;
432
433            Ok(inner_expr.between_locs(&expr, &loc))
434        } else {
435            return Ok(expr);
436        }?;
437
438        self.expression_suffix(base)
439    }
440}
441
442#[cfg(test)]
443mod test {
444    use spade_ast::testutil::{ast_ident, ast_path};
445    use spade_ast::*;
446
447    use super::*;
448    use crate::lexer::TokenKind;
449    use crate::{check_parse, format_parse_stack};
450
451    use colored::Colorize;
452    use logos::Logos;
453
454    use spade_common::location_info::WithLocation;
455
456    #[test]
457    fn addition_operatoins_are_expressions() {
458        let expected_value = Expression::BinaryOperator(
459            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
460            BinaryOperator::Add.nowhere(),
461            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
462        )
463        .nowhere();
464
465        check_parse!("a + b", expression, Ok(expected_value));
466    }
467
468    #[test]
469    fn unary_suptraction_works() {
470        let expected_value = Expression::UnaryOperator(
471            UnaryOperator::Sub.nowhere(),
472            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
473        )
474        .nowhere();
475
476        check_parse!("- b", expression, Ok(expected_value));
477    }
478
479    #[test]
480    fn not_operator_works() {
481        let expected_value = Expression::UnaryOperator(
482            UnaryOperator::Not.nowhere(),
483            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
484        )
485        .nowhere();
486
487        check_parse!("!b", expression, Ok(expected_value));
488    }
489
490    #[test]
491    fn bitwise_and_operatoins_are_expressions() {
492        let expected_value = Expression::BinaryOperator(
493            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
494            BinaryOperator::BitwiseAnd.nowhere(),
495            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
496        )
497        .nowhere();
498
499        check_parse!("a & b", expression, Ok(expected_value));
500    }
501
502    #[test]
503    fn bitwise_or_operatoins_are_expressions() {
504        let expected_value = Expression::BinaryOperator(
505            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
506            BinaryOperator::BitwiseOr.nowhere(),
507            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
508        )
509        .nowhere();
510
511        check_parse!("a | b", expression, Ok(expected_value));
512    }
513
514    #[test]
515    fn multiplications_are_expressions() {
516        let expected_value = Expression::BinaryOperator(
517            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
518            BinaryOperator::Mul.nowhere(),
519            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
520        )
521        .nowhere();
522
523        check_parse!("a * b", expression, Ok(expected_value));
524    }
525
526    #[test]
527    fn multiplication_before_addition() {
528        let expected_value = Expression::BinaryOperator(
529            Box::new(
530                Expression::BinaryOperator(
531                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
532                    BinaryOperator::Mul.nowhere(),
533                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
534                )
535                .nowhere(),
536            ),
537            BinaryOperator::Add.nowhere(),
538            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
539        )
540        .nowhere();
541
542        check_parse!("a*b + c", expression, Ok(expected_value));
543    }
544
545    #[test]
546    fn equals_after_addition() {
547        let expected_value = Expression::BinaryOperator(
548            Box::new(
549                Expression::BinaryOperator(
550                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
551                    BinaryOperator::Add.nowhere(),
552                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
553                )
554                .nowhere(),
555            ),
556            BinaryOperator::Equals.nowhere(),
557            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
558        )
559        .nowhere();
560
561        check_parse!("a+b == c", expression, Ok(expected_value));
562    }
563
564    #[test]
565    fn and_after_equals() {
566        {
567            let expected_value = Expression::BinaryOperator(
568                Box::new(
569                    Expression::BinaryOperator(
570                        Box::new(Expression::Identifier(ast_path("a")).nowhere()),
571                        BinaryOperator::Equals.nowhere(),
572                        Box::new(Expression::Identifier(ast_path("b")).nowhere()),
573                    )
574                    .nowhere(),
575                ),
576                BinaryOperator::LogicalAnd.nowhere(),
577                Box::new(Expression::Identifier(ast_path("c")).nowhere()),
578            )
579            .nowhere();
580
581            check_parse!("a == b && c", expression, Ok(expected_value));
582        }
583        {
584            let expected_value = Expression::BinaryOperator(
585                Box::new(Expression::Identifier(ast_path("a")).nowhere()),
586                BinaryOperator::LogicalAnd.nowhere(),
587                Box::new(
588                    Expression::BinaryOperator(
589                        Box::new(Expression::Identifier(ast_path("b")).nowhere()),
590                        BinaryOperator::Equals.nowhere(),
591                        Box::new(Expression::Identifier(ast_path("c")).nowhere()),
592                    )
593                    .nowhere(),
594                ),
595            )
596            .nowhere();
597
598            check_parse!("a && b == c", expression, Ok(expected_value));
599        }
600    }
601
602    #[test]
603    fn bracketed_expressions_are_expressions() {
604        let expected_value = Expression::BinaryOperator(
605            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
606            BinaryOperator::Add.nowhere(),
607            Box::new(
608                Expression::BinaryOperator(
609                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
610                    BinaryOperator::Add.nowhere(),
611                    Box::new(Expression::Identifier(ast_path("c")).nowhere()),
612                )
613                .nowhere(),
614            ),
615        )
616        .nowhere();
617
618        check_parse!("a + (b + c)", expression, Ok(expected_value));
619    }
620
621    #[test]
622    fn repeated_bracketed_expressions_work() {
623        let expected_value = Expression::BinaryOperator(
624            Box::new(
625                Expression::BinaryOperator(
626                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
627                    BinaryOperator::Add.nowhere(),
628                    Box::new(Expression::Identifier(ast_path("c")).nowhere()),
629                )
630                .nowhere(),
631            ),
632            BinaryOperator::Add.nowhere(),
633            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
634        )
635        .nowhere();
636
637        check_parse!("((b + c) + a)", expression, Ok(expected_value));
638    }
639
640    #[test]
641    fn functions_work() {
642        let code = "test(1, 2)";
643
644        let expected = Expression::Call {
645            kind: CallKind::Function,
646            callee: ast_path("test"),
647            args: ArgumentList::Positional(vec![
648                Expression::int_literal_signed(1).nowhere(),
649                Expression::int_literal_signed(2).nowhere(),
650            ])
651            .nowhere(),
652            turbofish: None,
653        }
654        .nowhere();
655
656        check_parse!(code, expression, Ok(expected));
657    }
658
659    #[test]
660    fn functions_with_named_arguments_work() {
661        let code = "test$(a, b)";
662
663        let expected = Expression::Call {
664            kind: CallKind::Function,
665            callee: ast_path("test"),
666            args: ArgumentList::Named(vec![
667                NamedArgument::Short(ast_ident("a")),
668                NamedArgument::Short(ast_ident("b")),
669            ])
670            .nowhere(),
671            turbofish: None,
672        }
673        .nowhere();
674
675        check_parse!(code, expression, Ok(expected));
676    }
677
678    #[test]
679    fn tuple_literals_parse() {
680        let code = "(1, true)";
681
682        let expected = Expression::TupleLiteral(vec![
683            Expression::int_literal_signed(1).nowhere(),
684            Expression::BoolLiteral(true).nowhere(),
685        ])
686        .nowhere();
687
688        check_parse!(code, expression, Ok(expected));
689    }
690
691    #[test]
692    fn array_literals_parse() {
693        let code = "[1, 2, 3]";
694
695        let expected = Expression::ArrayLiteral(vec![
696            Expression::int_literal_signed(1).nowhere(),
697            Expression::int_literal_signed(2).nowhere(),
698            Expression::int_literal_signed(3).nowhere(),
699        ])
700        .nowhere();
701
702        check_parse!(code, expression, Ok(expected));
703    }
704
705    #[test]
706    fn array_indexing_works() {
707        let code = "a[0]";
708
709        let expected = Expression::Index(
710            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
711            Box::new(Expression::int_literal_signed(0).nowhere()),
712        )
713        .nowhere();
714
715        check_parse!(code, expression, Ok(expected));
716    }
717
718    #[test]
719    fn tuple_indexing_parsese() {
720        let code = "a#0";
721
722        let expected = Expression::TupleIndex(
723            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
724            Loc::new(0, ().nowhere().span, 0),
725        )
726        .nowhere();
727
728        check_parse!(code, expression, Ok(expected));
729    }
730
731    #[test]
732    fn field_access_parses() {
733        let code = "a.b";
734        let expected = Expression::FieldAccess(
735            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
736            ast_ident("b"),
737        )
738        .nowhere();
739
740        check_parse!(code, expression, Ok(expected));
741    }
742
743    #[test]
744    fn method_call_parses() {
745        let code = "a.b(x)";
746
747        let expected = Expression::MethodCall {
748            target: Box::new(Expression::Identifier(ast_path("a")).nowhere()),
749            name: ast_ident("b"),
750            args: ArgumentList::Positional(vec![Expression::Identifier(ast_path("x")).nowhere()])
751                .nowhere(),
752            kind: CallKind::Function,
753            turbofish: None,
754        }
755        .nowhere();
756
757        check_parse!(code, expression, Ok(expected));
758    }
759
760    #[test]
761    fn inst_method_call_parses() {
762        let code = "a.inst b(x)";
763
764        let expected = Expression::MethodCall {
765            target: Box::new(Expression::Identifier(ast_path("a")).nowhere()),
766            name: ast_ident("b"),
767            args: ArgumentList::Positional(vec![Expression::Identifier(ast_path("x")).nowhere()])
768                .nowhere(),
769            kind: CallKind::Entity(().nowhere()),
770            turbofish: None,
771        }
772        .nowhere();
773
774        check_parse!(code, expression, Ok(expected));
775    }
776
777    #[test]
778    fn method_call_with_named_args_works() {
779        let code = "a.b$(x: y)";
780
781        let expected = Expression::MethodCall {
782            target: Box::new(Expression::Identifier(ast_path("a")).nowhere()),
783            name: ast_ident("b"),
784            args: ArgumentList::Named(vec![NamedArgument::Full(
785                ast_ident("x"),
786                Expression::Identifier(ast_path("y")).nowhere(),
787            )])
788            .nowhere(),
789            kind: CallKind::Function,
790            turbofish: None,
791        }
792        .nowhere();
793
794        check_parse!(code, expression, Ok(expected));
795    }
796
797    #[test]
798    fn if_expressions_work() {
799        let code = r#"
800        if a {b} else {c}
801        "#;
802
803        let expected = Expression::If(
804            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
805            Box::new(
806                Expression::Block(Box::new(Block {
807                    statements: vec![],
808                    result: Some(Expression::Identifier(ast_path("b")).nowhere()),
809                }))
810                .nowhere(),
811            ),
812            Box::new(
813                Expression::Block(Box::new(Block {
814                    statements: vec![],
815                    result: Some(Expression::Identifier(ast_path("c")).nowhere()),
816                }))
817                .nowhere(),
818            ),
819        )
820        .nowhere();
821
822        check_parse!(code, expression, Ok(expected));
823    }
824
825    #[test]
826    fn match_expressions_work() {
827        let code = r#"
828        match x {
829            (0, y) => y,
830            (x, y) => x,
831        }
832        "#;
833
834        let expected = Expression::Match(
835            Box::new(Expression::Identifier(ast_path("x")).nowhere()),
836            vec![
837                (
838                    Pattern::Tuple(vec![Pattern::integer(0).nowhere(), Pattern::name("y")])
839                        .nowhere(),
840                    Expression::Identifier(ast_path("y")).nowhere(),
841                ),
842                (
843                    Pattern::Tuple(vec![Pattern::name("x"), Pattern::name("y")]).nowhere(),
844                    Expression::Identifier(ast_path("x")).nowhere(),
845                ),
846            ]
847            .nowhere(),
848        )
849        .nowhere();
850
851        check_parse!(code, expression, Ok(expected));
852    }
853
854    #[test]
855    fn blocks_work() {
856        let code = r#"
857            {
858                let a = 0;
859                1
860            }
861            "#;
862
863        let expected = Block {
864            statements: vec![Statement::binding(
865                Pattern::name("a"),
866                None,
867                Expression::int_literal_signed(0).nowhere(),
868            )
869            .nowhere()],
870            result: Some(Expression::int_literal_signed(1).nowhere()),
871        }
872        .nowhere();
873
874        check_parse!(code, block(false), Ok(Some(expected)));
875    }
876
877    #[test]
878    fn blocks_are_expressions() {
879        let code = r#"
880            {
881                let a = 0;
882                1
883            }
884            "#;
885
886        let expected = Expression::Block(Box::new(Block {
887            statements: vec![Statement::binding(
888                Pattern::name("a"),
889                None,
890                Expression::int_literal_signed(0).nowhere(),
891            )
892            .nowhere()],
893            result: Some(Expression::int_literal_signed(1).nowhere()),
894        }))
895        .nowhere();
896
897        check_parse!(code, expression, Ok(expected));
898    }
899
900    #[test]
901    fn infix_operators_work() {
902        let code = r#"
903            1 `infix` 2
904            "#;
905
906        let expected = Expression::Call {
907            kind: CallKind::Function,
908            callee: ast_path("infix"),
909            args: ArgumentList::Positional(vec![
910                Expression::int_literal_signed(1).nowhere(),
911                Expression::int_literal_signed(2).nowhere(),
912            ])
913            .nowhere(),
914            turbofish: None,
915        }
916        .nowhere();
917
918        check_parse!(code, expression, Ok(expected));
919    }
920
921    #[test]
922    fn infix_operator_precedence_is_unchanged() {
923        // NOTE: the exact ordering here is somewhat unimportant, in general one
924        // should probably put parentheses around infix operators anyway. The main
925        // purpose of this test is to prevent accidental changes to the order in the future
926        let code = r#"
927            0 || 1 `infix` 2 `infix` 3
928            "#;
929
930        let expected = Expression::Call {
931            kind: CallKind::Function,
932            callee: ast_path("infix"),
933            args: ArgumentList::Positional(vec![
934                Expression::BinaryOperator(
935                    Box::new(Expression::int_literal_signed(0).nowhere()),
936                    BinaryOperator::LogicalOr.nowhere(),
937                    Box::new(Expression::int_literal_signed(1).nowhere()),
938                )
939                .nowhere(),
940                Expression::Call {
941                    kind: CallKind::Function,
942                    callee: ast_path("infix"),
943                    args: ArgumentList::Positional(vec![
944                        Expression::int_literal_signed(2).nowhere(),
945                        Expression::int_literal_signed(3).nowhere(),
946                    ])
947                    .nowhere(),
948                    turbofish: None,
949                }
950                .nowhere(),
951            ])
952            .nowhere(),
953            turbofish: None,
954        }
955        .nowhere();
956
957        check_parse!(code, expression, Ok(expected));
958    }
959
960    #[test]
961    fn field_access_operator_does_not_require_parens() {
962        let code = r#"x.y.z"#;
963
964        let expected = Expression::FieldAccess(
965            Box::new(
966                Expression::FieldAccess(
967                    Box::new(Expression::Identifier(ast_path("x")).nowhere()),
968                    ast_ident("y"),
969                )
970                .nowhere(),
971            ),
972            ast_ident("z"),
973        )
974        .nowhere();
975
976        check_parse!(code, expression, Ok(expected));
977    }
978
979    #[test]
980    fn array_index_operator_precedence_is_correct() {
981        let code = r#"x && y[z]"#;
982
983        let expected = Expression::BinaryOperator(
984            Box::new(Expression::Identifier(ast_path("x")).nowhere()),
985            BinaryOperator::LogicalAnd.nowhere(),
986            Box::new(
987                Expression::Index(
988                    Box::new(Expression::Identifier(ast_path("y")).nowhere()),
989                    Box::new(Expression::Identifier(ast_path("z")).nowhere()),
990                )
991                .nowhere(),
992            ),
993        )
994        .nowhere();
995
996        check_parse!(code, expression, Ok(expected));
997    }
998
999    #[test]
1000    fn tuple_index_operator_precedence_is_correct() {
1001        let code = r#"y#1#2"#;
1002
1003        let expected = Expression::TupleIndex(
1004            Box::new(
1005                Expression::TupleIndex(
1006                    Box::new(Expression::Identifier(ast_path("y")).nowhere()),
1007                    1u128.nowhere(),
1008                )
1009                .nowhere(),
1010            ),
1011            2.nowhere(),
1012        )
1013        .nowhere();
1014
1015        check_parse!(code, expression, Ok(expected));
1016    }
1017
1018    // Precedence related tests
1019    #[test]
1020    fn subtraction_occurs_in_correct_order() {
1021        let expected_value = Expression::BinaryOperator(
1022            Box::new(
1023                Expression::BinaryOperator(
1024                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1025                    BinaryOperator::Sub.nowhere(),
1026                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1027                )
1028                .nowhere(),
1029            ),
1030            BinaryOperator::Sub.nowhere(),
1031            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
1032        )
1033        .nowhere();
1034
1035        check_parse!("a - b - c", expression, Ok(expected_value));
1036    }
1037
1038    #[test]
1039    fn not_function_call_does_not_invert_function() {
1040        let expected_value = Expression::UnaryOperator(
1041            UnaryOperator::Not.nowhere(),
1042            Box::new(
1043                Expression::Call {
1044                    kind: CallKind::Function,
1045                    callee: ast_path("a"),
1046                    args: ArgumentList::Positional(vec![]).nowhere(),
1047                    turbofish: None,
1048                }
1049                .nowhere(),
1050            ),
1051        )
1052        .nowhere();
1053
1054        check_parse!("!a()", expression, Ok(expected_value));
1055    }
1056
1057    #[test]
1058    fn chained_array_indexing_is_left_to_right() {
1059        let expected_value = Expression::Index(
1060            Box::new(
1061                Expression::Index(
1062                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1063                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1064                )
1065                .nowhere(),
1066            ),
1067            Box::new(Expression::Identifier(ast_path("c")).nowhere()),
1068        )
1069        .nowhere();
1070
1071        check_parse!("a[b][c]", expression, Ok(expected_value));
1072    }
1073
1074    #[test]
1075    fn not_index_result_inverts_whole_result() {
1076        let expected_value = Expression::UnaryOperator(
1077            UnaryOperator::Not.nowhere(),
1078            Box::new(
1079                Expression::Index(
1080                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1081                    Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1082                )
1083                .nowhere(),
1084            ),
1085        )
1086        .nowhere();
1087
1088        check_parse!("!a[b]", expression, Ok(expected_value));
1089    }
1090
1091    #[test]
1092    fn unary_sub_binds_correctly() {
1093        let expected_value = Expression::BinaryOperator(
1094            Box::new(
1095                Expression::UnaryOperator(
1096                    UnaryOperator::Sub.nowhere(),
1097                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1098                )
1099                .nowhere(),
1100            ),
1101            BinaryOperator::Add.nowhere(),
1102            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1103        )
1104        .nowhere();
1105
1106        check_parse!("-a + b", expression, Ok(expected_value));
1107    }
1108
1109    #[test]
1110    fn unary_sub_binds_correctly_without_spaces() {
1111        let expected_value = Expression::BinaryOperator(
1112            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1113            BinaryOperator::Add.nowhere(),
1114            Box::new(
1115                Expression::UnaryOperator(
1116                    UnaryOperator::Sub.nowhere(),
1117                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1118                )
1119                .nowhere(),
1120            ),
1121        )
1122        .nowhere();
1123
1124        check_parse!("b+-a", expression, Ok(expected_value));
1125    }
1126
1127    #[test]
1128    fn binary_sub_binds_correctly_without_spaces() {
1129        let expected_value = Expression::BinaryOperator(
1130            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1131            BinaryOperator::Sub.nowhere(),
1132            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1133        )
1134        .nowhere();
1135
1136        check_parse!("b-a", expression, Ok(expected_value));
1137    }
1138
1139    #[test]
1140    fn deref_operator_works() {
1141        let expected = Expression::UnaryOperator(
1142            UnaryOperator::Dereference.nowhere(),
1143            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1144        )
1145        .nowhere();
1146
1147        check_parse!("*a", expression, Ok(expected));
1148    }
1149
1150    #[test]
1151    fn deref_operator_precedence() {
1152        let expected = Expression::BinaryOperator(
1153            Box::new(
1154                Expression::UnaryOperator(
1155                    UnaryOperator::Dereference.nowhere(),
1156                    Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1157                )
1158                .nowhere(),
1159            ),
1160            BinaryOperator::Add.nowhere(),
1161            Box::new(Expression::Identifier(ast_path("b")).nowhere()),
1162        )
1163        .nowhere();
1164
1165        check_parse!("*a + b", expression, Ok(expected));
1166    }
1167
1168    #[test]
1169    fn ref_operator_works() {
1170        let expected = Expression::UnaryOperator(
1171            UnaryOperator::Reference.nowhere(),
1172            Box::new(Expression::Identifier(ast_path("a")).nowhere()),
1173        )
1174        .nowhere();
1175
1176        check_parse!("&a", expression, Ok(expected));
1177    }
1178}