harec

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

commit dc46d6f9206a2f6c11a89a13f66b2c6513839a12
parent c9ddb0c6c63dc6d77a445ef1599c2f3c1d982115
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue,  2 Feb 2021 20:33:19 -0500

Implement struct autofill

Diffstat:
Minclude/expr.h | 9+++++++--
Mrt/Makefile | 1+
Art/memset.ha | 6++++++
Msrc/check.c | 14+++++++-------
Msrc/eval.c | 4++--
Msrc/gen.c | 13++++++++++++-
Mtests/06-structs.ha | 9+++++++--
7 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/include/expr.h b/include/expr.h @@ -254,10 +254,15 @@ struct expression_switch { struct switch_case *cases; }; -struct expression_struct { +struct expr_struct_field { const struct struct_field *field; struct expression *value; - struct expression_struct *next; + struct expr_struct_field *next; +}; + +struct expression_struct { + struct expr_struct_field fields; + bool autofill; }; enum unarithm_operator { diff --git a/rt/Makefile b/rt/Makefile @@ -3,6 +3,7 @@ libhart_srcs+=\ rt/compile.ha \ rt/malloc.ha \ rt/memcpy.ha \ + rt/memset.ha \ rt/rtmain.ha libhart.a: harec $(libhart_srcs) $(libhart_objs) $(rtstart) diff --git a/rt/memset.ha b/rt/memset.ha @@ -0,0 +1,6 @@ +export fn memset(dest: *void, val: u8, amt: size) void = { + let a = dest: *[*]u8; + for (let i = 0z; i < amt; i += 1z) { + a[i] = val; + }; +}; diff --git a/src/check.c b/src/check.c @@ -1201,8 +1201,6 @@ check_expr_struct(struct context *ctx, trenter(TR_CHECK, "struct"); expr->type = EXPR_STRUCT; - assert(!aexpr->_struct.autofill); // TODO - const struct type *stype = NULL; if (aexpr->_struct.type.name) { const struct scope_object *obj = scope_lookup(ctx->scope, @@ -1222,8 +1220,11 @@ check_expr_struct(struct context *ctx, }; struct ast_struct_union_type *tfield = &satype.struct_union; struct ast_struct_union_type **tnext = &tfield->next; - struct expression_struct *sexpr = &expr->_struct; - struct expression_struct **snext = &sexpr->next; + struct expr_struct_field *sexpr = &expr->_struct.fields; + struct expr_struct_field **snext = &sexpr->next; + expr->_struct.autofill = aexpr->_struct.autofill; + expect(&aexpr->loc, stype != NULL || !expr->_struct.autofill, + "Autofill is only permitted for named struct initializers"); struct ast_field_value *afield = aexpr->_struct.fields; while (afield) { @@ -1265,8 +1266,7 @@ check_expr_struct(struct context *ctx, 1, sizeof(struct ast_struct_union_type)); tnext = &tfield->next; } - *snext = sexpr = xcalloc( - 1, sizeof(struct expression_struct)); + *snext = sexpr = xcalloc(1, sizeof(struct expr_struct_field)); snext = &sexpr->next; } @@ -1280,7 +1280,7 @@ check_expr_struct(struct context *ctx, expr->result = type_store_lookup_atype(ctx->store, &satype); tfield = &satype.struct_union; - sexpr = &expr->_struct; + sexpr = &expr->_struct.fields; while (tfield) { const struct struct_field *field = type_get_field( expr->result, tfield->field.name); diff --git a/src/eval.c b/src/eval.c @@ -389,7 +389,7 @@ eval_struct(struct context *ctx, struct expression *in, struct expression *out) out->type = EXPR_CONSTANT; size_t n = 0; - for (const struct expression_struct *field = &in->_struct; + for (const struct expr_struct_field *field = &in->_struct.fields; field; field = field->next) { ++n; } @@ -398,7 +398,7 @@ eval_struct(struct context *ctx, struct expression *in, struct expression *out) struct struct_constant **fields = xcalloc(n, sizeof(struct struct_constant *)); n = 0; - for (const struct expression_struct *field = &in->_struct; + for (const struct expr_struct_field *field = &in->_struct.fields; field; field = field->next) { struct struct_constant *cfield = fields[n] = xcalloc(1, sizeof(struct struct_constant)); diff --git a/src/gen.c b/src/gen.c @@ -1886,7 +1886,18 @@ gen_expr_struct(struct gen_context *ctx, gen_temp(ctx, &ptr, &qbe_long, "ptr.%d"); pushi(ctx->current, &base, Q_COPY, out, NULL); - const struct expression_struct *field = &expr->_struct; + if (expr->_struct.autofill) { + struct qbe_value rtfunc = {0}, size = {0}, zero = {0}; + rtfunc.kind = QV_GLOBAL; + rtfunc.name = strdup("rt.memset"); + rtfunc.type = &qbe_long; + constl(&size, expr->result->size); + constl(&zero, 0); + pushi(ctx->current, NULL, Q_CALL, &rtfunc, + &base, &zero, &size, NULL); + } + + const struct expr_struct_field *field = &expr->_struct.fields; while (field) { constl(&offset, field->field->offset); ptr.type = &qbe_long; diff --git a/tests/06-structs.ha b/tests/06-structs.ha @@ -82,6 +82,11 @@ fn named() void = { assert(x.x == 20 && x.y == 10); }; +fn autofill() void = { + let x = coords { x = 10, ... }; + assert(x.x == 10 && x.y == 0); +}; + fn invariants() void = { const failures = [ // Assign field from non-assignable type: @@ -115,11 +120,11 @@ export fn main() void = { assignment(); deref(); nested(); - invariants(); named(); + autofill(); + invariants(); // TODO: // - Union tests // - Embedded structs // - offset() - // - Autofilling (...) and its invariants };