Cthulhu  0.2.10
Cthulhu compiler collection
decl.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-3.0-only
2 
3 #include "ctu/sema/decl.h"
4 #include "arena/arena.h"
5 #include "core/macros.h"
7 #include "ctu/driver.h"
8 #include "ctu/sema/type.h"
9 #include "ctu/sema/expr.h"
10 
11 #include "ctu/sema/decl/function.h"
12 
13 #include "cthulhu/tree/query.h"
14 
15 #include "cthulhu/util/util.h"
16 #include "cthulhu/util/types.h"
17 
18 #include "memory/memory.h"
19 #include "std/map.h"
20 #include "std/vector.h"
21 #include "std/str.h"
22 
23 #include "base/panic.h"
24 #include <stdio.h>
25 
29 
30 static const tree_attribs_t kAttribPrivate = {
31  .link = eLinkModule,
32  .visibility = eVisiblePrivate
33 };
34 
35 static const tree_attribs_t kAttribExport = {
36  .link = eLinkExport,
37  .visibility = eVisiblePublic
38 };
39 
40 static const tree_attribs_t kAttribForward = {
41  .link = eLinkImport,
42  .visibility = eVisiblePublic
43 };
44 
45 static const tree_attribs_t kAttribImport = {
46  .link = eLinkImport,
47  .visibility = eVisiblePrivate
48 };
49 
53 
54 static ctu_t *begin_resolve(tree_t *sema, tree_t *self, void *user, ctu_kind_t kind)
55 {
56  ctu_t *decl = user;
57  CTASSERTF(decl->kind == kind, "decl %s is not a %d", decl->name, kind);
58 
59  CT_UNUSED(sema);
60  CT_UNUSED(self);
61 
62  return decl;
63 }
64 
65 static void ctu_resolve_global(tree_t *sema, tree_t *self, void *user)
66 {
67  ctu_t *decl = begin_resolve(sema, self, user, eCtuDeclGlobal);
68 
69  arena_t *arena = get_global_arena();
70  ctu_sema_t ctx = ctu_sema_init(sema, self, vector_new(0, arena));
71 
72  tree_t *type = decl->type == NULL ? NULL : ctu_sema_type(&ctx, decl->type);
73  tree_t *expr = decl->value == NULL ? NULL : ctu_sema_rvalue(&ctx, decl->value, type);
74 
75  CTASSERT(expr != NULL || type != NULL);
76 
77  const tree_t *real_type = expr == NULL ? type : tree_get_type(expr);
78 
79  if (!decl->mut && !tree_is(real_type, eTreeError))
80  {
81  tree_t clone = *real_type;
82  tree_quals_t quals = tree_ty_get_quals(real_type);
83  tree_set_qualifiers(&clone, quals | eQualConst);
84 
85  real_type = arena_memdup(&clone, sizeof(tree_t), arena);
86  }
87 
88  size_t size = ctu_resolve_storage_length(real_type);
89  const tree_t *ty = ctu_resolve_storage_type(real_type);
90 
91  const tree_storage_t storage = {
92  .storage = ty,
93  .length = size,
94  .quals = decl->mut ? eQualMutable : eQualConst
95  };
96 
97  const tree_t *ref = real_type;
98  if (!tree_is(real_type, eTreeTypeArray))
99  {
100  ref = tree_type_reference(self->node, self->name, real_type);
101  }
102 
103  tree_set_type(self, ref);
104  tree_set_storage(self, storage);
105  tree_close_global(self, expr);
106 }
107 
108 static void ctu_resolve_typealias(tree_t *sema, tree_t *self, void *user)
109 {
110  ctu_t *decl = begin_resolve(sema, self, user, eCtuDeclTypeAlias);
111  CTASSERTF(decl->type_alias != NULL, "decl %s has no type", decl->name);
112 
113  arena_t *arena = get_global_arena();
114  ctu_sema_t inner = ctu_sema_init(sema, self, vector_new(0, arena));
115 
116  const tree_t *temp = tree_resolve(tree_get_cookie(sema), ctu_sema_type(&inner, decl->type_alias)); // TODO: doesnt support newtypes, also feels icky
117 
118  // TODO: bruh
119  tree_t *alias = tree_type_alias(self->node, self->name, temp, eQualNone);
120  tree_set_attrib(alias, decl->exported ? &kAttribExport : &kAttribPrivate);
121 
122  tree_close_decl(self, alias);
123 }
124 
125 static vector_t *ctu_collect_fields(tree_t *sema, tree_t *self, ctu_t *decl)
126 {
127  arena_t *arena = get_global_arena();
128  ctu_sema_t inner = ctu_sema_init(sema, self, vector_new(0, arena));
129  size_t len = vector_len(decl->fields);
130 
131  map_t *fields = map_optimal(len, kTypeInfoString, arena);
132 
133  vector_t *items = vector_of(len, arena);
134  for (size_t i = 0; i < len; i++)
135  {
136  ctu_t *field = vector_get(decl->fields, i);
137  tree_t *type = ctu_sema_type(&inner, field->field_type);
138  char *name = field->name == NULL ? str_format(arena, "field%zu", i) : field->name;
139  tree_t *item = tree_decl_field(field->node, name, type);
140 
141  tree_t *prev = map_get(fields, name);
142  if (prev != NULL)
143  {
144  msg_notify(sema->reports, &kEvent_DuplicateField, field->node, "aggregate decl `%s` has duplicate field `%s`", decl->name, name);
145  }
146 
147  vector_set(items, i, item);
148  map_set(fields, name, item);
149  }
150 
151  return items;
152 }
153 
154 static void ctu_resolve_struct(tree_t *sema, tree_t *self, void *user)
155 {
156  ctu_t *decl = begin_resolve(sema, self, user, eCtuDeclStruct);
157  vector_t *items = ctu_collect_fields(sema, self, decl);
158  tree_close_struct(self, items);
159 }
160 
161 static void ctu_resolve_union(tree_t *sema, tree_t *self, void *user)
162 {
163  ctu_t *decl = begin_resolve(sema, self, user, eCtuDeclUnion);
164  vector_t *items = ctu_collect_fields(sema, self, decl);
165  tree_close_union(self, items);
166 }
167 
168 static void ctu_resolve_variant(tree_t *sema, tree_t *self, void *user)
169 {
170  ctu_t *decl = begin_resolve(sema, self, user, eCtuDeclVariant);
171  arena_t *arena = get_global_arena();
172  ctu_sema_t inner = ctu_sema_init(sema, self, vector_new(0, arena));
173 
174  const tree_t *underlying = decl->underlying != NULL
175  ? ctu_sema_type(&inner, decl->underlying)
176  : ctu_get_int_type(eDigitInt, eSignSigned); // TODO: have an enum type
177 
178  if (!tree_is(underlying, eTreeTypeDigit))
179  {
180  msg_notify(sema->reports, &kEvent_InvalidEnumUnderlyingType, decl->node, "decl `%s` has non-integer underlying type", decl->name);
181  return;
182  }
183 
184  size_t len = vector_len(decl->cases);
185 
186  tree_t *default_case = NULL;
187  vector_t *result = vector_of(len, arena);
188 
189  for (size_t i = 0; i < len; i++)
190  {
191  ctu_t *it = vector_get(decl->cases, i);
192  CTASSERTF(it->kind == eCtuVariantCase, "decl %s is not a variant case", it->name);
193  CTASSERTF(it->case_value != NULL, "decl %s has no case value", it->name);
194 
195  tree_t *val = ctu_sema_rvalue(&inner, it->case_value, underlying);
196  tree_t *field = tree_decl_case(it->node, it->name, self, val);
197  vector_set(result, i, field);
198 
199  if (it->default_case)
200  {
201  if (default_case != NULL)
202  {
203  event_builder_t id = msg_notify(sema->reports, &kEvent_DuplicateDefaultCases, it->node, "decl `%s` has multiple default cases", decl->name);
204  msg_append(id, default_case->node, "previous default case");
205  }
206  else
207  {
208  default_case = field;
209  }
210  }
211  }
212 
213  tree_close_enum(self, underlying, result, default_case);
214 }
215 
219 
220 static tree_t *ctu_forward_global(tree_t *sema, ctu_t *decl)
221 {
222  CTASSERTF(decl->kind == eCtuDeclGlobal, "decl %s is not a global", decl->name);
223  CTASSERTF(decl->type != NULL || decl->value != NULL, "decl %s has no type and no init expr", decl->name);
224 
225  arena_t *arena = get_global_arena();
226  ctu_sema_t inner = ctu_sema_init(sema, NULL, vector_new(0, arena));
227  tree_t *type = decl->type == NULL ? NULL : ctu_sema_type(&inner, decl->type);
228 
229  tree_resolve_info_t resolve = {
230  .sema = sema,
231  .user = decl,
232  .fn_resolve = ctu_resolve_global
233  };
234 
235  tree_storage_t storage = {
236  .storage = type,
237  .length = 1,
238  .quals = decl->mut ? eQualMutable : eQualConst
239  };
240 
241  tree_t *global = tree_open_global(decl->node, decl->name, type, resolve);
242  tree_set_storage(global, storage);
243 
244  return global;
245 }
246 
247 static tree_t *ctu_forward_function(tree_t *sema, ctu_t *decl)
248 {
249  CTASSERTF(decl->kind == eCtuDeclFunction, "decl %s is not a function", decl->name);
250 
251  tree_resolve_info_t resolve = {
252  .sema = sema,
253  .user = decl,
254  .fn_resolve = ctu_resolve_function,
255  .fn_resolve_type = ctu_resolve_function_type
256  };
257 
258  return tree_open_function(decl->node, decl->name, NULL, resolve);
259 }
260 
261 static tree_t *ctu_forward_type(tree_t *sema, ctu_t *decl)
262 {
263  CTASSERTF(decl->kind == eCtuDeclTypeAlias, "decl %s is not a type alias", decl->name);
264 
265  tree_resolve_info_t resolve = {
266  .sema = sema,
267  .user = decl,
268  .fn_resolve = ctu_resolve_typealias,
269  .fn_resolve_type = ctu_resolve_typealias
270  };
271 
272  return tree_open_decl(decl->node, decl->name, resolve);
273 }
274 
275 static tree_t *ctu_forward_struct(tree_t *sema, ctu_t *decl)
276 {
277  CTASSERTF(decl->kind == eCtuDeclStruct, "decl %s is not a struct", decl->name);
278 
279  tree_resolve_info_t resolve = {
280  .sema = sema,
281  .user = decl,
282  .fn_resolve = ctu_resolve_struct
283  };
284 
285  return tree_open_struct(decl->node, decl->name, resolve);
286 }
287 
288 static tree_t *ctu_forward_union(tree_t *sema, ctu_t *decl)
289 {
290  CTASSERTF(decl->kind == eCtuDeclUnion, "decl %s is not a union", decl->name);
291 
292  tree_resolve_info_t resolve = {
293  .sema = sema,
294  .user = decl,
295  .fn_resolve = ctu_resolve_union
296  };
297 
298  return tree_open_union(decl->node, decl->name, resolve);
299 }
300 
301 static tree_t *ctu_forward_variant(tree_t *sema, ctu_t *decl)
302 {
303  CTASSERTF(decl->kind == eCtuDeclVariant, "decl %s is not a variant", decl->name);
304 
305  tree_resolve_info_t resolve = {
306  .sema = sema,
307  .user = decl,
308  .fn_resolve = ctu_resolve_variant
309  };
310 
311  return tree_open_enum(decl->node, decl->name, resolve);
312 }
313 
314 static ctu_forward_t new_forward(ctu_tag_t tag, tree_t *decl)
315 {
316  ctu_forward_t fwd = {
317  .tag = tag,
318  .decl = decl
319  };
320 
321  return fwd;
322 }
323 
324 static ctu_forward_t forward_decl_inner(tree_t *sema, ctu_t *decl)
325 {
326  switch (decl->kind)
327  {
328  case eCtuDeclGlobal:
329  return new_forward(eCtuTagValues, ctu_forward_global(sema, decl));
330  case eCtuDeclFunction:
331  return new_forward(eCtuTagFunctions, ctu_forward_function(sema, decl));
332  case eCtuDeclTypeAlias:
333  return new_forward(eCtuTagTypes, ctu_forward_type(sema, decl));
334  case eCtuDeclUnion:
335  return new_forward(eCtuTagTypes, ctu_forward_union(sema, decl));
336  case eCtuDeclStruct:
337  return new_forward(eCtuTagTypes, ctu_forward_struct(sema, decl));
338  case eCtuDeclVariant:
339  return new_forward(eCtuTagTypes, ctu_forward_variant(sema, decl));
340 
341  default: CT_NEVER("invalid decl kind %d", decl->kind);
342  }
343 }
344 
346 {
347  ctu_forward_t fwd = forward_decl_inner(sema, decl);
348 
349  if (decl->kind == eCtuDeclFunction && decl->body == NULL)
350  {
351  tree_set_attrib(fwd.decl, decl->exported ? &kAttribForward : &kAttribImport);
352  }
353  else
354  {
355  tree_set_attrib(fwd.decl, decl->exported ? &kAttribExport : &kAttribPrivate);
356  }
357 
358  ctu_apply_attribs(sema, fwd.decl, decl->attribs);
359 
360  return fwd;
361 }
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_TREE_API void tree_set_storage(tree_t *tree, tree_storage_t storage)
Definition: context.c:58
CT_TREE_API void tree_set_qualifiers(tree_t *tree, tree_quals_t qualifiers)
Definition: context.c:42
CT_PUREFN CT_TREE_API tree_quals_t tree_ty_get_quals(const tree_t *self)
Definition: query.c:257
ctu_kind_t
Definition: ast.h:21
@ eCtuDeclStruct
Definition: ast.h:72
@ eCtuDeclUnion
Definition: ast.h:71
@ eCtuDeclVariant
Definition: ast.h:70
@ eCtuDeclTypeAlias
Definition: ast.h:69
@ eCtuDeclGlobal
Definition: ast.h:65
@ eCtuVariantCase
Definition: ast.h:79
@ eCtuDeclFunction
Definition: ast.h:66
const tree_t * ctu_resolve_storage_type(const tree_t *type)
Definition: expr.c:955
size_t ctu_resolve_storage_length(const tree_t *type)
Definition: expr.c:942
tree_t * ctu_sema_rvalue(ctu_sema_t *sema, const ctu_t *expr, const tree_t *implicit_type)
Definition: expr.c:723
ctu_tag_t
Definition: sema.h:14
tree_t * ctu_get_int_type(digit_t digit, sign_t sign)
Definition: sema.c:202
ctu_sema_t ctu_sema_init(tree_t *sema, tree_t *decl, vector_t *block)
Definition: sema.c:21
tree_t * ctu_sema_type(ctu_sema_t *sema, const ctu_t *type)
Definition: type.c:114
void ctu_resolve_function(tree_t *sema, tree_t *self, void *user)
Definition: function.c:44
void ctu_resolve_function_type(tree_t *sema, tree_t *self, void *user)
Definition: function.c:93
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
Definition: memory.c:16
CT_NODISCARD CT_STD_API map_t * map_optimal(size_t size, hash_info_t info, arena_t *arena)
create a new map with an optimal size
Definition: optimal.c:85
CT_STD_API void map_set(map_t *map, const void *key, void *value)
set a key-value pair in a map
Definition: map.c:294
CT_NODISCARD CT_PUREFN CT_STD_API void * map_get(const map_t *map, const void *key)
get a value from a map
Definition: map.c:324
#define CT_UNUSED(x)
mark a variable as unused
Definition: macros.h:46
CT_NODISCARD CT_ARENA_API void * arena_memdup(STA_READS(size) const void *ptr, size_t size, arena_t *arena)
duplicate a memory region from a custom allocator duplicate a region of memory and return a pointer t...
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
CT_NOTIFY_API void msg_append(event_builder_t builder, const node_t *node, STA_FORMAT_STRING const char *fmt,...)
append additional information to a 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
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
tree_t * tree_open_decl(const node_t *node, const char *name, tree_resolve_info_t resolve)
Definition: decl.c:212
tree_t * tree_type_alias(const node_t *node, const char *name, const tree_t *type, tree_quals_t quals)
Definition: decl.c:268
tree_t * tree_open_function(const node_t *node, const char *name, const tree_t *signature, tree_resolve_info_t resolve)
Definition: decl.c:147
CT_TREE_API tree_t * tree_type_reference(const node_t *node, const char *name, const tree_t *reference)
create a reference type
Definition: tree.c:185
void tree_close_enum(tree_t *self, const tree_t *underlying, vector_t *cases, tree_t *default_case)
Definition: decl.c:383
void tree_close_union(tree_t *self, vector_t *fields)
Definition: decl.c:343
tree_t * tree_open_global(const node_t *node, const char *name, const tree_t *type, tree_resolve_info_t resolve)
Definition: decl.c:140
tree_quals_t
all type qualifiers
Definition: ops.h:25
tree_t * tree_decl_field(const node_t *node, const char *name, const tree_t *type)
Definition: decl.c:193
tree_t * tree_open_struct(const node_t *node, const char *name, tree_resolve_info_t resolve)
Definition: decl.c:307
tree_t * tree_open_enum(const node_t *node, const char *name, tree_resolve_info_t resolve)
Definition: decl.c:373
CT_TREE_API tree_cookie_t * tree_get_cookie(tree_t *sema)
return a resolution cookie
Definition: sema.c:136
tree_t * tree_open_union(const node_t *node, const char *name, tree_resolve_info_t resolve)
Definition: decl.c:335
void tree_close_global(tree_t *self, tree_t *value)
Definition: decl.c:162
void tree_close_struct(tree_t *self, vector_t *fields)
Definition: decl.c:315
tree_t * tree_decl_case(const node_t *node, const char *name, const tree_t *type, tree_t *expr)
Definition: decl.c:205
CT_TREE_API void tree_set_type(tree_t *self, const tree_t *type)
Definition: context.c:150
void tree_close_decl(tree_t *self, const tree_t *other)
Definition: decl.c:217
tree_t * tree_resolve(tree_cookie_t *cookie, const tree_t *decl)
Definition: decl.c:47
void tree_set_attrib(tree_t *self, const tree_attribs_t *attrib)
Definition: decl.c:251
CT_STD_API const hash_info_t kTypeInfoString
type information for a c style string
Definition: typeinfo.c:35
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_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
Definition: vector.c:63
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
void ctu_apply_attribs(tree_t *sema, tree_t *decl, const vector_t *attribs)
Definition: attrib.c:249
ctu_forward_t ctu_forward_decl(tree_t *sema, ctu_t *decl)
Definition: decl.c:345
ctu_t * begin_resolve(tree_t *sema, tree_t *self, void *user, ctu_kind_t kind)
Definition: resolve.c:12
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
Definition: str.c:97
an allocator object
Definition: arena.h:86
ctu_tag_t tag
Definition: decl.h:8
tree_t * decl
Definition: decl.h:9
Definition: ast.h:86
ctu_t * body
Definition: ast.h:119
ctu_kind_t kind
Definition: ast.h:87
const vector_t * attribs
Definition: ast.h:94
const vector_t * fields
Definition: ast.h:129
ctu_t * value
Definition: ast.h:110
ctu_t * underlying
Definition: ast.h:139
ctu_t * case_value
Definition: ast.h:146
bool mut
Definition: ast.h:111
bool default_case
Definition: ast.h:145
const node_t * node
Definition: ast.h:88
ctu_t * type
Definition: ast.h:109
ctu_t * field_type
Definition: ast.h:132
ctu_t * type_alias
Definition: ast.h:125
const vector_t * cases
Definition: ast.h:140
char * name
Definition: ast.h:92
bool exported
Definition: ast.h:93
an event builder handles adding additional information to an event
Definition: notify.h:68
an unordered hash map
Definition: map.h:38
tree_linkage_t link
the link type of the declaration
Definition: tree.h:51
tree_t * sema
Definition: tree.h:60
storage for a value
Definition: context.h:23
const tree_t * storage
the underlying storage type
Definition: context.h:25
Definition: tree.h:67
logger_t * reports
Definition: tree.h:227
size_t length
Definition: tree.h:174
const node_t * node
Definition: tree.h:69
a generic vector of pointers
Definition: vector.c:16