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 Model,
29}
30
31impl Type {
32 pub fn scalar() -> Self {
34 Self::Quantity(QuantityType::Scalar)
35 }
36
37 pub fn length() -> Self {
39 Self::Quantity(QuantityType::Length)
40 }
41
42 pub fn is_array_of(&self, ty: &Type) -> bool {
44 match self {
45 Self::Array(array_type) => array_type.as_ref() == ty,
46 _ => false,
47 }
48 }
49
50 pub fn is_compatible_to(&self, rhs: &Self) -> bool {
52 rhs == self
53 || (*self == Type::Integer && *rhs == Type::scalar())
54 || (*rhs == Type::Integer && *self == Type::scalar())
55 }
56
57 pub fn is_matching(&self, param_type: &Type) -> bool {
59 match (self, param_type) {
60 (_, Type::Quantity(QuantityType::Scalar)) => {
61 self == &Type::scalar()
62 || self == &Type::Integer
63 || self.is_array_of(&Type::scalar())
64 || self.is_array_of(&Type::Integer)
65 }
66 (Type::Tuple(ty_s), Type::Tuple(ty_p)) => ty_s.is_matching(ty_p),
67 _ => self == param_type || self.is_array_of(param_type),
68 }
69 }
70}
71
72impl std::ops::Mul for Type {
73 type Output = Type;
74
75 fn mul(self, rhs: Self) -> Self::Output {
76 if self == Self::Invalid || rhs == Self::Invalid {
77 return Self::Invalid;
78 }
79
80 match (self, rhs) {
81 (Type::Integer, ty) | (ty, Type::Integer) => ty,
82 (Type::Quantity(lhs), Type::Quantity(rhs)) => Type::Quantity(lhs * rhs),
83 (ty, Type::Array(array_type)) | (Type::Array(array_type), ty) => *array_type * ty,
84 (Type::Tuple(_), _) | (_, Type::Tuple(_)) => todo!(),
85 (Type::Matrix(_), _) | (_, Type::Matrix(_)) => todo!(),
86 (lhs, rhs) => unimplemented!("Multiplication for {lhs} * {rhs}"),
87 }
88 }
89}
90
91impl std::ops::Div for Type {
92 type Output = Type;
93
94 fn div(self, rhs: Self) -> Self::Output {
95 if self == Self::Invalid || rhs == Self::Invalid {
96 return Self::Invalid;
97 }
98
99 match (self, rhs) {
100 (Type::Integer, ty) | (ty, Type::Integer) => ty,
101 (Type::Quantity(lhs), Type::Quantity(rhs)) => Type::Quantity(lhs / rhs),
102 (Type::Array(array_type), ty) => *array_type / ty,
103 (Type::Tuple(_), _) => todo!(),
104 (Type::Matrix(_), _) | (_, Type::Matrix(_)) => todo!(),
105 (lhs, rhs) => unimplemented!("Division for {lhs} * {rhs}"),
106 }
107 }
108}
109
110impl From<QuantityType> for Type {
111 fn from(value: QuantityType) -> Self {
112 Type::Quantity(value)
113 }
114}
115
116impl std::fmt::Display for Type {
117 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
118 match self {
119 Self::Invalid => write!(f, microcad_lang_base::invalid_no_ansi!(TYPE)),
120 Self::Integer => write!(f, "Integer"),
121 Self::Quantity(quantity) => write!(f, "{quantity}"),
122 Self::String => write!(f, "String"),
123 Self::Bool => write!(f, "Bool"),
124 Self::Array(t) => write!(f, "[{t}]"),
125 Self::Tuple(t) => write!(f, "{t}"),
126 Self::Matrix(t) => write!(f, "{t}"),
127 Self::Model => write!(f, "Model"),
128 }
129 }
130}
131
132impl std::fmt::Debug for Type {
133 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
134 match self {
135 Self::Invalid => write!(f, microcad_lang_base::invalid!(TYPE)),
136 Self::Integer => write!(f, "Integer"),
137 Self::Quantity(quantity) => write!(f, "{quantity}"),
138 Self::String => write!(f, "String"),
139 Self::Bool => write!(f, "Bool"),
140 Self::Array(t) => write!(f, "[{t}]"),
141 Self::Tuple(t) => write!(f, "{t}"),
142 Self::Matrix(t) => write!(f, "{t}"),
143 Self::Model => write!(f, "Models"),
144 }
145 }
146}
147
148#[test]
149fn type_matching() {
150 assert!(Type::scalar().is_matching(&Type::scalar()));
151 assert!(!Type::scalar().is_matching(&Type::Integer));
152 assert!(Type::Integer.is_matching(&Type::scalar()));
153 assert!(!Type::scalar().is_matching(&Type::String));
154 assert!(!Type::String.is_matching(&Type::scalar()));
155}