aboutsummaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c26
1 files changed, 15 insertions, 11 deletions
diff --git a/compile.c b/compile.c
index 326ee5ec..949d7adb 100644
--- a/compile.c
+++ b/compile.c
@@ -684,16 +684,17 @@ CORD compile_statement(env_t *env, ast_t *ast)
type_t *lhs_t = get_type(env, update->lhs);
type_t *rhs_t = get_type(env, update->rhs);
- if (!promote(env, update->rhs, &rhs, rhs_t, lhs_t)) {
- if (update->rhs->tag == Int && (lhs_t->tag == IntType || lhs_t->tag == ByteType))
- rhs = compile_int_to_type(env, update->rhs, lhs_t);
- else if (!(lhs_t->tag == ArrayType && promote(env, update->rhs, &rhs, rhs_t, Match(lhs_t, ArrayType)->item_type)))
+ if (update->rhs->tag == Int && is_numeric_type(non_optional(lhs_t))) {
+ rhs = compile_int_to_type(env, update->rhs, lhs_t);
+ } else if (!promote(env, update->rhs, &rhs, rhs_t, lhs_t)) {
+ if (!(lhs_t->tag == ArrayType && promote(env, update->rhs, &rhs, rhs_t, Match(lhs_t, ArrayType)->item_type)))
code_err(ast, "I can't do operations between %T and %T", lhs_t, rhs_t);
}
+ bool lhs_is_optional_num = (lhs_t->tag == OptionalType && Match(lhs_t, OptionalType)->type && Match(lhs_t, OptionalType)->type->tag == NumType);
switch (update->op) {
case BINOP_MULT:
- if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType)
+ if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType && !lhs_is_optional_num)
code_err(ast, "I can't do a multiply assignment with this operator between %T and %T", lhs_t, rhs_t);
if (lhs_t->tag == NumType) { // 0*INF -> NaN, needs checking
return CORD_asprintf("%r *= %r;\n"
@@ -706,7 +707,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
}
return CORD_all(lhs, " *= ", rhs, ";");
case BINOP_DIVIDE:
- if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType)
+ if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType && !lhs_is_optional_num)
code_err(ast, "I can't do a divide assignment with this operator between %T and %T", lhs_t, rhs_t);
if (lhs_t->tag == NumType) { // 0/0 or INF/INF -> NaN, needs checking
return CORD_asprintf("%r /= %r;\n"
@@ -719,23 +720,23 @@ CORD compile_statement(env_t *env, ast_t *ast)
}
return CORD_all(lhs, " /= ", rhs, ";");
case BINOP_MOD:
- if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType)
+ if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType && !lhs_is_optional_num)
code_err(ast, "I can't do a mod assignment with this operator between %T and %T", lhs_t, rhs_t);
return CORD_all(lhs, " = ", lhs, " % ", rhs);
case BINOP_MOD1:
- if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType)
+ if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType && !lhs_is_optional_num)
code_err(ast, "I can't do a mod assignment with this operator between %T and %T", lhs_t, rhs_t);
return CORD_all(lhs, " = (((", lhs, ") - 1) % ", rhs, ") + 1;");
case BINOP_PLUS:
- if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType)
+ if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType && !lhs_is_optional_num)
code_err(ast, "I can't do an addition assignment with this operator between %T and %T", lhs_t, rhs_t);
return CORD_all(lhs, " += ", rhs, ";");
case BINOP_MINUS:
- if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType)
+ if (lhs_t->tag != IntType && lhs_t->tag != NumType && lhs_t->tag != ByteType && !lhs_is_optional_num)
code_err(ast, "I can't do a subtraction assignment with this operator between %T and %T", lhs_t, rhs_t);
return CORD_all(lhs, " -= ", rhs, ";");
case BINOP_POWER: {
- if (lhs_t->tag != NumType)
+ if (lhs_t->tag != NumType && !lhs_is_optional_num)
code_err(ast, "'^=' is only supported for Num types");
if (lhs_t->tag == NumType && Match(lhs_t, NumType)->bits == TYPE_NBITS32)
return CORD_all(lhs, " = powf(", lhs, ", ", rhs, ");");
@@ -1612,6 +1613,9 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
if (target->tag == BigIntType)
return compile(env, ast);
+ if (target->tag == OptionalType && Match(target, OptionalType)->type)
+ return compile_int_to_type(env, ast, Match(target, OptionalType)->type);
+
const char *literal = Match(ast, Int)->str;
OptionalInt_t int_val = Int$from_str(literal);
if (int_val.small == 0)