aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-11-07 13:27:09 -0500
committerBruce Hill <bruce@bruce-hill.com>2024-11-07 13:27:09 -0500
commitbd3df661656adecae089045a5afa51a46b94666b (patch)
tree86c2a33b5295619513153b9dd80bd874c04a9a9c
parent3d9e562e2cc6141ea8c5c66477c036404a868ecd (diff)
Fix up some stuff with boolean operators and reductions
-rw-r--r--compile.c47
-rw-r--r--typecheck.c35
2 files changed, 35 insertions, 47 deletions
diff --git a/compile.c b/compile.c
index 4c8e3785..c6f23d4e 100644
--- a/compile.c
+++ b/compile.c
@@ -2082,6 +2082,17 @@ CORD compile(env_t *env, ast_t *ast)
} else {
code_err(ast, "I don't know how to do an 'or' operation between %T and %T", lhs_t, rhs_t);
}
+ } else if (binop->op == BINOP_AND && lhs_t->tag == OptionalType) {
+ if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) {
+ return CORD_all("({ ", compile_declaration(lhs_t, "lhs"), " = ", compile(env, binop->lhs), "; ",
+ "if (!", check_null(lhs_t, "lhs"), ") ", compile_statement(env, binop->rhs), " ",
+ optional_into_nonnull(lhs_t, "lhs"), "; })");
+ } 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_null(lhs_t, "lhs"), " ? 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);
+ }
}
CORD lhs, rhs;
@@ -2226,13 +2237,12 @@ CORD compile(env_t *env, ast_t *ast)
}
}
case BINOP_AND: {
- // TODO: support optional values in `and` expressions
if (operand_t->tag == BoolType)
return CORD_all("(", lhs, " && ", rhs, ")");
else if (operand_t->tag == IntType || operand_t->tag == ByteType)
return CORD_all("(", lhs, " & ", rhs, ")");
else
- code_err(ast, "Boolean operators are only supported for Bool and integer types");
+ code_err(ast, "The 'and' operator isn't supported for %T and %T", lhs_t, rhs_t);
}
case BINOP_CMP: {
return CORD_all("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(env, operand_t), ")");
@@ -2243,14 +2253,14 @@ CORD compile(env_t *env, ast_t *ast)
else if (operand_t->tag == IntType || operand_t->tag == ByteType)
return CORD_all("(", lhs, " | ", rhs, ")");
else
- code_err(ast, "Boolean operators are only supported for Bool and integer types");
+ code_err(ast, "The 'or' operator isn't supported for %T and %T", lhs_t, rhs_t);
}
case BINOP_XOR: {
// TODO: support optional values in `xor` expressions
if (operand_t->tag == BoolType || operand_t->tag == IntType || operand_t->tag == ByteType)
return CORD_all("(", lhs, " ^ ", rhs, ")");
else
- code_err(ast, "Boolean operators are only supported for Bool and integer types");
+ code_err(ast, "The 'xor' operator isn't supported for %T and %T", lhs_t, rhs_t);
}
case BINOP_CONCAT: {
switch (operand_t->tag) {
@@ -3238,15 +3248,13 @@ CORD compile(env_t *env, ast_t *ast)
}
case Reduction: {
auto reduction = Match(ast, Reduction);
- type_t *optional_t = get_type(env, ast);
- type_t *t = Match(optional_t, OptionalType)->type;
binop_e op = reduction->combination->tag == BinaryOp ? Match(reduction->combination, BinaryOp)->op : BINOP_UNKNOWN;
+ type_t *iter_t = get_type(env, reduction->iter);
+ type_t *item_t = get_iterated_type(iter_t);
+ if (!item_t) code_err(reduction->iter, "I couldn't figure out how to iterate over this type: %T", iter_t);
if (op == BINOP_EQ || op == BINOP_NE || op == BINOP_LT || op == BINOP_LE || op == BINOP_GT || op == BINOP_GE) {
// Chained comparisons like ==, <, etc.
- type_t *iter_t = get_type(env, reduction->iter);
- type_t *item_t = get_iterated_type(iter_t);
- if (!item_t) code_err(reduction->iter, "I couldn't figure out how to iterate over this type: %T", iter_t);
CORD code = CORD_all(
"({ // Reduction:\n",
compile_declaration(item_t, "prev"), ";\n"
@@ -3277,11 +3285,11 @@ CORD compile(env_t *env, ast_t *ast)
// Accumulator-style reductions like +, ++, *, etc.
CORD code = CORD_all(
"({ // Reduction:\n",
- compile_declaration(t, "reduction"), ";\n"
+ compile_declaration(item_t, "reduction"), ";\n"
"Bool_t has_value = no;\n"
);
env_t *scope = fresh_scope(env);
- set_binding(scope, "$reduction", new(binding_t, .type=t, .code="reduction"));
+ set_binding(scope, "$reduction", new(binding_t, .type=item_t, .code="reduction"));
ast_t *item = FakeAST(Var, "$iter_value");
ast_t *body = FakeAST(InlineCCode, .code="{}"); // placeholder
ast_t *loop = FakeAST(For, .vars=new(ast_list_t, .ast=item), .iter=reduction->iter, .body=body);
@@ -3290,18 +3298,18 @@ CORD compile(env_t *env, ast_t *ast)
// For the special case of (or)/(and), we need to early out if we can:
CORD early_out = CORD_EMPTY;
if (op == BINOP_CMP) {
- if (t->tag != IntType || Match(t, IntType)->bits != TYPE_IBITS32)
+ if (item_t->tag != IntType || Match(item_t, IntType)->bits != TYPE_IBITS32)
code_err(ast, "<> reductions are only supported for Int32 values");
} else if (op == BINOP_AND) {
- if (t->tag == BoolType)
+ if (item_t->tag == BoolType)
early_out = "if (!reduction) break;";
- else if (t->tag == OptionalType)
- early_out = CORD_all("if (", check_null(t, "reduction"), ") break;");
+ else if (item_t->tag == OptionalType)
+ early_out = CORD_all("if (", check_null(item_t, "reduction"), ") break;");
} else if (op == BINOP_OR) {
- if (t->tag == BoolType)
+ if (item_t->tag == BoolType)
early_out = "if (reduction) break;";
- else if (t->tag == OptionalType)
- early_out = CORD_all("if (!", check_null(t, "reduction"), ") break;");
+ else if (item_t->tag == OptionalType)
+ early_out = CORD_all("if (!", check_null(item_t, "reduction"), ") break;");
}
body->__data.InlineCCode.code = CORD_all(
@@ -3313,7 +3321,8 @@ CORD compile(env_t *env, ast_t *ast)
early_out,
"}\n");
- code = CORD_all(code, compile_statement(scope, loop), "\nhas_value ? ", promote_to_optional(t, "reduction"), " : ", compile_null(t), ";})");
+ code = CORD_all(code, compile_statement(scope, loop), "\nhas_value ? ", promote_to_optional(item_t, "reduction"),
+ " : ", compile_null(item_t), ";})");
return code;
}
}
diff --git a/typecheck.c b/typecheck.c
index 2dcfda42..49eba2ca 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -950,8 +950,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|| (lhs_t->tag == ByteType && rhs_t->tag == ByteType)) {
return get_math_type(env, ast, lhs_t, rhs_t);
}
- code_err(ast, "I can't figure out the type of this `and` expression because the left side is a %T, but the right side is a %T",
- lhs_t, rhs_t);
+ code_err(ast, "I can't figure out the type of this `and` expression between a %T and a %T", lhs_t, rhs_t);
}
case BINOP_OR: {
if (lhs_t->tag == BoolType && rhs_t->tag == BoolType) {
@@ -976,8 +975,7 @@ type_t *get_type(env_t *env, ast_t *ast)
return Type(PointerType, .pointed=lhs_ptr->pointed);
}
}
- code_err(ast, "I can't figure out the type of this `or` expression because the left side is a %T, but the right side is a %T",
- lhs_t, rhs_t);
+ code_err(ast, "I can't figure out the type of this `or` expression between a %T and a %T", lhs_t, rhs_t);
}
case BINOP_XOR: {
if (lhs_t->tag == BoolType && rhs_t->tag == BoolType) {
@@ -987,8 +985,7 @@ type_t *get_type(env_t *env, ast_t *ast)
return get_math_type(env, ast, lhs_t, rhs_t);
}
- code_err(ast, "I can't figure out the type of this `xor` expression because the left side is a %T, but the right side is a %T",
- lhs_t, rhs_t);
+ code_err(ast, "I can't figure out the type of this `xor` expression between a %T and a %T", lhs_t, rhs_t);
}
case BINOP_CONCAT: {
if (!type_eq(lhs_t, rhs_t))
@@ -1028,28 +1025,10 @@ type_t *get_type(env_t *env, ast_t *ast)
return Type(OptionalType, .type=Type(BoolType));
}
- type_t *value_t;
- type_t *iter_value_t = value_type(iter_t);
- switch (iter_value_t->tag) {
- case BigIntType: case IntType: value_t = iter_value_t; break;
- case ArrayType: value_t = Match(iter_value_t, ArrayType)->item_type; break;
- case SetType: value_t = Match(iter_value_t, SetType)->item_type; break;
- case TableType: code_err(reduction->iter, "To do a reduction over a table, please specify either .keys or .values");
- case FunctionType: case ClosureType: {
- // Iterator function
- auto fn = iter_value_t->tag == ClosureType ?
- Match(Match(iter_value_t, ClosureType)->fn, FunctionType) : Match(iter_value_t, FunctionType);
- if (fn->args)
- code_err(reduction->iter, "I expected this iterator function to not take any arguments, but it's %T", iter_value_t);
- if (fn->ret->tag != OptionalType)
- code_err(reduction->iter, "I expected this iterator function to return an optional value, but it's %T", iter_value_t);
- value_t = Match(fn->ret, OptionalType)->type;
- break;
- }
- default: code_err(reduction->iter, "I don't know how to do a reduction over %T values", iter_t);
- }
-
- return Type(OptionalType, .type=value_t);
+ type_t *iterated = get_iterated_type(iter_t);
+ if (!iterated)
+ code_err(reduction->iter, "I don't know how to do a reduction over %T values", iter_t);
+ return iterated->tag == OptionalType ? iterated : Type(OptionalType, .type=iterated);
}
case UpdateAssign: