commit 03ff7b8d5ff70bf9d5b01f1627b130381260c644
parent 432a0d63a3e351f2d398f7bbf861ac232b9e4fd8
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 21 Dec 2020 09:37:27 -0500
Initial riggings for scope management
Diffstat:
6 files changed, 152 insertions(+), 10 deletions(-)
diff --git a/configure b/configure
@@ -14,6 +14,7 @@ harec() {
src/qbe.c \
src/qinstr.c \
src/qtype.c \
+ src/scope.c \
src/trace.c \
src/type_store.c \
src/types.c \
diff --git a/include/expr.h b/include/expr.h
@@ -1,8 +1,11 @@
#ifndef HAREC_EXPR_H
#define HAREC_EXPR_H
#include <stdint.h>
+#include "identifier.h"
#include "types.h"
+struct scope;
+
enum expr_type {
EXPR_ACCESS,
EXPR_ASSERT,
@@ -43,9 +46,14 @@ union expression_constant {
// TODO: Array, slice, struct constants
};
-struct expression_list {
+struct expressions {
struct expression *expr;
- struct expression_list *next;
+ struct expressions *next;
+};
+
+struct expression_list {
+ struct scope *scope;
+ struct expressions exprs;
};
struct expression_return {
diff --git a/include/scope.h b/include/scope.h
@@ -0,0 +1,32 @@
+#ifndef HAREC_SCOPE_H
+#define HAREC_SCOPE_H
+#include "identifier.h"
+#include "trace.h"
+
+// XXX: This might be better as a hash map
+struct scope_object {
+ struct identifier ident;
+ const struct type *type;
+ struct scope_object *next;
+};
+
+struct scope {
+ struct scope_object *objects;
+ struct scope *parent;
+};
+
+struct scopes {
+ struct scope *scope;
+ struct scopes *next;
+};
+
+struct scope *scope_push(struct scope **stack, enum trace_sys sys);
+struct scope *scope_pop(struct scope **stack, enum trace_sys sys);
+
+void scope_free(struct scope *scope);
+void scope_free_all(struct scopes *scopes);
+
+void scope_insert(const struct identifier *ident, const struct type *type);
+const struct type *scope_lookup(const struct identifier *ident);
+
+#endif
diff --git a/src/check.c b/src/check.c
@@ -5,12 +5,15 @@
#include "ast.h"
#include "check.h"
#include "expr.h"
+#include "scope.h"
#include "trace.h"
#include "type_store.h"
#include "types.h"
struct context {
struct type_store store;
+ struct scope *unit;
+ struct scope *scope;
};
static void
@@ -86,8 +89,8 @@ check_expr_list(struct context *ctx,
trenter(TR_CHECK, "expression-list");
expr->type = EXPR_LIST;
- struct expression_list *list = &expr->list;
- struct expression_list **next = &list->next;
+ struct expressions *list = &expr->list.exprs;
+ struct expressions **next = &list->next;
const struct ast_expression_list *alist = &aexpr->list;
while (alist) {
@@ -97,7 +100,7 @@ check_expr_list(struct context *ctx,
alist = alist->next;
if (alist) {
- *next = calloc(1, sizeof(struct expression_list));
+ *next = calloc(1, sizeof(struct expressions));
list = *next;
next = &list->next;
} else {
@@ -289,18 +292,45 @@ void
check(const struct ast_unit *aunit, struct unit *unit)
{
struct context ctx = {0};
+
+ // Top-level scope management involves:
+ //
+ // - Creating a top-level scope for the whole unit, to which
+ // declarations are added.
+ // - Creating a scope for each sub-unit, and populating it with imports.
+ //
+ // Further down the call frame, subsequent functions will create
+ // sub-scopes for each declaration, expression-list, etc.
+ ctx.unit = scope_push(&ctx.scope, TR_MAX);
+
+ struct scopes *subunit_scopes;
+ struct scopes **next = &subunit_scopes;
+
// First pass populates the type graph
for (const struct ast_subunit *su = &aunit->subunits;
su; su = su->next) {
+ scope_push(&ctx.scope, TR_SCAN);
+
assert(!su->imports); // TODO
scan_declarations(&ctx, &su->decls);
+
+ *next = calloc(1, sizeof(struct scopes));
+ (*next)->scope = scope_pop(&ctx.scope, TR_SCAN);
+ next = &(*next)->next;
}
// Second pass populates the expression graph
+ struct scopes *scope = subunit_scopes;
for (const struct ast_subunit *su = &aunit->subunits;
su; su = su->next) {
+ ctx.scope = scope->scope;
+ trenter(TR_CHECK, "scope %p", ctx.scope);
check_declarations(&ctx, &su->decls, &unit->declarations);
+ trleave(TR_CHECK, NULL);
+ scope = scope->next;
}
assert(unit->declarations);
+ scope_free_all(subunit_scopes);
+ scope_free(ctx.unit);
}
diff --git a/src/gen.c b/src/gen.c
@@ -138,15 +138,15 @@ gen_expr_list(struct gen_context *ctx,
const struct expression *expr,
const struct qbe_value *out)
{
- const struct expression_list *list = &expr->list;
- while (list) {
+ const struct expressions *exprs = &expr->list.exprs;
+ while (exprs) {
const struct qbe_value *dest = NULL;
- if (!list->next) {
+ if (!exprs->next) {
// Last value determines expression result
dest = out;
}
- gen_expression(ctx, list->expr, dest);
- list = list->next;
+ gen_expression(ctx, exprs->expr, dest);
+ exprs = exprs->next;
}
}
diff --git a/src/scope.c b/src/scope.c
@@ -0,0 +1,71 @@
+#include <assert.h>
+#include <stdlib.h>
+#include "identifier.h"
+#include "scope.h"
+#include "trace.h"
+
+struct scope *
+scope_push(struct scope **stack, enum trace_sys sys)
+{
+ struct scope *new = calloc(1, sizeof(struct scope));
+ if (*stack) {
+ new->parent = *stack;
+ }
+ *stack = new;
+ if (sys != TR_MAX) {
+ trenter(sys, "scope %p", new);
+ }
+ return new;
+}
+
+struct scope *
+scope_pop(struct scope **stack, enum trace_sys sys)
+{
+ struct scope *prev = *stack;
+ assert(prev);
+ *stack = prev->parent;
+ if (sys != TR_MAX) {
+ trleave(sys, NULL);
+ }
+ return prev;
+}
+
+void
+scope_free(struct scope *scope)
+{
+ if (!scope) {
+ return;
+ }
+
+ struct scope_object *obj = scope->objects;
+ while (obj) {
+ struct scope_object *next = obj->next;
+ free(obj);
+ obj = next;
+ }
+
+ free(scope);
+}
+
+void
+scope_free_all(struct scopes *scopes)
+{
+ while (scopes) {
+ struct scopes *next = scopes->next;
+ scope_free(scopes->scope);
+ free(scopes);
+ scopes = next;
+ }
+}
+
+void
+scope_insert(const struct identifier *ident, const struct type *type)
+{
+ assert(0); // TODO
+}
+
+const struct type *
+scope_lookup(const struct identifier *ident)
+{
+ assert(0); // TODO
+}