Fix up some stuff with boolean operators and reductions
This commit is contained in:
parent
3d9e562e2c
commit
bd3df66165
47
compile.c
47
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;
|
||||
}
|
||||
}
|
||||
|
35
typecheck.c
35
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:
|
||||
|
Loading…
Reference in New Issue
Block a user