harec

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

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:
Mconfigure | 1+
Minclude/expr.h | 12++++++++++--
Ainclude/scope.h | 32++++++++++++++++++++++++++++++++
Msrc/check.c | 36+++++++++++++++++++++++++++++++++---
Msrc/gen.c | 10+++++-----
Asrc/scope.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 +}