diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-08-13 16:32:00 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-08-13 16:32:00 -0400 |
| commit | e0223a4c201b42ca35c73bfad84477efc61f06b2 (patch) | |
| tree | 7f83903c19433c67e102a8688c3af02fd63eab0a | |
| parent | aaac5dff28b2fa4835dd9a3a352f274069a7b432 (diff) | |
Support ^ exponentiation for integers
| -rw-r--r-- | builtins/integers.c | 11 | ||||
| -rw-r--r-- | builtins/integers.h | 7 | ||||
| -rw-r--r-- | compile.c | 2 | ||||
| -rw-r--r-- | environment.c | 1 | ||||
| -rw-r--r-- | typecheck.c | 2 |
5 files changed, 19 insertions, 4 deletions
diff --git a/builtins/integers.c b/builtins/integers.c index 53e38aab..e55d2ab0 100644 --- a/builtins/integers.c +++ b/builtins/integers.c @@ -291,6 +291,17 @@ public Int_t Int$abs(Int_t x) return Int$from_mpz(result); } +public Int_t Int$power(Int_t base, Int_t exponent) +{ + int64_t exp = Int$as_i64(exponent); + if (__builtin_expect(exp < 0, 0)) + fail("Cannot take a negative power of an integer!"); + mpz_t result; + mpz_init_set_int(result, base); + mpz_pow_ui(result, result, exp); + return Int$from_mpz(result); +} + public Int_t Int$random(Int_t min, Int_t max) { int32_t cmp = Int$compare(&min, &max, &$Int); if (cmp > 0) diff --git a/builtins/integers.h b/builtins/integers.h index 385113b0..8250e0dc 100644 --- a/builtins/integers.h +++ b/builtins/integers.h @@ -59,6 +59,7 @@ Int_t Int$random(Int_t min, Int_t max); Range_t Int$to(Int_t from, Int_t to); Int_t Int$from_text(CORD text); Int_t Int$abs(Int_t x); +Int_t Int$power(Int_t base, Int_t exponent); #define BIGGEST_SMALL_INT ((1<<29)-1) @@ -72,11 +73,13 @@ Int_t Int$abs(Int_t x); })) #define mpz_init_set_int(mpz, i) do { \ - if ((i).small & 1) mpz_init_set_si(mpz, (i).small >> 2); \ + if (__builtin_expect((i).small & 1, 1)) mpz_init_set_si(mpz, (i).small >> 2); \ else mpz_init_set(mpz, *(i).big); \ } while (0) -#define Int$as_i64(i) (((i).small & 1) ? (int64_t)((i).small >> 2) : mpz_get_si(*(i).big)) +#define Int$as_i64(i) (__builtin_expect((i).small & 1, 1) ? (int64_t)((i).small >> 2) : \ + ({ if (!__builtin_expect(mpz_fits_slong_p(*(i).big), 1)) fail("Integer is too big to fit in a 64-bit integer!"); \ + mpz_get_si(*(i).big); })) Int_t Int$from_i64(int64_t i); Int_t Int$from_num(double n); double Int$as_num(Int_t i); @@ -1351,7 +1351,7 @@ CORD compile_math_method(env_t *env, binop_e op, ast_t *lhs, ast_t *rhs, type_t break; } case BINOP_POWER: { - if (rhs_t->tag == NumType) { + if (rhs_t->tag == NumType || rhs_t->tag == IntType) { binding_t *b = get_namespace_binding(env, lhs, binop_method_names[op]); if (binding_works(b, lhs_t, rhs_t, lhs_t)) return CORD_all(b->code, "(", compile(env, lhs), ", ", compile(env, rhs), ")"); diff --git a/environment.c b/environment.c index 57fbc6fa..c8056cc5 100644 --- a/environment.c +++ b/environment.c @@ -107,6 +107,7 @@ env_t *new_compilation_unit(CORD *libname) {"negative", "Int$negative", "func(x:Int)->Int"}, {"negated", "Int$negated", "func(x:Int)->Int"}, {"abs", "Int$abs", "func(x:Int)->Int"}, + {"power", "Int$power", "func(base:Int,exponent:Int)->Int"}, )}, {"Int64", Type(IntType, .bits=64), "Int64_t", "$Int64", TypedArray(ns_entry_t, {"format", "Int64$format", "func(i:Int64, digits=0)->Text"}, diff --git a/typecheck.c b/typecheck.c index 3e657dfa..1100aedc 100644 --- a/typecheck.c +++ b/typecheck.c @@ -899,7 +899,7 @@ type_t *get_type(env_t *env, ast_t *ast) break; } case BINOP_POWER: { - if (rhs_t->tag == NumType && binding_works(binop_method_names[binop->op], binop->lhs, lhs_t, rhs_t, lhs_t)) + if ((rhs_t->tag == NumType || rhs_t->tag == IntType) && binding_works(binop_method_names[binop->op], binop->lhs, lhs_t, rhs_t, lhs_t)) return lhs_t; break; } |
