commit aad6f3700a12f7bb82d3ecc3e3790794a47e2a4a
parent 05e4a34b280f6802a41d0a53072268226d179b3d
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 2 Aug 2021 15:27:55 +0200
gen: implement call expressions
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
M | src/gen.c | | | 65 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
1 file changed, 62 insertions(+), 3 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -73,6 +73,7 @@ gen_load(struct gen_context *ctx, struct gen_value object)
{
switch (type_dealias(object.type)->storage) {
case STORAGE_ARRAY:
+ case STORAGE_FUNCTION:
case STORAGE_SLICE:
case STORAGE_STRING:
case STORAGE_STRUCT:
@@ -110,10 +111,25 @@ static struct gen_value gen_expr_with(struct gen_context *ctx,
static struct gen_value
gen_access_ident(struct gen_context *ctx, const struct expression *expr)
{
- for (const struct gen_binding *gb = ctx->bindings; gb; gb = gb->next) {
- if (gb->object == expr->access.object) {
- return gb->value;
+ const struct scope_object *obj = expr->access.object;
+ switch (obj->otype) {
+ case O_BIND:
+ for (const struct gen_binding *gb = ctx->bindings;
+ gb; gb = gb->next) {
+ if (gb->object == obj) {
+ return gb->value;
+ }
}
+ break;
+ case O_DECL:
+ return (struct gen_value){
+ .kind = GV_GLOBAL,
+ .type = obj->type,
+ .name = ident_to_sym(&obj->ident),
+ };
+ case O_CONST:
+ case O_TYPE:
+ abort(); // Invariant
}
abort(); // Invariant
}
@@ -159,6 +175,47 @@ gen_expr_binding(struct gen_context *ctx, const struct expression *expr)
}
static struct gen_value
+gen_expr_call(struct gen_context *ctx, const struct expression *expr)
+{
+ struct gen_value lvalue = gen_expr(ctx, expr->call.lvalue);
+ assert(type_dealias(lvalue.type)->storage != STORAGE_POINTER); // TODO
+
+ const struct type *rtype = lvalue.type;
+ assert(rtype->storage == STORAGE_FUNCTION);
+ // TODO: Run deferred expressions if rtype->func.flags & FN_NORETURN
+
+ struct qbe_statement call = {
+ .type = Q_INSTR,
+ .instr = Q_CALL,
+ };
+ struct gen_value rval = gv_void;
+ if (type_dealias(rtype->func.result)->storage != STORAGE_VOID) {
+ rval = (struct gen_value){
+ .kind = GV_TEMP,
+ .type = rtype->func.result,
+ .name = gen_name(ctx, "returns.%d"),
+ };
+ call.out = xcalloc(1, sizeof(struct qbe_value));
+ *call.out = mkqval(ctx, &rval);
+ }
+
+ struct qbe_arguments *args, **next = &call.args;
+ args = *next = xcalloc(1, sizeof(struct qbe_arguments));
+ args->value = mkqval(ctx, &lvalue);
+ next = &args->next;
+ for (struct call_argument *carg = expr->call.args;
+ carg; carg = carg->next) {
+ args = *next = xcalloc(1, sizeof(struct qbe_arguments));
+ struct gen_value arg = gen_expr(ctx, carg->value);
+ args->value = mkqval(ctx, &arg);
+ next = &args->next;
+ }
+ push(&ctx->current->body, &call);
+
+ return rval;
+}
+
+static struct gen_value
gen_expr_const(struct gen_context *ctx, const struct expression *expr)
{
struct gen_value val = {
@@ -289,7 +346,9 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
case EXPR_BINDING:
return gen_expr_binding(ctx, expr);
case EXPR_BREAK:
+ assert(0); // TODO
case EXPR_CALL:
+ return gen_expr_call(ctx, expr);
case EXPR_CAST:
assert(0); // TODO
case EXPR_CONSTANT: