use crate::{ArrayDimensions, Identifier, IntegerType};
use leo_grammar::types::{ArrayType, CircuitType, DataType, TupleType, Type as GrammarType};
use leo_input::types::{
ArrayType as InputArrayType,
DataType as InputDataType,
TupleType as InputTupleType,
Type as InputType,
};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Type {
Address,
Boolean,
Field,
Group,
IntegerType(IntegerType),
Array(Box<Type>, ArrayDimensions),
Tuple(Vec<Type>),
Circuit(Identifier),
SelfType,
}
impl Type {
pub fn is_self(&self) -> bool {
matches!(self, Type::SelfType)
}
pub fn is_circuit(&self) -> bool {
matches!(self, Type::Circuit(_))
}
pub fn eq_flat(&self, other: &Self) -> bool {
match (self, other) {
(Type::Address, Type::Address) => true,
(Type::Boolean, Type::Boolean) => true,
(Type::Field, Type::Field) => true,
(Type::Group, Type::Group) => true,
(Type::IntegerType(left), Type::IntegerType(right)) => left.eq(&right),
(Type::Circuit(left), Type::Circuit(right)) => left.eq(&right),
(Type::SelfType, Type::SelfType) => true,
(Type::Array(left_type, left_dim), Type::Array(right_type, right_dim)) => {
let mut left_dim_owned = left_dim.to_owned();
let mut right_dim_owned = right_dim.to_owned();
let left_first = left_dim_owned.remove_first();
let right_first = right_dim_owned.remove_first();
if left_first.ne(&right_first) {
return false;
}
let left_new_type = inner_array_type(*left_type.to_owned(), left_dim_owned);
let right_new_type = inner_array_type(*right_type.to_owned(), right_dim_owned);
left_new_type.eq_flat(&right_new_type)
}
(Type::Tuple(left), Type::Tuple(right)) => left
.iter()
.zip(right)
.all(|(left_type, right_type)| left_type.eq_flat(right_type)),
_ => false,
}
}
}
impl From<DataType> for Type {
fn from(data_type: DataType) -> Self {
match data_type {
DataType::Address(_type) => Type::Address,
DataType::Boolean(_type) => Type::Boolean,
DataType::Field(_type) => Type::Field,
DataType::Group(_type) => Type::Group,
DataType::Integer(_type) => Type::IntegerType(IntegerType::from(_type)),
}
}
}
impl<'ast> From<ArrayType<'ast>> for Type {
fn from(array_type: ArrayType<'ast>) -> Self {
let element_type = Box::new(Type::from(*array_type.type_));
let dimensions = ArrayDimensions::from(array_type.dimensions);
Type::Array(element_type, dimensions)
}
}
impl<'ast> From<TupleType<'ast>> for Type {
fn from(tuple_type: TupleType<'ast>) -> Self {
let types = tuple_type.types.into_iter().map(Type::from).collect();
Type::Tuple(types)
}
}
impl<'ast> From<CircuitType<'ast>> for Type {
fn from(circuit_type: CircuitType<'ast>) -> Self {
Type::Circuit(Identifier::from(circuit_type.identifier))
}
}
impl<'ast> From<GrammarType<'ast>> for Type {
fn from(type_: GrammarType<'ast>) -> Self {
match type_ {
GrammarType::Basic(type_) => Type::from(type_),
GrammarType::Array(type_) => Type::from(type_),
GrammarType::Tuple(type_) => Type::from(type_),
GrammarType::Circuit(type_) => Type::from(type_),
GrammarType::SelfType(_type) => Type::SelfType,
}
}
}
impl From<InputDataType> for Type {
fn from(data_type: InputDataType) -> Self {
match data_type {
InputDataType::Address(_type) => Type::Address,
InputDataType::Boolean(_type) => Type::Boolean,
InputDataType::Field(_type) => Type::Field,
InputDataType::Group(_type) => Type::Group,
InputDataType::Integer(type_) => Type::IntegerType(IntegerType::from(type_)),
}
}
}
impl<'ast> From<InputArrayType<'ast>> for Type {
fn from(array_type: InputArrayType<'ast>) -> Self {
let element_type = Box::new(Type::from(*array_type.type_));
let dimensions = ArrayDimensions::from(array_type.dimensions);
Type::Array(element_type, dimensions)
}
}
impl<'ast> From<InputTupleType<'ast>> for Type {
fn from(tuple_type: InputTupleType<'ast>) -> Self {
let types = tuple_type.types_.into_iter().map(Type::from).collect();
Type::Tuple(types)
}
}
impl<'ast> From<InputType<'ast>> for Type {
fn from(type_: InputType<'ast>) -> Self {
match type_ {
InputType::Basic(type_) => Type::from(type_),
InputType::Array(type_) => Type::from(type_),
InputType::Tuple(type_) => Type::from(type_),
}
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Type::Address => write!(f, "address"),
Type::Boolean => write!(f, "bool"),
Type::Field => write!(f, "field"),
Type::Group => write!(f, "group"),
Type::IntegerType(ref integer_type) => write!(f, "{}", integer_type),
Type::Circuit(ref variable) => write!(f, "circuit {}", variable),
Type::SelfType => write!(f, "SelfType"),
Type::Array(ref array, ref dimensions) => write!(f, "[{}; {}]", *array, dimensions),
Type::Tuple(ref tuple) => {
let types = tuple.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");
write!(f, "({})", types)
}
}
}
}
pub fn inner_array_type(element_type: Type, dimensions: ArrayDimensions) -> Type {
if dimensions.is_empty() {
element_type
} else {
Type::Array(Box::new(element_type), dimensions)
}
}