diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-12-21 15:13:26 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-12-21 15:13:26 -0500 |
| commit | 325b367a1342826fe7174ce45cfab92091d4dbb5 (patch) | |
| tree | 921b306025e495f71f008f9f9a4b1291ce2cdcb3 | |
| parent | 478ddad9aaf837005f5401126f8872c0e3058bba (diff) | |
Support logical binary operators on optionals (promote to booleans)
| -rw-r--r-- | compile.c | 10 | ||||
| -rw-r--r-- | test/optionals.tm | 5 | ||||
| -rw-r--r-- | typecheck.c | 9 | ||||
| -rw-r--r-- | types.c | 3 |
4 files changed, 27 insertions, 0 deletions
@@ -70,6 +70,12 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * return true; } + // Optional -> Bool promotion + if (actual->tag == OptionalType && needed->tag == BoolType) { + *code = CORD_all("(!", check_none(actual, *code), ")"); + return true; + } + // Automatic optional checking for nums: if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType) { *code = CORD_all("({ ", compile_declaration(actual, "opt"), " = ", *code, "; ", @@ -2155,6 +2161,8 @@ CORD compile(env_t *env, ast_t *ast) return CORD_all("({ ", compile_declaration(lhs_t, "lhs"), " = ", compile(env, binop->lhs), "; ", check_none(lhs_t, "lhs"), " ? ", compile(env, binop->rhs), " : ", optional_into_nonnone(lhs_t, "lhs"), "; })"); + } else if (rhs_t->tag == BoolType) { + return CORD_all("((!", check_none(lhs_t, compile(env, binop->lhs)), ") || ", compile(env, binop->rhs), ")"); } else { code_err(ast, "I don't know how to do an 'or' operation between %T and %T", lhs_t, rhs_t); } @@ -2166,6 +2174,8 @@ CORD compile(env_t *env, ast_t *ast) } else if (rhs_t->tag == OptionalType && type_eq(lhs_t, rhs_t)) { return CORD_all("({ ", compile_declaration(lhs_t, "lhs"), " = ", compile(env, binop->lhs), "; ", check_none(lhs_t, "lhs"), " ? lhs : ", compile(env, binop->rhs), "; })"); + } else if (rhs_t->tag == BoolType) { + return CORD_all("((!", check_none(lhs_t, compile(env, binop->lhs)), ") && ", compile(env, binop->rhs), ")"); } else { code_err(ast, "I don't know how to do an 'or' operation between %T and %T", lhs_t, rhs_t); } diff --git a/test/optionals.tm b/test/optionals.tm index 2ccdf392..5aefedf4 100644 --- a/test/optionals.tm +++ b/test/optionals.tm @@ -326,3 +326,8 @@ func main(): >> [Struct(5,"A")?, Struct(6,"B"), Struct(7,"C")] = [Struct(x=5, y="A"), Struct(x=6, y="B"), Struct(x=7, y="C")] + + if 5? or no: + say("Binary op 'or' works with optionals") + else: + fail("Failed to do binary op 'or' on optional") diff --git a/typecheck.c b/typecheck.c index ea3cd3af..7f655606 100644 --- a/typecheck.c +++ b/typecheck.c @@ -1027,6 +1027,9 @@ type_t *get_type(env_t *env, ast_t *ast) case BINOP_AND: { if (lhs_t->tag == BoolType && rhs_t->tag == BoolType) { return lhs_t; + } else if ((lhs_t->tag == BoolType && rhs_t->tag == OptionalType) || + (lhs_t->tag == OptionalType && rhs_t->tag == BoolType)) { + return Type(BoolType); } else if (lhs_t->tag == BoolType && (rhs_t->tag == AbortType || rhs_t->tag == ReturnType)) { return lhs_t; } else if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) { @@ -1048,6 +1051,9 @@ type_t *get_type(env_t *env, ast_t *ast) case BINOP_OR: { if (lhs_t->tag == BoolType && rhs_t->tag == BoolType) { return lhs_t; + } else if ((lhs_t->tag == BoolType && rhs_t->tag == OptionalType) || + (lhs_t->tag == OptionalType && rhs_t->tag == BoolType)) { + return Type(BoolType); } else if (lhs_t->tag == BoolType && (rhs_t->tag == AbortType || rhs_t->tag == ReturnType)) { return lhs_t; } else if ((is_int_type(lhs_t) && is_int_type(rhs_t)) @@ -1075,6 +1081,9 @@ type_t *get_type(env_t *env, ast_t *ast) case BINOP_XOR: { if (lhs_t->tag == BoolType && rhs_t->tag == BoolType) { return lhs_t; + } else if ((lhs_t->tag == BoolType && rhs_t->tag == OptionalType) || + (lhs_t->tag == OptionalType && rhs_t->tag == BoolType)) { + return Type(BoolType); } else if ((is_int_type(lhs_t) && is_int_type(rhs_t)) || (lhs_t->tag == ByteType && rhs_t->tag == ByteType)) { return get_math_type(env, ast, lhs_t, rhs_t); @@ -358,6 +358,9 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed) return true; if (actual->tag == OptionalType) { + if (needed->tag == BoolType) + return true; + // Ambiguous `none` to concrete optional if (Match(actual, OptionalType)->type == NULL) return (needed->tag == OptionalType); |
