leo_parser/parser/
statement.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use super::*;
18
19use leo_errors::{ParserError, Result};
20
21const ASSIGN_TOKENS: &[Token] = &[
22    Token::Assign,
23    Token::AddAssign,
24    Token::SubAssign,
25    Token::MulAssign,
26    Token::DivAssign,
27    Token::RemAssign,
28    Token::PowAssign,
29    Token::OrAssign,
30    Token::AndAssign,
31    Token::BitAndAssign,
32    Token::BitOrAssign,
33    Token::BitXorAssign,
34    Token::ShrAssign,
35    Token::ShlAssign,
36];
37
38impl ParserContext<'_> {
39    /// Returns a [`Statement`] AST node if the next tokens represent a statement.
40    pub(crate) fn parse_statement(&mut self) -> Result<Statement> {
41        match &self.token.token {
42            Token::Return => Ok(self.parse_return_statement()?.into()),
43            Token::If => Ok(self.parse_conditional_statement()?.into()),
44            Token::For => Ok(self.parse_loop_statement()?.into()),
45            Token::Assert | Token::AssertEq | Token::AssertNeq => Ok(self.parse_assert_statement()?),
46            Token::Let => Ok(self.parse_definition_statement()?.into()),
47            Token::Const => Ok(self.parse_const_declaration_statement()?.into()),
48            Token::LeftCurly => Ok(self.parse_block()?.into()),
49            _ => Ok(self.parse_assign_statement()?),
50        }
51    }
52
53    /// Returns an [`AssertStatement`] AST node if the next tokens represent an assertion statement.
54    fn parse_assert_statement(&mut self) -> Result<Statement> {
55        // Check which variant of the assert statement is being used.
56        // Note that `parse_assert_statement` is called only if the next token is an assertion token.
57        let is_assert = self.check(&Token::Assert);
58        let is_assert_eq = self.check(&Token::AssertEq);
59        let is_assert_neq = self.check(&Token::AssertNeq);
60        // Parse the span of the assertion statement.
61        let span = self.expect_any(&[Token::Assert, Token::AssertEq, Token::AssertNeq])?;
62        // Parse the left parenthesis token.
63        self.expect(&Token::LeftParen)?;
64        // Parse the variant.
65        let variant = match (is_assert, is_assert_eq, is_assert_neq) {
66            (true, false, false) => AssertVariant::Assert(self.parse_expression()?),
67            (false, true, false) => AssertVariant::AssertEq(self.parse_expression()?, {
68                self.expect(&Token::Comma)?;
69                self.parse_expression()?
70            }),
71            (false, false, true) => AssertVariant::AssertNeq(self.parse_expression()?, {
72                self.expect(&Token::Comma)?;
73                self.parse_expression()?
74            }),
75            _ => unreachable!("The call the `expect_any` ensures that only one of the three tokens is true."),
76        };
77        // Parse the right parenthesis token.
78        self.expect(&Token::RightParen)?;
79        // Parse the semicolon token.
80        self.expect(&Token::Semicolon)?;
81
82        // Return the assertion statement.
83        Ok(AssertStatement { variant, span, id: self.node_builder.next_id() }.into())
84    }
85
86    /// Returns an [`AssignStatement`] AST node if the next tokens represent an assignment, otherwise expects an expression statement.
87    fn parse_assign_statement(&mut self) -> Result<Statement> {
88        let expression = self.parse_expression()?;
89        if self.eat_any(ASSIGN_TOKENS) {
90            // Determine the corresponding binary operation for each token, if it exists.
91            let operation = match &self.prev_token.token {
92                Token::Assign => None,
93                Token::AddAssign => Some(BinaryOperation::Add),
94                Token::SubAssign => Some(BinaryOperation::Sub),
95                Token::MulAssign => Some(BinaryOperation::Mul),
96                Token::DivAssign => Some(BinaryOperation::Div),
97                Token::RemAssign => Some(BinaryOperation::Rem),
98                Token::PowAssign => Some(BinaryOperation::Pow),
99                Token::OrAssign => Some(BinaryOperation::Or),
100                Token::AndAssign => Some(BinaryOperation::And),
101                Token::BitAndAssign => Some(BinaryOperation::BitwiseAnd),
102                Token::BitOrAssign => Some(BinaryOperation::BitwiseOr),
103                Token::BitXorAssign => Some(BinaryOperation::Xor),
104                Token::ShrAssign => Some(BinaryOperation::Shr),
105                Token::ShlAssign => Some(BinaryOperation::Shl),
106                _ => panic!("`parse_assign_statement` shouldn't produce this"),
107            };
108
109            let value = self.parse_expression()?;
110            self.expect(&Token::Semicolon)?;
111
112            // Construct the span for the statement.
113            let span = expression.span() + value.span();
114
115            // Construct a copy of the lhs with a unique id.
116            let mut left = expression.clone();
117            left.set_id(self.node_builder.next_id());
118
119            // Simplify complex assignments into simple assignments.
120            // For example, `x += 1` becomes `x = x + 1`, while simple assignments like `x = y` remain unchanged.
121            let value = match operation {
122                None => value,
123                Some(op) => BinaryExpression { left, right: value, op, span, id: self.node_builder.next_id() }.into(),
124            };
125
126            return Ok(AssignStatement { span, place: expression, value, id: self.node_builder.next_id() }.into());
127        }
128
129        let end = self.expect(&Token::Semicolon)?;
130
131        Ok(ExpressionStatement { span: expression.span() + end, expression, id: self.node_builder.next_id() }.into())
132    }
133
134    /// Returns a [`Block`] AST node if the next tokens represent a block of statements.
135    pub(super) fn parse_block(&mut self) -> Result<Block> {
136        self.parse_list(Delimiter::Brace, None, |p| p.parse_statement().map(Some)).map(|(statements, _, span)| Block {
137            statements,
138            span,
139            id: self.node_builder.next_id(),
140        })
141    }
142
143    /// Returns a [`ReturnStatement`] AST node if the next tokens represent a return statement.
144    fn parse_return_statement(&mut self) -> Result<ReturnStatement> {
145        let start = self.expect(&Token::Return)?;
146
147        let expression = match self.token.token {
148            // If the next token is a semicolon, implicitly return a unit expression, `()`.
149            Token::Semicolon => {
150                Expression::Unit(UnitExpression { span: self.token.span, id: self.node_builder.next_id() })
151            }
152            // Otherwise, attempt to parse an expression.
153            _ => self.parse_expression()?,
154        };
155        let end = self.expect(&Token::Semicolon)?;
156        let span = start + end;
157        Ok(ReturnStatement { span, expression, id: self.node_builder.next_id() })
158    }
159
160    /// Returns a [`ConditionalStatement`] AST node if the next tokens represent a conditional statement.
161    fn parse_conditional_statement(&mut self) -> Result<ConditionalStatement> {
162        let start = self.expect(&Token::If)?;
163        self.disallow_struct_construction = true;
164        let expr = self.parse_conditional_expression()?;
165        self.disallow_struct_construction = false;
166        let body = self.parse_block()?;
167        let next = if self.eat(&Token::Else) {
168            let s = self.parse_statement()?;
169            if !matches!(s, Statement::Block(_) | Statement::Conditional(_)) {
170                self.emit_err(ParserError::unexpected_statement(&s, "Block or Conditional", s.span()));
171            }
172            Some(Box::new(s))
173        } else {
174            None
175        };
176
177        Ok(ConditionalStatement {
178            span: start + next.as_ref().map(|x| x.span()).unwrap_or(body.span),
179            condition: expr,
180            then: body,
181            otherwise: next,
182            id: self.node_builder.next_id(),
183        })
184    }
185
186    /// Returns an [`IterationStatement`] AST node if the next tokens represent an iteration statement.
187    fn parse_loop_statement(&mut self) -> Result<IterationStatement> {
188        let start_span = self.expect(&Token::For)?;
189
190        // Parse the iterator name
191        let ident = self.expect_identifier()?;
192
193        // The type annotation is optional
194        let type_ = if self.eat(&Token::Colon) { Some(self.parse_type()?.0) } else { None };
195        self.expect(&Token::In)?;
196
197        // Parse iteration range.
198        let start = self.parse_expression()?;
199        self.expect(&Token::DotDot)?;
200        self.disallow_struct_construction = true;
201        let stop = self.parse_conditional_expression()?;
202        self.disallow_struct_construction = false;
203
204        let block = self.parse_block()?;
205
206        Ok(IterationStatement {
207            span: start_span + block.span,
208            variable: ident,
209            type_,
210            start,
211            stop,
212            inclusive: false,
213            block,
214            id: self.node_builder.next_id(),
215        })
216    }
217
218    /// Returns a [`ConstDeclaration`] AST node if the next tokens represent a const declaration statement.
219    pub(super) fn parse_const_declaration_statement(&mut self) -> Result<ConstDeclaration> {
220        self.expect(&Token::Const)?;
221        let decl_span = self.prev_token.span;
222
223        // Parse variable name and type.
224        let (place, type_, _) = self.parse_typed_ident()?;
225
226        self.expect(&Token::Assign)?;
227        let value = self.parse_expression()?;
228        self.expect(&Token::Semicolon)?;
229
230        Ok(ConstDeclaration { span: decl_span + value.span(), place, type_, value, id: self.node_builder.next_id() })
231    }
232
233    fn parse_definition_place(&mut self) -> Result<DefinitionPlace> {
234        if let Some(identifier) = self.eat_identifier() {
235            return Ok(DefinitionPlace::Single(identifier));
236        }
237
238        let (identifiers, _, _) = self.parse_paren_comma_list(|p| {
239            let span = p.token.span;
240
241            let eaten = p.eat_identifier();
242
243            if eaten.is_some() { Ok(eaten) } else { Err(ParserError::expected_identifier(span).into()) }
244        })?;
245
246        Ok(DefinitionPlace::Multiple(identifiers))
247    }
248
249    /// Returns a [`DefinitionStatement`] AST node if the next tokens represent a definition statement.
250    pub(super) fn parse_definition_statement(&mut self) -> Result<DefinitionStatement> {
251        self.expect(&Token::Let)?;
252        let decl_span = self.prev_token.span;
253
254        // Parse definition place which can either be an identifier or a group of identifiers.
255        let place = self.parse_definition_place()?;
256
257        // The type annotation is optional
258        let type_ = if self.eat(&Token::Colon) { Some(self.parse_type()?.0) } else { None };
259
260        self.expect(&Token::Assign)?;
261        let value = self.parse_expression()?;
262        self.expect(&Token::Semicolon)?;
263
264        Ok(DefinitionStatement { span: decl_span + value.span(), place, type_, value, id: self.node_builder.next_id() })
265    }
266}