commit dc46d6f9206a2f6c11a89a13f66b2c6513839a12
parent c9ddb0c6c63dc6d77a445ef1599c2f3c1d982115
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 2 Feb 2021 20:33:19 -0500
Implement struct autofill
Diffstat:
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
};