Cthulhu  0.2.10
Cthulhu compiler collection
expr.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-3.0-only
2 
3 #include "oberon/sema/expr.h"
4 #include "oberon/sema/sema.h"
5 #include "oberon/sema/type.h"
6 
7 #include "cthulhu/util/util.h"
8 #include "cthulhu/util/types.h"
9 
10 #include "cthulhu/events/events.h"
11 
12 #include "memory/memory.h"
13 
14 #include "std/vector.h"
15 #include "std/str.h"
16 
17 #include "base/panic.h"
18 
19 #include "core/macros.h"
20 
24 
25 static tree_t *sema_digit(tree_t *sema, obr_t *expr, const tree_t *implicit_type)
26 {
27  CT_UNUSED(sema);
28 
29  // TODO: get correct digit size
30  const tree_t *type = implicit_type == NULL
32  : implicit_type;
33 
34  return tree_expr_digit(expr->node, type, expr->digit);
35 }
36 
37 static tree_t *sema_string(tree_t *sema, obr_t *expr)
38 {
39  CT_UNUSED(sema);
40 
41  tree_t *str = obr_get_string_type(expr->node, expr->length);
42  return tree_expr_string(expr->node, str, expr->text, expr->length);
43 }
44 
45 static tree_t *sema_unary(tree_t *sema, obr_t *expr, const tree_t *implicit_type)
46 {
47  tree_t *operand = obr_sema_rvalue(sema, expr->expr, implicit_type);
48  return tree_expr_unary(expr->node, expr->unary, operand);
49 }
50 
51 static tree_t *sema_binary(tree_t *sema, obr_t *expr, const tree_t *implicit_type)
52 {
53  // TODO: get common type
54  const tree_t *type = implicit_type == NULL
56  : implicit_type;
57 
58  tree_t *lhs = obr_sema_rvalue(sema, expr->lhs, implicit_type);
59  tree_t *rhs = obr_sema_rvalue(sema, expr->rhs, implicit_type);
60 
61  return tree_expr_binary(expr->node, type, expr->binary, lhs, rhs);
62 }
63 
64 static tree_t *sema_compare(tree_t *sema, obr_t *expr)
65 {
66  tree_t *lhs = obr_sema_rvalue(sema, expr->lhs, NULL);
67  tree_t *rhs = obr_sema_rvalue(sema, expr->rhs, NULL);
68 
69  if (!util_types_comparable(tree_get_cookie(sema), lhs, rhs))
70  {
71  return tree_raise(expr->node, sema->reports, &kEvent_InvalidBinaryOperation, "cannot compare types %s and %s", tree_to_string(lhs), tree_to_string(rhs));
72  }
73 
74  return tree_expr_compare(expr->node, obr_get_bool_type(), expr->compare, lhs, rhs);
75 }
76 
77 static tree_t *sema_name(tree_t *sema, obr_t *expr)
78 {
79  tree_t *var = obr_get_symbol(sema, eObrTagValues, expr->object);
80  if (var != NULL) { return var; }
81 
82  tree_t *fn = obr_get_symbol(sema, eObrTagProcs, expr->object);
83  if (fn != NULL) { return fn; }
84 
85  tree_t *mod = obr_get_namespace(sema, expr->object);
86  if (mod != NULL) { return mod; }
87 
88  return tree_raise(expr->node, sema->reports, &kEvent_SymbolNotFound, "unknown name `%s`", expr->object);
89 }
90 
91 static tree_t *sema_name_rvalue(tree_t *sema, obr_t *expr)
92 {
93  tree_t *name = sema_name(sema, expr);
94  if (!tree_is(name, eTreeDeclParam))
95  {
96  return tree_expr_load(expr->node, name);
97  }
98 
99  return name;
100 }
101 
102 static const tree_t *get_param_checked(const vector_t *params, size_t i)
103 {
104  if (i >= vector_len(params))
105  {
106  return NULL;
107  }
108 
109  tree_t *param = vector_get(params, i);
110  return tree_get_type(param);
111 }
112 
113 static tree_t *sema_call(tree_t *sema, obr_t *expr)
114 {
115  tree_t *callee = obr_sema_lvalue(sema, expr->expr);
116  if (tree_is(callee, eTreeError)) { return callee; }
117 
118  const vector_t *params = tree_fn_get_params(callee);
119 
120  arena_t *arena = get_global_arena();
121  size_t len = vector_len(expr->args);
122  vector_t *args = vector_of(len, arena);
123  for (size_t i = 0; i < len; i++)
124  {
125  obr_t *it = vector_get(expr->args, i);
126  const tree_t *expected = get_param_checked(params, i);
127  tree_t *arg = obr_sema_rvalue(sema, it, expected); // funky
128  tree_t *casted = obr_cast_type(arg, expected);
129  vector_set(args, i, casted);
130  }
131 
132  return tree_expr_call(expr->node, callee, args);
133 }
134 
135 static tree_t *sema_field(tree_t *sema, obr_t *expr)
136 {
137  tree_t *decl = obr_sema_lvalue(sema, expr->expr);
138  switch(tree_get_kind(decl))
139  {
140  case eTreeDeclModule: return sema_name(decl, expr);
141  case eTreeError: return decl;
142  default: break;
143  }
144 
145  const tree_t *resolved = tree_resolve(tree_get_cookie(sema), tree_get_type(decl));
146  if (!tree_is(resolved, eTreeTypeStruct))
147  {
148  return tree_raise(expr->node, sema->reports, &kEvent_InvalidIndirection, "cannot access field of non-struct type %s", tree_to_string(decl));
149  }
150 
151  tree_t *field = tree_ty_get_field(resolved, expr->object);
152  if (field == NULL)
153  {
154  return tree_raise(expr->node, sema->reports, &kEvent_FieldNotFound, "struct %s has no field %s", tree_to_string(decl), expr->object);
155  }
156 
157  return tree_expr_field(expr->node, tree_get_type(field), decl, field);
158 }
159 
160 tree_t *obr_sema_rvalue(tree_t *sema, obr_t *expr, const tree_t *implicit_type)
161 {
162  const tree_t *type = implicit_type != NULL ? tree_ty_load_type(tree_resolve(tree_get_cookie(sema), implicit_type)) : NULL;
163 
164  switch (expr->kind)
165  {
166  case eObrExprDigit: return sema_digit(sema, expr, type);
167  case eObrExprString: return sema_string(sema, expr);
168  case eObrExprUnary: return sema_unary(sema, expr, type);
169  case eObrExprBinary: return sema_binary(sema, expr, type);
170  case eObrExprCompare: return sema_compare(sema, expr);
171  case eObrExprName: return sema_name_rvalue(sema, expr); // TODO: this feels wrong for functions
172  case eObrExprField: return tree_expr_load(expr->node, sema_field(sema, expr)); // TODO: may also be wrong for functions
173  case eObrExprCall: return sema_call(sema, expr);
174 
175  default: CT_NEVER("unknown expr kind %d", expr->kind);
176  }
177 }
178 
182 
184 {
185  switch (expr->kind)
186  {
187  case eObrExprName: return sema_name(sema, expr);
188  case eObrExprField: return sema_field(sema, expr);
189  default: CT_NEVER("unknown expr kind %d", expr->kind);
190  }
191 }
192 
196 
197 tree_t *obr_default_value(const node_t *node, const tree_t *type)
198 {
199  switch (tree_get_kind(type))
200  {
201  case eTreeTypeBool: return tree_expr_bool(node, type, false);
202  case eTreeTypeUnit: return tree_expr_unit(node, type);
203 
204  case eTreeTypeDigit: {
205  mpz_t zero;
206  mpz_init(zero);
207  return tree_expr_digit(node, type, zero);
208  }
209 
210  case eTreeTypeReference: return obr_default_value(node, tree_ty_load_type(type));
211 
212  default: CT_NEVER("obr-default-value unknown type kind %s", tree_to_string(type));
213  }
214 }
215 
219 
220 static tree_t *sema_assign(tree_t *sema, obr_t *stmt)
221 {
222  tree_t *dst = obr_sema_lvalue(sema, stmt->dst);
223  tree_t *src = obr_sema_rvalue(sema, stmt->src, (tree_t*)tree_get_type(dst)); // TODO: a little evil cast
224 
225  return tree_stmt_assign(stmt->node, dst, src);
226 }
227 
228 static tree_t *sema_return(tree_t *sema, obr_t *stmt)
229 {
230  // TODO: get implicit return type
231  tree_t *value = stmt->expr == NULL
233  : obr_sema_rvalue(sema, stmt->expr, NULL);
234  return tree_stmt_return(stmt->node, value);
235 }
236 
237 static tree_t *sema_block(tree_t *sema, obr_t *stmt)
238 {
239  const size_t sizes[eObrTagTotal] = {
240  [eObrTagValues] = 4,
241  [eObrTagTypes] = 4,
242  [eObrTagProcs] = 4,
243  [eObrTagModules] = 4,
244  [eObrTagImports] = 4,
245  };
246 
247  tree_t *ctx = tree_module(sema, stmt->node, NULL, eObrTagTotal, sizes);
248 
249  return obr_sema_stmts(ctx, stmt->node, stmt->stmts);
250 }
251 
252 static tree_t *sema_stmt(tree_t *sema, obr_t *stmt);
253 
254 static tree_t *sema_branch(tree_t *sema, obr_t *stmt)
255 {
256  tree_t *cond = obr_sema_rvalue(sema, stmt->branch, obr_get_bool_type());
257  tree_t *then = obr_sema_stmts(sema, stmt->node, stmt->branch_body);
258  tree_t *els = stmt->branch_else == NULL ? NULL : sema_stmt(sema, stmt->branch_else);
259 
260  return tree_stmt_branch(stmt->node, cond, then, els);
261 }
262 
263 static tree_t *sema_loop(tree_t *sema, obr_t *stmt)
264 {
265  tree_t *body = obr_sema_stmts(sema, stmt->node, stmt->loop);
266 
267  tree_t *truthy = tree_expr_bool(stmt->node, obr_get_bool_type(), true);
268 
269  return tree_stmt_loop(stmt->node, truthy, body, NULL);
270 }
271 
272 static tree_t *sema_while(tree_t *sema, obr_t *stmt)
273 {
274  tree_t *cond = obr_sema_rvalue(sema, stmt->cond, obr_get_bool_type());
275  tree_t *body = obr_sema_stmts(sema, stmt->node, stmt->then);
276 
277  return tree_stmt_loop(stmt->node, cond, body, NULL);
278 }
279 
280 static tree_t *sema_repeat(tree_t *sema, obr_t *stmt)
281 {
282  tree_t *cond = obr_sema_rvalue(sema, stmt->until, obr_get_bool_type());
283  tree_t *body = obr_sema_stmts(sema, stmt->node, stmt->repeat);
284 
285  // we lower a repeat until loop into a while loop and an initial body
286 
287  arena_t *arena = get_global_arena();
288  vector_t *stmts = vector_of(2, arena);
289  vector_push(&stmts, body);
290 
291  tree_t *loop = tree_stmt_loop(stmt->node, cond, body, NULL);
292  vector_push(&stmts, loop);
293 
294  return tree_stmt_block(stmt->node, stmts);
295 }
296 
297 static tree_t *sema_stmt(tree_t *sema, obr_t *stmt)
298 {
299  switch (stmt->kind)
300  {
301  case eObrStmtAssign: return sema_assign(sema, stmt);
302  case eObrStmtReturn: return sema_return(sema, stmt);
303  case eObrStmtLoop: return sema_loop(sema, stmt);
304  case eObrStmtWhile: return sema_while(sema, stmt);
305  case eObrStmtRepeat: return sema_repeat(sema, stmt);
306  case eObrExprCall: return sema_call(sema, stmt);
307  case eObrStmtBlock: return sema_block(sema, stmt);
308  case eObrStmtBranch: return sema_branch(sema, stmt);
309  default: CT_NEVER("unknown stmt kind %d", stmt->kind);
310  }
311 }
312 
313 tree_t *obr_sema_stmts(tree_t *sema, const node_t *node, vector_t *stmts)
314 {
315  arena_t *arena = get_global_arena();
316  size_t len = vector_len(stmts);
317  vector_t *result = vector_of(len, arena);
318  for (size_t i = 0; i < len; i++)
319  {
320  obr_t *stmt = vector_get(stmts, i);
321  tree_t *tree = sema_stmt(sema, stmt);
322  vector_set(result, i, tree);
323  }
324 
325  return tree_stmt_block(node, result);
326 }
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
CT_PUREFN CT_TREE_API tree_t * tree_ty_get_field(const tree_t *self, const char *name)
Definition: query.c:224
CT_PUREFN CT_TREE_API const vector_t * tree_fn_get_params(const tree_t *self)
Definition: query.c:179
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_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
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
CT_UTIL_API 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
CT_TREE_API tree_t * tree_expr_unit(const node_t *node, const tree_t *type)
Definition: tree.c:203
CT_TREE_API tree_t * tree_expr_field(const node_t *node, const tree_t *type, tree_t *object, tree_t *field)
Definition: tree.c:319
CT_TREE_API tree_t * tree_stmt_loop(const node_t *node, tree_t *cond, tree_t *body, tree_t *other)
Definition: tree.c:401
CT_TREE_API tree_t * tree_expr_digit(const node_t *node, const tree_t *type, const mpz_t value)
Definition: tree.c:217
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
CT_TREE_API tree_t * tree_expr_unary(const node_t *node, unary_t unary, tree_t *expr)
Definition: tree.c:290
CT_TREE_API tree_t * tree_stmt_return(const node_t *node, const tree_t *value)
create a return statement
Definition: tree.c:368
CT_TREE_API 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
CT_TREE_API tree_cookie_t * tree_get_cookie(tree_t *sema)
return a resolution cookie
Definition: sema.c:136
CT_TREE_API tree_t * tree_raise(const node_t *node, logger_t *reports, const diagnostic_t *diagnostic, const char *message,...)
Definition: tree.c:76
CT_TREE_API tree_t * tree_expr_call(const node_t *node, const tree_t *callee, const vector_t *args)
Definition: tree.c:344
CT_TREE_API 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
CT_TREE_API tree_t * tree_expr_bool(const node_t *node, const tree_t *type, bool value)
Definition: tree.c:208
CT_TREE_API 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
CT_TREE_API tree_t * tree_expr_load(const node_t *node, tree_t *expr)
load a value from a pointer or storage
Definition: tree.c:261
CT_TREE_API tree_t * tree_stmt_assign(const node_t *node, tree_t *dst, const tree_t *src)
Definition: tree.c:391
CT_TREE_API tree_t * tree_stmt_block(const node_t *node, const vector_t *stmts)
create a block statement
Definition: tree.c:359
CT_TREE_API tree_t * tree_resolve(tree_cookie_t *cookie, const tree_t *decl)
Definition: decl.c:47
CT_TREE_API tree_t * tree_stmt_branch(const node_t *node, tree_t *cond, tree_t *then, tree_t *other)
Definition: tree.c:413
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 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_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
@ eObrExprCall
Definition: ast.h:57
@ eObrStmtLoop
Definition: ast.h:69
@ eObrExprDigit
Definition: ast.h:52
@ eObrStmtBlock
Definition: ast.h:72
@ eObrExprBinary
Definition: ast.h:60
@ eObrExprCompare
Definition: ast.h:61
@ eObrExprField
Definition: ast.h:56
@ eObrExprName
Definition: ast.h:55
@ eObrExprUnary
Definition: ast.h:59
@ eObrStmtWhile
Definition: ast.h:68
@ eObrStmtBranch
Definition: ast.h:73
@ eObrExprString
Definition: ast.h:53
@ eObrStmtAssign
Definition: ast.h:71
@ eObrStmtRepeat
Definition: ast.h:70
@ eObrStmtReturn
Definition: ast.h:67
tree_t * obr_get_symbol(tree_t *sema, obr_tag_t tag, const char *name)
getters
Definition: sema.c:29
tree_t * obr_get_integer_type(void)
Definition: sema.c:87
tree_t * obr_get_string_type(const node_t *node, size_t length)
Definition: sema.c:93
tree_t * obr_get_void_type(void)
Definition: sema.c:117
@ eObrTagTotal
Definition: sema.h:13
tree_t * obr_get_bool_type(void)
builtin types
Definition: sema.c:69
tree_t * obr_get_namespace(tree_t *sema, const char *name)
Definition: sema.c:36
tree_t * obr_cast_type(tree_t *expr, const tree_t *type)
Definition: type.c:164
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_lvalue(tree_t *sema, obr_t *expr)
Definition: expr.c:183
tree_t * obr_sema_stmts(tree_t *sema, const node_t *node, vector_t *stmts)
Definition: expr.c:313
an allocator object
Definition: arena.h:86
a position in a source file
Definition: node.h:23
Definition: ast.h:93
vector_t * then
Definition: ast.h:120
obr_kind_t kind
Definition: ast.h:94
obr_t * dst
Definition: ast.h:145
obr_t * until
Definition: ast.h:129
unary_t unary
Definition: ast.h:104
obr_t * lhs
Definition: ast.h:139
const vector_t * args
Definition: ast.h:110
obr_t * cond
Definition: ast.h:119
const node_t * node
Definition: ast.h:95
char * text
Definition: ast.h:179
mpz_t digit
Definition: ast.h:172
obr_t * branch
Definition: ast.h:154
vector_t * branch_body
Definition: ast.h:155
binary_t binary
Definition: ast.h:136
obr_t * expr
Definition: ast.h:114
obr_t * src
Definition: ast.h:146
vector_t * repeat
Definition: ast.h:128
char * object
Definition: ast.h:175
vector_t * stmts
Definition: ast.h:150
size_t length
Definition: ast.h:180
compare_t compare
Definition: ast.h:135
vector_t * loop
Definition: ast.h:124
obr_t * branch_else
Definition: ast.h:156
obr_t * rhs
Definition: ast.h:140
Definition: tree.h:67
logger_t * reports
Definition: tree.h:227
a generic vector of pointers
Definition: vector.c:16