Cthulhu  0.2.10
Cthulhu compiler collection
util.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
3 #include "cthulhu/util/util.h"
5 #include "cthulhu/util/types.h"
6 
7 #include "cthulhu/tree/query.h"
8 
9 #include "memory/memory.h"
10 #include "std/str.h"
11 
12 #include "base/panic.h"
13 
14 #include <stdint.h>
15 
16 void *util_select_decl(tree_t *sema, search_t search, const char *name)
17 {
18  CTASSERT(search.tags != NULL);
19  CTASSERT(search.count > 0);
20 
21  for (size_t i = 0; i < search.count; i++)
22  {
23  tree_t *decl = tree_module_get(sema, search.tags[i], name);
24  if (decl != NULL)
25  {
26  return decl;
27  }
28  }
29 
30  return NULL;
31 }
32 
33 bool util_types_equal(const tree_t *lhs, const tree_t *rhs)
34 {
35  CTASSERTF(lhs != NULL && rhs != NULL, "(lhs=%p, rhs=%p)", (void *)lhs, (void *)rhs);
36 
37  lhs = tree_follow_type(lhs);
38  rhs = tree_follow_type(rhs);
39 
40  if (lhs == rhs)
41  {
42  return true;
43  }
44 
45  tree_kind_t lhs_kind = tree_get_kind(lhs);
46  tree_kind_t rhs_kind = tree_get_kind(rhs);
47 
48  if (lhs_kind != rhs_kind)
49  {
50  return false;
51  }
52 
53  switch (lhs_kind)
54  {
55  case eTreeTypeEmpty:
56  case eTreeTypeUnit:
57  case eTreeTypeOpaque:
58  case eTreeTypeBool: return true;
59 
60  case eTreeTypeDigit: return (lhs->digit == rhs->digit) && (lhs->sign == rhs->sign);
61 
62  case eTreeTypeReference:
63  case eTreeTypePointer: return util_types_equal(lhs->ptr, rhs->ptr);
64 
65  default: return false;
66  }
67 }
68 
69 bool util_types_comparable(tree_cookie_t *cookie, const tree_t *lhs, const tree_t *rhs)
70 {
71  lhs = tree_follow_type(tree_resolve_type(cookie, lhs));
72  rhs = tree_follow_type(tree_resolve_type(cookie, rhs));
73 
74  if (util_types_equal(lhs, rhs))
75  {
76  return true;
77  }
78 
79  tree_kind_t lhs_kind = tree_get_kind(lhs);
80  tree_kind_t rhs_kind = tree_get_kind(rhs);
81 
82  if (lhs_kind == rhs_kind)
83  {
84  switch (lhs_kind)
85  {
86  case eTreeTypeBool:
87  case eTreeTypeOpaque:
88  case eTreeTypeDigit:
89  return true;
90 
91  default: break;
92  }
93  }
94 
96  return true;
97 
99  return true;
100 
101  return false;
102 }
103 
104 static bool can_cast_length(size_t dst, size_t src)
105 {
106  if (!util_length_bounded(dst))
107  {
108  return true;
109  }
110  if (!util_length_bounded(src))
111  {
112  return true;
113  }
114 
115  return dst < src;
116 }
117 
118 static tree_t *cast_check_length(const tree_t *dst, tree_t *expr, size_t dstlen, size_t srclen)
119 {
120  if (!can_cast_length(dstlen, srclen))
121  {
122  return tree_error(
123  tree_get_node(expr), &kEvent_InvalidCast,
124  "creating an array with a length greater than its backing memory is unwise. (%s < %s)",
125  util_length_name(srclen), util_length_name(dstlen));
126  }
127 
128  return tree_expr_cast(tree_get_node(expr), dst, expr, eCastBit);
129 }
130 
131 static tree_t *cast_to_opaque(const tree_t *dst, tree_t *expr)
132 {
133  CTASSERTF(tree_is(dst, eTreeTypeOpaque), "(dst=%s)", tree_to_string(dst));
134 
135  const tree_t *src = tree_get_type(expr);
136 
137  switch (tree_get_kind(src))
138  {
139  case eTreeTypePointer:
140  case eTreeTypeDigit:
141  return tree_expr_cast(tree_get_node(expr), dst, expr, eCastBit); // TODO: a little iffy
142 
143  default:
144  return tree_error(tree_get_node(expr), &kEvent_InvalidCast, "cannot cast `%s` to `%s`",
145  tree_to_string(src), tree_to_string(dst));
146  }
147 }
148 
149 static tree_t *cast_to_pointer(const tree_t *dst, tree_t *expr)
150 {
151  CTASSERTF(tree_is(dst, eTreeTypePointer), "(dst=%s)", tree_to_string(dst));
152 
153  const tree_t *src = tree_get_type(expr);
154 
155  switch (tree_get_kind(src))
156  {
157  case eTreeTypePointer:
158  if (!util_types_equal(dst->ptr, src->ptr))
159  {
160  return tree_error(tree_get_node(expr), &kEvent_InvalidCast,
161  "cannot cast unrelated pointer types `%s` to `%s`",
162  tree_to_string(src), tree_to_string(dst));
163  }
164 
165  return cast_check_length(dst, expr, dst->length, src->length);
166 
167  default:
168  return tree_error(tree_get_node(expr), &kEvent_InvalidCast, "cannot cast `%s` to `%s`",
169  tree_to_string(src), tree_to_string(dst));
170  }
171 }
172 
173 static tree_t *cast_to_digit(const tree_t *dst, tree_t *expr)
174 {
175  CTASSERTF(tree_is(dst, eTreeTypeDigit), "(dst=%s)", tree_to_string(dst));
176 
177  const tree_t *src = tree_get_type(expr);
178 
179  if (util_type_is_pointer(src) && dst->digit == eDigitPtr)
180  {
181  return tree_expr_cast(tree_get_node(expr), dst, expr, eCastBit);
182  }
183 
184  // TODO: need to distinguish between explicit and implicit casts
185  switch (tree_get_kind(src))
186  {
187  case eTreeTypeDigit:
188  return tree_expr_cast(tree_get_node(expr), dst, expr, eCastSignExtend);
189 
190  default:
191  return tree_error(tree_get_node(expr), &kEvent_InvalidCast, "cannot cast `%s` to `%s`",
192  tree_to_string(src), tree_to_string(dst));
193  }
194 }
195 
196 static tree_t *cast_to_bool(const tree_t *dst, tree_t *expr)
197 {
198  CTASSERTF(tree_is(dst, eTreeTypeBool), "(dst=%s)", tree_to_string(dst));
199 
200  const tree_t *src = tree_get_type(expr);
201 
202  switch (tree_get_kind(src))
203  {
204  case eTreeTypeBool: return expr;
205 
206  default:
207  return tree_error(tree_get_node(expr), &kEvent_InvalidCast, "cannot cast `%s` to `%s`",
208  tree_to_string(src), tree_to_string(dst));
209  }
210 }
211 
212 tree_t *util_type_cast(const tree_t *dst, tree_t *expr)
213 {
214  CTASSERTF(dst != NULL && expr != NULL, "(dst=%p, expr=%p)", (void *)dst, (void *)expr);
215 
216  const tree_t *src = tree_get_type(expr);
217 
218  dst = tree_follow_type(dst);
219 
220  if (util_types_equal(dst, src))
221  {
222  return expr;
223  }
224 
225  switch (tree_get_kind(dst))
226  {
227  case eTreeTypeOpaque: return cast_to_opaque(dst, expr);
228 
229  case eTreeTypePointer: return cast_to_pointer(dst, expr);
230 
231  case eTreeTypeReference: return util_type_cast(dst->ptr, expr);
232 
233  case eTreeTypeDigit: return cast_to_digit(dst, expr);
234 
235  case eTreeTypeBool: return cast_to_bool(dst, expr);
236 
237  default:
238  return tree_error(tree_get_node(expr), &kEvent_InvalidCast, "cannot cast `%s` to `%s`",
239  tree_to_string(src), tree_to_string(dst));
240  }
241 }
242 
243 static bool eval_binary(mpz_t value, const tree_t *expr)
244 {
245  CTASSERT(expr != NULL);
246 
247  mpz_t lhs;
248  mpz_t rhs;
249  mpz_init(lhs);
250  mpz_init(rhs);
251 
252  if (!util_eval_digit(lhs, expr->lhs))
253  {
254  return false;
255  }
256  if (!util_eval_digit(rhs, expr->rhs))
257  {
258  return false;
259  }
260 
261  switch (expr->binary)
262  {
263  case eBinaryAdd: mpz_add(value, lhs, rhs); break;
264  case eBinarySub: mpz_sub(value, lhs, rhs); break;
265  case eBinaryMul: mpz_mul(value, lhs, rhs); break;
266  default: return false;
267  }
268 
269  return true;
270 }
271 
272 static bool eval_cast(mpz_t value, const tree_t *expr)
273 {
274  CTASSERT(expr != NULL);
275 
276  mpz_t src;
277  mpz_init(src);
278 
279  if (!util_eval_digit(src, expr->expr))
280  {
281  return false;
282  }
283 
284  switch (expr->cast)
285  {
286  case eCastSignExtend: mpz_set(value, src); break;
287  default: return false;
288  }
289 
290  return true;
291 }
292 
293 bool util_eval_digit(mpz_t value, const tree_t *expr)
294 {
295  CTASSERT(expr != NULL);
296  switch (tree_get_kind(expr))
297  {
298  case eTreeExprDigit:
299  mpz_set(value, expr->digit_value);
300  return true;
301 
302  case eTreeExprBinary:
303  return eval_binary(value, expr);
304 
305  case eTreeExprCast:
306  return eval_cast(value, expr);
307 
308  default: return false;
309  }
310 }
311 
312 bool util_length_bounded(size_t length)
313 {
314  return length != SIZE_MAX;
315 }
316 
317 const char *util_length_name(size_t length)
318 {
319  arena_t *arena = get_global_arena();
320  return util_length_bounded(length) ? str_format(arena, "%zu", length) : "unbounded";
321 }
322 
324 {
325  CTASSERTF(!tree_is(type, eTreeTypeAlias), "(type=%s)", tree_to_string(type));
326  return tree_is(type, eTreeTypeUnion) || tree_is(type, eTreeTypeStruct);
327 }
328 
329 bool util_type_is_pointer(const tree_t *type)
330 {
331  CTASSERTF(!tree_is(type, eTreeTypeAlias), "(type=%s)", tree_to_string(type));
332  return tree_is(type, eTreeTypePointer);
333 }
334 
335 bool util_type_is_array(const tree_t *type)
336 {
337  CTASSERTF(!tree_is(type, eTreeTypeAlias), "(type=%s)", tree_to_string(type));
338  return tree_is(type, eTreeTypeArray);
339 }
340 
341 bool util_type_is_opaque(const tree_t *type)
342 {
343  CTASSERTF(!tree_is(type, eTreeTypeAlias), "(type=%s)", tree_to_string(type));
344  return tree_is(type, eTreeTypeOpaque);
345 }
346 
348 {
349  CTASSERTF(!tree_is(type, eTreeTypeAlias), "(type=%s)", tree_to_string(type));
350  return tree_is(type, eTreeTypeReference);
351 }
352 
353 bool util_type_is_digit(const tree_t *type)
354 {
355  CTASSERTF(!tree_is(type, eTreeTypeAlias), "(type=%s)", tree_to_string(type));
356  return tree_is(type, eTreeTypeDigit);
357 }
CT_PUREFN CT_TREE_API const node_t * tree_get_node(const tree_t *tree)
Definition: context.c:94
CT_PUREFN CT_TREE_API tree_kind_t tree_get_kind(const tree_t *tree)
Definition: context.c:143
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_TREE_API const char * tree_to_string(const tree_t *self)
Definition: query.c:40
bool util_type_is_aggregate(const tree_t *type)
Definition: util.c:323
bool util_type_is_digit(const tree_t *type)
Definition: util.c:353
const char * util_length_name(size_t length)
get the pretty name of a length return either the length as a string or "unbounded" if the length is ...
Definition: util.c:317
bool util_type_is_reference(const tree_t *type)
Definition: util.c:347
bool util_type_is_pointer(const tree_t *type)
Definition: util.c:329
bool util_length_bounded(size_t length)
check if the length of an array is bounded
Definition: util.c:312
bool util_type_is_array(const tree_t *type)
Definition: util.c:335
bool util_types_comparable(tree_cookie_t *cookie, const tree_t *lhs, const tree_t *rhs)
query two types for comparability in binary logic operations
Definition: util.c:69
bool util_type_is_opaque(const tree_t *type)
Definition: util.c:341
tree_t * util_type_cast(const tree_t *dst, tree_t *expr)
attempt to cast an expression to a type
Definition: util.c:212
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
Definition: memory.c:16
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
void * util_select_decl(tree_t *sema, search_t search, const char *name)
search for a declaration by name in a set of tags
Definition: util.c:16
bool util_eval_digit(mpz_t value, const tree_t *expr)
evaluate a digit expression
Definition: util.c:293
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_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_error(const node_t *node, const diagnostic_t *diagnostic, const char *message,...)
Definition: tree.c:67
CT_TREE_API tree_t * tree_resolve_type(tree_cookie_t *cookie, const tree_t *decl)
Definition: decl.c:102
tree_kind_t
all tree node types
Definition: ops.h:17
CT_TREE_API const tree_t * tree_follow_type(const tree_t *type)
Definition: decl.c:274
CT_TREE_API void * tree_module_get(tree_t *self, size_t tag, const char *name)
recursively search for a declaration in a module
Definition: sema.c:59
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
Definition: str.c:97
an allocator object
Definition: arena.h:86
Definition: util.h:28
size_t count
Definition: util.h:30
const size_t * tags
Definition: util.h:29
Definition: tree.h:67
sign_t sign
Definition: tree.h:180
const tree_t * rhs
Definition: tree.h:108
const tree_t * lhs
Definition: tree.h:107
size_t length
Definition: tree.h:174
binary_t binary
Definition: tree.h:103
tree_cast_t cast
Definition: tree.h:91
const tree_t * ptr
Definition: tree.h:172
mpz_t digit_value
Definition: tree.h:75
digit_t digit
Definition: tree.h:179
const tree_t * expr
Definition: tree.h:88