about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-06-06 12:11:14 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-06-06 12:11:14 -0700
commit3bdf3b1a7f146998078975e2f7c1d5e887f84e9f (patch)
tree19ff09df06e4f6bcf26adf58a2a79e674cdb5234
parentd555a71cb327a7fd52f3d16d03d02f212346c0a7 (diff)
downloadmu-3bdf3b1a7f146998078975e2f7c1d5e887f84e9f.tar.gz
shell: remainder operation
-rw-r--r--shell/primitives.mu66
1 files changed, 65 insertions, 1 deletions
diff --git a/shell/primitives.mu b/shell/primitives.mu
index 73c58ce0..a8f22141 100644
--- a/shell/primitives.mu
+++ b/shell/primitives.mu
@@ -5,6 +5,7 @@ fn initialize-primitives _self: (addr global-table) {
   append-primitive self, "-"
   append-primitive self, "*"
   append-primitive self, "/"
+  append-primitive self, "%"
   append-primitive self, "sqrt"
   append-primitive self, "abs"
   append-primitive self, "sgn"
@@ -105,7 +106,7 @@ fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
   var tmpx/eax: int <- copy xmin
   tmpx <- draw-text-rightward screen, "fn set if while cons car cdr no not and or = ", tmpx, xmax, y, 0x2a/fg=orange, 0xdc/bg=green-bg
   # numbers
-  tmpx <- draw-text-rightward screen, "< > <= >= + - * / sqrt abs sgn", tmpx, xmax, y, 0x2a/fg=orange, 0xdc/bg=green-bg
+  tmpx <- draw-text-rightward screen, "< > <= >= + - * / % sqrt abs sgn", tmpx, xmax, y, 0x2a/fg=orange, 0xdc/bg=green-bg
 }
 
 fn primitive-global? _x: (addr global) -> _/eax: boolean {
@@ -193,6 +194,19 @@ fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr hand
     apply-divide args-ah, out, trace
     return
   }
+  # '%' is the remainder operator, because modulo isn't really meaningful for
+  # non-integers
+  #
+  # I considered calling this operator 'rem', but I want to follow Arc in
+  # using 'rem' for filtering out elements from lists.
+  #   https://arclanguage.github.io/ref/list.html#rem
+  {
+    var remainder?/eax: boolean <- string-equal? f-name, "%"
+    compare remainder?, 0/false
+    break-if-=
+    apply-remainder args-ah, out, trace
+    return
+  }
   {
     var square-root?/eax: boolean <- string-equal? f-name, "sqrt"
     compare square-root?, 0/false
@@ -584,6 +598,56 @@ fn apply-divide _args-ah: (addr handle cell), out: (addr handle cell), trace: (a
   new-float out, result
 }
 
+fn apply-remainder _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
+  trace-text trace, "eval", "apply %"
+  var args-ah/eax: (addr handle cell) <- copy _args-ah
+  var _args/eax: (addr cell) <- lookup *args-ah
+  var args/esi: (addr cell) <- copy _args
+  # TODO: check that args is a pair
+  var empty-args?/eax: boolean <- nil? args
+  compare empty-args?, 0/false
+  {
+    break-if-=
+    error trace, "% needs 2 args but got 0"
+    return
+  }
+  # args->left->value
+  var first-ah/eax: (addr handle cell) <- get args, left
+  var first/eax: (addr cell) <- lookup *first-ah
+  var first-type/ecx: (addr int) <- get first, type
+  compare *first-type, 1/number
+  {
+    break-if-=
+    error trace, "first arg for % is not a number"
+    return
+  }
+  var first-value/ecx: (addr float) <- get first, number-data
+  # args->right->left->value
+  var right-ah/eax: (addr handle cell) <- get args, right
+  var right/eax: (addr cell) <- lookup *right-ah
+  # TODO: check that right is a pair
+  var second-ah/eax: (addr handle cell) <- get right, left
+  var second/eax: (addr cell) <- lookup *second-ah
+  var second-type/edx: (addr int) <- get second, type
+  compare *second-type, 1/number
+  {
+    break-if-=
+    error trace, "second arg for % is not a number"
+    return
+  }
+  var second-value/edx: (addr float) <- get second, number-data
+  # divide
+  var quotient/xmm0: float <- copy *first-value
+  quotient <- divide *second-value
+  var quotient-int/eax: int <- truncate quotient
+  quotient <- convert quotient-int
+  var sub-result/xmm1: float <- copy quotient
+  sub-result <- multiply *second-value
+  var result/xmm0: float <- copy *first-value
+  result <- subtract sub-result
+  new-float out, result
+}
+
 fn apply-square-root _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
   trace-text trace, "eval", "apply sqrt"
   var args-ah/eax: (addr handle cell) <- copy _args-ah