1use crate::ty::*;
7
8#[derive(Clone, PartialEq, Eq, Hash)]
10pub enum Type {
11 Invalid,
13 Integer,
15 Quantity(QuantityType),
17 String,
19 Bool,
21 Array(Box<Type>),
23 Tuple(Box<TupleType>),
25 Matrix(MatrixType),
27 Models,
29 Target,
31}
32
33impl Type {
34 pub fn scalar() -> Self {
36 Self::Quantity(QuantityType::Scalar)
37 }
38
39 pub fn length() -> Self {
41 Self::Quantity(QuantityType::Length)
42 }
43
44 pub fn is_array_of(&self, ty: &Type) -> bool {
46 match self {
47 Self::Array(array_type) => array_type.as_ref() == ty,
48 _ => false,
49 }
50 }
51
52 pub fn is_compatible_to(&self, rhs: &Self) -> bool {
54 rhs == self
55 || (*self == Type::Integer && *rhs == Type::scalar())
56 || (*rhs == Type::Integer && *self == Type::scalar())
57 }
58
59 pub fn is_matching(&self, param_type: &Type) -> bool {
61 match (self, param_type) {
62 (_, Type::Quantity(QuantityType::Scalar)) => {
63 self == &Type::scalar()
64 || self == &Type::Integer
65 || self.is_array_of(&Type::scalar())
66 || self.is_array_of(&Type::Integer)
67 }
68 (Type::Tuple(ty_s), Type::Tuple(ty_p)) => ty_s.matches(ty_p),
69 _ => self == param_type || self.is_array_of(param_type),
70 }
71 }
72}
73
74impl std::ops::Mul for Type {
75 type Output = Type;
76
77 fn mul(self, rhs: Self) -> Self::Output {
78 if self == Self::Invalid || rhs == Self::Invalid {
79 return Self::Invalid;
80 }
81
82 match (self, rhs) {
83 (Type::Integer, ty) | (ty, Type::Integer) => ty,
84 (Type::Quantity(lhs), Type::Quantity(rhs)) => Type::Quantity(lhs * rhs),
85 (ty, Type::Array(array_type)) | (Type::Array(array_type), ty) => *array_type * ty,
86 (Type::Tuple(_), _) | (_, Type::Tuple(_)) => todo!(),
87 (Type::Matrix(_), _) | (_, Type::Matrix(_)) => todo!(),
88 (lhs, rhs) => unimplemented!("Multiplication for {lhs} * {rhs}"),
89 }
90 }
91}
92
93impl std::ops::Div for Type {
94 type Output = Type;
95
96 fn div(self, rhs: Self) -> Self::Output {
97 if self == Self::Invalid || rhs == Self::Invalid {
98 return Self::Invalid;
99 }
100
101 match (self, rhs) {
102 (Type::Integer, ty) | (ty, Type::Integer) => ty,
103 (Type::Quantity(lhs), Type::Quantity(rhs)) => Type::Quantity(lhs / rhs),
104 (Type::Array(array_type), ty) => *array_type / ty,
105 (Type::Tuple(_), _) => todo!(),
106 (Type::Matrix(_), _) | (_, Type::Matrix(_)) => todo!(),
107 (lhs, rhs) => unimplemented!("Division for {lhs} * {rhs}"),
108 }
109 }
110}
111
112impl From<QuantityType> for Type {
113 fn from(value: QuantityType) -> Self {
114 Type::Quantity(value)
115 }
116}
117
118impl std::fmt::Display for Type {
119 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
120 match self {
121 Self::Invalid => write!(f, crate::invalid_no_ansi!(TYPE)),
122 Self::Integer => write!(f, "Integer"),
123 Self::Quantity(quantity) => write!(f, "{quantity}"),
124 Self::String => write!(f, "String"),
125 Self::Bool => write!(f, "Bool"),
126 Self::Array(t) => write!(f, "[{t}]"),
127 Self::Tuple(t) => write!(f, "{t}"),
128 Self::Matrix(t) => write!(f, "{t}"),
129 Self::Models => write!(f, "Models"),
130 Self::Target => write!(f, "Target"),
131 }
132 }
133}
134
135impl std::fmt::Debug for Type {
136 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
137 match self {
138 Self::Invalid => write!(f, crate::invalid!(TYPE)),
139 Self::Integer => write!(f, "Integer"),
140 Self::Quantity(quantity) => write!(f, "{quantity}"),
141 Self::String => write!(f, "String"),
142 Self::Bool => write!(f, "Bool"),
143 Self::Array(t) => write!(f, "[{t}]"),
144 Self::Tuple(t) => write!(f, "{t}"),
145 Self::Matrix(t) => write!(f, "{t}"),
146 Self::Models => write!(f, "Models"),
147 Self::Target => write!(f, "Target"),
148 }
149 }
150}
151
152#[test]
153fn builtin_type() {
154 use crate::parser::*;
155 use crate::syntax::*;
156
157 let ty = Parser::parse_rule::<TypeAnnotation>(Rule::r#type, "Integer", 0).expect("test error");
158 assert_eq!(ty.0.to_string(), "Integer");
159 assert_eq!(ty.0.value, Type::Integer);
160}
161
162#[test]
163fn type_matching() {
164 assert!(Type::scalar().is_matching(&Type::scalar()));
165 assert!(!Type::scalar().is_matching(&Type::Integer));
166 assert!(Type::Integer.is_matching(&Type::scalar()));
167 assert!(!Type::scalar().is_matching(&Type::String));
168 assert!(!Type::String.is_matching(&Type::scalar()));
169}