leo_parser/parser/
type_.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
21pub(super) const TYPE_TOKENS: &[Token] = &[
22    Token::Address,
23    Token::Bool,
24    Token::Field,
25    Token::Future,
26    Token::Group,
27    Token::Scalar,
28    Token::Signature,
29    Token::String,
30    Token::I8,
31    Token::I16,
32    Token::I32,
33    Token::I64,
34    Token::I128,
35    Token::U8,
36    Token::U16,
37    Token::U32,
38    Token::U64,
39    Token::U128,
40];
41
42impl<N: Network> ParserContext<'_, N> {
43    /// Returns a [`IntegerType`] AST node if the given token is a supported integer type, or [`None`].
44    pub(super) fn token_to_int_type(token: &Token) -> Option<IntegerType> {
45        Some(match token {
46            Token::I8 => IntegerType::I8,
47            Token::I16 => IntegerType::I16,
48            Token::I32 => IntegerType::I32,
49            Token::I64 => IntegerType::I64,
50            Token::I128 => IntegerType::I128,
51            Token::U8 => IntegerType::U8,
52            Token::U16 => IntegerType::U16,
53            Token::U32 => IntegerType::U32,
54            Token::U64 => IntegerType::U64,
55            Token::U128 => IntegerType::U128,
56            _ => return None,
57        })
58    }
59
60    /// Returns a [`(Type, Span)`] tuple of AST nodes if the next token represents a primitive type.
61    /// Also returns the span of the parsed token.
62    ///
63    /// These correspond to what the ABNF grammar calls 'named primitive types';
64    /// the 'primitive types' according to the ABNF grammar include also the unit type.
65    pub fn parse_primitive_type(&mut self) -> Result<(Type, Span)> {
66        let span = self.expect_any(TYPE_TOKENS)?;
67        Ok((
68            match &self.prev_token.token {
69                Token::Address => Type::Address,
70                Token::Bool => Type::Boolean,
71                Token::Field => Type::Field,
72                Token::Group => Type::Group,
73                Token::Scalar => Type::Scalar,
74                Token::Signature => Type::Signature,
75                Token::String => Type::String,
76                x => Type::Integer(Self::token_to_int_type(x).expect("invalid int type")),
77            },
78            span,
79        ))
80    }
81
82    /// Returns a [`(Type, Span)`] tuple of AST nodes if the next token represents a type.
83    /// Also returns the span of the parsed token.
84    pub fn parse_type(&mut self) -> Result<(Type, Span)> {
85        if let Some(ident) = self.eat_identifier() {
86            // Check if using external type
87            let file_type = self.look_ahead(1, |t| &t.token);
88            if self.token.token == Token::Dot && (file_type == &Token::Aleo) {
89                // Only allow `.aleo` as the network identifier
90                if file_type == &Token::Leo {
91                    return Err(ParserError::invalid_network(self.token.span).into());
92                }
93
94                // Parse `.aleo/`
95                self.expect(&Token::Dot)?;
96                self.expect(&Token::Aleo)?;
97                self.expect(&Token::Div)?;
98
99                // Parse the record name
100                if let Some(record_name) = self.eat_identifier() {
101                    // Return the external type
102                    return Ok((
103                        Type::Composite(CompositeType {
104                            id: record_name,
105                            const_arguments: Vec::new(), // For now, external composite types can't have const generics
106                            program: Some(ident.name),
107                        }),
108                        ident.span + record_name.span,
109                    ));
110                } else {
111                    return Err(ParserError::invalid_external_type(self.token.span).into());
112                }
113            }
114
115            // Parse a list of const arguments in between `::[..]`
116            let const_arguments = if self.eat(&Token::DoubleColon) {
117                self.parse_bracket_comma_list(|p| p.parse_expression().map(Some))?.0
118            } else {
119                Vec::new()
120            };
121
122            Ok((Type::Composite(CompositeType { id: ident, const_arguments, program: None }), ident.span))
123        } else if self.token.token == Token::LeftSquare {
124            // Parse the left bracket.
125            self.expect(&Token::LeftSquare)?;
126            // Parse the element type.
127            let (element_type, _) = self.parse_type()?;
128            // Parse the semi-colon.
129            self.expect(&Token::Semicolon)?;
130            // Parse the length as an expression.
131            let length = self.parse_expression()?;
132            // Parse the right bracket.
133            self.expect(&Token::RightSquare)?;
134            // Return the array type.
135            Ok((Type::Array(ArrayType::new(element_type, length)), self.prev_token.span))
136        } else if self.token.token == Token::LeftParen {
137            let (types, _, span) = self.parse_paren_comma_list(|p| p.parse_type().map(Some))?;
138            match types.len() {
139                // If the parenthetical block is empty, e.g. `()` or `( )`, it should be parsed into `Unit` types.
140                0 => Ok((Type::Unit, span)),
141                // If the parenthetical block contains a single type, e.g. `(u8)`, emit an error, since tuples must have at least two elements.
142                1 => Err(ParserError::tuple_must_have_at_least_two_elements("type", span).into()),
143                // Otherwise, parse it into a `Tuple` type.
144                // Note: This is the only place where `Tuple` type is constructed in the parser.
145                _ => Ok((Type::Tuple(TupleType::new(types.into_iter().map(|t| t.0).collect())), span)),
146            }
147        } else if self.token.token == Token::Future {
148            // Parse the `Future` token.
149            let span = self.expect(&Token::Future)?;
150            // Parse the explicit future type, e.g. `Future<Fn(u32, u32)>`, `Future<Fn(u32, Future<Fn(u32, u32, u64)>)>` etc.
151            if self.token.token == Token::Lt {
152                // Expect the sequence `<`, `Fn`.
153                self.expect(&Token::Lt)?;
154                self.expect(&Token::Fn)?;
155                // Parse the parenthesized list of function arguments.
156                let (types, _, full_span) = self.parse_paren_comma_list(|p| p.parse_type().map(Some))?;
157                // Expect the closing `>`.
158                self.expect(&Token::Gt)?;
159                Ok((
160                    Type::Future(FutureType::new(types.into_iter().map(|t| t.0).collect(), None, true)),
161                    span + full_span,
162                ))
163            } else {
164                Ok((Type::Future(Default::default()), span))
165            }
166        } else {
167            self.parse_primitive_type()
168        }
169    }
170}