harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 63ab73c5535a958ec4e3524a640a75a220076f5f
parent fcfe4f06cd9c8ad38d5b2d1fbf888fcc54c52a85
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 13 Jan 2021 15:24:24 -0500

check, gen: implement static bindings

Diffstat:
Minclude/check.h | 1+
Msrc/check.c | 27+++++++++++++++++++++------
Msrc/emit.c | 3++-
Msrc/gen.c | 22++++++++++++++++++++--
Mtests/11-globals.ha | 13+++++++++++++
5 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/include/check.h b/include/check.h @@ -15,6 +15,7 @@ struct context { struct identifier *ns; struct scope *unit; struct scope *scope; + int id; }; enum func_decl_flags { diff --git a/src/check.c b/src/check.c @@ -273,8 +273,6 @@ check_expr_binding(struct context *ctx, const struct ast_expression_binding *abinding = &aexpr->binding; while (abinding) { - assert(!abinding->is_static); // TODO - const struct type *type = NULL; if (abinding->type) { type = type_store_lookup_atype( @@ -303,13 +301,30 @@ check_expr_binding(struct context *ctx, expect(&aexpr->loc, type_is_assignable(&ctx->store, type, initializer->result), "Initializer is not assignable to binding type"); - - const struct scope_object *obj = scope_insert( - ctx->scope, O_BIND, &ident, &ident, type, NULL); - binding->object = obj; binding->initializer = lower_implicit_cast(type, initializer); + if (!abinding->is_static) { + binding->object = scope_insert(ctx->scope, O_BIND, + &ident, &ident, type, NULL); + } else { + struct expression *value = + xcalloc(1, sizeof(struct expression)); + enum eval_result r = eval_expr(ctx, initializer, value); + expect(&abinding->initializer->loc, r == EVAL_OK, + "Unable to evaluate static initializer at compile time"); + // TODO: Free initializer + initializer = value; + + struct identifier gen = {0}; + int n = snprintf(NULL, 0, "static.%d", ctx->id); + gen.name = xcalloc(n + 1, 1); + snprintf(gen.name, n + 1, "static.%d", ctx->id); + ++ctx->id; + binding->object = scope_insert(ctx->scope, O_DECL, + &gen, &ident, type, NULL); + } + if (abinding->next) { binding = *next = xcalloc(1, sizeof(struct expression_binding)); diff --git a/src/emit.c b/src/emit.c @@ -239,7 +239,8 @@ emit_data(struct qbe_def *def, FILE *out) emit_value(&item->value, out); break; case QD_ZEROED: - assert(0); // TODO + fprintf(out, "z %zu", item->zeroed); + break; case QD_STRING: emit_data_string(item->str, item->sz, out); break; diff --git a/src/gen.c b/src/gen.c @@ -60,6 +60,9 @@ alloc_temp(struct gen_context *ctx, struct qbe_value *val, val->type = qtype; } +static void qval_for_object(struct gen_context *ctx, + struct qbe_value *val, const struct scope_object *obj); + static struct gen_binding * binding_alloc(struct gen_context *ctx, const struct scope_object *obj, struct qbe_value *val, const char *fmt) @@ -477,6 +480,9 @@ gen_expr_assign(struct gen_context *ctx, } } +static void gen_global_decl(struct gen_context *ctx, + const struct declaration *decl); + static void gen_expr_binding(struct gen_context *ctx, const struct expression *expr, @@ -487,8 +493,20 @@ gen_expr_binding(struct gen_context *ctx, const struct expression_binding *binding = &expr->binding; while (binding) { struct qbe_value temp = {0}; - binding_alloc(ctx, binding->object, &temp, "binding.%d"); - gen_expression(ctx, binding->initializer, &temp); + if (binding->object->otype != O_DECL) { + binding_alloc(ctx, binding->object, &temp, "binding.%d"); + gen_expression(ctx, binding->initializer, &temp); + } else { + struct declaration decl = { + .type = DECL_GLOBAL, + .ident = binding->object->ident, + .global = { + .type = binding->object->type, + .value = binding->initializer, + }, + }; + gen_global_decl(ctx, &decl); + } binding = binding->next; } } diff --git a/tests/11-globals.ha b/tests/11-globals.ha @@ -12,10 +12,23 @@ fn invariants() void = { assert(rt::compile("fn test() int; let x: int = test();") != 0); }; +fn counter() int = { + static let x = 0; + x += 1; + return x; +}; + +fn static_binding() void = { + assert(counter() == 1); + assert(counter() == 2); + assert(counter() == 3); +}; + export fn main() void = { // TODO: Expand this test: // - Declare & validate globals of more types // - Globals which are pointers to other globals write(); invariants(); + static_binding(); };