about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--311parse-decimal-int.subx54
-rw-r--r--400.mu2
-rw-r--r--403unicode.mu21
-rw-r--r--apps/tile/environment.mu50
-rw-r--r--apps/tile/gap-buffer.mu54
-rw-r--r--apps/tile/int-stack.mu20
-rw-r--r--apps/tile/rpn.mu122
-rw-r--r--apps/tile/word.mu6
8 files changed, 267 insertions, 62 deletions
diff --git a/311parse-decimal-int.subx b/311parse-decimal-int.subx
index 538f3e87..fe08b932 100644
--- a/311parse-decimal-int.subx
+++ b/311parse-decimal-int.subx
@@ -1,6 +1,7 @@
 # Helpers for parsing decimal ints.
 
-parse-decimal-int-from-slice:  # in: (addr slice) -> out/eax: int    # . prologue
+parse-decimal-int-from-slice:  # in: (addr slice) -> out/eax: int
+    # . prologue
     55/push-ebp
     89/<- %ebp 4/r32/esp
     # . save registers
@@ -17,6 +18,57 @@ $parse-decimal-int-from-slice:end:
     5d/pop-to-ebp
     c3/return
 
+parse-decimal-int:  # in: (addr array byte) -> result/eax: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    51/push-ecx
+    52/push-edx
+    # eax = in
+    8b/-> *(ebp+8) 0/r32/eax
+    # var start/ecx: (addr byte) = &in->data
+    8d/copy-address *(eax+4) 1/r32/ecx
+    # var end/edx: (addr byte) = &in->data[in->size]
+    8b/-> *eax 2/r32/edx
+    8d/copy-address *(eax+edx+4) 2/r32/edx
+    #
+    (parse-decimal-int-helper %ecx %edx)  # => eax
+$parse-decimal-int:end:
+    # . restore registers
+    5a/pop-to-edx
+    59/pop-to-ecx
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+parse-decimal-int-from-stream:  # in: (addr stream byte) -> result/eax: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    51/push-ecx
+    52/push-edx
+    # eax = in
+    8b/-> *(ebp+8) 0/r32/eax
+    # var start/ecx: (addr byte) = &in->data[in->read]
+    8b/-> *(eax+4) 1/r32/ecx
+    8d/copy-address *(eax+ecx+0xc) 1/r32/ecx
+    # var end/edx: (addr byte) = &in->data[in->write]
+    8b/-> *eax 2/r32/edx
+    8d/copy-address *(eax+edx+0xc) 2/r32/edx
+    #
+    (parse-decimal-int-helper %ecx %edx)  # => eax
+$parse-decimal-int-from-stream:end:
+    # . restore registers
+    5a/pop-to-edx
+    59/pop-to-ecx
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
 parse-decimal-int-helper:  # start: (addr byte), end: (addr byte) -> result/eax: int
     # . prologue
     55/push-ebp
diff --git a/400.mu b/400.mu
index d3f4c0f0..db32cdc9 100644
--- a/400.mu
+++ b/400.mu
@@ -69,7 +69,9 @@ sig parse-hex-int-from-slice in: (addr slice) -> result/eax: int
 #sig parse-hex-int-helper start: (addr byte), end: (addr byte) -> result/eax: int
 sig is-hex-digit? c: byte -> result/eax: boolean
 #sig from-hex-char in/eax: byte -> out/eax: nibble
+sig parse-decimal-int in: (addr array byte) -> result/eax: int
 sig parse-decimal-int-from-slice in: (addr slice) -> result/eax: int
+sig parse-decimal-int-from-stream in: (addr stream byte) -> result/eax: int
 #sig parse-decimal-int-helper start: (addr byte), end: (addr byte) -> result/eax: int
 sig error-byte ed: (addr exit-descriptor), out: (addr buffered-file), msg: (addr array byte), n: byte
 #sig allocate ad: (addr allocation-descriptor), n: int, out: (addr handle _)
diff --git a/403unicode.mu b/403unicode.mu
index 23f14d8f..dcb1e658 100644
--- a/403unicode.mu
+++ b/403unicode.mu
@@ -373,3 +373,24 @@ fn test-shift-left-bytes-5 {
 #?   run-tests
 #?   r <- copy 0
 #? }
+
+# write a grapheme to a stream of bytes
+# this is like write-to-stream, except we skip leading 0 bytes
+fn write-grapheme out: (addr stream byte), g: grapheme {
+$write-grapheme:body: {
+  var c/eax: int <- copy g
+  append-byte out, c  # first byte is always written
+  c <- shift-right 8
+  compare c, 0
+  break-if-= $write-grapheme:body
+  append-byte out, c
+  c <- shift-right 8
+  compare c, 0
+  break-if-= $write-grapheme:body
+  append-byte out, c
+  c <- shift-right 8
+  compare c, 0
+  break-if-= $write-grapheme:body
+  append-byte out, c
+}
+}
diff --git a/apps/tile/environment.mu b/apps/tile/environment.mu
index 8c5f1b2a..929e4d6f 100644
--- a/apps/tile/environment.mu
+++ b/apps/tile/environment.mu
@@ -94,6 +94,8 @@ fn render _env: (addr environment), max-depth: int {
   var screen/edi: (addr screen) <- copy _screen
   # prepare screen
   clear-screen screen
+  move-cursor screen, 5, 1  # input-row+stack-margin-top
+  print-string screen, "stack:"
   move-cursor screen, 3, 3  # input-row, input-col
   # cursor-word
   var cursor-word-ah/esi: (addr handle word) <- get env, cursor-word
@@ -115,7 +117,7 @@ fn render _env: (addr environment), max-depth: int {
     compare curr-word, 0
     break-if-=
     move-cursor screen, 3, curr-col  # input-row
-    curr-col <- render-stack screen, first-word, curr-word, max-depth, curr-col, cursor-word, cursor-col-a
+    curr-col <- render-column screen, first-word, curr-word, max-depth, curr-col, cursor-word, cursor-col-a
     var next-word-ah/edx: (addr handle word) <- get curr-word, next
     curr-word <- lookup *next-word-ah
     loop
@@ -123,27 +125,49 @@ fn render _env: (addr environment), max-depth: int {
   move-cursor screen, 3, *cursor-col-a  # input-row
 }
 
-# Render the stack result from interpreting first-world to final-word (inclusive)
-# with the bottom-left corner at botleft-row, botleft-col.
+# Render:
+#   - final-word
+#   - the stack result from interpreting first-world to final-word (inclusive)
+#     with the bottom-left corner at botleft-row, botleft-col.
 #
 # Outputs:
 # - Return the farthest column written.
 # - If final-word is same as cursor-word, do some additional computation to set
 #   cursor-col-a.
-fn render-stack screen: (addr screen), first-word: (addr word), final-word: (addr word), botleft-depth: int, botleft-col: int, cursor-word: (addr word), cursor-col-a: (addr int) -> right-col/ecx: int {
+fn render-column screen: (addr screen), first-word: (addr word), final-word: (addr word), botleft-depth: int, botleft-col: int, cursor-word: (addr word), cursor-col-a: (addr int) -> right-col/ecx: int {
+  # compute stack
+  var stack: int-stack
+  var stack-addr/edi: (addr int-stack) <- address stack
+  initialize-int-stack stack-addr, 0x10  # max-words
+  evaluate first-word, final-word, stack-addr
+  # render stack
+  var curr-row/ecx: int <- copy botleft-depth
+  curr-row <- add 6  # input-row 3 + stack-margin-top 3
+  var i/eax: int <- int-stack-length stack-addr
+  curr-row <- subtract i
+  {
+    compare i, 0
+    break-if-<=
+    move-cursor screen, curr-row, botleft-col
+    {
+      var val/eax: int <- pop-int-stack stack-addr
+      print-int32-decimal screen, val
+    }
+    curr-row <- increment
+    i <- decrement
+    loop
+  }
+  right-col <- copy 8  # TODO: adaptive
+
   # render word, initialize result
   move-cursor screen, 3, botleft-col  # input-row
   print-word screen, final-word
-  right-col <- copy botleft-col
-  var len/eax: int <- word-length final-word
-  right-col <- add len
-  right-col <- add 3  # margin-right
+#?   var len/eax: int <- word-length final-word
+#?   right-col <- copy len
 
-  # render stack
-  var botleft-row/eax: int <- copy botleft-depth
-  botleft-row <- add 4  # input-row 3 + 1 stack-margin-top
-  move-cursor screen, botleft-row, botleft-col
-  print-string screen "-"
+  # post-process right-col
+  right-col <- add botleft-col
+  right-col <- add 3  # margin-right
 }
 
 # We could be a little faster by not using 'first-word' (since max is commutative),
diff --git a/apps/tile/gap-buffer.mu b/apps/tile/gap-buffer.mu
index 1503690b..75f88122 100644
--- a/apps/tile/gap-buffer.mu
+++ b/apps/tile/gap-buffer.mu
@@ -6,15 +6,15 @@ type gap-buffer {
 fn initialize-gap-buffer _self: (addr gap-buffer) {
   var self/esi: (addr gap-buffer) <- copy _self
   var left/eax: (addr grapheme-stack) <- get self, left
-  initialize-grapheme-stack left, 0x10
+  initialize-grapheme-stack left, 0x10  # max-word-size
   var right/eax: (addr grapheme-stack) <- get self, right
-  initialize-grapheme-stack right, 0x10
+  initialize-grapheme-stack right, 0x10  # max-word-size
 }
 
 # just for tests
 fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) {
   initialize-gap-buffer self
-  var stream-storage: (stream byte 0x10)
+  var stream-storage: (stream byte 0x10)  # max-word-size
   var stream/ecx: (addr stream byte) <- address stream-storage
   write stream, s
   {
@@ -27,6 +27,52 @@ fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) {
   }
 }
 
+fn emit-gap-buffer _self: (addr gap-buffer), out: (addr stream byte) {
+  var self/esi: (addr gap-buffer) <- copy _self
+  clear-stream out
+  var left/eax: (addr grapheme-stack) <- get self, left
+  emit-stack-from-bottom left, out
+  var right/eax: (addr grapheme-stack) <- get self, right
+  emit-stack-from-top right, out
+}
+
+# dump stack from bottom to top
+fn emit-stack-from-bottom _self: (addr grapheme-stack), out: (addr stream byte) {
+  var self/esi: (addr grapheme-stack) <- copy _self
+  var data-ah/edi: (addr handle array grapheme) <- get self, data
+  var _data/eax: (addr array grapheme) <- lookup *data-ah
+  var data/edi: (addr array grapheme) <- copy _data
+  var top-addr/ecx: (addr int) <- get self, top
+  var i/eax: int <- copy 0
+  {
+    compare i, *top-addr
+    break-if->=
+    var g/edx: (addr grapheme) <- index data, i
+    write-grapheme out, *g
+    i <- increment
+    loop
+  }
+}
+
+# dump stack from top to bottom
+fn emit-stack-from-top _self: (addr grapheme-stack), out: (addr stream byte) {
+  var self/esi: (addr grapheme-stack) <- copy _self
+  var data-ah/edi: (addr handle array grapheme) <- get self, data
+  var _data/eax: (addr array grapheme) <- lookup *data-ah
+  var data/edi: (addr array grapheme) <- copy _data
+  var top-addr/ecx: (addr int) <- get self, top
+  var i/eax: int <- copy *top-addr
+  i <- decrement
+  {
+    compare i, 0
+    break-if-<
+    var g/edx: (addr grapheme) <- index data, i
+    write-grapheme out, *g
+    i <- decrement
+    loop
+  }
+}
+
 fn render-gap-buffer screen: (addr screen), _gap: (addr gap-buffer) {
   var gap/esi: (addr gap-buffer) <- copy _gap
   var left/eax: (addr grapheme-stack) <- get gap, left
@@ -111,7 +157,7 @@ $gap-buffer-equal?:body: {
   # complication: graphemes may be multiple bytes
   # so don't rely on length
   # instead turn the expected result into a stream and arrange to read from it in order
-  var stream-storage: (stream byte 0x10)
+  var stream-storage: (stream byte 0x10)  # max-word-size
   var expected-stream/ecx: (addr stream byte) <- address stream-storage
   write expected-stream, s
   # compare left
diff --git a/apps/tile/int-stack.mu b/apps/tile/int-stack.mu
index 5e7a2223..3bb9336f 100644
--- a/apps/tile/int-stack.mu
+++ b/apps/tile/int-stack.mu
@@ -47,3 +47,23 @@ $pop-int-stack:body: {
   val <- copy *result-addr
 }
 }
+
+fn int-stack-empty? _self: (addr int-stack) -> result/eax: boolean {
+$int-stack-empty?:body: {
+  var self/esi: (addr int-stack) <- copy _self
+  var top-addr/eax: (addr int) <- get self, top
+  compare *top-addr, 0
+  {
+    break-if-!=
+    result <- copy 1  # true
+    break $int-stack-empty?:body
+  }
+  result <- copy 0  # false
+}
+}
+
+fn int-stack-length _self: (addr int-stack) -> result/eax: int {
+  var self/esi: (addr int-stack) <- copy _self
+  var top-addr/eax: (addr int) <- get self, top
+  result <- copy *top-addr
+}
diff --git a/apps/tile/rpn.mu b/apps/tile/rpn.mu
index 696912fd..3ca8a38f 100644
--- a/apps/tile/rpn.mu
+++ b/apps/tile/rpn.mu
@@ -1,53 +1,87 @@
-fn simplify in: (addr stream byte), out: (addr int-stack) {
-  var word-storage: slice
-  var word/ecx: (addr slice) <- address word-storage
+fn evaluate start: (addr word), end: (addr word), out: (addr int-stack) {
+  var curr/eax: (addr word) <- copy start
+  var curr-text-storage: (stream byte 0x10)
+  var curr-text/edi: (addr stream byte) <- address curr-text-storage
   clear-int-stack out
-  $simplify:word-loop: {
-    next-word in, word
-    var done?/eax: boolean <- slice-empty? word
-    compare done?, 0
-    break-if-!=
-    # if word is an operator, perform it
-    {
-      var is-add?/eax: boolean <- slice-equal? word, "+"
-      compare is-add?, 0
-      break-if-=
-      var _b/eax: int <- pop-int-stack out
-      var b/edx: int <- copy _b
-      var a/eax: int <- pop-int-stack out
-      a <- add b
-      push-int-stack out, a
-      loop $simplify:word-loop
-    }
-    {
-      var is-sub?/eax: boolean <- slice-equal? word, "-"
-      compare is-sub?, 0
-      break-if-=
-      var _b/eax: int <- pop-int-stack out
-      var b/edx: int <- copy _b
-      var a/eax: int <- pop-int-stack out
-      a <- subtract b
-      push-int-stack out, a
-      loop $simplify:word-loop
-    }
-    {
-      var is-mul?/eax: boolean <- slice-equal? word, "*"
-      compare is-mul?, 0
-      break-if-=
-      var _b/eax: int <- pop-int-stack out
-      var b/edx: int <- copy _b
-      var a/eax: int <- pop-int-stack out
-      a <- multiply b
-      push-int-stack out, a
-      loop $simplify:word-loop
+  $evaluate:loop: {
+    # precondition (should never hit)
+    compare curr, 0
+    break-if-=
+    # update curr-text
+    emit-word curr, curr-text
+    $evaluate:process-word: {
+      # if curr-text is an operator, perform it
+      {
+        var is-add?/eax: boolean <- stream-data-equal? curr-text, "+"
+        compare is-add?, 0
+        break-if-=
+        var _b/eax: int <- pop-int-stack out
+        var b/edx: int <- copy _b
+        var a/eax: int <- pop-int-stack out
+        a <- add b
+        push-int-stack out, a
+        break $evaluate:process-word
+      }
+      {
+        var is-sub?/eax: boolean <- stream-data-equal? curr-text, "-"
+        compare is-sub?, 0
+        break-if-=
+        var _b/eax: int <- pop-int-stack out
+        var b/edx: int <- copy _b
+        var a/eax: int <- pop-int-stack out
+        a <- subtract b
+        push-int-stack out, a
+        break $evaluate:process-word
+      }
+      {
+        var is-mul?/eax: boolean <- stream-data-equal? curr-text, "*"
+        compare is-mul?, 0
+        break-if-=
+        var _b/eax: int <- pop-int-stack out
+        var b/edx: int <- copy _b
+        var a/eax: int <- pop-int-stack out
+        a <- multiply b
+        push-int-stack out, a
+        break $evaluate:process-word
+      }
+      # otherwise it's an int
+      {
+        var n/eax: int <- parse-decimal-int-from-stream curr-text
+        push-int-stack out, n
+      }
     }
-    # otherwise it's an int
-    var n/eax: int <- parse-decimal-int-from-slice word
-    push-int-stack out, n
+    # termination check
+    compare curr, end
+    break-if-=
+    # update
+    var next-word-ah/edx: (addr handle word) <- get curr, next
+    curr <- lookup *next-word-ah
+    #
     loop
   }
 }
 
+fn test-evaluate {
+  # input = [1, 2, +]
+  var w: (handle word)
+  var wah/eax: (addr handle word) <- address w
+  allocate wah
+  var wa/eax: (addr word) <- lookup w
+  initialize-word-with wa, "1"
+  append-word-with w, "2"
+  var next/ecx: (addr handle word) <- get wa, next
+  append-word-with *next, "+"
+  # initialize output
+  var stack-storage: int-stack
+  var stack/edx: (addr int-stack) <- address stack-storage
+  initialize-int-stack stack, 0x10
+  #
+  evaluate wa, 0, stack
+  # check output
+  var x/eax: int <- pop-int-stack stack
+  check-ints-equal x, 3, "F - test-evaluate"
+}
+
 # Copy of 'simplify' that just tracks the maximum stack depth needed
 # Doesn't actually need to simulate the stack, since every word has a predictable effect.
 fn max-stack-depth first-word: (addr word), final-word: (addr word) -> result/edi: int {
diff --git a/apps/tile/word.mu b/apps/tile/word.mu
index e1c5e22d..9e683985 100644
--- a/apps/tile/word.mu
+++ b/apps/tile/word.mu
@@ -116,3 +116,9 @@ fn append-word _self-ah: (addr handle word) {
   var prev-ah/eax: (addr handle word) <- get next, prev
   copy-handle *self-ah, prev-ah
 }
+
+fn emit-word _self: (addr word), out: (addr stream byte) {
+  var self/esi: (addr word) <- copy _self
+  var data/eax: (addr gap-buffer) <- get self, data
+  emit-gap-buffer data, out
+}