1use crate::{syntax::*, 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 Custom(QualifiedName),
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_add_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
60impl std::ops::Mul for Type {
61 type Output = Type;
62
63 fn mul(self, rhs: Self) -> Self::Output {
64 if self == Self::Invalid || rhs == Self::Invalid {
65 return Self::Invalid;
66 }
67
68 match (self, rhs) {
69 (Type::Integer, ty) | (ty, Type::Integer) => ty,
70 (Type::Quantity(lhs), Type::Quantity(rhs)) => Type::Quantity(lhs * rhs),
71 (ty, Type::Array(array_type)) | (Type::Array(array_type), ty) => *array_type * ty,
72 (Type::Tuple(_), _) | (_, Type::Tuple(_)) => todo!(),
73 (Type::Matrix(_), _) | (_, Type::Matrix(_)) => todo!(),
74 (lhs, rhs) => unimplemented!("Multiplication for {lhs} * {rhs}"),
75 }
76 }
77}
78
79impl std::ops::Div for Type {
80 type Output = Type;
81
82 fn div(self, rhs: Self) -> Self::Output {
83 if self == Self::Invalid || rhs == Self::Invalid {
84 return Self::Invalid;
85 }
86
87 match (self, rhs) {
88 (Type::Integer, ty) | (ty, Type::Integer) => ty,
89 (Type::Quantity(lhs), Type::Quantity(rhs)) => Type::Quantity(lhs / rhs),
90 (Type::Array(array_type), ty) => *array_type / ty,
91 (Type::Tuple(_), _) => todo!(),
92 (Type::Matrix(_), _) | (_, Type::Matrix(_)) => todo!(),
93 (lhs, rhs) => unimplemented!("Division for {lhs} * {rhs}"),
94 }
95 }
96}
97
98impl From<QuantityType> for Type {
99 fn from(value: QuantityType) -> Self {
100 Type::Quantity(value)
101 }
102}
103
104impl std::fmt::Display for Type {
105 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
106 match self {
107 Self::Invalid => write!(f, crate::invalid_no_ansi!(TYPE)),
108 Self::Integer => write!(f, "Integer"),
109 Self::Quantity(quantity) => write!(f, "{quantity}"),
110 Self::String => write!(f, "String"),
111 Self::Bool => write!(f, "Bool"),
112 Self::Array(t) => write!(f, "[{t}]"),
113 Self::Tuple(t) => write!(f, "{t}"),
114 Self::Matrix(t) => write!(f, "{t}"),
115 Self::Models => write!(f, "Models"),
116 Self::Custom(n) => write!(f, "Custom({n})"),
117 }
118 }
119}
120
121impl std::fmt::Debug for Type {
122 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
123 match self {
124 Self::Invalid => write!(f, crate::invalid!(TYPE)),
125 Self::Integer => write!(f, "Integer"),
126 Self::Quantity(quantity) => write!(f, "{quantity}"),
127 Self::String => write!(f, "String"),
128 Self::Bool => write!(f, "Bool"),
129 Self::Array(t) => write!(f, "[{t}]"),
130 Self::Tuple(t) => write!(f, "{t}"),
131 Self::Matrix(t) => write!(f, "{t}"),
132 Self::Models => write!(f, "Models"),
133 Self::Custom(n) => write!(f, "Custom({n})"),
134 }
135 }
136}
137
138#[test]
139fn builtin_type() {
140 use crate::parser::*;
141
142 let ty = Parser::parse_rule::<TypeAnnotation>(Rule::r#type, "Integer", 0).expect("test error");
143 assert_eq!(ty.0.to_string(), "Integer");
144 assert_eq!(ty.0.value, Type::Integer);
145}