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:
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, <rue);
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;
+};