about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-02-11 19:34:55 -0800
committerKartik K. Agaram <vc@akkartik.com>2021-02-11 19:34:55 -0800
commitd1bcd1421f7a0e87105499a738bae3b3a5c92de9 (patch)
tree550a6070a56dac6ed41f0a8161ee19976ee476c0
parent884c92984fd1341eed3725263434534dd915a795 (diff)
downloadmu-d1bcd1421f7a0e87105499a738bae3b3a5c92de9.tar.gz
7723 - baremetal: rendering string values
-rw-r--r--baremetal/112read-byte.subx75
-rw-r--r--baremetal/310copy-bytes.subx99
-rw-r--r--baremetal/312copy.subx13
-rw-r--r--baremetal/400.mu10
-rw-r--r--baremetal/411string.mu125
-rw-r--r--baremetal/shell/value.mu51
6 files changed, 370 insertions, 3 deletions
diff --git a/baremetal/112read-byte.subx b/baremetal/112read-byte.subx
index 64666e9b..0c9af75b 100644
--- a/baremetal/112read-byte.subx
+++ b/baremetal/112read-byte.subx
@@ -45,4 +45,79 @@ $read-byte:abort:
     }
     # never gets here
 
+== data
+
+_test-input-stream:  # (stream byte)
+    # current write index
+    0/imm32
+    # current read index
+    0/imm32
+    # size
+    0x400/imm32  # 1024 bytes
+    # data (64 lines x 16 bytes/line)
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
 # . . vim:nowrap:textwidth=0
diff --git a/baremetal/310copy-bytes.subx b/baremetal/310copy-bytes.subx
index 26fc807e..2586a53f 100644
--- a/baremetal/310copy-bytes.subx
+++ b/baremetal/310copy-bytes.subx
@@ -56,3 +56,102 @@ $copy-bytes:end:
     89/<- %esp 5/r32/ebp
     5d/pop-to-ebp
     c3/return
+
+stream-to-array:  # in: (addr stream _), out: (addr handle array _)
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    52/push-edx
+    56/push-esi
+    # esi = s
+    8b/-> *(ebp+8) 6/r32/esi
+    # var len/ecx: int = s->write - s->read
+    8b/-> *esi 1/r32/ecx
+    2b/subtract *(esi+4) 1/r32/ecx
+    # allocate
+    (allocate-array Heap %ecx *(ebp+0xc))
+    # var in/edx: (addr byte) = s->data + s->read
+    8b/-> *(esi+4) 2/r32/edx
+    8d/copy-address *(esi+edx+0xc) 2/r32/edx
+    # var dest/eax: (addr byte) = data for out
+    8b/-> *(ebp+0xc) 0/r32/eax
+    (lookup *eax *(eax+4))  # => eax
+    8d/copy-address *(eax+4) 0/r32/eax
+    #
+    (copy-bytes %edx %eax %ecx)
+$stream-to-array:end:
+    # . restore registers
+    5e/pop-to-esi
+    5a/pop-to-edx
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+test-stream-to-array:
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # setup
+    (clear-stream _test-input-stream)
+    (write _test-input-stream "abc")
+    # skip something
+    (read-byte _test-input-stream)  # => eax
+    # var out/ecx: (handle array byte)
+    68/push 0/imm32
+    68/push 0/imm32
+    89/<- %ecx 4/r32/esp
+    #
+    (stream-to-array _test-input-stream %ecx)
+    (lookup *ecx *(ecx+4))  # => eax
+    (check-strings-equal %eax "bc")
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+# like stream-to-array but ignore surrounding quotes
+# we might do other stuff here later
+unquote-stream-to-array:  # in: (addr stream _), out: (addr handle array _)
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    52/push-edx
+    56/push-esi
+    # esi = s
+    8b/-> *(ebp+8) 6/r32/esi
+    # var len/ecx: int = s->write - s->read - 2
+    8b/-> *esi 1/r32/ecx
+    2b/subtract *(esi+4) 1/r32/ecx
+    81 7/subop/compare %ecx 2/imm32
+    7c/jump-if-< $unquote-stream-to-array:end/disp8
+    81 5/subop/subtract %ecx 2/imm32
+    # allocate
+    (allocate-array Heap %ecx *(ebp+0xc))
+    # var in/edx: (addr byte) = s->data + s->read + 1
+    8b/-> *(esi+4) 2/r32/edx
+    8d/copy-address *(esi+edx+0xd) 2/r32/edx  # Stream-data + 1
+    # var dest/eax: (addr byte) = data for out
+    8b/-> *(ebp+0xc) 0/r32/eax
+    (lookup *eax *(eax+4))  # => eax
+    8d/copy-address *(eax+4) 0/r32/eax
+    #
+    (copy-bytes %edx %eax %ecx)
+$unquote-stream-to-array:end:
+    # . restore registers
+    5e/pop-to-esi
+    5a/pop-to-edx
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
diff --git a/baremetal/312copy.subx b/baremetal/312copy.subx
new file mode 100644
index 00000000..d2a6f661
--- /dev/null
+++ b/baremetal/312copy.subx
@@ -0,0 +1,13 @@
+== code
+
+copy-array-object:  # src: (addr array T), dest-ah: (addr handle array T)
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    #
+    (copy-array Heap *(ebp+8) *(ebp+0xc))
+$copy-array-object:end:
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
diff --git a/baremetal/400.mu b/baremetal/400.mu
index d2b84ad1..99195b2c 100644
--- a/baremetal/400.mu
+++ b/baremetal/400.mu
@@ -12,6 +12,8 @@ sig read-key kbd: (addr keyboard) -> _/eax: byte
 sig count-test-failure
 sig num-test-failures -> _/eax: int
 
+sig check-strings-equal s: (addr array byte), expected: (addr array byte), msg: (addr array byte)
+
 # streams
 sig clear-stream f: (addr stream _)
 sig rewind-stream f: (addr stream _)
@@ -57,5 +59,13 @@ sig to-decimal-digit in: grapheme -> _/eax: int
 sig next-word line: (addr stream byte), out: (addr slice)  # skips '#' comments
 sig next-raw-word line: (addr stream byte), out: (addr slice)  # does not skip '#' comments
 sig stream-empty? s: (addr stream _) -> _/eax: boolean
+sig stream-full? s: (addr stream _) -> _/eax: boolean
+sig stream-to-array in: (addr stream _), out: (addr handle array _)
+sig unquote-stream-to-array in: (addr stream _), out: (addr handle array _)
+sig stream-first s: (addr stream byte) -> _/eax: byte
+sig stream-final s: (addr stream byte) -> _/eax: byte
+
+#sig copy-bytes src: (addr byte), dest: (addr byte), n: int
+sig copy-array-object src: (addr array _), dest-ah: (addr handle array _)
 
 sig integer-divide a: int, b: int -> _/eax: int, _/edx: int
diff --git a/baremetal/411string.mu b/baremetal/411string.mu
new file mode 100644
index 00000000..cf0471ac
--- /dev/null
+++ b/baremetal/411string.mu
@@ -0,0 +1,125 @@
+# read up to 'len' graphemes after skipping the first 'start' ones
+fn substring in: (addr array byte), start: int, len: int, out-ah: (addr handle array byte) {
+  var in-stream: (stream byte 0x100)
+  var in-stream-addr/esi: (addr stream byte) <- address in-stream
+  write in-stream-addr, in
+  var out-stream: (stream byte 0x100)
+  var out-stream-addr/edi: (addr stream byte) <- address out-stream
+  $substring:core: {
+    # skip 'start' graphemes
+    var i/eax: int <- copy 0
+    {
+      compare i, start
+      break-if->=
+      {
+        var dummy/eax: grapheme <- read-grapheme in-stream-addr
+        compare dummy, 0xffffffff/end-of-file
+        break-if-= $substring:core
+      }
+      i <- increment
+      loop
+    }
+    # copy 'len' graphemes
+    i <- copy 0
+    {
+      compare i, len
+      break-if->=
+      {
+        var g/eax: grapheme <- read-grapheme in-stream-addr
+        compare g, 0xffffffff/end-of-file
+        break-if-= $substring:core
+        write-grapheme out-stream-addr, g
+      }
+      i <- increment
+      loop
+    }
+  }
+  stream-to-array out-stream-addr, out-ah
+}
+
+fn test-substring {
+  var out-h: (handle array byte)
+  var out-ah/edi: (addr handle array byte) <- address out-h
+  # prefix substrings
+  substring 0, 0, 3, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "", "F - test-substring/null"
+  substring "", 0, 3, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+#?   print-string-to-real-screen out
+#?   print-string-to-real-screen "\n"
+  check-strings-equal out, "", "F - test-substring/empty"
+  #
+  substring "abcde", 0, 3, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+#?   print-string-to-real-screen out
+#?   print-string-to-real-screen "\n"
+  check-strings-equal out, "abc", "F - test-substring/truncate"
+  #
+  substring "abcde", 0, 5, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "abcde", "F - test-substring/all"
+  #
+  substring "abcde", 0, 7, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "abcde", "F - test-substring/too-small"
+  # substrings outside string
+  substring "abcde", 6, 1, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "", "F - test-substring/start-too-large"
+  # trim prefix
+  substring "", 2, 3, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "", "F - test-substring/middle-empty"
+  #
+  substring "abcde", 1, 2, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "bc", "F - test-substring/middle-truncate"
+  #
+  substring "abcde", 1, 4, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "bcde", "F - test-substring/middle-all"
+  #
+  substring "abcde", 1, 5, out-ah
+  var out/eax: (addr array byte) <- lookup *out-ah
+  check-strings-equal out, "bcde", "F - test-substring/middle-too-small"
+}
+
+fn split-string in: (addr array byte), delim: grapheme, out: (addr handle array (handle array byte)) {
+  var in-stream: (stream byte 0x100)
+  var in-stream-addr/esi: (addr stream byte) <- address in-stream
+  write in-stream-addr, in
+  var tokens-stream: (stream (handle array byte) 0x100)
+  var tokens-stream-addr/edi: (addr stream (handle array byte)) <- address tokens-stream
+  var curr-stream: (stream byte 0x100)
+  var curr-stream-addr/ecx: (addr stream byte) <- address curr-stream
+  $split-string:core: {
+    var g/eax: grapheme <- read-grapheme in-stream-addr
+    compare g, 0xffffffff
+    break-if-=
+#?     print-grapheme-to-real-screen g
+#?     print-string-to-real-screen "\n"
+    compare g, delim
+    {
+      break-if-!=
+      # token complete; flush
+      var token: (handle array byte)
+      var token-ah/eax: (addr handle array byte) <- address token
+      stream-to-array curr-stream-addr, token-ah
+      write-to-stream tokens-stream-addr, token-ah
+      clear-stream curr-stream-addr
+      loop $split-string:core
+    }
+    write-grapheme curr-stream-addr, g
+    loop
+  }
+  stream-to-array tokens-stream-addr, out
+}
+
+fn test-split-string {
+  var out-h: (handle array (handle array byte))
+  var out-ah/edi: (addr handle array (handle array byte)) <- address out-h
+  # prefix substrings
+  split-string "bab", 0x61, out-ah
+  # no crash
+}
diff --git a/baremetal/shell/value.mu b/baremetal/shell/value.mu
index 4a14c758..64b1d772 100644
--- a/baremetal/shell/value.mu
+++ b/baremetal/shell/value.mu
@@ -4,9 +4,6 @@ type value {
   number-data: float  # if type = 0
   text-data: (handle array byte)  # if type = 1
   array-data: (handle array value)  # if type = 2
-  file-data: (handle buffered-file)  # if type = 3
-  filename: (handle array byte)  # if type = 3
-  screen-data: (handle screen)  # if type = 4
 }
 
 fn initialize-value-with-integer _self: (addr value), n: int {
@@ -82,3 +79,51 @@ fn test-render-number {
   check-ints-equal new-x, 3, "F - test-render-number: result"
   # we won't bother testing the background colors; lots of flexibility there
 }
+
+fn initialize-value-with-string _self: (addr value), s: (addr array byte) {
+  var self/esi: (addr value) <- copy _self
+  var type/eax: (addr int) <- get self, type
+  copy-to *type, 1/string
+  var dest/eax: (addr handle array byte) <- get self, text-data
+  copy-array-object s, dest
+}
+
+fn render-string screen: (addr screen), _val: (addr array byte), x: int, y: int -> _/eax: int {
+  var val/esi: (addr array byte) <- copy _val
+  compare val, 0
+  {
+    break-if-!=
+    return x
+  }
+  var orig-len/ecx: int <- length val
+  # truncate to 12 graphemes
+  # TODO: more sophisticated interactive rendering
+  var truncated: (handle array byte)
+  var truncated-ah/eax: (addr handle array byte) <- address truncated
+  substring val, 0, 0xc, truncated-ah
+  var _truncated-string/eax: (addr array byte) <- lookup *truncated-ah
+  var truncated-string/edx: (addr array byte) <- copy _truncated-string
+  var len/ebx: int <- length truncated-string
+  draw-code-point screen, 0x22/double-quote, x, y, 7/fg, 0/bg
+  increment x
+  var new-x/eax: int <- draw-text-rightward-over-full-screen screen, truncated-string, x, y, 7/fg, 0/bg
+  compare len, orig-len
+  {
+    break-if-=
+    new-x <- draw-text-rightward-over-full-screen screen, "...", new-x, y, 7/fg, 0/bg
+  }
+  draw-code-point screen, 0x22/double-quote, new-x, y, 7/fg, 0/bg
+  new-x <- increment
+  return new-x
+}
+
+fn test-render-string {
+  # setup: screen
+  var screen-on-stack: screen
+  var screen/edi: (addr screen) <- address screen-on-stack
+  initialize-screen screen, 0x20, 4
+  # strings render with quotes
+  var new-x/eax: int <- render-string screen, "abc", 0/x, 0/y
+  check-screen-row screen, 0/y, "\"abc\"", "F - test-render-string"
+  check-ints-equal new-x, 5, "F - test-render-string: result"
+}