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}