commit 1a7e587288efdf94541756f27a0d15195717aa32
parent 34c063ebdda44768262a2ecae2cb3b4f320f8c8b
Author: Umar Getagazov <umar@handlerug.me>
Date: Sun, 11 Jul 2021 02:16:25 +0700
gen: switching on str
Signed-off-by: Umar Getagazov <umar@handlerug.me>
Diffstat:
2 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -2694,16 +2694,27 @@ gen_expr_switch(struct gen_context *ctx,
const struct qbe_value *out)
{
struct qbe_value sval = {0};
- gen_temp(ctx, &sval,
- qtype_for_type(ctx, expr->_switch.value->result, false),
- "switch.%d");
+ if (type_is_aggregate(expr->_switch.value->result)) {
+ alloc_temp(ctx, &sval, expr->_switch.value->result, "switch.%d");
+ qval_deref(&sval);
+ } else {
+ gen_temp(ctx, &sval,
+ qtype_for_type(ctx, expr->_switch.value->result, false),
+ "switch.%d");
+ }
gen_expression(ctx, expr->_switch.value, &sval);
struct qbe_value match = {0}, temp = {0};
- gen_temp(ctx, &match,
- qtype_for_type(ctx, expr->_switch.value->result, false),
- "value.%d");
+ if (type_is_aggregate(expr->_switch.value->result)) {
+ alloc_temp(ctx, &match, expr->_switch.value->result, "value.%d");
+ qval_deref(&match);
+ } else {
+ gen_temp(ctx, &match,
+ qtype_for_type(ctx, expr->_switch.value->result, false),
+ "value.%d");
+ }
gen_temp(ctx, &temp, &qbe_word, "temp.%d");
+
struct qbe_statement olabel = {0};
struct qbe_value obranch = {0};
obranch.kind = QV_LABEL;
@@ -2731,10 +2742,22 @@ gen_expr_switch(struct gen_context *ctx,
nbranch.kind = QV_LABEL;
nbranch.name = strdup(genl(&nlabel, &ctx->id, "next.opt.%d"));
- gen_expr_constant(ctx, opt->value, &match);
- pushi(ctx->current, &temp, binarithm_for_op(
- BIN_LEQUAL, sval.type, sval.type->is_signed),
- &match, &sval, NULL);
+ gen_expression(ctx, opt->value, &match);
+
+ if (type_dealias(opt->value->result)->storage ==
+ STORAGE_STRING) {
+ struct qbe_value rtfunc = {0};
+ rtfunc.kind = QV_GLOBAL;
+ rtfunc.name = strdup("rt.strcmp");
+ rtfunc.type = &qbe_long;
+ pushi(ctx->current, &temp, Q_CALL,
+ &rtfunc, &match, &sval, NULL);
+ } else {
+ pushi(ctx->current, &temp, binarithm_for_op(
+ BIN_LEQUAL, sval.type, sval.type->is_signed),
+ &match, &sval, NULL);
+ }
+
pushi(ctx->current, NULL, Q_JNZ,
&temp, &tbranch, &nbranch, NULL);
push(&ctx->current->body, &nlabel);
diff --git a/tests/14-switch.ha b/tests/14-switch.ha
@@ -40,9 +40,18 @@ fn tagged_result() void = {
assert(y is uint);
};
+fn str_switching() void = {
+ let result = switch ("hare") {
+ "world" => abort(),
+ "hare" => true,
+ };
+ assert(result == true);
+};
+
export fn main() void = {
basics();
termination();
tagged_result();
+ str_switching();
// TODO: Test exhaustiveness and dupe detection
};