harec

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

commit c9ddb0c6c63dc6d77a445ef1599c2f3c1d982115
parent aaee24a6426cac9490712aefe03221bbf6813e8d
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue,  2 Feb 2021 20:08:15 -0500

gen: implement match against tagged subset

Diffstat:
Msrc/gen.c | 24+++++++++++++++++++++++-
Mtests/18-match.ha | 22++++++++++++++++++++++
2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/src/gen.c b/src/gen.c @@ -1521,6 +1521,27 @@ gen_recursive_match_tests(struct gen_context *ctx, const struct type *mtype, } static void +gen_match_tagged_subset(struct gen_context *ctx, + struct qbe_value *tbranch, struct qbe_value *fbranch, + struct qbe_value *tag, struct match_case *_case) +{ + struct qbe_value temp = {0}, match = {0}; + gen_temp(ctx, &temp, &qbe_word, "temp.%d"); + const struct type_tagged_union *tu = &type_dealias(_case->type)->tagged; + while (tu) { + struct qbe_statement nlabel = {0}; + struct qbe_value nbranch = {0}; + nbranch.kind = QV_LABEL; + nbranch.name = strdup(genl(&nlabel, &ctx->id, "match.subtype.%d")); + constw(&match, tu->type->id); + pushi(ctx->current, &temp, Q_CEQW, &match, tag, NULL); + pushi(ctx->current, NULL, Q_JNZ, &temp, tbranch, &nbranch, NULL); + push(&ctx->current->body, &nlabel); + tu = tu->next; + } +} + +static void gen_match_tagged(struct gen_context *ctx, const struct expression *expr, const struct qbe_value *out) @@ -1566,7 +1587,8 @@ gen_match_tagged(struct gen_context *ctx, // tag, rather than advancing it to the value area, // before initializing a binding for it. reinterpret = true; - assert(0); // TODO + gen_match_tagged_subset(ctx, &tbranch, + &fbranch, &tag, _case); } else { gen_recursive_match_tests(ctx, mtype, &fbranch, &tag, &mval, _case); diff --git a/tests/18-match.ha b/tests/18-match.ha @@ -160,6 +160,27 @@ fn transitivity() void = { assert(visit); }; +type signed = (i8 | i16 | i32 | i64 | int); +type unsigned = (u8 | u16 | u32 | u64 | uint | size); +type integer = (...signed | ...unsigned); + +export fn numeric() void = { + // Real-world test + let visit = true; + let x: integer = 1337; + match (x) { + s: signed => match (s) { + i: int => { + visit = true; + assert(i == 1337); + }, + * => abort(), + }, + u: unsigned => abort(), + }; + assert(visit); +}; + export fn main() void = { tagged(); termination(); @@ -169,5 +190,6 @@ export fn main() void = { tagged_result(); implicit_cast(); transitivity(); + numeric(); // TODO: Test exhaustiveness and dupe detection };