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 "oberon/sema/decl.h"
4 #include "oberon/sema/type.h"
5 #include "oberon/sema/expr.h"
6 
7 #include "memory/memory.h"
8 
9 #include "cthulhu/util/util.h"
10 
11 #include "notify/notify.h"
12 
13 #include "arena/arena.h"
14 
15 #include "std/vector.h"
16 
17 #include "base/panic.h"
18 
19 #include "core/macros.h"
20 
21 static tree_visibility_t remap_visibility(obr_visibility_t vis)
22 {
23  switch (vis)
24  {
25  case eObrVisPrivate: return eVisiblePrivate;
26  case eObrVisPublic:
27  case eObrVisReadOnly: return eVisiblePublic;
28  default: CT_NEVER("remap-visibility %d", vis);
29  }
30 }
31 
32 static tree_linkage_t remap_linkage(obr_visibility_t vis)
33 {
34  switch (vis)
35  {
36  case eObrVisPublic:
37  case eObrVisReadOnly:
38  return eLinkExport;
39  default: return eLinkModule;
40  }
41 }
42 
43 static void set_attribs(tree_t *decl, obr_visibility_t vis, tree_linkage_t linkage)
44 {
45  tree_attribs_t attrib = {
46  .link = linkage,
47  .visibility = remap_visibility(vis)
48  };
49  arena_t *arena = get_global_arena();
50  tree_attribs_t *ptr = arena_memdup(&attrib, sizeof(tree_attribs_t), arena);
51 
52  tree_set_attrib(decl, ptr);
53 }
54 
55 static obr_t *begin_resolve(tree_t *sema, tree_t *self, void *user, obr_kind_t kind)
56 {
57  obr_t *decl = user;
58  CTASSERTF(decl->kind == kind, "decl %s is not a %d", decl->name, kind);
59 
60  CT_UNUSED(sema);
61  CT_UNUSED(self);
62 
63  return decl;
64 }
65 
66 static void set_const_type(tree_t *self, obr_t *decl, const tree_t *type)
67 {
68  tree_t *ref = tree_type_reference(decl->node, decl->name, type);
69  tree_storage_t storage = {
70  .storage = type,
71  .length = 1,
72  .quals = eQualConst
73  };
74 
75  tree_set_storage(self, storage);
76  tree_set_type(self, ref);
77 }
78 
79 static void resolve_const(tree_t *sema, tree_t *self, void *user)
80 {
81  obr_t *decl = begin_resolve(sema, self, user, eObrDeclConst);
82 
83  tree_t *expr = obr_sema_rvalue(sema, decl->value, NULL);
84 
85  set_const_type(self, decl, tree_get_type(expr));
86  tree_close_global(self, expr);
87 }
88 
89 static void resolve_const_type(tree_t *sema, tree_t *self, void *user)
90 {
91  obr_t *decl = begin_resolve(sema, self, user, eObrDeclConst);
92 
93  const tree_t *type = self->initial ? tree_get_type(self->initial) : obr_sema_rvalue(sema, decl->value, NULL);
94  set_const_type(self, decl, type);
95 }
96 
97 static void resolve_var(tree_t *sema, tree_t *self, void *user)
98 {
99  begin_resolve(sema, self, user, eObrDeclVar);
100 
101  tree_t *value = obr_default_value(self->node, tree_get_type(self));
102 
103  tree_close_global(self, value);
104 }
105 
106 static void resolve_type(tree_t *sema, tree_t *self, void *user)
107 {
108  obr_t *decl = begin_resolve(sema, self, user, eObrDeclType);
109 
110  tree_t *type = obr_sema_type(sema, decl->type, decl->name);
111  tree_t *alias = tree_alias(tree_resolve(tree_get_cookie(sema), type), decl->name);
112 
113  tree_close_decl(self, alias);
114 }
115 
116 static void resolve_proc(tree_t *sema, tree_t *self, void *user)
117 {
118  obr_t *decl = begin_resolve(sema, self, user, eObrDeclProcedure);
119 
120  const vector_t *params = tree_fn_get_params(self);
121  size_t param_count = vector_len(params);
122 
123  size_t locals = vector_len(decl->locals);
124  const size_t sizes[eObrTagTotal] = {
125  [eObrTagValues] = locals + param_count,
126  [eObrTagTypes] = 0,
127  [eObrTagProcs] = 0,
128  [eObrTagModules] = 0
129  };
130 
131  tree_t *ctx = tree_module(sema, decl->node, decl->name, eObrTagTotal, sizes);
132 
133  for (size_t i = 0; i < locals; i++)
134  {
135  obr_t *local = vector_get(decl->locals, i);
136  tree_t *type = obr_sema_type(sema, local->type, local->name);
137  tree_t *ref = tree_type_reference(local->node, local->name, type);
138  tree_storage_t storage = {
139  .storage = type,
140  .length = 1,
141  .quals = eQualMutable
142  };
143 
144  tree_t *local_decl = tree_decl_local(local->node, local->name, storage, ref);
145  tree_add_local(self, local_decl);
146  obr_add_decl(ctx, eObrTagValues, local->name, local_decl);
147  }
148 
149  for (size_t i = 0; i < param_count; i++)
150  {
151  tree_t *param = vector_get(params, i);
152  obr_add_decl(ctx, eObrTagValues, param->name, param);
153  }
154 
155  tree_t *body = obr_sema_stmts(ctx, decl->node, decl->body);
156 
157  tree_close_function(self, body);
158 }
159 
160 static tree_t *forward_const(tree_t *sema, obr_t *decl)
161 {
162  tree_resolve_info_t resolve = {
163  .sema = sema,
164  .user = decl,
165  .fn_resolve = resolve_const,
166  .fn_resolve_type = resolve_const_type
167  };
168 
169  // const declarations never have a type, we infer it from the value
170  tree_t *it = tree_open_global(decl->node, decl->name, NULL, resolve);
171  return it;
172 }
173 
174 static tree_t *forward_var(tree_t *sema, obr_t *decl)
175 {
176  tree_resolve_info_t resolve = {
177  .sema = sema,
178  .user = decl,
179  .fn_resolve = resolve_var
180  };
181 
182  tree_t *type = obr_sema_type(sema, decl->type, decl->name);
183  tree_t *ref = tree_type_reference(decl->node, decl->name, type);
184 
185  CTASSERTF(type != NULL, "var %s has no type", decl->name);
186 
187  tree_storage_t storage = {
188  .storage = type,
189  .length = 1,
190  .quals = eQualMutable
191  };
192 
193  tree_t *it = tree_open_global(decl->node, decl->name, ref, resolve);
194  tree_set_storage(it, storage);
195  return it;
196 }
197 
198 static tree_t *forward_type(tree_t *sema, obr_t *decl)
199 {
200  tree_resolve_info_t resolve = {
201  .sema = sema,
202  .user = decl,
203  .fn_resolve = resolve_type
204  };
205 
206  return tree_open_decl(decl->node, decl->name, resolve);
207 }
208 
209 static tree_t *forward_proc(tree_t *sema, obr_t *decl)
210 {
211  tree_t *result = decl->result == NULL ? obr_get_void_type() : obr_sema_type(sema, decl->result, decl->name);
212  arena_t *arena = get_global_arena();
213  size_t len = vector_len(decl->params);
214  vector_t *params = vector_of(len, arena);
215  for (size_t i = 0; i < len; i++)
216  {
217  obr_t *param = vector_get(decl->params, i);
218  CTASSERTF(param->kind == eObrParam, "param %s is not a param (type=%d)", param->name, param->kind);
219 
220  tree_t *type = obr_sema_type(sema, param->type, param->name);
221  vector_set(params, i, tree_decl_param(param->node, param->name, type));
222  }
223 
224  tree_t *signature = tree_type_closure(decl->node, decl->name, result, params, eArityFixed);
225 
226  // if this is an extern declaration it doesnt need a body
227  if (decl->body == NULL)
228  {
229  return tree_decl_function(decl->node, decl->name, signature, params, &gEmptyVector, NULL);
230  }
231 
232  tree_resolve_info_t resolve = {
233  .sema = sema,
234  .user = decl,
235  .fn_resolve = resolve_proc
236  };
237 
238  return tree_open_function(decl->node, decl->name, signature, resolve);
239 }
240 
241 static obr_forward_t forward_inner(tree_t *sema, obr_t *decl)
242 {
243  switch (decl->kind)
244  {
245  case eObrDeclConst: {
246  obr_forward_t fwd = {
247  .tag = eObrTagValues,
248  .decl = forward_const(sema, decl)
249  };
250  return fwd;
251  }
252 
253  case eObrDeclVar: {
254  obr_forward_t fwd = {
255  .tag = eObrTagValues,
256  .decl = forward_var(sema, decl)
257  };
258  return fwd;
259  }
260 
261  case eObrDeclType: {
262  obr_forward_t fwd = {
263  .tag = eObrTagTypes,
264  .decl = forward_type(sema, decl)
265  };
266  return fwd;
267  }
268 
269  default: CT_NEVER("obr-forward-decl %d", decl->kind);
270  }
271 }
272 
274 {
275  if (decl->kind == eObrDeclProcedure)
276  {
277  tree_t *inner = forward_proc(sema, decl);
278  obr_forward_t fwd = {
279  .tag = eObrTagProcs,
280  .decl = inner
281  };
282 
283  set_attribs(fwd.decl, decl->visibility, decl->body == NULL ? eLinkImport : eLinkModule);
284  return fwd;
285  }
286 
287  obr_forward_t fwd = forward_inner(sema, decl);
288  set_attribs(fwd.decl, decl->visibility, remap_linkage(decl->visibility));
289  return fwd;
290 }
291 
292 static void obr_resolve_init(tree_t *sema, tree_t *self, void *user)
293 {
294  obr_t *mod = begin_resolve(sema, self, user, eObrModule);
295 
296  tree_t *body = obr_sema_stmts(sema, mod->node, mod->init);
297  tree_close_function(self, body);
298 }
299 
300 static const tree_attribs_t kEntryPoint = {
301  .link = eLinkEntryCli
302 };
303 
305 {
306  if (mod->init == NULL) { return NULL; }
307 
308  tree_resolve_info_t resolve = {
309  .sema = sema,
310  .user = mod,
311  .fn_resolve = obr_resolve_init
312  };
313 
314  tree_t *signature = tree_type_closure(mod->node, mod->name, obr_get_void_type(), &kEmptyVector, eArityFixed);
315  tree_t *init = tree_open_function(mod->node, mod->name, signature, resolve);
316  tree_set_attrib(init, &kEntryPoint);
317  return init;
318 }
CT_PUREFN CT_TREE_API const tree_t * tree_get_type(const tree_t *tree)
Definition: context.c:132
CT_TREE_API void tree_set_storage(tree_t *tree, tree_storage_t storage)
Definition: context.c:58
CT_PUREFN CT_TREE_API const vector_t * tree_fn_get_params(const tree_t *self)
Definition: query.c:179
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...
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
#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_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
CT_TREE_API tree_t * tree_type_closure(const node_t *node, const char *name, const tree_t *result, const vector_t *params, tree_arity_t arity)
create a function pointer type
Definition: tree.c:146
CT_TREE_API tree_t * tree_module(tree_t *parent, const node_t *node, const char *name, size_t decls, const size_t *sizes)
create a new module
Definition: sema.c:52
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
void tree_close_function(tree_t *self, tree_t *body)
Definition: decl.c:168
tree_visibility_t
symbol visibility
Definition: ops.h:88
CT_TREE_API tree_cookie_t * tree_get_cookie(tree_t *sema)
return a resolution cookie
Definition: sema.c:136
tree_t * tree_decl_param(const node_t *node, const char *name, const tree_t *type)
Definition: decl.c:188
void tree_close_global(tree_t *self, tree_t *value)
Definition: decl.c:162
tree_linkage_t
the linkage of a declaration
Definition: ops.h:72
CT_TREE_API void tree_set_type(tree_t *self, const tree_t *type)
Definition: context.c:150
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_of(size_t len, arena_t *arena)
create a new vector with a specified length
Definition: vector.c:71
CT_STD_API const vector_t kEmptyVector
a global empty vector used to avoid allocating alot of empty vectors
Definition: vector.c:25
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_STD_API vector_t gEmptyVector
a global empty vector used to avoid allocating alot of empty vectors
Definition: vector.c:24
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
obr_forward_t obr_forward_decl(tree_t *sema, obr_t *decl)
Definition: decl.c:273
tree_t * obr_add_init(tree_t *sema, obr_t *mod)
Definition: decl.c:304
obr_visibility_t
Definition: ast.h:23
obr_kind_t
Definition: ast.h:42
@ eObrDeclVar
Definition: ast.h:77
@ eObrDeclConst
Definition: ast.h:78
@ eObrDeclProcedure
Definition: ast.h:80
@ eObrDeclType
Definition: ast.h:79
@ eObrModule
Definition: ast.h:88
@ eObrParam
Definition: ast.h:84
tree_t * obr_default_value(const node_t *node, const tree_t *type)
Definition: expr.c:197
tree_t * obr_sema_rvalue(tree_t *sema, obr_t *expr, const tree_t *implicit_type)
Definition: expr.c:160
tree_t * obr_sema_stmts(tree_t *sema, const node_t *node, vector_t *stmts)
Definition: expr.c:313
void obr_add_decl(tree_t *sema, obr_tag_t tag, const char *name, tree_t *decl)
add decls
Definition: sema.c:43
tree_t * obr_get_void_type(void)
Definition: sema.c:117
@ eObrTagTotal
Definition: sema.h:13
tree_t * obr_sema_type(tree_t *sema, obr_t *type, const char *name)
Definition: type.c:128
ctu_t * begin_resolve(tree_t *sema, tree_t *self, void *user, ctu_kind_t kind)
Definition: resolve.c:12
an allocator object
Definition: arena.h:86
tree_t * decl
Definition: decl.h:11
obr_tag_t tag
Definition: decl.h:10
Definition: ast.h:93
obr_kind_t kind
Definition: ast.h:94
obr_t * result
Definition: ast.h:208
char * name
Definition: ast.h:184
const node_t * node
Definition: ast.h:95
const vector_t * params
Definition: ast.h:207
obr_t * type
Definition: ast.h:198
vector_t * body
Definition: ast.h:211
vector_t * init
Definition: ast.h:192
vector_t * locals
Definition: ast.h:210
obr_t * value
Definition: ast.h:202
obr_visibility_t visibility
Definition: ast.h:185
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
tree_t * initial
Definition: tree.h:218
size_t length
Definition: tree.h:174
const char * name
the name of the declaration
Definition: tree.h:163
a generic vector of pointers
Definition: vector.c:16