1use std::{fmt::Display, str::FromStr};
2
3use crate::loader::Module;
4
5#[derive(Default, Debug, Clone, PartialEq, Eq)]
6pub enum VariableType {
7 #[default]
8 Void,
9 Bool,
10 Str,
11 Int,
12 Char,
13 Any,
15 Unknown,
16 Func {
17 params: Vec<VariableType>,
18 return_type: Box<VariableType>,
19 source: Option<Module<()>>,
20 },
21 ArraySlice(Box<VariableType>),
22 TupleArray {
23 item_type: Box<VariableType>,
24 size: usize,
25 },
26}
27
28pub struct VariableParseError(String);
29
30impl FromStr for VariableType {
31 type Err = VariableParseError;
32
33 fn from_str(s: &str) -> Result<Self, Self::Err> {
34 match s {
35 "void" => Ok(Self::Void),
36 "bool" => Ok(Self::Bool),
37 "str" => Ok(Self::Str),
38 "int" => Ok(Self::Int),
39 "any" => Ok(Self::Any),
40 "char" => Ok(Self::Char),
41 "unknown" => Ok(Self::Unknown),
42 _ => Err(VariableParseError(format!("Invalid type '{s}'"))),
43 }
44 }
45}
46
47impl Display for VariableType {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 use VariableType::*;
50
51 let value = &match self {
52 Void => "void".to_owned(),
53 Bool => "bool".to_owned(),
54 Int => "int".to_owned(),
55 Str => "str".to_owned(),
56 Any => "any".to_owned(),
57 Char => "char".to_owned(),
58 Unknown => "unknown".to_owned(),
59 Func {
60 params,
61 return_type: return_value,
62 ..
63 } => format!("{params:?} -> {return_value:?}"),
64 ArraySlice(item_type) => format!("&[{item_type}]"),
65 TupleArray { item_type, size } => format!("[{item_type}; {size}]"),
66 };
67
68 f.write_str(value)
69 }
70}
71
72#[derive(Debug, PartialEq)]
73pub struct VariableConversionError;
74
75impl VariableType {
76 pub fn size(&self) -> usize {
77 match self {
78 VariableType::Void => 0,
79 VariableType::Bool => 1,
80 VariableType::Str => 8,
81 VariableType::Int => 8,
82 VariableType::Char => 1,
83 VariableType::Any => 8,
84 VariableType::Unknown => 8,
85 VariableType::Func { .. } => 8,
86 VariableType::ArraySlice(_) => 8,
87 VariableType::TupleArray { .. } => 8,
88 }
89 }
90
91 pub fn set_source(self, source: Module<()>) -> Self {
92 match self {
93 VariableType::Func {
94 params,
95 return_type: return_value,
96 ..
97 } => VariableType::Func {
98 params,
99 return_type: return_value,
100 source: Some(source),
101 },
102 _ => self,
103 }
104 }
105
106 pub fn get_source(&self) -> Option<Module<()>> {
107 match self {
108 VariableType::Func { source, .. } => source.clone(),
109 _ => None,
110 }
111 }
112
113 pub fn convert_to(&self, to_convert_to: &Self) -> Result<Self, VariableConversionError> {
123 use VariableType::*;
124 match (self, to_convert_to) {
125 (Unknown, other) => Ok(other.clone()),
126 (_, Any) => Ok(Any),
127 (TupleArray { item_type, .. }, ArraySlice(other_item_type)) => {
128 Ok(ArraySlice(Box::new(item_type.convert_to(other_item_type)?)))
129 }
130 (Str, ArraySlice(other_item_type)) => {
131 if *other_item_type == Box::new(Char) {
132 Ok(ArraySlice(Box::new(Char)))
133 } else {
134 Err(VariableConversionError)
135 }
136 }
137 (Char, Int) => Ok(Int),
138 (Int, Char) => Ok(Char),
139 (TupleArray { item_type, .. }, Str) => {
140 if *item_type == Box::new(Char) {
141 Ok(Str)
142 } else {
143 Err(VariableConversionError)
144 }
145 }
146 (left, right) => {
149 if left == right {
150 Ok(right.clone())
151 } else {
152 Err(VariableConversionError)
153 }
154 }
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::{VariableConversionError, VariableType::*};
162
163 #[test]
164 fn test_convert_to_any() {
165 assert_eq!(Void.convert_to(&Any), Ok(Any));
166 assert_eq!(Int.convert_to(&Any), Ok(Any));
167 assert_eq!(Any.convert_to(&Any), Ok(Any));
168 }
169
170 #[test]
171 fn test_convert_from_any() {
172 assert_eq!(Any.convert_to(&Void), Err(VariableConversionError));
173 assert_eq!(Any.convert_to(&Int), Err(VariableConversionError));
174 assert_eq!(Any.convert_to(&Str), Err(VariableConversionError));
175 }
176
177 #[test]
178 fn test_convert_from_unknown() {
179 assert_eq!(Unknown.convert_to(&Int), Ok(Int));
180 assert_eq!(Unknown.convert_to(&Any), Ok(Any));
181 assert_eq!(Unknown.convert_to(&Unknown), Ok(Unknown));
182 }
183
184 #[test]
185 fn test_conver_to_unknown() {
186 assert_eq!(Int.convert_to(&Unknown), Err(VariableConversionError));
187 assert_eq!(Any.convert_to(&Unknown), Err(VariableConversionError));
188 assert_eq!(Void.convert_to(&Unknown), Err(VariableConversionError));
189 }
190}