/ compiler / ast / src / types / array.rs
array.rs
  1  // Copyright (C) 2019-2025 ADnet Contributors
  2  // This file is part of the ADL library.
  3  
  4  // The ADL 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 ADL 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 ADL library. If not, see <https://www.gnu.org/licenses/>.
 16  
 17  use crate::{Expression, IntegerType, Literal, LiteralVariant, Type};
 18  use snarkvm::console::program::ArrayType as ConsoleArrayType;
 19  
 20  use adl_span::{Span, Symbol};
 21  use serde::{Deserialize, Serialize};
 22  use snarkvm::prelude::Network;
 23  use std::fmt;
 24  
 25  /// An array type.
 26  #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 27  pub struct ArrayType {
 28      pub element_type: Box<Type>,
 29      pub length: Box<Expression>,
 30  }
 31  
 32  impl ArrayType {
 33      /// Creates a new array type.
 34      pub fn new(element: Type, length: Expression) -> Self {
 35          Self { element_type: Box::new(element), length: Box::new(length) }
 36      }
 37  
 38      /// Creates a new bit array type.
 39      pub fn bit_array(length: u32) -> Self {
 40          Self {
 41              element_type: Box::new(Type::Boolean),
 42              length: Box::new(Expression::Literal(Literal {
 43                  variant: LiteralVariant::Integer(IntegerType::U32, length.to_string()),
 44                  id: Default::default(),
 45                  span: Span::default(),
 46              })),
 47          }
 48      }
 49  
 50      /// Returns the element type of the array.
 51      pub fn element_type(&self) -> &Type {
 52          &self.element_type
 53      }
 54  
 55      /// Returns the base element type of the array.
 56      pub fn base_element_type(&self) -> &Type {
 57          match self.element_type.as_ref() {
 58              Type::Array(array_type) => array_type.base_element_type(),
 59              type_ => type_,
 60          }
 61      }
 62  
 63      pub fn from_snarkvm<N: Network>(array_type: &ConsoleArrayType<N>, program: Option<Symbol>) -> Self {
 64          Self {
 65              element_type: Box::new(Type::from_snarkvm(array_type.next_element_type(), program)),
 66              length: Box::new(Expression::Literal(Literal {
 67                  variant: LiteralVariant::Integer(IntegerType::U32, array_type.length().to_string().replace("u32", "")),
 68                  id: Default::default(),
 69                  span: Span::default(),
 70              })),
 71          }
 72      }
 73  
 74      pub fn to_snarkvm<N: Network>(&self) -> anyhow::Result<ConsoleArrayType<N>> {
 75          let length = if let Expression::Literal(literal) = &*self.length {
 76              match &literal.variant {
 77                  LiteralVariant::Integer(_, s) => s.parse::<u32>().unwrap(),
 78                  LiteralVariant::Unsuffixed(s) => s.parse::<u32>().unwrap(),
 79                  _ => anyhow::bail!("Array length must be an integer literal"),
 80              }
 81          } else {
 82              anyhow::bail!("Array length must be an integer literal")
 83          };
 84  
 85          ConsoleArrayType::new(self.element_type.to_snarkvm()?, vec![snarkvm::console::types::U32::new(length)])
 86      }
 87  }
 88  
 89  impl fmt::Display for ArrayType {
 90      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 91          // For display purposes (in error messages for example.), do not include the type suffix.
 92          if let Expression::Literal(literal) = &*self.length
 93              && let LiteralVariant::Integer(_, s) = &literal.variant
 94          {
 95              return write!(f, "[{}; {s}]", self.element_type);
 96          }
 97  
 98          write!(f, "[{}; {}]", self.element_type, self.length)
 99      }
100  }
101  
102  impl From<ArrayType> for Type {
103      fn from(value: ArrayType) -> Self {
104          Type::Array(value)
105      }
106  }