Cthulhu  0.2.10
Cthulhu compiler collection
type.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-3.0-only
2 
3 #include "oberon/sema/type.h"
4 
5 #include "oberon/driver.h"
6 #include "oberon/sema/expr.h"
7 #include "oberon/sema/sema.h"
8 
10 #include "cthulhu/util/types.h"
11 #include "cthulhu/util/util.h"
12 
13 #include "std/vector.h"
14 
15 #include "memory/memory.h"
16 #include "base/panic.h"
17 
18 static const size_t kModuleTags[] = { eObrTagModules, eObrTagImports };
19 static const size_t kDeclTags[] = { eObrTagTypes };
20 
21 static const decl_search_t kSearchDecl = {
22  .module_tags = kModuleTags,
23  .module_count = sizeof(kModuleTags) / sizeof(size_t),
24 
25  .decl_tags = kDeclTags,
26  .decl_count = sizeof(kDeclTags) / sizeof(size_t)
27 };
28 
29 static tree_t *sema_type_name(tree_t *sema, obr_t *type)
30 {
31  tree_t *it = obr_get_type(sema, type->name);
32  if (it == NULL)
33  {
34  return tree_raise(type->node, sema->reports, &kEvent_TypeNotFound, "type '%s' not found", type->name);
35  }
36 
37  return it;
38 }
39 
40 static tree_t *sema_type_qual(tree_t *sema, obr_t *type)
41 {
42  return util_search_qualified(sema, &kSearchDecl, type->node, type->name, type->symbol);
43 }
44 
45 static tree_t *sema_type_pointer(tree_t *sema, obr_t *type, const char *name)
46 {
47  tree_t *it = obr_sema_type(sema, type->pointer, name);
48  return tree_type_pointer(type->node, name, it, SIZE_MAX);
49 }
50 
51 static size_t sema_array_length(tree_t *sema, obr_t *expr)
52 {
53  CTASSERT(sema != NULL);
54  if (expr == NULL) return SIZE_MAX;
55 
56  tree_t *it = obr_sema_rvalue(sema, expr, obr_get_integer_type());
57  if (tree_is(it, eTreeExprDigit))
58  {
59  int sign = mpz_sgn(it->digit_value);
60  if (sign < 0)
61  {
62  msg_notify(sema->reports, &kEvent_ArrayLengthNegative, it->node, "array length cannot be negative");
63  return SIZE_MAX;
64  }
65  else if (sign == 0)
66  {
67  msg_notify(sema->reports, &kEvent_ArrayLengthZero, it->node, "array length cannot be zero");
68  return SIZE_MAX;
69  }
70  else if (mpz_fits_uint_p(it->digit_value) == 0)
71  {
72  msg_notify(sema->reports, &kEvent_ArrayLengthOverflow, it->node, "`%s` is too large to be an array length", mpz_get_str(NULL, 10, it->digit_value));
73  return SIZE_MAX;
74  }
75 
76  return mpz_get_ui(it->digit_value);
77  }
78 
79  msg_notify(sema->reports, &kEvent_ArrayLengthNotConstant, it->node, "array length must be a constant");
80  return SIZE_MAX;
81 }
82 
83 static tree_t *sema_array_segment(tree_t *sema, obr_t *size, tree_t *element, const char *name)
84 {
85  // even if get_array_length fails we still want to return a valid type
86  size_t len = sema_array_length(sema, size);
87 
88  return tree_type_array(size->node, name, element, len);
89 }
90 
91 static tree_t *sema_type_array(tree_t *sema, obr_t *type, const char *name)
92 {
93  tree_t *it = obr_sema_type(sema, type->array_element, name); // TODO: will the name clash matter?
94 
95  size_t len = vector_len(type->sizes);
96 
97  // if theres no sizes its an open array
98  if (len == 0)
99  return tree_type_array(type->node, name, it, SIZE_MAX);
100 
101  // otherwise we need to iterate backwards over the sizes
102  // to build up the array type
103  for (size_t i = len; i > 0; i--)
104  {
105  obr_t *size = vector_get(type->sizes, i - 1);
106  it = sema_array_segment(sema, size, it, name);
107  }
108 
109  return it;
110 }
111 
112 static tree_t *sema_type_record(tree_t *sema, obr_t *type, const char *name)
113 {
114  size_t len = vector_len(type->fields);
115  arena_t *arena = get_global_arena();
116  vector_t *result = vector_of(len, arena);
117  for (size_t i = 0; i < len; i++)
118  {
119  obr_t *field = vector_get(type->fields, i);
120  tree_t *it = obr_sema_type(sema, field->type, field->name);
121  tree_t *decl = tree_decl_field(field->node, field->name, it);
122  vector_set(result, i, decl);
123  }
124 
125  return tree_decl_struct(type->node, name, result);
126 }
127 
128 tree_t *obr_sema_type(tree_t *sema, obr_t *type, const char *name)
129 {
130  CTASSERT(type != NULL);
131 
132  switch (type->kind)
133  {
134  case eObrTypeName: return sema_type_name(sema, type);
135  case eObrTypeQual: return sema_type_qual(sema, type);
136  case eObrTypePointer: return sema_type_pointer(sema, type, name);
137  case eObrTypeArray: return sema_type_array(sema, type, name);
138  case eObrTypeRecord: return sema_type_record(sema, type, name);
139 
140  default: CT_NEVER("unknown type kind %d", type->kind);
141  }
142 }
143 
144 
148 
149 const tree_t *obr_rvalue_type(const tree_t *self)
150 {
151  return tree_ty_load_type(tree_get_type(self));
152 }
153 
154 
158 
159 static bool is_open_array(const tree_t *type)
160 {
161  return tree_is(type, eTreeTypeArray) && !util_length_bounded(type->length);
162 }
163 
164 tree_t *obr_cast_type(tree_t *expr, const tree_t *type)
165 {
166  const tree_t *exprtype = tree_get_type(expr);
167 
168  // pointers can convert to open arrays and vice versa
169  if ((is_open_array(exprtype) && tree_is(type, eTreeTypePointer))
170  || (is_open_array(type) && tree_is(exprtype, eTreeTypePointer))
171  )
172  {
173  if (util_types_equal(exprtype->ptr, type->ptr))
174  {
175  return tree_expr_cast(expr->node, type, expr, eCastBit);
176  }
177  }
178 
179  if (tree_is(exprtype, eTreeTypeArray) && tree_is(type, eTreeTypeArray))
180  {
181  if (exprtype->length >= type->length || !util_length_bounded(exprtype->length) || !util_length_bounded(type->length))
182  {
183  if (util_types_equal(exprtype->ptr, type->ptr))
184  {
185  return tree_expr_cast(expr->node, type, expr, eCastBit);
186  }
187  }
188  }
189 
190  // TODO: deal with other casts
191  return expr;
192 }
CT_NODISCARD size_t size
Definition: scan.h:128
CT_PUREFN CT_TREE_API const tree_t * tree_get_type(const tree_t *tree)
Definition: context.c:132
CT_PUREFN CT_TREE_API bool tree_is(const tree_t *self, tree_kind_t kind)
Definition: query.c:91
CT_PUREFN CT_TREE_API const tree_t * tree_ty_load_type(const tree_t *self)
get the type of a type after it has been loaded
Definition: query.c:267
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
Definition: memory.c:16
CT_NOTIFY_API event_builder_t msg_notify(INOUT_NOTNULL logger_t *logs, const diagnostic_t *diagnostic, const node_t *node, STA_FORMAT_STRING const char *fmt,...)
notify the logger of a new message
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
CT_UTIL_API tree_t * util_search_qualified(tree_t *sema, const decl_search_t *search, const node_t *node, const char *mod, const char *name)
search for a decl inside a module
Definition: query.c:125
CT_UTIL_API bool util_length_bounded(size_t length)
check if the length of an array is bounded
Definition: util.c:312
CT_BEGIN_API CT_UTIL_API bool util_types_equal(const tree_t *lhs, const tree_t *rhs)
compare two types for strict equality compares two types for exact equality, does not follow typedefs
Definition: util.c:33
CT_TREE_API tree_t * tree_decl_struct(const node_t *node, const char *name, vector_t *fields)
Definition: decl.c:298
CT_TREE_API tree_t * tree_expr_cast(const node_t *node, const tree_t *type, const tree_t *expr, tree_cast_t cast)
create a cast expression
Definition: tree.c:251
CT_TREE_API tree_t * tree_decl_field(const node_t *node, const char *name, const tree_t *type)
Definition: decl.c:193
CT_TREE_API tree_t * tree_type_pointer(const node_t *node, const char *name, const tree_t *pointer, size_t length)
create a pointer type
Definition: tree.c:165
CT_TREE_API tree_t * tree_raise(const node_t *node, logger_t *reports, const diagnostic_t *diagnostic, const char *message,...)
Definition: tree.c:76
CT_TREE_API tree_t * tree_type_array(const node_t *node, const char *name, const tree_t *array, size_t length)
create a new array type
Definition: tree.c:175
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
Definition: vector.c:134
CT_NODISCARD CT_STD_API vector_t * vector_of(size_t len, arena_t *arena)
create a new vector with a specified length
Definition: vector.c:71
CT_STD_API void vector_set(vector_t *vector, size_t index, void *value)
set a value in a vector
Definition: vector.c:125
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
Definition: vector.c:152
const tree_t * obr_rvalue_type(const tree_t *self)
Definition: type.c:149
tree_t * obr_cast_type(tree_t *expr, const tree_t *type)
Definition: type.c:164
tree_t * obr_sema_type(tree_t *sema, obr_t *type, const char *name)
Definition: type.c:128
@ eObrTypeQual
Definition: ast.h:45
@ eObrTypeArray
Definition: ast.h:47
@ eObrTypeRecord
Definition: ast.h:48
@ eObrTypePointer
Definition: ast.h:46
@ eObrTypeName
Definition: ast.h:44
tree_t * obr_sema_rvalue(tree_t *sema, obr_t *expr, const tree_t *implicit_type)
Definition: expr.c:160
tree_t * obr_get_integer_type(void)
Definition: sema.c:87
tree_t * obr_get_type(tree_t *sema, const char *name)
Definition: sema.c:15
an allocator object
Definition: arena.h:86
const size_t * module_tags
Definition: util.h:43
Definition: ast.h:93
obr_t * array_element
Definition: ast.h:165
obr_kind_t kind
Definition: ast.h:94
char * name
Definition: ast.h:184
const node_t * node
Definition: ast.h:95
obr_t * type
Definition: ast.h:198
vector_t * fields
Definition: ast.h:169
char * symbol
Definition: ast.h:215
const vector_t * sizes
Definition: ast.h:164
obr_t * pointer
Definition: ast.h:160
Definition: tree.h:67
logger_t * reports
Definition: tree.h:227
size_t length
Definition: tree.h:174
const tree_t * ptr
Definition: tree.h:172
mpz_t digit_value
Definition: tree.h:75
const node_t * node
Definition: tree.h:69
a generic vector of pointers
Definition: vector.c:16