harec

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

commit 222d6e74557a996834397b82c3e453a883c6c230
parent 96e04656ccd9dd628191b31a3e9dfaa86d3bb1c0
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 23 Jan 2021 09:18:50 -0500

check: partially implement match expressions

Diffstat:
Minclude/expr.h | 13+++++++++++++
Msrc/check.c | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/include/expr.h b/include/expr.h @@ -195,6 +195,18 @@ struct expression_list { struct expressions exprs; }; +struct match_case { + const struct scope_object *object; // May be NULL + const struct type *type; + struct expression *value; + struct match_case *next; +}; + +struct expression_match { + struct expression *value; + struct match_case *cases; +}; + enum measure_operator { M_LEN, M_SIZE, @@ -274,6 +286,7 @@ struct expression { struct expression_for _for; struct expression_if _if; struct expression_list list; + struct expression_match match; struct expression_measure measure; struct expression_return _return; struct expression_switch _switch; diff --git a/src/check.c b/src/check.c @@ -862,6 +862,96 @@ check_expr_list(struct context *ctx, } static void +check_expr_match(struct context *ctx, + const struct ast_expression *aexpr, + struct expression *expr, + const struct type *hint) +{ + trenter(TR_CHECK, "match"); + expr->type = EXPR_MATCH; + + struct expression *value = xcalloc(1, sizeof(struct expression)); + check_expression(ctx, aexpr->match.value, value, NULL); + expr->match.value = value; + + const struct type *type = value->result; + bool is_ptr = type->storage == TYPE_STORAGE_POINTER + && type->pointer.flags & PTR_NULLABLE; + expect(&aexpr->match.value->loc, + type->storage == TYPE_STORAGE_TAGGED_UNION || is_ptr, + "match value must be tagged union or nullable pointer type"); + + struct match_case **next = &expr->match.cases, *_case = NULL; + for (struct ast_match_case *acase = aexpr->match.cases; + acase; acase = acase->next) { + _case = *next = xcalloc(1, sizeof(struct match_case)); + next = &_case->next; + + const struct type *ctype = type_store_lookup_atype( + ctx->store, acase->type); + struct expression *value = xcalloc(1, sizeof(struct expression)); + check_expression(ctx, acase->value, value, NULL); + + // TODO: Figure out alias semantics properly + if (is_ptr) { + switch (ctype->storage) { + case TYPE_STORAGE_POINTER: + expect(&acase->type->loc, + type->pointer.referent == ctype->pointer.referent, + "Match case of incompatible pointer type"); + break; + case TYPE_STORAGE_NULL: + // No additional tests required + break; + default: + expect(&acase->type->loc, false, + "Invalid type for match case"); + break; + } + } else { + bool valid = false; + switch (ctype->storage) { + case TYPE_STORAGE_TAGGED_UNION: + expect(&acase->type->loc, type_is_assignable( + ctx->store, type, ctype), + "Invalid type for match case"); + break; + default: + for (const struct type_tagged_union *tu = &type->tagged; + tu; tu = tu->next) { + if (tu->type == ctype) { + valid = true; + break; + } + } + expect(&acase->type->loc, valid, + "Invalid type for match case"); + break; + } + } + + _case->value = xcalloc(1, sizeof(struct expression)); + check_expression(ctx, acase->value, _case->value, type); + if (_case->value->terminates) { + continue; + } + + if (expr->result == NULL) { + expr->result = _case->value->result; + } else if (expr->result != _case->value->result) { + assert(0); // TODO: Form tagged union + } + } + + if (expr->result == NULL) { + expr->result = &builtin_type_void; + expr->terminates = true; + } + + trleave(TR_CHECK, NULL); +} + +static void check_expr_measure(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, @@ -1219,7 +1309,8 @@ check_expression(struct context *ctx, check_expr_list(ctx, aexpr, expr, hint); break; case EXPR_MATCH: - assert(0); // TODO + check_expr_match(ctx, aexpr, expr, hint); + break; case EXPR_MEASURE: check_expr_measure(ctx, aexpr, expr, hint); break;