sammine-lang
Loading...
Searching...
No Matches
Types.h
Go to the documentation of this file.
1#pragma once
2#include "util/QualifiedName.h"
3#include "util/Utilities.h"
4#include <array>
5#include <map>
6#include <memory>
7#include <optional>
8#include <span>
9#include <string>
10#include <string_view>
11#include <variant>
12#include <vector>
15enum class TypeKind {
16 I32_t,
17 I64_t,
18 U32_t,
19 U64_t,
20 F64_t,
21 Unit,
22 Bool,
23 Char,
24 String,
25 Function,
26 Pointer,
27 Array,
28 Struct,
29 Enum,
30 Tuple,
31 Never,
32 NonExistent,
33 Poisoned,
34 Integer,
35 Flt,
36 TypeParam
37};
38
39struct Type;
40class FunctionType;
41
42using TypePtr = std::shared_ptr<Type>;
43class FunctionType {
44 std::vector<Type> param_types;
45 TypePtr return_type; // shared_ptr because Type is incomplete here
46 bool var_arg = false;
47
48public:
49 bool operator==(const FunctionType &t) const;
50
51 std::span<const Type> get_params_types() const;
52 Type get_return_type() const;
53 bool is_var_arg() const { return var_arg; }
54
55 FunctionType(std::vector<Type> param_types, Type return_type,
56 bool var_arg = false);
57 // Legacy: total_types = [params..., return_type]
58 FunctionType(const std::vector<Type> &total_types, bool var_arg = false);
59};
60class PointerType {
61 TypePtr pointee;
62
63public:
64 bool operator==(const PointerType &t) const;
65 Type get_pointee() const;
66 PointerType(Type pointee);
67};
68class ArrayType {
69 TypePtr element;
70 size_t size;
71
72public:
73 bool operator==(const ArrayType &t) const;
74 Type get_element() const;
75 size_t get_size() const;
76 ArrayType(Type element, size_t size);
77};
78class StructType {
80 std::vector<std::string> field_names;
81 std::vector<Type> field_types;
82
83public:
84 bool operator==(const StructType &t) const;
85 const sammine_util::QualifiedName &get_name() const { return name; }
86 const std::vector<std::string> &get_field_names() const {
87 return field_names;
88 }
89 const std::vector<Type> &get_field_types() const { return field_types; }
90 std::optional<size_t> get_field_index(const std::string &field) const;
91 Type get_field_type(size_t idx) const;
92 size_t field_count() const { return field_names.size(); }
93 StructType(sammine_util::QualifiedName name,
94 std::vector<std::string> field_names,
95 std::vector<Type> field_types);
96};
97class EnumType {
99
100public:
101 struct VariantInfo {
102 std::string name;
103 std::vector<Type> payload_types;
104 std::optional<int64_t> discriminant_value;
105 };
106
107private:
108 std::vector<VariantInfo> variants;
109 bool integer_backed_ = false;
110 TypeKind backing_type_ = TypeKind::I32_t;
111
112public:
113 bool operator==(const EnumType &t) const;
114 const sammine_util::QualifiedName &get_name() const { return name; }
115 const std::vector<VariantInfo> &get_variants() const { return variants; }
116 std::optional<size_t>
117 get_variant_index(const std::string &variant_name) const;
118 const VariantInfo &get_variant(size_t idx) const { return variants[idx]; }
119 size_t variant_count() const { return variants.size(); }
120 bool is_integer_backed() const { return integer_backed_; }
121 TypeKind get_backing_type() const { return backing_type_; }
122 EnumType(sammine_util::QualifiedName name, std::vector<VariantInfo> variants,
123 bool integer_backed = false,
124 TypeKind backing_type = TypeKind::I32_t);
125};
126class TupleType {
127 std::shared_ptr<std::vector<Type>> element_types;
128
129public:
130 bool operator==(const TupleType &t) const;
131 const std::vector<Type> &get_element_types() const;
132 size_t size() const;
133 Type get_element(size_t idx) const;
134 TupleType(std::vector<Type> element_types);
135};
136using TypeData = std::variant<FunctionType, PointerType, ArrayType, StructType,
137 EnumType, TupleType, std::string, std::monostate>;
138
139struct Type {
140 TypeKind type_kind;
141 TypeData type_data;
142 bool is_mutable = false;
143 bool is_linear = false;
144 // Constructors
145 Type() : type_kind(TypeKind::NonExistent), type_data(std::monostate()) {}
146 static Type I32_t() { return Type{TypeKind::I32_t, std::monostate()}; }
147 static Type I64_t() { return Type{TypeKind::I64_t, std::monostate()}; }
148 static Type U32_t() { return Type{TypeKind::U32_t, std::monostate()}; }
149 static Type U64_t() { return Type{TypeKind::U64_t, std::monostate()}; }
150 static Type F64_t() { return Type{TypeKind::F64_t, std::monostate()}; }
151 static Type Bool() { return Type{TypeKind::Bool, std::monostate()}; }
152 static Type Char() { return Type{TypeKind::Char, std::monostate()}; }
153 static Type Poisoned() { return Type{TypeKind::Poisoned, std::monostate()}; }
154 static Type Unit() { return Type{TypeKind::Unit, std::monostate()}; }
155 static Type Never() { return Type{TypeKind::Never, std::monostate()}; }
156 static Type Integer() { return Type{TypeKind::Integer, std::monostate()}; }
157 static Type Flt() { return Type{TypeKind::Flt, std::monostate()}; }
158 static Type String(const std::string &str) {
159 return Type{TypeKind::String, str};
160 }
161 static Type NonExistent() {
162 return Type{TypeKind::NonExistent, std::monostate()};
163 }
164 static Type TypeParam(const std::string &name) {
165 return Type{TypeKind::TypeParam, name};
166 }
167 static Type Pointer(Type pointee) {
168 return Type{TypeKind::Pointer, PointerType(pointee)};
169 }
170 static Type Array(Type element, size_t size) {
171 return Type{TypeKind::Array, ArrayType(element, size)};
172 }
173 static Type Struct(sammine_util::QualifiedName name,
174 std::vector<std::string> field_names,
175 std::vector<Type> field_types) {
176 return Type{TypeKind::Struct,
177 StructType(std::move(name), std::move(field_names),
178 std::move(field_types))};
179 }
180 static Type Enum(sammine_util::QualifiedName name,
181 std::vector<EnumType::VariantInfo> variants,
182 bool integer_backed = false,
183 TypeKind backing_type = TypeKind::I32_t) {
184 return Type{TypeKind::Enum,
185 EnumType(std::move(name), std::move(variants), integer_backed,
186 backing_type)};
187 }
188 static Type Tuple(std::vector<Type> element_types) {
189 return Type{TypeKind::Tuple, TupleType(std::move(element_types))};
190 }
191 static Type Function(std::vector<Type> params, bool var_arg = false);
192 explicit operator bool() const {
193 return this->type_kind != TypeKind::Poisoned;
194 }
195 bool synthesized() const {
196 return this->type_kind != TypeKind::NonExistent ||
197 this->type_kind == TypeKind::Poisoned;
198 }
199 Type(TypeKind type_kind, TypeData type_data)
200 : type_kind(type_kind), type_data(type_data) {}
201
202 Type(const Type &other);
203 Type(Type &&other) noexcept;
204 Type &operator=(const Type &other);
205 Type &operator=(Type &&other) noexcept;
206 ~Type();
207
208 bool operator==(const Type &other) const;
209
210 bool operator!=(const Type &other) const;
211 bool operator<(const Type &t) const;
212 bool operator>(const Type &t) const;
213
214 std::string to_string() const {
215 switch (type_kind) {
216 case TypeKind::I32_t:
217 return "i32";
218 case TypeKind::I64_t:
219 return "i64";
220 case TypeKind::U32_t:
221 return "u32";
222 case TypeKind::U64_t:
223 return "u64";
224 case TypeKind::F64_t:
225 return "f64";
226 case TypeKind::Unit:
227 return "()";
228 case TypeKind::Struct:
229 return std::get<StructType>(type_data).get_name().mangled();
230 case TypeKind::Enum:
231 return std::get<EnumType>(type_data).get_name().mangled();
232 case TypeKind::Bool:
233 return "bool";
234 case TypeKind::Char:
235 return "char";
236 case TypeKind::Pointer:
237 return (is_linear ? "'" : "") + std::string("ptr<") +
238 std::get<PointerType>(type_data).get_pointee().to_string() + ">";
239 case TypeKind::Array:
240 return "[" + std::get<ArrayType>(type_data).get_element().to_string() +
241 ";" + std::to_string(std::get<ArrayType>(type_data).get_size()) +
242 "]";
243 case TypeKind::Function: {
244 std::string res = "(";
245 auto fn_type = std::get<FunctionType>(type_data);
246 auto param = fn_type.get_params_types();
247 for (size_t i = 0; i < param.size(); i++) {
248 res += param[i].to_string();
249 if (i != param.size() - 1)
250 res += ", ";
251 }
252 res += ") -> ";
253 res += fn_type.get_return_type().to_string();
254
255 return res;
256 }
257 case TypeKind::Tuple: {
258 std::string res = "(";
259 auto &tt = std::get<TupleType>(type_data);
260 for (size_t i = 0; i < tt.size(); i++) {
261 res += tt.get_element(i).to_string();
262 if (i != tt.size() - 1)
263 res += ", ";
264 }
265 res += ")";
266 return res;
267 }
268 case TypeKind::Never:
269 return "!";
270 case TypeKind::NonExistent:
271 return "??";
272 case TypeKind::Poisoned:
273 return "Poisoned";
274 case TypeKind::String:
275 return fmt::format("\"{}\"", std::get<std::string>(type_data));
276 case TypeKind::Integer:
277 return "numeric literal";
278 case TypeKind::Flt:
279 return "float literal";
280 case TypeKind::TypeParam:
281 return std::get<std::string>(type_data);
282 }
283 sammine_util::abort("Reaching the end of switch case and still cant "
284 "convert to string, blame Jasmine (badumbatish)!!!!!");
285 }
286
287 bool is_poisoned() const { return this->type_kind == TypeKind::Poisoned; }
288
289 bool is_literal() const {
290 switch (type_kind) {
291 case TypeKind::I32_t:
292 case TypeKind::I64_t:
293 case TypeKind::U32_t:
294 case TypeKind::U64_t:
295 case TypeKind::F64_t:
296 case TypeKind::Bool:
297 case TypeKind::Char:
298 case TypeKind::Unit:
299 case TypeKind::String:
300 case TypeKind::Integer:
301 case TypeKind::Flt:
302 return true;
303 case TypeKind::TypeParam:
304 return false;
305 default:
306 return false;
307 }
308 }
309
310 bool is_polymorphic_numeric() const {
311 return type_kind == TypeKind::Integer || type_kind == TypeKind::Flt;
312 }
313
314 bool isTypeWrapping() const {
315 switch (type_kind) {
316 case TypeKind::Pointer:
317 case TypeKind::Array:
318 case TypeKind::Struct:
319 case TypeKind::Enum:
320 case TypeKind::Function:
321 case TypeKind::Tuple:
322 return true;
323 default:
324 return false;
325 }
326 }
327
328 bool containsLinear() const {
329 if (is_linear)
330 return true;
331 bool found = false;
332 forEachInnerType([&](const Type &inner) {
333 if (inner.containsLinear())
334 found = true;
335 });
336 return found;
337 }
338
339 template <typename F> void forEachInnerType(F &&callback) const {
340 switch (type_kind) {
341 case TypeKind::Pointer: {
342 auto &pt = std::get<PointerType>(type_data);
343 callback(pt.get_pointee());
344 break;
345 }
346 case TypeKind::Array: {
347 auto &at = std::get<ArrayType>(type_data);
348 callback(at.get_element());
349 break;
350 }
351 case TypeKind::Struct: {
352 auto &st = std::get<StructType>(type_data);
353 for (auto &ft : st.get_field_types())
354 callback(ft);
355 break;
356 }
357 case TypeKind::Enum: {
358 auto &et = std::get<EnumType>(type_data);
359 for (auto &variant : et.get_variants())
360 for (auto &pt : variant.payload_types)
361 callback(pt);
362 break;
363 }
364 case TypeKind::Function: {
365 auto &fn = std::get<FunctionType>(type_data);
366 for (auto &p : fn.get_params_types())
367 callback(p);
368 callback(fn.get_return_type());
369 break;
370 }
371 case TypeKind::Tuple: {
372 auto &tt = std::get<TupleType>(type_data);
373 for (auto &et : tt.get_element_types())
374 callback(et);
375 break;
376 }
377 default:
378 break;
379 }
380 }
381
382 operator std::string() const { return to_string(); }
383};
384
385std::optional<std::string> incompatibility_hint(const Type &expected,
386 const Type &actual);
387
388inline constexpr std::array<std::string_view, 10> kBuiltinTypeNames = {
389 "i32", "i64", "f32", "f64", "bool", "char", "u32", "u64", "string", "unit"};
390
391inline bool is_builtin_type_name(std::string_view name) {
392 for (auto b : kBuiltinTypeNames)
393 if (b == name)
394 return true;
395 return false;
396}
397
399 // TODO: Planned for future subtyping support — don't remove
400 std::map<Type, Type> type_map;
401 // TODO: Planned for future subtyping support — don't remove
402 std::vector<Type> visit_ancestor(const Type &t) const;
403 // TODO: Planned for future subtyping support — don't remove
404 std::optional<Type> lowest_common_type(const Type &a, const Type &b) const;
405
406 bool compatible_to_from(const Type &a, const Type &b) const;
407};
Holds classes and functionalities for dealing with Error handling, source locations caching & indexin...
Definition Types.h:68
Definition Types.h:97
Definition Types.h:43
Definition Types.h:60
Definition Types.h:78
Definition Types.h:126
Definition Types.h:101
Definition Types.h:398
Definition Types.h:139
Definition QualifiedName.h:23