harec

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

commit d256036430e8ad2aa3661dd53e21bacf8b32d8c4
parent c5e2fbb8695cde54150ebe59645651553d88e45d
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu, 31 Dec 2020 14:07:12 -0500

Initial implementation of constants

Some work is needed to make this work better with forward references and
aggregate types.

Diffstat:
Minclude/scope.h | 4+++-
Msrc/check.c | 59++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/gen.c | 2++
Msrc/scope.c | 9++++++++-
4 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/include/scope.h b/include/scope.h @@ -5,6 +5,7 @@ enum object_type { O_BIND, + O_CONST, O_DECL, }; @@ -13,6 +14,7 @@ struct scope_object { enum object_type otype; struct identifier ident; const struct type *type; + struct expression *value; // For O_CONST struct scope_object *next; }; @@ -35,7 +37,7 @@ void scope_free_all(struct scopes *scopes); const struct scope_object *scope_insert(struct scope *scope, enum object_type otype, const struct identifier *ident, - const struct type *type); + const struct type *type, struct expression *value); const struct scope_object *scope_lookup(struct scope *scope, const struct identifier *ident); diff --git a/src/check.c b/src/check.c @@ -5,6 +5,7 @@ #include <string.h> #include "ast.h" #include "check.h" +#include "eval.h" #include "expr.h" #include "scope.h" #include "trace.h" @@ -64,8 +65,13 @@ check_expr_access(struct context *ctx, char buf[1024]; identifier_unparse_static(&aexpr->access.ident, buf, sizeof(buf)); expect(obj, "Unknown object", buf); - expr->result = obj->type; - expr->access.object = obj; + if (obj->otype == O_CONST) { + // Lower constants + *expr = *obj->value; + } else { + expr->result = obj->type; + expr->access.object = obj; + } break; case ACCESS_INDEX: expr->access.array = xcalloc(1, sizeof(struct expression)); @@ -239,8 +245,8 @@ check_expr_binding(struct context *ctx, expect(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, type); + const struct scope_object *obj = scope_insert( + ctx->scope, O_BIND, &ident, type, NULL); binding->object = obj; binding->initializer = initializer; @@ -733,7 +739,7 @@ check_function(struct context *ctx, }; const struct type *type = type_store_lookup_atype( &ctx->store, params->type); - scope_insert(decl->func.scope, O_BIND, &ident, type); + scope_insert(decl->func.scope, O_BIND, &ident, type, NULL); params = params->next; } @@ -768,7 +774,7 @@ check_declarations(struct context *ctx, { trenter(TR_CHECK, "declarations"); while (adecls) { - struct declaration *decl; + struct declaration *decl = NULL; const struct ast_decl *adecl = &adecls->decl; switch (adecl->decl_type) { case AST_DECL_FUNC: @@ -779,7 +785,7 @@ check_declarations(struct context *ctx, case AST_DECL_GLOBAL: assert(0); // TODO case AST_DECL_CONST: - assert(0); // TODO + break; // Handled in scan } if (decl) { @@ -809,11 +815,45 @@ scan_function(struct context *ctx, const struct ast_function_decl *decl) &ctx->store, &fn_atype); assert(fntype); // TODO: Forward references + struct identifier ident = {0}; + mkident(ctx, &ident, &decl->ident); + scope_insert(ctx->unit, O_DECL, &ident, fntype, NULL); + char buf[1024]; identifier_unparse_static(&decl->ident, buf, sizeof(buf)); trleave(TR_SCAN, "func %s", buf); +} - scope_insert(ctx->unit, O_DECL, &decl->ident, fntype); +static void +scan_const(struct context *ctx, const struct ast_global_decl *decl) +{ + trenter(TR_SCAN, "constant"); + assert(!decl->symbol); // Invariant + + const struct type *type = type_store_lookup_atype( + &ctx->store, decl->type); + // TODO: + // - Free the initializer + // - Defer if we can't evaluate it now (for forward references) + struct expression *initializer = + xcalloc(1, sizeof(struct expression)); + check_expression(ctx, decl->init, initializer); + + // TODO: Lower implicit casts + expect(type_is_assignable(&ctx->store, type, initializer->result), + "Constnat type is not assignable from initializer type"); + + struct expression *value = + xcalloc(1, sizeof(struct expression)); + enum eval_result r = eval_expr(ctx, initializer, value); + // TODO: More forward reference issues: + expect(r == EVAL_OK, "Unable to evaluate initializer at compile time"); + + struct identifier ident = {0}; + mkident(ctx, &ident, &decl->ident); + scope_insert(ctx->unit, O_CONST, &ident, type, value); + + trleave(TR_SCAN, NULL); } static void @@ -831,7 +871,8 @@ scan_declarations(struct context *ctx, const struct ast_decls *decls) case AST_DECL_GLOBAL: assert(0); // TODO case AST_DECL_CONST: - assert(0); // TODO + scan_const(ctx, &decl->constant); + break; } decls = decls->next; } diff --git a/src/gen.c b/src/gen.c @@ -105,6 +105,8 @@ qval_for_object(struct gen_context *ctx, val->kind = QV_GLOBAL; val->indirect = false; break; + case O_CONST: + assert(0); // Invariant (lowered in check) } if (type_is_aggregate(obj->type)) { diff --git a/src/scope.c b/src/scope.c @@ -1,5 +1,6 @@ #include <assert.h> #include <stdlib.h> +#include "expr.h" #include "identifier.h" #include "scope.h" #include "trace.h" @@ -64,12 +65,18 @@ const struct scope_object * scope_insert(struct scope *scope, enum object_type otype, const struct identifier *ident, - const struct type *type) + const struct type *type, + struct expression *value) { struct scope_object *o = xcalloc(1, sizeof(struct scope_object)); identifier_dup(&o->ident, ident); o->otype = otype; o->type = type; + o->value = value; + if (value) { + assert(otype == O_CONST); + assert(value->type == EXPR_CONSTANT); + } *scope->next = o; scope->next = &o->next; return o;