Cthulhu  0.2.10
Cthulhu compiler collection
tree.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
3 #include "arena/arena.h"
4 #include "base/util.h"
5 #include "common.h"
6 
7 #include "cthulhu/tree/query.h"
8 
9 #include "notify/notify.h"
10 #include "std/vector.h"
11 #include "std/str.h"
12 
13 #include "memory/memory.h"
14 
15 #include "base/panic.h"
16 
17 static const tree_attribs_t kDefaultAttrib = {
18  .link = eLinkModule,
19  .visibility = eVisiblePrivate
20 };
21 
22 tree_t *tree_new(tree_kind_t kind, const node_t *node, const tree_t *type)
23 {
24  arena_t *arena = get_global_arena();
25  tree_t *self = ARENA_MALLOC(sizeof(tree_t), tree_kind_to_string(kind), NULL, arena);
26 
27  self->kind = kind;
28  self->node = node;
29  self->type = type;
30  self->attribs = NULL;
31 
32  return self;
33 }
34 
35 tree_t *tree_decl(tree_kind_t kind, const node_t *node, const tree_t *type, const char *name, tree_quals_t quals)
36 {
37  tree_t *self = tree_new(kind, node, type);
38  ARENA_RENAME(self, (name == NULL) ? "<anonymous>" : name, get_global_arena());
39 
40  self->name = name;
41  self->attrib = &kDefaultAttrib;
42  self->resolve = NULL;
43  self->quals = quals;
44  self->eval_model = eEvalRuntime;
45 
46  return self;
47 }
48 
49 void tree_report(logger_t *reports, const tree_t *error)
50 {
51  msg_notify(reports, error->diagnostic, tree_get_node(error), "%s", error->message);
52 }
53 
54 static tree_t *error_vformat(const node_t *node, const diagnostic_t *diagnostic, const char *message, va_list args)
55 {
56  CTASSERT(diagnostic != NULL);
57 
58  arena_t *arena = get_global_arena();
59 
60  tree_t *self = tree_new(eTreeError, node, NULL);
61  self->type = self;
62  self->diagnostic = diagnostic;
63  self->message = str_vformat(arena, message, args);
64  return self;
65 }
66 
67 tree_t *tree_error(const node_t *node, const diagnostic_t *diagnostic, const char *message, ...)
68 {
69  va_list args;
70  va_start(args, message);
71  tree_t *self = error_vformat(node, diagnostic, message, args);
72  va_end(args);
73  return self;
74 }
75 
76 tree_t *tree_raise(const node_t *node, logger_t *reports, const diagnostic_t *diagnostic, const char *message, ...)
77 {
78  va_list args;
79  va_start(args, message);
80  tree_t *self = error_vformat(node, diagnostic, message, args);
81  va_end(args);
82 
83  tree_report(reports, self);
84 
85  return self;
86 }
87 
91 
93 static bool is_type(tree_kind_t kind)
94 {
95  return kind_has_tag(kind, eTagIsType) || (kind == eTreeError);
96 }
97 
99 static bool is_load_type(tree_kind_t kind)
100 {
101  switch (kind)
102  {
103  case eTreeError:
104  case eTreeTypePointer:
105  case eTreeTypeArray:
106  case eTreeTypeReference:
107  return true;
108 
109  default:
110  return false;
111  }
112 }
113 
114 #define EXPECT_TYPE(TYPE) CTASSERTF(is_type(tree_get_kind(TYPE)), "expected type, found %s", tree_to_string(TYPE))
115 
116 #define EXPECT_LOAD_TYPE(TYPE) CTASSERTF(is_load_type(tree_get_kind(TYPE)), "expected load type, found %s", tree_to_string(TYPE))
117 
118 tree_t *tree_type_empty(const node_t *node, const char *name)
119 {
120  return tree_decl(eTreeTypeUnit, node, NULL, name, eQualNone);
121 }
122 
123 tree_t *tree_type_unit(const node_t *node, const char *name)
124 {
125  return tree_decl(eTreeTypeUnit, node, NULL, name, eQualNone);
126 }
127 
128 tree_t *tree_type_bool(const node_t *node, const char *name)
129 {
130  return tree_decl(eTreeTypeBool, node, NULL, name, eQualNone);
131 }
132 
133 tree_t *tree_type_opaque(const node_t *node, const char *name)
134 {
135  return tree_decl(eTreeTypeOpaque, node, NULL, name, eQualNone);
136 }
137 
138 tree_t *tree_type_digit(const node_t *node, const char *name, digit_t digit, sign_t sign)
139 {
140  tree_t *self = tree_decl(eTreeTypeDigit, node, NULL, name, eQualNone);
141  self->digit = digit;
142  self->sign = sign;
143  return self;
144 }
145 
146 tree_t *tree_type_closure(const node_t *node, const char *name, const tree_t *result, const vector_t *params, tree_arity_t arity)
147 {
148  EXPECT_TYPE(result);
149  CTASSERT(params != NULL);
150 
151  size_t len = vector_len(params);
152  for (size_t i = 0; i < len; i++)
153  {
154  const tree_t *param = vector_get(params, i);
155  TREE_EXPECT(param, eTreeDeclParam);
156  }
157 
158  tree_t *self = tree_decl(eTreeTypeClosure, node, NULL, name, eQualNone);
159  self->return_type = result;
160  self->params = params;
161  self->arity = arity;
162  return self;
163 }
164 
165 tree_t *tree_type_pointer(const node_t *node, const char *name, const tree_t *pointer, size_t length)
166 {
167  EXPECT_TYPE(pointer);
168 
169  tree_t *self = tree_decl(eTreeTypePointer, node, NULL, name, eQualNone);
170  self->ptr = pointer;
171  self->length = length;
172  return self;
173 }
174 
175 tree_t *tree_type_array(const node_t *node, const char *name, const tree_t *array, size_t length)
176 {
177  EXPECT_TYPE(array);
178 
179  tree_t *self = tree_decl(eTreeTypeArray, node, NULL, name, eQualNone);
180  self->ptr = array;
181  self->length = length;
182  return self;
183 }
184 
185 tree_t *tree_type_reference(const node_t *node, const char *name, const tree_t *reference)
186 {
187  EXPECT_TYPE(reference);
188 
189  tree_t *self = tree_decl(eTreeTypeReference, node, NULL, name, eQualNone);
190  self->ptr = reference;
191  return self;
192 }
193 
197 
198 tree_t *tree_expr_empty(const node_t *node, const tree_t *type)
199 {
200  return tree_new(eTreeExprEmpty, node, type);
201 }
202 
203 tree_t *tree_expr_unit(const node_t *node, const tree_t *type)
204 {
205  return tree_new(eTreeExprUnit, node, type);
206 }
207 
208 tree_t *tree_expr_bool(const node_t *node, const tree_t *type, bool value)
209 {
210  TREE_EXPECT(type, eTreeTypeBool);
211 
212  tree_t *self = tree_new(eTreeExprBool, node, type);
213  self->bool_value = value;
214  return self;
215 }
216 
217 tree_t *tree_expr_digit(const node_t *node, const tree_t *type, const mpz_t value)
218 {
219  TREE_EXPECT(type, eTreeTypeDigit);
220 
221  tree_t *self = tree_new(eTreeExprDigit, node, type);
222  mpz_init_set(self->digit_value, value);
223  return self;
224 }
225 
226 tree_t *tree_expr_digit_int(const node_t *node, const tree_t *type, int value)
227 {
228  mpz_t val;
229  mpz_init_set_si(val, value);
230  tree_t *self = tree_expr_digit(node, type, val);
231  mpz_clear(val);
232  return self;
233 }
234 
235 tree_t *tree_expr_string(const node_t *node, const tree_t *type, const char *value, size_t length)
236 {
237  CTASSERT(value != NULL);
238 
239  tree_t *self = tree_new(eTreeExprString, node, type);
240  self->string_value = text_view_make(value, length);
241  return self;
242 }
243 
247 
249 #define TREE_EXPECT_ADDRESS(TYPE) CTASSERTF(tree_is(TYPE, eTreeTypePointer) || tree_is(TYPE, eTreeTypeReference) || tree_is(TYPE, eTreeTypeOpaque) || tree_is(TYPE, eTreeError), "expected reference or pointer, found %s", tree_to_string(TYPE))
250 
251 tree_t *tree_expr_cast(const node_t *node, const tree_t *type, const tree_t *expr, tree_cast_t cast)
252 {
253  CTASSERT(expr != NULL);
254 
255  tree_t *self = tree_new(eTreeExprCast, node, type);
256  self->expr = expr;
257  self->cast = cast;
258  return self;
259 }
260 
261 tree_t *tree_expr_load(const node_t *node, tree_t *expr)
262 {
263  const tree_t *type = tree_get_type(expr);
264  EXPECT_LOAD_TYPE(type);
265 
266  tree_t *self = tree_new(eTreeExprLoad, node, tree_ty_load_type(type));
267  self->load = expr;
268  return self;
269 }
270 
271 static const tree_t *get_ref_inner(const tree_t *ty)
272 {
273  if (tree_is(ty, eTreeTypeReference) || tree_is(ty, eTreeTypePointer))
274  {
275  return ty->ptr;
276  }
277 
278  return ty;
279 }
280 
281 tree_t *tree_expr_address(const node_t *node, tree_t *expr)
282 {
283  const tree_t *type = tree_get_type(expr);
284  tree_t *inner = tree_type_pointer(node, tree_get_name(type), get_ref_inner(type), 1);
285  tree_t *self = tree_new(eTreeExprAddressOf, node, inner);
286  self->expr = expr;
287  return self;
288 }
289 
290 tree_t *tree_expr_unary(const node_t *node, unary_t unary, tree_t *expr)
291 {
292  tree_t *self = tree_new(eTreeExprUnary, node, tree_get_type(expr));
293  self->unary = unary;
294  self->operand = expr;
295  return self;
296 }
297 
298 tree_t *tree_expr_binary(const node_t *node, const tree_t *type, binary_t binary, const tree_t *lhs, const tree_t *rhs)
299 {
300  tree_t *self = tree_new(eTreeExprBinary, node, type);
301  self->binary = binary;
302  self->lhs = lhs;
303  self->rhs = rhs;
304  return self;
305 }
306 
307 tree_t *tree_expr_compare(const node_t *node, const tree_t *type, compare_t compare, const tree_t *lhs, const tree_t *rhs)
308 {
309  CTASSERT(lhs != NULL);
310  CTASSERT(rhs != NULL);
311 
312  tree_t *self = tree_new(eTreeExprCompare, node, type);
313  self->compare = compare;
314  self->lhs = lhs;
315  self->rhs = rhs;
316  return self;
317 }
318 
319 tree_t *tree_expr_field(const node_t *node, const tree_t *type, tree_t *object, tree_t *field)
320 {
321  const tree_t *outer = tree_get_type(object);
322  const tree_t *ty = get_ref_inner(outer);
323 
324  CTASSERTF(tree_ty_is_address(outer), "object must be an address, found %s", tree_to_string(outer));
325  CTASSERTF(tree_is(ty, eTreeTypeStruct), "object must be an aggregate, found %s", tree_to_string(ty));
326 
327  tree_t *self = tree_new(eTreeExprField, node, type);
328  self->object = object;
329  self->field = field;
330  return self;
331 }
332 
333 tree_t *tree_expr_offset(const node_t *node, const tree_t *type, tree_t *object, tree_t *offset)
334 {
335  CTASSERT(object != NULL);
336  CTASSERT(offset != NULL);
337 
338  tree_t *self = tree_new(eTreeExprOffset, node, type);
339  self->object = object;
340  self->offset = offset;
341  return self;
342 }
343 
344 tree_t *tree_expr_call(const node_t *node, const tree_t *callee, const vector_t *args)
345 {
346  CTASSERT(callee != NULL);
347  CTASSERT(args != NULL);
348 
349  tree_t *self = tree_new(eTreeExprCall, node, tree_fn_get_return(tree_get_type(callee)));
350  self->callee = callee;
351  self->args = args;
352  return self;
353 }
354 
358 
359 tree_t *tree_stmt_block(const node_t *node, const vector_t *stmts)
360 {
361  CTASSERT(stmts != NULL);
362 
363  tree_t *self = tree_new(eTreeStmtBlock, node, NULL);
364  self->stmts = stmts;
365  return self;
366 }
367 
368 tree_t *tree_stmt_return(const node_t *node, const tree_t *value)
369 {
370  CTASSERT(value != NULL);
371 
372  tree_t *self = tree_new(eTreeStmtReturn, node, NULL);
373  self->value = value;
374  return self;
375 }
376 
377 static tree_t *stmt_assign_inner(const node_t *node, tree_t *dst, const tree_t *src, bool init)
378 {
379  const tree_t *dst_type = tree_get_type(dst);
380  TREE_EXPECT_ADDRESS(dst_type);
381 
382  CTASSERT(src != NULL);
383 
384  tree_t *self = tree_new(eTreeStmtAssign, node, NULL);
385  self->dst = dst;
386  self->src = src;
387  self->init = init;
388  return self;
389 }
390 
391 tree_t *tree_stmt_assign(const node_t *node, tree_t *dst, const tree_t *src)
392 {
393  return stmt_assign_inner(node, dst, src, false);
394 }
395 
396 tree_t *tree_stmt_init(const node_t *node, tree_t *dst, tree_t *src)
397 {
398  return stmt_assign_inner(node, dst, src, true);
399 }
400 
401 tree_t *tree_stmt_loop(const node_t *node, tree_t *cond, tree_t *body, tree_t *other)
402 {
403  CTASSERT(cond != NULL);
404  CTASSERT(body != NULL);
405 
406  tree_t *self = tree_new(eTreeStmtLoop, node, NULL);
407  self->cond = cond;
408  self->then = body;
409  self->other = other;
410  return self;
411 }
412 
413 tree_t *tree_stmt_branch(const node_t *node, tree_t *cond, tree_t *then, tree_t *other)
414 {
415  CTASSERT(cond != NULL);
416  CTASSERT(then != NULL);
417 
418  tree_t *self = tree_new(eTreeStmtBranch, node, NULL);
419  self->cond = cond;
420  self->then = then;
421  self->other = other;
422  return self;
423 }
424 
425 tree_t *tree_stmt_jump(const node_t *node, tree_t *label, tree_jump_t jump)
426 {
427  CTASSERT(label != NULL);
428  CTASSERTF(tree_is(label, eTreeStmtLoop), "label must be a loop, found %s", tree_to_string(label));
429 
430  tree_t *self = tree_new(eTreeStmtJump, node, NULL);
431  self->label = label;
432  self->jump = jump;
433  return self;
434 }
CT_PUREFN CT_TREE_API const node_t * tree_get_node(const tree_t *tree)
Definition: context.c:94
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_PUREFN CT_TREE_API bool tree_ty_is_address(const tree_t *type)
Definition: query.c:238
CT_TREE_API const char * tree_to_string(const tree_t *self)
Definition: query.c:40
CT_PUREFN CT_TREE_API const tree_t * tree_fn_get_return(const tree_t *self)
Definition: query.c:167
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 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_CONSTFN CT_LOCAL bool kind_has_tag(tree_kind_t kind, tree_tags_t tags)
Definition: context.c:17
#define TREE_EXPECT(SELF, KIND)
Definition: common.h:22
#define EXPECT_LOAD_TYPE(TYPE)
Definition: tree.c:116
#define EXPECT_TYPE(TYPE)
Definition: tree.c:114
#define TREE_EXPECT_ADDRESS(TYPE)
must be either storage or a pointer
Definition: tree.c:249
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
tree_t * tree_new(tree_kind_t kind, const node_t *node, const tree_t *type)
Definition: tree.c:22
#define CT_CONSTFN
mark a function as const, has no side effects and always returns the same value for the same argument...
Definition: analyze.h:227
CT_CONSTFN CT_BASE_API text_view_t text_view_make(STA_READS(length) const char *text, size_t length)
create a new non-owning text array text must be at least length bytes long
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
Definition: memory.c:16
#define ARENA_RENAME(arena, ptr, name)
rename a pointer in a custom allocator
Definition: arena.h:390
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
Definition: arena.h:392
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
CT_NODISCARD STA_FORMAT_STRING const char CT_NODISCARD CT_STD_API char * str_vformat(arena_t *arena, const char *fmt, va_list args)
format a string
Definition: str.c:110
tree_arity_t
all arities
Definition: ops.h:64
tree_jump_t
the type of jump
Definition: ops.h:80
tree_t * tree_expr_unit(const node_t *node, const tree_t *type)
Definition: tree.c:203
tree_t * tree_stmt_jump(const node_t *node, tree_t *label, tree_jump_t jump)
Definition: tree.c:425
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_report(logger_t *reports, const tree_t *error)
Definition: tree.c:49
tree_t * tree_expr_field(const node_t *node, const tree_t *type, tree_t *object, tree_t *field)
Definition: tree.c:319
tree_t * tree_stmt_loop(const node_t *node, tree_t *cond, tree_t *body, tree_t *other)
Definition: tree.c:401
tree_t * tree_expr_offset(const node_t *node, const tree_t *type, tree_t *object, tree_t *offset)
Definition: tree.c:333
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
tree_t * tree_type_empty(const node_t *node, const char *name)
create an empty type, this is a type that has no values and can never be created in a well defined pr...
Definition: tree.c:118
tree_t * tree_expr_digit(const node_t *node, const tree_t *type, const mpz_t value)
Definition: tree.c:217
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
tree_t * tree_type_bool(const node_t *node, const char *name)
create a bool type, this is a type that has only two values, true and false
Definition: tree.c:128
tree_cast_t
all casts
Definition: ops.h:56
tree_quals_t
all type qualifiers
Definition: ops.h:25
tree_t * tree_expr_unary(const node_t *node, unary_t unary, tree_t *expr)
Definition: tree.c:290
tree_t * tree_stmt_init(const node_t *node, tree_t *dst, tree_t *src)
Definition: tree.c:396
tree_t * tree_stmt_return(const node_t *node, const tree_t *value)
create a return statement
Definition: tree.c:368
tree_t * tree_error(const node_t *node, const diagnostic_t *diagnostic, const char *message,...)
Definition: tree.c:67
tree_t * tree_expr_compare(const node_t *node, const tree_t *type, compare_t compare, const tree_t *lhs, const tree_t *rhs)
Definition: tree.c:307
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
tree_t * tree_type_opaque(const node_t *node, const char *name)
create an opaque pointer type
Definition: tree.c:133
sign_t
integer sign
Definition: ops.h:104
binary_t
all binary operators
Definition: ops.h:32
tree_t * tree_raise(const node_t *node, logger_t *reports, const diagnostic_t *diagnostic, const char *message,...)
Definition: tree.c:76
tree_t * tree_expr_call(const node_t *node, const tree_t *callee, const vector_t *args)
Definition: tree.c:344
tree_t * tree_expr_string(const node_t *node, const tree_t *type, const char *value, size_t length)
create a string expression
Definition: tree.c:235
tree_t * tree_expr_digit_int(const node_t *node, const tree_t *type, int value)
Definition: tree.c:226
tree_t * tree_expr_bool(const node_t *node, const tree_t *type, bool value)
Definition: tree.c:208
tree_t * tree_expr_binary(const node_t *node, const tree_t *type, binary_t binary, const tree_t *lhs, const tree_t *rhs)
Definition: tree.c:298
tree_t * tree_expr_load(const node_t *node, tree_t *expr)
load a value from a pointer or storage
Definition: tree.c:261
tree_kind_t
all tree node types
Definition: ops.h:17
digit_t
digit width
Definition: ops.h:96
tree_t * tree_expr_address(const node_t *node, tree_t *expr)
create a reference to an object
Definition: tree.c:281
tree_t * tree_type_digit(const node_t *node, const char *name, digit_t digit, sign_t sign)
create a digit type
Definition: tree.c:138
unary_t
all unary operators
Definition: ops.h:48
tree_t * tree_stmt_assign(const node_t *node, tree_t *dst, const tree_t *src)
Definition: tree.c:391
tree_t * tree_stmt_block(const node_t *node, const vector_t *stmts)
create a block statement
Definition: tree.c:359
tree_t * tree_type_unit(const node_t *node, const char *name)
create a unit type, this is a type that has only one value. equivilent to void
Definition: tree.c:123
compare_t
all comparison operators
Definition: ops.h:40
tree_t * tree_stmt_branch(const node_t *node, tree_t *cond, tree_t *then, tree_t *other)
Definition: tree.c:413
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
tree_t * tree_expr_empty(const node_t *node, const tree_t *type)
Definition: tree.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_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 diagnostic
Definition: diagnostic.h:27
a logging sink
Definition: notify.c:14
a position in a source file
Definition: node.h:23
tree_linkage_t link
the link type of the declaration
Definition: tree.h:51
Definition: tree.h:67
const char * message
Definition: tree.h:120
const tree_t * field
Definition: tree.h:151
tree_t * other
Definition: tree.h:140
const tree_t * rhs
Definition: tree.h:108
size_t length
Definition: tree.h:174
const vector_t * args
Definition: tree.h:114
tree_cast_t cast
Definition: tree.h:91
const tree_t * ptr
Definition: tree.h:172
tree_t * then
Definition: tree.h:139
const tree_t * offset
Definition: tree.h:148
const diagnostic_t * diagnostic
Definition: tree.h:119
const vector_t * params
Definition: tree.h:197
tree_attribs_t * attribs
Definition: tree.h:71
bool init
Definition: tree.h:133
const tree_t * src
Definition: tree.h:132
tree_jump_t jump
Definition: tree.h:158
a generic vector of pointers
Definition: vector.c:16