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:
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();
};