about summary refs log tree commit diff stats
path: root/tutorial/converter.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-10-20 11:51:24 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-10-20 12:01:55 -0700
commit619dc31dfc565a2f8d76b6ab701b64394506f5ae (patch)
treee6fa4595c885f1582cdf7b6e89e5439aecdd0f68 /tutorial/converter.mu
parent909a0e2530142ea5bf506d66111a6ff75bf645e9 (diff)
downloadmu-619dc31dfc565a2f8d76b6ab701b64394506f5ae.tar.gz
sketching out a slow tutorial
Diffstat (limited to 'tutorial/converter.mu')
-rw-r--r--tutorial/converter.mu138
1 files changed, 138 insertions, 0 deletions
diff --git a/tutorial/converter.mu b/tutorial/converter.mu
new file mode 100644
index 00000000..a8aa26e3
--- /dev/null
+++ b/tutorial/converter.mu
@@ -0,0 +1,138 @@
+# Temperature Converter app
+#   https://eugenkiss.github.io/7guis/tasks/#temp
+#
+# To build:
+#   $ ./translate converter.mu
+# To run:
+#   $ qemu-system-i386 code.img
+
+# todo:
+#   less duplication
+#   error checking for input without hard-aborting
+
+fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+  # celsius numeric representation
+  var zero: float
+  var celsius/xmm1: float <- fahrenheit-to-celsius zero
+  # celsius string representation
+  var s-storage: (stream byte 0x10)
+  var s/ecx: (addr stream byte) <- address s-storage
+  write-float-decimal-approximate s, celsius, 2/decimal-places
+  # celsius input/display
+  var celsius-input-storage: gap-buffer
+  var celsius-input/esi: (addr gap-buffer) <- address celsius-input-storage
+  initialize-gap-buffer celsius-input, 8/capacity
+  load-gap-buffer-from-stream celsius-input, s
+  var cursor-in-celsius?/edx: boolean <- copy 0xffffffff/true
+  # fahrenheit numeric representation
+  var fahrenheit/xmm2: float <- celsius-to-fahrenheit celsius
+  # fahrenheit string representation
+  clear-stream s
+  write-float-decimal-approximate s, fahrenheit, 2/decimal-places
+  # fahrenheit input/display
+  var fahrenheit-input-storage: gap-buffer
+  var fahrenheit-input/edi: (addr gap-buffer) <- address fahrenheit-input-storage
+  initialize-gap-buffer fahrenheit-input, 8/capacity
+  load-gap-buffer-from-stream fahrenheit-input, s
+  var cursor-in-fahrenheit?/ebx: boolean <- copy 0/false  # exactly one cursor boolean must be true at any time
+  # widget title
+  set-cursor-position screen, 0x1f/x 0xe/y
+  draw-text-rightward-from-cursor-over-full-screen screen, " Converter                            ", 0xf/fg 0x16/bg
+  # event loop
+  {
+    # draw current state to screen
+    clear-rect screen, 0x1f/xmin 0xf/ymin, 0x45/xmax 0x14/ymax, 0xc5/color
+    var x/eax: int <- render-gap-buffer screen, celsius-input, 0x20/x 0x10/y, cursor-in-celsius?, 7/fg 0/bg
+    x <- draw-text-rightward screen, " celsius = ", x, 0x45/xmax, 0x10/y, 7/fg 0xc5/bg
+    x <- render-gap-buffer screen, fahrenheit-input, x 0x10/y, cursor-in-fahrenheit?, 7/fg 0/bg
+    x <- draw-text-rightward screen, " fahrenheit", x, 0x45/xmax, 0x10/y, 7/fg 0xc5/bg
+    # render a menu bar
+    set-cursor-position screen, 0x21/x 0x12/y
+    draw-text-rightward-from-cursor-over-full-screen screen, " tab ", 0/fg 0x5c/bg=highlight
+    draw-text-rightward-from-cursor-over-full-screen screen, " switch sides ", 7/fg 0xc5/bg
+    draw-text-rightward-from-cursor-over-full-screen screen, " enter ", 0/fg 0x5c/bg=highlight
+    draw-text-rightward-from-cursor-over-full-screen screen, " convert ", 7/fg 0xc5/bg
+    # process a single keystroke
+    $main:input: {
+      var key/eax: byte <- read-key keyboard
+      var key/eax: grapheme <- copy key
+      compare key, 0
+      loop-if-=
+      # tab = switch cursor between input areas
+      compare key, 9/tab
+      {
+        break-if-!=
+        cursor-in-celsius? <- not
+        cursor-in-fahrenheit? <- not
+        break $main:input
+      }
+      # enter = convert in appropriate direction
+      compare key, 0xa/newline
+      {
+        break-if-!=
+        {
+          compare cursor-in-celsius?, 0/false
+          break-if-=
+          clear-stream s
+          emit-gap-buffer celsius-input, s
+          celsius <- parse-float-decimal s
+          fahrenheit <- celsius-to-fahrenheit celsius
+          clear-stream s
+          write-float-decimal-approximate s, fahrenheit, 2/decimal-places
+          clear-gap-buffer fahrenheit-input
+          load-gap-buffer-from-stream fahrenheit-input, s
+        }
+        {
+          compare cursor-in-fahrenheit?, 0/false
+          break-if-=
+          clear-stream s
+          emit-gap-buffer fahrenheit-input, s
+          {
+            var tmp/xmm1: float <- parse-float-decimal s
+            fahrenheit <- copy tmp
+          }
+          celsius <- fahrenheit-to-celsius fahrenheit
+          clear-stream s
+          write-float-decimal-approximate s, celsius, 2/decimal-places
+          clear-gap-buffer celsius-input
+          load-gap-buffer-from-stream celsius-input, s
+        }
+        break $main:input
+      }
+      # otherwise pass key to appropriate input area
+      compare cursor-in-celsius?, 0/false
+      {
+        break-if-=
+        edit-gap-buffer celsius-input, key
+        break $main:input
+      }
+      compare cursor-in-fahrenheit?, 0/false
+      {
+        break-if-=
+        edit-gap-buffer fahrenheit-input, key
+        break $main:input
+      }
+    }
+    loop
+  }
+}
+
+fn fahrenheit-to-celsius f: float -> _/xmm1: float {
+  var result/xmm1: float <- copy f
+  var thirty-two/eax: int <- copy 0x20
+  var thirty-two-f/xmm0: float <- convert thirty-two
+  result <- subtract thirty-two-f
+  var factor/xmm0: float <- rational 5, 9
+  result <- multiply factor
+  return result
+}
+
+fn celsius-to-fahrenheit c: float -> _/xmm2: float {
+  var result/xmm1: float <- copy c
+  var factor/xmm0: float <- rational 9, 5
+  result <- multiply factor
+  var thirty-two/eax: int <- copy 0x20
+  var thirty-two-f/xmm0: float <- convert thirty-two
+  result <- add thirty-two-f
+  return result
+}