about summary refs log tree commit diff
path: root/boot
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-05-24 20:30:11 +0200
committerMel <mel@rnrd.eu>2026-05-24 20:30:11 +0200
commit7af54064b23efe1f18fab9e7ee20b0fc811c36b5 (patch)
treed8482ce29cdee1892c843f57be881e6fecb98d2d /boot
parent2a893246711442dd8407264c05991b44d1d1f66f (diff)
downloadcatskill-7af54064b23efe1f18fab9e7ee20b0fc811c36b5.tar.zst
catskill-7af54064b23efe1f18fab9e7ee20b0fc811c36b5.zip
Power operator via runtime library implementation
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot')
-rw-r--r--boot/runtime/core.c20
-rw-r--r--boot/tests/transpile/expressions.cskt9
-rw-r--r--boot/transpile.c13
3 files changed, 42 insertions, 0 deletions
diff --git a/boot/runtime/core.c b/boot/runtime/core.c
index e377e0a..cc9210e 100644
--- a/boot/runtime/core.c
+++ b/boot/runtime/core.c
@@ -87,6 +87,26 @@ println(const ascii* s)
 
 // `printf` is already linked in via <stdio.h>.
 
+// integer exponentiation by squaring.
+// see: https://en.wikipedia.org/wiki/Exponentiation_by_squaring
+// negative exponent rounds to 0 for any base except 1 / -1.
+integer
+pow_integer(integer base, integer exponent)
+{
+    if (exponent < 0) {
+        if (base == 1) return 1;
+        if (base == -1) return (exponent & 1) ? -1 : 1;
+        return 0;
+    }
+    integer result = 1;
+    while (exponent > 0) {
+        if (exponent & 1) result *= base;
+        base *= base;
+        exponent >>= 1;
+    }
+    return result;
+}
+
 void*
 allocate(size_t size)
 {
diff --git a/boot/tests/transpile/expressions.cskt b/boot/tests/transpile/expressions.cskt
index c127b9a..0ca3c01 100644
--- a/boot/tests/transpile/expressions.cskt
+++ b/boot/tests/transpile/expressions.cskt
@@ -1,5 +1,8 @@
 precedence-aware expression emission only inserts parentheses when the
 child binds more loosely than the parent expects.
+`**` has no c equivalent and is routed through the integer-power
+runtime helper, with right-associative chaining preserved by the
+recursive expansion of the call arguments.
 
 <<<
 
@@ -10,6 +13,9 @@ main = fun () {
     var d int = 10 - (4 - 1)
     var e int = -1 + 2
     var f bool = a == b && c != 0 || d > 0
+    var g int = 2 ** 10
+    var h int = 2 ** 2 ** 3
+    var i int = 1 + 2 ** 3
 }
 
 >>>
@@ -23,5 +29,8 @@ void catskill_main(void) {
     integer d = 10 - (4 - 1);
     integer e = -1 + 2;
     bool f = a == b && c != 0 || d > 0;
+    integer g = pow_integer(2, 10);
+    integer h = pow_integer(2, pow_integer(2, 3));
+    integer i = 1 + pow_integer(2, 3);
 }
 #include "runtime.c"
diff --git a/boot/transpile.c b/boot/transpile.c
index 0627bcb..9c94706 100644
--- a/boot/transpile.c
+++ b/boot/transpile.c
@@ -406,6 +406,19 @@ transpile_visit_expression_binary_operation(struct Visit* visit, struct Expressi
     TRANSPILE_PREAMBLE
 
     enum Binary_Operation op = expression->value.binary_operator.operation;
+
+    // c has no built-in power operator.
+    // we route the operation via our own runtime library `pow_integer` function,
+    // which performs fast exponentiation by squaring.
+    if (op == BINARY_POWER) {
+        TRANSPILE_WRITE("pow_integer(");
+        transpile_emit_expression(visit, expression->value.binary_operator.left_operand, 0);
+        TRANSPILE_WRITE(", ");
+        transpile_emit_expression(visit, expression->value.binary_operator.right_operand, 0);
+        TRANSPILE_WRITE(")");
+        return;
+    }
+
     uint my_precedence = binary_operation_precedence(op);
     uint parent = transpiler->expression_parent_precedence;
     bool needs_parens = my_precedence < parent;