harec

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

commit b5728c918f1b1d3b74d8f021d012fbd482b5317e
parent 14b8916bf93f17d3d2402981021a445c6dc3e111
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon,  9 Aug 2021 11:07:34 +0200

gen: implement str == str, str != str

Also expands the switch tests, which grow in functionality for free
thanks to this change.

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Msrc/gen.c | 21++++++++++++++++++++-
Msrc/qtype.c | 4+++-
Mtests/914-switch.ha | 9+++++++++
Mtests/rt.ha | 19+++++++++++++++++++
4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -426,12 +426,29 @@ gen_expr_assign(struct gen_context *ctx, const struct expression *expr) static struct gen_value gen_expr_binarithm(struct gen_context *ctx, const struct expression *expr) { + const struct type *ltype = type_dealias(expr->binarithm.lvalue->result); + const struct type *rtype = type_dealias(expr->binarithm.rvalue->result); struct gen_value lvalue = gen_expr(ctx, expr->binarithm.lvalue); struct gen_value rvalue = gen_expr(ctx, expr->binarithm.rvalue); struct gen_value result = mktemp(ctx, expr->result, ".%d"); struct qbe_value qlval = mkqval(ctx, &lvalue); struct qbe_value qrval = mkqval(ctx, &rvalue); struct qbe_value qresult = mkqval(ctx, &result); + + assert((ltype->storage == STORAGE_STRING) == (rtype->storage == STORAGE_STRING)); + if (ltype->storage == STORAGE_STRING) { + struct qbe_value rtfunc = mkrtfunc(ctx, "rt.strcmp"); + pushi(ctx->current, &qresult, Q_CALL, + &rtfunc, &qlval, &qrval, NULL); + if (expr->binarithm.op == BIN_NEQUAL) { + struct qbe_value one = constl(1); + pushi(ctx->current, &qresult, Q_XOR, &qresult, &one, NULL); + } else { + assert(expr->binarithm.op == BIN_LEQUAL); + } + return result; + } + enum qbe_instr instr = binarithm_for_op(ctx, expr->binarithm.op, expr->binarithm.lvalue->result); pushi(ctx->current, &qresult, instr, &qlval, &qrval, NULL); @@ -1071,7 +1088,9 @@ gen_expr_if_with(struct gen_context *ctx, push(&ctx->current->body, &ltrue); struct gen_value vtrue = gen_expr_with(ctx, expr->_if.true_branch, out); branch_copyresult(ctx, vtrue, gvout, out); - pushi(ctx->current, NULL, Q_JMP, &bend, NULL); + if (!expr->_if.true_branch->terminates) { + pushi(ctx->current, NULL, Q_JMP, &bend, NULL); + } push(&ctx->current->body, &lfalse); if (expr->_if.false_branch) { diff --git a/src/qtype.c b/src/qtype.c @@ -80,7 +80,9 @@ aggregate_lookup(struct gen_context *ctx, const struct type *type) struct qbe_field *field = &def->type.fields; switch (type->storage) { case STORAGE_ARRAY: - assert(type->array.length != SIZE_UNDEFINED); + if (type->array.length != SIZE_UNDEFINED) { + return &qbe_long; // Special case + } field->count = type->array.length; field->type = qtype_lookup(ctx, type->array.members, true); break; diff --git a/tests/914-switch.ha b/tests/914-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() int = { basics(); termination(); tagged_result(); + str_switching(); return 0; }; diff --git a/tests/rt.ha b/tests/rt.ha @@ -9,3 +9,22 @@ fn c_memcpy(x: *void, y: *void, z: size) *void; export @symbol("rt.memcpy") fn memcpy(x: *void, y: *void, z: size) *void = { return c_memcpy(x, y, z); }; + +type string = struct { + data: *[*]u8, + length: size, + capacity: size, +}; + +export @symbol("rt.strcmp") fn strcmp(_a: str, _b: str) bool = { + if (len(_a) != len(_b)) { + return false; + }; + let a = (&_a: *string).data, b = (&_b: *string).data; + for (let i = 0z; i < len(_a); i += 1) { + if (a[i] != b[i]) { + return false; + }; + }; + return true; +};