Skip to main content

spade_parser/
expression.rs

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