Cthulhu  0.2.10
Cthulhu compiler collection
decl.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
3 #include "common.h"
4 
5 #include "core/macros.h"
7 #include "cthulhu/tree/query.h"
8 
9 #include "std/vector.h"
10 
11 #include "memory/memory.h"
12 #include "arena/arena.h"
13 
14 #include "base/panic.h"
15 #include <stdint.h>
16 #include <stdio.h>
17 
18 static const tree_storage_t kEmptyStorage = {
19  .storage = NULL,
20  .length = SIZE_MAX,
21  .quals = eQualNone
22 };
23 
24 static tree_t *decl_open(const node_t *node, const char *name, const tree_t *type, tree_kind_t expected, const tree_resolve_info_t *resolve)
25 {
26  tree_t *self = tree_decl(expected, node, type, name, eQualNone);
27 
28  if (resolve != NULL)
29  {
30  CTASSERT(resolve->fn_resolve != NULL);
31  CTASSERT(resolve->sema != NULL);
32  }
33 
34  self->resolve = resolve;
35 
36  return self;
37 }
38 
39 static void decl_close(tree_t *decl, tree_kind_t kind)
40 {
41  CTASSERTF(tree_is(decl, kind), "decl %s is the wrong type, expected %s", tree_to_string(decl), tree_kind_to_string(kind));
42 
43  decl->kind = kind;
44  decl->resolve = NULL;
45 }
46 
47 tree_t *tree_resolve(tree_cookie_t *cookie, const tree_t *decl)
48 {
49  tree_t *inner = (tree_t*)decl;
50  if (tree_is(decl, eTreeError)) { return inner; }
51 
52  const tree_resolve_info_t *res = decl->resolve;
53  if (res == NULL) { return inner; }
54 
55  size_t index = vector_find(cookie->stack, decl);
56  if (index != SIZE_MAX)
57  {
58  // TODO: better reporting
59  msg_notify(cookie->reports, &kEvent_CyclicDependency, decl->node, "cyclic dependency when resolving %s", tree_get_name(decl));
60  return tree_error(decl->node, &kEvent_CyclicDependency, "cyclic dependency");
61  }
62 
63  vector_push(&cookie->stack, inner);
64 
65  CTASSERTF(res->fn_resolve != NULL, "resolve function for %s is NULL", tree_to_string(inner));
66  res->fn_resolve(res->sema, inner, res->user);
67 
68  vector_drop(cookie->stack);
69 
70  return inner;
71 }
72 
73 static tree_t *resolve_type_inner(const tree_t *decl)
74 {
75  tree_t *inner = (tree_t*)decl;
76  if (tree_is(decl, eTreeError)) { return inner; }
77 
78  if (tree_is(decl, eTreePartial))
79  {
80  const tree_resolve_info_t *res = decl->resolve;
81  CTASSERTF(res != NULL, "resolve info for %s is NULL", tree_to_string(decl));
82  CTASSERTF(res->fn_resolve_type != NULL, "resolve type function for %s is NULL", tree_to_string(decl));
83 
84  res->fn_resolve_type(res->sema, inner, res->user);
85 
86  return inner;
87  }
88 
89  if (!tree_is(decl, eTreeDeclFunction)) { return inner; }
90 
91  const tree_resolve_info_t *res = decl->resolve;
92  if (res == NULL) { return inner; }
93 
94  // TODO: should this be ok?
95  if (res->fn_resolve_type == NULL) { return inner; }
96 
97  res->fn_resolve_type(res->sema, inner, res->user);
98 
99  return inner;
100 }
101 
103 {
104  CTASSERT(cookie != NULL);
105 
106  size_t index = vector_find(cookie->types, decl);
107  if (index != SIZE_MAX)
108  {
109  // TODO: better reporting
110  msg_notify(cookie->reports, &kEvent_CyclicDependency, decl->node, "cyclic dependency when resolving %s", tree_get_name(decl));
111  return tree_error(decl->node, &kEvent_CyclicDependency, "cyclic dependency");
112  }
113 
114  vector_push(&cookie->types, (tree_t*)decl);
115 
116  tree_t *result = resolve_type_inner(decl);
117 
118  vector_drop(cookie->types);
119 
120  return result;
121 }
122 
124  const node_t *node, const char *name,
125  tree_storage_t storage, const tree_t *type, tree_t *value)
126 {
127  tree_t *self = decl_open(node, name, type, eTreeDeclGlobal, NULL);
128  tree_set_storage(self, storage);
129  tree_close_global(self, value);
130  return self;
131 }
132 
133 static tree_resolve_info_t *dup_resolve_info(tree_resolve_info_t *info)
134 {
135  arena_t *arena = get_global_arena();
136  tree_resolve_info_t *copy = arena_memdup(info, sizeof(tree_resolve_info_t), arena);
137  return copy;
138 }
139 
140 tree_t *tree_open_global(const node_t *node, const char *name, const tree_t *type, tree_resolve_info_t resolve)
141 {
142  tree_t *self = decl_open(node, name, type, eTreeDeclGlobal, dup_resolve_info(&resolve));
143  tree_set_storage(self, kEmptyStorage);
144  return self;
145 }
146 
147 tree_t *tree_open_function(const node_t *node, const char *name, const tree_t *signature, tree_resolve_info_t resolve)
148 {
149  if (signature != NULL)
150  {
151  CTASSERTF(tree_is(signature, eTreeTypeClosure), "signature %s is not a closure", tree_to_string(signature));
152  }
153 
154  arena_t *arena = get_global_arena();
155 
156  tree_t *self = decl_open(node, name, signature, eTreeDeclFunction, dup_resolve_info(&resolve));
157  self->params = signature == NULL ? NULL : signature->params;
158  self->locals = vector_new(4, arena);
159  return self;
160 }
161 
162 void tree_close_global(tree_t *self, tree_t *value)
163 {
164  decl_close(self, eTreeDeclGlobal);
165  self->initial = value;
166 }
167 
169 {
170  TREE_EXPECT(self, eTreeDeclFunction);
171  TREE_EXPECT(tree_get_type(self), eTreeTypeClosure);
172 
173  decl_close(self, eTreeDeclFunction);
174  self->body = body;
175 
176  const vector_t *params = tree_fn_get_params(self);
177  tree_arity_t arity = tree_fn_get_arity(self);
178 
179  CT_UNUSED(arity);
180 
181  CTASSERTF(vector_len(self->params) == vector_len(params),
182  "decl %s has %zu params, expected %zu%s parameter(s)",
183  tree_get_name(self), vector_len(self->params),
184  vector_len(params), (arity == eArityFixed) ? "" : " or more"
185  );
186 }
187 
188 tree_t *tree_decl_param(const node_t *node, const char *name, const tree_t *type)
189 {
190  return tree_decl(eTreeDeclParam, node, type, name, eQualNone);
191 }
192 
193 tree_t *tree_decl_field(const node_t *node, const char *name, const tree_t *type)
194 {
195  return tree_decl(eTreeDeclField, node, type, name, eQualNone);
196 }
197 
198 tree_t *tree_decl_local(const node_t *node, const char *name, tree_storage_t storage, const tree_t *type)
199 {
200  tree_t *self = tree_decl(eTreeDeclLocal, node, type, name, eQualNone);
201  tree_set_storage(self, storage);
202  return self;
203 }
204 
205 tree_t *tree_decl_case(const node_t *node, const char *name, const tree_t *type, tree_t *expr)
206 {
207  tree_t *self = tree_decl(eTreeDeclCase, node, type, name, eQualNone);
208  self->case_value = expr;
209  return self;
210 }
211 
212 tree_t *tree_open_decl(const node_t *node, const char *name, tree_resolve_info_t resolve)
213 {
214  return decl_open(node, name, NULL, eTreePartial, dup_resolve_info(&resolve));
215 }
216 
217 void tree_close_decl(tree_t *self, const tree_t *other)
218 {
219  CTASSERT(other != NULL);
220 
221  *self = *other;
222 }
223 
225  const node_t *node, const char *name, const tree_t *signature,
226  const vector_t *params, vector_t *locals, tree_t *body
227 )
228 {
229  tree_t *self = decl_open(node, name, signature, eTreeDeclFunction, NULL);
230  self->params = params;
231  self->locals = locals;
232  tree_close_function(self, body);
233  return self;
234 }
235 
236 tree_t *tree_decl_attrib(const node_t *node, const char *name, vector_t *params)
237 {
238  tree_t *self = tree_decl(eTreeDeclAttrib, node, NULL, name, eQualNone);
239  self->params = params;
240  return self;
241 }
242 
243 void tree_add_local(tree_t *self, tree_t *decl)
244 {
245  CTASSERTF(tree_is(self, eTreeDeclFunction), "cannot add locals to a declaration %s", tree_to_string(self));
246  CTASSERTF(tree_is(decl, eTreeDeclLocal), "cannot add a non-local %s to a function as a local", tree_to_string(decl));
247 
248  vector_push(&self->locals, decl);
249 }
250 
251 void tree_set_attrib(tree_t *self, const tree_attribs_t *attrib)
252 {
253  CTASSERT(self != NULL);
254 
255  self->attrib = attrib;
256 }
257 
258 tree_t *tree_alias(const tree_t *tree, const char *name)
259 {
260  CTASSERTF(tree != NULL && name != NULL, "(tree=%p, name=%p)", (void*)tree, (void*)name);
261 
262  arena_t *arena = get_global_arena();
263  tree_t *copy = arena_memdup(tree, sizeof(tree_t), arena);
264  copy->name = name;
265  return copy;
266 }
267 
268 tree_t *tree_type_alias(const node_t *node, const char *name, const tree_t *type, tree_quals_t quals)
269 {
270  tree_t *self = tree_decl(eTreeTypeAlias, node, type, name, quals);
271  return self;
272 }
273 
274 const tree_t *tree_follow_type(const tree_t *type)
275 {
276  if (type == NULL) return NULL;
277 
278  if (tree_is(type, eTreeTypeAlias))
279  return tree_follow_type(tree_get_type(type));
280 
281  return type;
282 }
283 
287 
288 static void check_aggregate_fields(vector_t *fields)
289 {
290  size_t len = vector_len(fields);
291  for (size_t i = 0; i < len; i++)
292  {
293  const tree_t *field = vector_get(fields, i);
294  CTASSERTF(tree_is(field, eTreeDeclField), "expected field, got %s", tree_to_string(field));
295  }
296 }
297 
298 tree_t *tree_decl_struct(const node_t *node, const char *name, vector_t *fields)
299 {
300  check_aggregate_fields(fields);
301 
302  tree_t *self = decl_open(node, name, NULL, eTreeTypeStruct, NULL);
303  self->fields = fields;
304  return self;
305 }
306 
307 tree_t *tree_open_struct(const node_t *node, const char *name, tree_resolve_info_t resolve)
308 {
309  arena_t *arena = get_global_arena();
310  tree_t *self = decl_open(node, name, NULL, eTreeTypeStruct, dup_resolve_info(&resolve));
311  self->fields = vector_new(4, arena);
312  return self;
313 }
314 
315 void tree_close_struct(tree_t *self, vector_t *fields)
316 {
317  decl_close(self, eTreeTypeStruct);
318  self->fields = fields;
319  check_aggregate_fields(fields);
320 }
321 
325 
326 tree_t *tree_decl_union(const node_t *node, const char *name, vector_t *fields)
327 {
328  check_aggregate_fields(fields);
329 
330  tree_t *self = decl_open(node, name, NULL, eTreeTypeUnion, NULL);
331  self->fields = fields;
332  return self;
333 }
334 
335 tree_t *tree_open_union(const node_t *node, const char *name, tree_resolve_info_t resolve)
336 {
337  arena_t *arena = get_global_arena();
338  tree_t *self = decl_open(node, name, NULL, eTreeTypeUnion, dup_resolve_info(&resolve));
339  self->fields = vector_new(4, arena);
340  return self;
341 }
342 
343 void tree_close_union(tree_t *self, vector_t *fields)
344 {
345  decl_close(self, eTreeTypeUnion);
346  self->fields = fields;
347  check_aggregate_fields(fields);
348 }
349 
353 
354 #define CHECK_CASE(TY) CTASSERTF(tree_is(TY, eTreeDeclCase), "expected case, got %s", tree_to_string(TY));
355 
356 static void check_enum_cases(vector_t *cases)
357 {
358  size_t len = vector_len(cases);
359  for (size_t i = 0; i < len; i++)
360  {
361  const tree_t *field = vector_get(cases, i);
362  CHECK_CASE(field);
363  }
364 }
365 
366 tree_t *tree_decl_enum(const node_t *node, const char *name, const tree_t *underlying, vector_t *fields, tree_t *default_case)
367 {
368  tree_t *self = decl_open(node, name, NULL, eTreeTypeEnum, NULL);
369  tree_close_enum(self, underlying, fields, default_case);
370  return self;
371 }
372 
373 tree_t *tree_open_enum(const node_t *node, const char *name, tree_resolve_info_t resolve)
374 {
375  arena_t *arena = get_global_arena();
376  tree_t *self = decl_open(node, name, NULL, eTreeTypeEnum, dup_resolve_info(&resolve));
377  self->underlying = NULL;
378  self->cases = vector_new(4, arena);
379  self->default_case = NULL;
380  return self;
381 }
382 
383 void tree_close_enum(tree_t *self, const tree_t *underlying, vector_t *cases, tree_t *default_case)
384 {
385  decl_close(self, eTreeTypeEnum);
386 
387  self->underlying = underlying;
388  self->cases = cases;
389 
390  // TODO: should this be a responsibility of tree?
391  self->default_case = default_case;
392 
393  CTASSERTF(tree_is(underlying, eTreeTypeDigit), "enums must have an underlying digit type, got %s", tree_to_string(underlying));
394 
395  check_enum_cases(cases);
396  if (default_case != NULL)
397  {
398  CHECK_CASE(default_case);
399  }
400 }
CT_PUREFN CT_TREE_API const char * tree_get_name(const tree_t *tree)
Definition: context.c:102
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_PUREFN CT_TREE_API tree_arity_t tree_fn_get_arity(const tree_t *self)
Definition: query.c:191
CT_TREE_API const char * tree_to_string(const tree_t *self)
Definition: query.c:40
CT_BEGIN_API CT_TREE_API const char * tree_kind_to_string(tree_kind_t kind)
Definition: query.c:23
CT_PUREFN CT_TREE_API const vector_t * tree_fn_get_params(const tree_t *self)
Definition: query.c:179
CT_LOCAL tree_t * tree_decl(tree_kind_t kind, const node_t *node, const tree_t *type, const char *name, tree_quals_t quals)
Definition: tree.c:35
#define TREE_EXPECT(SELF, KIND)
Definition: common.h:22
tree_t * tree_decl_attrib(const node_t *node, const char *name, vector_t *params)
Definition: decl.c:236
#define CHECK_CASE(TY)
Definition: decl.c:354
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
Definition: memory.c:16
#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
#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_arity_t
all arities
Definition: ops.h:64
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
tree_t * tree_decl_enum(const node_t *node, const char *name, const tree_t *underlying, vector_t *fields, tree_t *default_case)
Definition: decl.c:366
tree_t * tree_decl_struct(const node_t *node, const char *name, vector_t *fields)
Definition: decl.c:298
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
void tree_close_function(tree_t *self, tree_t *body)
Definition: decl.c:168
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_decl_global(const node_t *node, const char *name, tree_storage_t storage, const tree_t *type, tree_t *value)
Definition: decl.c:123
CT_TREE_API tree_t * tree_error(const node_t *node, const diagnostic_t *diagnostic, const char *message,...)
Definition: tree.c:67
tree_t * tree_decl_union(const node_t *node, const char *name, vector_t *fields)
Definition: decl.c:326
tree_t * tree_open_enum(const node_t *node, const char *name, tree_resolve_info_t resolve)
Definition: decl.c:373
tree_t * tree_decl_param(const node_t *node, const char *name, const tree_t *type)
Definition: decl.c:188
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_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
tree_t * tree_decl_case(const node_t *node, const char *name, const tree_t *type, tree_t *expr)
Definition: decl.c:205
const tree_t * tree_follow_type(const tree_t *type)
Definition: decl.c:274
void tree_add_local(tree_t *self, tree_t *decl)
Definition: decl.c:243
tree_t * tree_alias(const tree_t *tree, const char *name)
Definition: decl.c:258
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
tree_t * tree_decl_function(const node_t *node, const char *name, const tree_t *signature, const vector_t *params, vector_t *locals, tree_t *body)
Definition: decl.c:224
tree_t * tree_decl_local(const node_t *node, const char *name, tree_storage_t storage, const tree_t *type)
Definition: decl.c:198
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_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
Definition: vector.c:108
CT_STD_API void vector_drop(vector_t *vector)
pop a value from the end of a vector
Definition: vector.c:117
CT_PUREFN CT_STD_API size_t vector_find(vector_t *vector, const void *element)
find an element in a vector searches via pointer equality
Definition: vector.c:160
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
an allocator object
Definition: arena.h:86
a position in a source file
Definition: node.h:23
tree_resolve_type_t fn_resolve_type
Definition: tree.h:64
tree_t * sema
Definition: tree.h:60
tree_resolve_t fn_resolve
Definition: tree.h:63
void * user
Definition: tree.h:61
storage for a value
Definition: context.h:23
const tree_t * storage
the underlying storage type
Definition: context.h:25
Definition: tree.h:67
tree_kind_t kind
Definition: tree.h:68
vector_t * cases
Definition: tree.h:189
size_t length
Definition: tree.h:174
const char * name
the name of the declaration
Definition: tree.h:163
const tree_resolve_info_t * resolve
the resolve configuration of the declaration, NULL if resolved
Definition: tree.h:165
const vector_t * params
Definition: tree.h:197
const node_t * node
Definition: tree.h:69
a generic vector of pointers
Definition: vector.c:16