about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-02-13 23:55:21 -0800
committerKartik K. Agaram <vc@akkartik.com>2021-02-14 00:05:12 -0800
commit90a8d404afcad67dd2ad87ed6241285149d3ca6e (patch)
tree5922d81e06dc371a79fb5161f8a7153f608a5cde
parentfdc9096dfdcba8c14e3b9b490e85a0c0d86c0246 (diff)
downloadmu-90a8d404afcad67dd2ad87ed6241285149d3ca6e.tar.gz
7739 - baremetal/shell: first draft of loop
This is quite new and speculative. I tried to list out some potential future
tests later when we add 'return'. We'll see how it goes.
-rw-r--r--baremetal/shell/eval.mu253
-rw-r--r--baremetal/shell/value-stack.mu46
2 files changed, 237 insertions, 62 deletions
diff --git a/baremetal/shell/eval.mu b/baremetal/shell/eval.mu
index d3525a0f..2c56705a 100644
--- a/baremetal/shell/eval.mu
+++ b/baremetal/shell/eval.mu
@@ -38,20 +38,34 @@
 #     If no containing `}`, clear stack (error)
 
 fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
+  clear-value-stack out
   var line/eax: (addr line) <- copy _in
   var curr-ah/eax: (addr handle word) <- get line, data
-  var _curr/eax: (addr word) <- lookup *curr-ah
+  var curr/eax: (addr word) <- lookup *curr-ah
+  evaluate-sub curr, end, out, 1/top-level
+}
+
+fn evaluate-sub _curr: (addr word), end: (addr word), out: (addr value-stack), top-level?: boolean {
   var curr/ecx: (addr word) <- copy _curr
   var curr-stream-storage: (stream byte 0x10)
   var curr-stream/edi: (addr stream byte) <- address curr-stream-storage
-  clear-value-stack out
-  $evaluate:loop: {
+  $evaluate-sub:loop: {
     # safety net (should never hit)
     compare curr, 0
     break-if-=
     # pull next word in for parsing
     emit-word curr, curr-stream
-    $evaluate:process-word: {
+#?     {
+#?       clear-screen 0/screen
+#?       dump-stack out
+#?       var foo/eax: int <- render-word 0/screen, curr, 0/x, 0/y, 0/no-cursor
+#?       {
+#?         var key/eax: byte <- read-key 0/keyboard
+#?         compare key, 0
+#?         loop-if-=
+#?       }
+#?     }
+    $evaluate-sub:process-word: {
       ### if curr-stream is an operator, perform it
       {
         var is-add?/eax: boolean <- stream-data-equal? curr-stream, "+"
@@ -62,7 +76,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         var a/xmm0: float <- pop-number-from-value-stack out
         a <- add b
         push-number-to-value-stack out, a
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-sub?/eax: boolean <- stream-data-equal? curr-stream, "-"
@@ -73,7 +87,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         var a/xmm0: float <- pop-number-from-value-stack out
         a <- subtract b
         push-number-to-value-stack out, a
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-mul?/eax: boolean <- stream-data-equal? curr-stream, "*"
@@ -84,7 +98,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         var a/xmm0: float <- pop-number-from-value-stack out
         a <- multiply b
         push-number-to-value-stack out, a
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-div?/eax: boolean <- stream-data-equal? curr-stream, "/"
@@ -95,7 +109,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         var a/xmm0: float <- pop-number-from-value-stack out
         a <- divide b
         push-number-to-value-stack out, a
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-sqrt?/eax: boolean <- stream-data-equal? curr-stream, "sqrt"
@@ -104,7 +118,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         var a/xmm0: float <- pop-number-from-value-stack out
         a <- square-root a
         push-number-to-value-stack out, a
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-lesser?/eax: boolean <- stream-data-equal? curr-stream, "<"
@@ -117,10 +131,10 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         {
           break-if-float<
           push-boolean-to-value-stack out, 0/false
-          break $evaluate:process-word
+          break $evaluate-sub:process-word
         }
         push-boolean-to-value-stack out, 1/true
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-greater?/eax: boolean <- stream-data-equal? curr-stream, ">"
@@ -133,10 +147,10 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         {
           break-if-float>
           push-boolean-to-value-stack out, 0/false
-          break $evaluate:process-word
+          break $evaluate-sub:process-word
         }
         push-boolean-to-value-stack out, 1/true
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-equal?/eax: boolean <- stream-data-equal? curr-stream, "=="  # TODO support non-numbers
@@ -149,10 +163,10 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         {
           break-if-=
           push-boolean-to-value-stack out, 0/false
-          break $evaluate:process-word
+          break $evaluate-sub:process-word
         }
         push-boolean-to-value-stack out, 1/true
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       ## control flow
       {
@@ -170,35 +184,35 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
           var _curr/eax: (addr word) <- lookup *next-word-ah
           curr <- copy _curr
         }
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-group-start?/eax: boolean <- stream-data-equal? curr-stream, "{"
         compare is-group-start?, 0/false
         break-if-=
-        # if this is the final word, clear the stack
+        # if top-level? and this is the final word, clear the stack
+        compare top-level?, 0/false
+        break-if-= $evaluate-sub:process-word
         compare curr, end
-        {
-          break-if-!=
-          clear-value-stack out
-        }
-        break $evaluate:process-word
+        break-if-!= $evaluate-sub:process-word
+        clear-value-stack out
+        break $evaluate-sub:process-word
       }
       {
-        var is-group-start?/eax: boolean <- stream-data-equal? curr-stream, "}"
-        compare is-group-start?, 0/false
+        var is-group-end?/eax: boolean <- stream-data-equal? curr-stream, "}"
+        compare is-group-end?, 0/false
         break-if-=
-        # if this is the final word, clear the stack
+        # if top-level? and this is the final word, clear the stack
+        compare top-level?, 0/false
+        break-if-= $evaluate-sub:process-word
         compare curr, end
-        {
-          break-if-!=
-          clear-value-stack out
-        }
-        break $evaluate:process-word
+        break-if-!= $evaluate-sub:process-word
+        clear-value-stack out
+        break $evaluate-sub:process-word
       }
       {
-        var is-group-start?/eax: boolean <- stream-data-equal? curr-stream, "break"
-        compare is-group-start?, 0/false
+        var is-break?/eax: boolean <- stream-data-equal? curr-stream, "break"
+        compare is-break?, 0/false
         break-if-=
         # scan ahead to containing '}'
         var next-word: (handle word)
@@ -206,7 +220,27 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         skip-rest-of-group curr, end, next-word-ah
         var _curr/eax: (addr word) <- lookup *next-word-ah
         curr <- copy _curr
-        loop $evaluate:loop
+        loop $evaluate-sub:loop
+      }
+      {
+        var is-loop?/eax: boolean <- stream-data-equal? curr-stream, "loop"
+        compare is-loop?, 0/false
+        break-if-=
+        # scan back to containing '{'
+        var open-word: (handle word)
+        var open-word-ah/edx: (addr handle word) <- address open-word
+        scan-to-start-of-group curr, end, open-word-ah
+        # scan ahead to the containing '}'; record that as next word to eval at
+        var close-word: (handle word)
+        var close-word-ah/ebx: (addr handle word) <- address close-word
+        skip-rest-of-group curr, end, close-word-ah
+        var _curr/eax: (addr word) <- lookup *close-word-ah
+        curr <- copy _curr
+        # now eval until getting there
+        # TODO: can 'curr' be after 'end' at this point?
+        var open/eax: (addr word) <- lookup *open-word-ah
+        evaluate-sub open, curr, out, 0/nested
+        loop $evaluate-sub:loop
       }
       ## TEMPORARY HACKS; we're trying to avoid turning this into Forth
       {
@@ -232,7 +266,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         # commit
         var top-addr/ecx: (addr int) <- get out2, top
         increment *top-addr
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       {
         var is-swap?/eax: boolean <- stream-data-equal? curr-stream, "swap"
@@ -259,7 +293,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         copy-object top-val, tmp-a
         copy-object pen-top-val, top-val
         copy-object tmp-a, pen-top-val
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       ### if the word starts with a quote and ends with a quote, turn it into a string
       {
@@ -274,7 +308,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
         var s/eax: (addr handle array byte) <- address h
         unquote-stream-to-array curr-stream, s  # leak
         push-string-to-value-stack out, *s
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       ### if the word starts with a '[' and ends with a ']', turn it into an array
       {
@@ -320,7 +354,7 @@ fn evaluate _in: (addr line), end: (addr word), out: (addr value-stack) {
           i <- increment
           loop
         }
-        break $evaluate:process-word
+        break $evaluate-sub:process-word
       }
       ### otherwise assume it's a literal number and push it (can't parse floats yet)
       {
@@ -402,6 +436,34 @@ fn skip-rest-of-group _curr: (addr word), end: (addr word), out: (addr handle wo
   copy-object result-ah, out
 }
 
+fn scan-to-start-of-group _curr: (addr word), end: (addr word), out: (addr handle word) {
+  var curr/eax: (addr word) <- copy _curr
+  var bracket-count/ecx: int <- copy 0
+  var result-ah/esi: (addr handle word) <- get curr, prev
+  $scan-to-start-of-group:loop: {
+    var result-val/eax: (addr word) <- lookup *result-ah
+    compare result-val, end
+    break-if-=
+    {
+      var open?/eax: boolean <- word-equal? result-val, "{"
+      compare open?, 0/false
+      break-if-=
+      compare bracket-count, 0
+      break-if-= $scan-to-start-of-group:loop
+      bracket-count <- increment
+    }
+    {
+      var close?/eax: boolean <- word-equal? result-val, "}"
+      compare close?, 0/false
+      break-if-=
+      bracket-count <- decrement
+    }
+    result-ah <- get result-val, prev
+    loop
+  }
+  copy-object result-ah, out
+}
+
 fn test-eval-arithmetic {
   # in
   var in-storage: line
@@ -718,7 +780,7 @@ fn test-eval-conditional-skips-nested-group {
 # TODO: test error-handling on:
 #   1 2 > -> }
 
-# break skips to next `}`
+# break skips to next containing `}`
 fn test-eval-break {
   # in
   var in-storage: line
@@ -768,3 +830,118 @@ fn test-eval-break-nested {
   var n2/eax: int <- convert n
   check-ints-equal n2, 7, "F - test-eval-break-nested result"
 }
+
+#? 1 2 3 4 6 5 { <       -> break loop }
+#?  1 2 3 4 6 5   false            2
+#?    1 2 3 4 6   4                1
+#?      1 2 3 4   3
+#?        1 2 3   2
+#?          1 2   1
+#?            1
+
+#? 1 2 3 4 { 3 ==     -> return loop }
+#?  1 2 3 4   3 false            2      => 3
+#?    1 2 3   4 3                1
+#?      1 2   3 2
+#?        1   2 1
+#?            1
+
+# loop skips to previous containing `{` and continues evaluating until control
+# leaves the group
+fn test-eval-loop {
+  # in
+  var in-storage: line
+  var in/esi: (addr line) <- address in-storage
+  parse-line "1 2 4 3 { < -> break loop } 9", in
+  # end
+  var w-ah/eax: (addr handle word) <- get in, data
+  var end-h: (handle word)
+  var end-ah/ecx: (addr handle word) <- address end-h
+  final-word w-ah, end-ah
+  var end/eax: (addr word) <- lookup *end-ah
+  # out
+  var out-storage: value-stack
+  var out/edi: (addr value-stack) <- address out-storage
+  initialize-value-stack out, 8
+  #
+  evaluate in, end, out
+  # evaluation order: 1 2 4 3 { < -> loop { < -> break 9
+  # stack contents: 9
+  var len/eax: int <- value-stack-length out
+  check-ints-equal len, 1, "F - test-eval-loop stack size"
+}
+
+fn test-eval-loop-2 {
+  # in
+  var in-storage: line
+  var in/esi: (addr line) <- address in-storage
+  parse-line "1 2 4 3 { 4 == -> break loop } 9", in
+  # end
+  var w-ah/eax: (addr handle word) <- get in, data
+  var end-h: (handle word)
+  var end-ah/ecx: (addr handle word) <- address end-h
+  final-word w-ah, end-ah
+  var end/eax: (addr word) <- lookup *end-ah
+  # out
+  var out-storage: value-stack
+  var out/edi: (addr value-stack) <- address out-storage
+  initialize-value-stack out, 8
+  #
+  evaluate in, end, out
+  # evaluation order: 1 2 4 3 { 4 == -> loop { 4 == -> break 9
+  # stack contents: 1 2 9
+#?   dump-stack out
+  var len/eax: int <- value-stack-length out
+#?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, len, 0xc/red, 0/black
+  check-ints-equal len, 3, "F - test-eval-loop-2 stack size"
+}
+
+fn test-eval-loop-conditional {
+  # in
+  var in-storage: line
+  var in/esi: (addr line) <- address in-storage
+  parse-line "1 2 3 { 3 == -> loop } 9", in
+  # end
+  var w-ah/eax: (addr handle word) <- get in, data
+  var end-h: (handle word)
+  var end-ah/ecx: (addr handle word) <- address end-h
+  final-word w-ah, end-ah
+  var end/eax: (addr word) <- lookup *end-ah
+  # out
+  var out-storage: value-stack
+  var out/edi: (addr value-stack) <- address out-storage
+  initialize-value-stack out, 8
+  #
+  evaluate in, end, out
+  # evaluation order: 1 2 3 { 3 == -> loop { 3 == -> 9
+  # stack contents: 1 9
+#?   dump-stack out
+  var len/eax: int <- value-stack-length out
+#?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, len, 0xc/red, 0/black
+  check-ints-equal len, 2, "F - test-eval-loop-2-conditional stack size"
+}
+
+fn test-eval-loop-with-words-after-in-group {
+  # in
+  var in-storage: line
+  var in/esi: (addr line) <- address in-storage
+  parse-line "1 2 3 { 3 == -> loop 37 } 9", in
+  # end
+  var w-ah/eax: (addr handle word) <- get in, data
+  var end-h: (handle word)
+  var end-ah/ecx: (addr handle word) <- address end-h
+  final-word w-ah, end-ah
+  var end/eax: (addr word) <- lookup *end-ah
+  # out
+  var out-storage: value-stack
+  var out/edi: (addr value-stack) <- address out-storage
+  initialize-value-stack out, 8
+  #
+  evaluate in, end, out
+  # evaluation order: 1 2 3 { 3 == -> loop { 3 == -> 37 } 9
+  # stack contents: 1 37 9
+#?   dump-stack out
+  var len/eax: int <- value-stack-length out
+#?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, len, 0xc/red, 0/black
+  check-ints-equal len, 3, "F - test-eval-loop-with-words-after-in-group stack size"
+}
diff --git a/baremetal/shell/value-stack.mu b/baremetal/shell/value-stack.mu
index ee1ae3f9..e58d91d2 100644
--- a/baremetal/shell/value-stack.mu
+++ b/baremetal/shell/value-stack.mu
@@ -148,30 +148,6 @@ fn value-stack-length _self: (addr value-stack) -> _/eax: int {
   return *top-addr
 }
 
-fn save-lines in-h: (handle array (handle array byte)), _out-ah: (addr handle array value) {
-  var _in/eax: (addr array (handle array byte)) <- lookup in-h
-  var in/esi: (addr array (handle array byte)) <- copy _in
-  var len/ecx: int <- length in
-  var out-ah/edi: (addr handle array value) <- copy _out-ah
-  populate out-ah, len
-  var out/eax: (addr array value) <- lookup *out-ah
-  # copy in into out
-  var i/ebx: int <- copy 0
-  {
-    compare i, len
-    break-if->=
-    var src/ecx: (addr handle array byte) <- index in, i
-    var dest-offset/edx: (offset value) <- compute-offset out, i
-    var dest-val/edx: (addr value) <- index out, dest-offset
-    var dest/eax: (addr handle array byte) <- get dest-val, text-data
-    copy-object src, dest
-    var type/edx: (addr int) <- get dest-val, type
-    copy-to *type, 1/string
-    i <- increment
-    loop
-  }
-}
-
 fn test-boolean {
   var stack-storage: value-stack
   var stack/esi: (addr value-stack) <- address stack-storage
@@ -182,3 +158,25 @@ fn test-boolean {
   var result/eax: boolean <- pop-boolean-from-value-stack stack
   check result, "F - test-boolean/true"
 }
+
+fn dump-stack _self: (addr value-stack) {
+  var self/esi: (addr value-stack) <- copy _self
+  var data-ah/eax: (addr handle array value) <- get self, data
+  var _data/eax: (addr array value) <- lookup *data-ah
+  var data/edi: (addr array value) <- copy _data
+  var top-addr/ecx: (addr int) <- get self, top
+  var top/ecx: int <- copy *top-addr
+  top <- decrement
+  var y/edx: int <- copy 0xa
+  var dummy/eax: int <- draw-text-rightward-over-full-screen 0/screen, "==", 0/x, 9/y, 0xc/red, 0/bg
+  {
+    compare top, 0
+    break-if-<
+    var dest-offset/eax: (offset value) <- compute-offset data, top
+    var curr/eax: (addr value) <- index data, dest-offset
+    var dummy/eax: int <- render-value 0/screen, curr, 0/x, y, 0/no-color
+    top <- decrement
+    y <- increment
+    loop
+  }
+}