aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-06-28 22:08:49 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-06-28 22:08:49 +0200
commit5911ffe467650907eb09521ca83290e4a4702d8d (patch)
tree8a3cc2137a6a2d2319c3b294f35418b0d07317eb
parent8e9ae1c325533818f43efa9577d15cc17295d9ee (diff)
Make division work as expected
-rw-r--r--src/analyzer.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/src/analyzer.c b/src/analyzer.c
index fff7716..4a5a2c6 100644
--- a/src/analyzer.c
+++ b/src/analyzer.c
@@ -329,15 +329,27 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast,
rhs = ast.kids[i].rhs;
analyzeexpr(ctx, scps, types, ast, aux, toks, lhs);
idx_t ni = analyzeexpr(ctx, scps, types, ast, aux, toks, rhs);
+
if (!typecompat(types[lhs], types[rhs]))
err("analyzer: Binary oprand type mismatch");
+
if (ast.kinds[i] == ASTBINMOD) {
if (types[lhs].kind != TYPE_NUM || types[lhs].isfloat)
err("analyzer: Remainder is not defined for non-integer types");
if (types[rhs].kind != TYPE_NUM || types[rhs].isfloat)
err("analyzer: Remainder is not defined for non-integer types");
}
- types[i] = types[rhs];
+
+ /* In the expression ‘x ⋆ y’ where ⋆ is a binary operator, the
+ expression has type T if both x and y have type T. If one of
+ x or y is a sized type and the other isn’t, then the
+ expression has the type of the sized type.
+
+ Additionally if both x and y are unsized types but one is a
+ floating-point type and the other isn’t, the type of the
+ expression is an unsized floating-point type. */
+ types[i] = types[lhs].size != 0 ? types[lhs] : types[rhs];
+ types[i].isfloat = types[lhs].isfloat || types[rhs].isfloat;
return ni;
}
case ASTFN:
@@ -519,14 +531,12 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
}
case ASTBINADD:
case ASTBINSUB:
- case ASTBINMUL:
- case ASTBINDIV: {
+ case ASTBINMUL: {
static void (*const mpq_fns[UINT8_MAX])(mpq_t, const mpq_t,
const mpq_t) = {
['+'] = mpq_add,
['-'] = mpq_sub,
['*'] = mpq_mul,
- ['/'] = mpq_div,
};
idx_t lhs, rhs;
lhs = ast.kids[i].lhs;
@@ -539,6 +549,25 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
}
return ni;
}
+ case ASTBINDIV: {
+ idx_t lhs, rhs;
+ lhs = ast.kids[i].lhs;
+ rhs = ast.kids[i].rhs;
+
+ (void)constfoldexpr(ctx, folds, scps, types, ast, toks, lhs);
+ idx_t ni = constfoldexpr(ctx, folds, scps, types, ast, toks, rhs);
+
+ if (MPQ_IS_INIT(folds[lhs]) && MPQ_IS_INIT(folds[rhs])) {
+ mpq_init(folds[i]);
+ if (types[i].isfloat)
+ mpq_div(folds[i], folds[lhs], folds[rhs]);
+ else {
+ mpz_tdiv_q(mpq_numref(folds[i]), mpq_numref(folds[lhs]),
+ mpq_numref(folds[rhs]));
+ }
+ }
+ return ni;
+ }
case ASTBINMOD: {
idx_t lhs, rhs;
lhs = ast.kids[i].lhs;