about summary refs log tree commit diff stats
path: root/baremetal
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-02-19 02:39:22 -0800
committerKartik K. Agaram <vc@akkartik.com>2021-02-19 02:39:22 -0800
commit446a6704cbe875326920bb6cc287ebdb752dbc41 (patch)
treedb4638119fde6444334efd2cf8a2056fbaed4119 /baremetal
parent3b1686b610dad6d5b15cb7a04a4459218aa76dc0 (diff)
downloadmu-446a6704cbe875326920bb6cc287ebdb752dbc41.tar.gz
7757
Diffstat (limited to 'baremetal')
-rw-r--r--baremetal/shell/eval.mu111
-rw-r--r--baremetal/shell/word.mu23
2 files changed, 119 insertions, 15 deletions
diff --git a/baremetal/shell/eval.mu b/baremetal/shell/eval.mu
index 2c56705a..0dc4aee9 100644
--- a/baremetal/shell/eval.mu
+++ b/baremetal/shell/eval.mu
@@ -214,12 +214,28 @@ fn evaluate-sub _curr: (addr word), end: (addr word), out: (addr value-stack), t
         var is-break?/eax: boolean <- stream-data-equal? curr-stream, "break"
         compare is-break?, 0/false
         break-if-=
+        # if curr == end, clear stack and break
+        # (TODO: move this into skip-rest-of-group)
+        compare curr, end
+        {
+          break-if-!=
+          clear-value-stack out
+          break $evaluate-sub:loop
+        }
         # scan ahead to containing '}'
         var next-word: (handle word)
         var next-word-ah/eax: (addr handle word) <- address next-word
         skip-rest-of-group curr, end, next-word-ah
         var _curr/eax: (addr word) <- lookup *next-word-ah
         curr <- copy _curr
+        # if '}' isn't found before end, we're rendering a word that isn't executed
+        # skip everything else and clear stack
+        var close-found?/eax: boolean <- word-equal? curr, "}"
+        compare close-found?, 0/false
+        {
+          break-if-!=
+          clear-value-stack out
+        }
         loop $evaluate-sub:loop
       }
       {
@@ -408,13 +424,15 @@ fn skip-word _curr: (addr word), end: (addr word), out: (addr handle word) {
   copy-object result-ah, out
 }
 
+# find next "}" from curr
+# if you hit 'end' before "}", return null
 fn skip-rest-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, next
   $skip-rest-of-group:loop: {
     var result-val/eax: (addr word) <- lookup *result-ah
-    compare result-val, end
+    compare result-val, 0
     break-if-=
     {
       var open?/eax: boolean <- word-equal? result-val, "{"
@@ -430,6 +448,12 @@ fn skip-rest-of-group _curr: (addr word), end: (addr word), out: (addr handle wo
       break-if-= $skip-rest-of-group:loop
       bracket-count <- decrement
     }
+    compare result-val, end
+    {
+      break-if-!=
+      clear-object out
+      return
+    }
     result-ah <- get result-val, next
     loop
   }
@@ -442,7 +466,9 @@ fn scan-to-start-of-group _curr: (addr word), end: (addr word), out: (addr handl
   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
+    compare result-val, 0
+    break-if-=
+    compare result-val, end  # not sure what error-detection should happen here
     break-if-=
     {
       var open?/eax: boolean <- word-equal? result-val, "{"
@@ -780,6 +806,87 @@ fn test-eval-conditional-skips-nested-group {
 # TODO: test error-handling on:
 #   1 2 > -> }
 
+# incomplete group rendering at 'break'
+fn test-eval-break-incomplete {
+  # in
+  var in-storage: line
+  var in/esi: (addr line) <- address in-storage
+  parse-line "3 { 4 break", 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
+  # break clears stack when final word
+  var len/eax: int <- value-stack-length out
+  check-ints-equal len, 0, "F - test-eval-break-incomplete stack size"
+}
+
+# incomplete group rendering after 'break'
+fn test-eval-break-incomplete-2 {
+  # in
+  var in-storage: line
+  var in/esi: (addr line) <- address in-storage
+  parse-line "3 { 4 break 5", 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
+  # break clears stack when final word
+#?   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, 0, "F - test-eval-break-incomplete-2 stack size"
+}
+
+# complete group rendering at 'break'
+fn test-eval-break-incomplete-3 {
+  # in
+  var in-storage: line
+  var in/esi: (addr line) <- address in-storage
+  parse-line "{ 3 break 4 } 5", in
+  # end = 'break'
+  var w-ah/edx: (addr handle word) <- get in, data
+  var end-h: (handle word)
+  var end-ah/ecx: (addr handle word) <- address end-h
+  skip-one-word w-ah, end-ah
+  skip-one-word end-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
+  # break clears stack when final word
+  var len/eax: int <- value-stack-length out
+  check-ints-equal len, 0, "F - test-eval-break-incomplete-3 stack size"
+}
+
+# { 1 break 2 } 3   => empty
+#           ^
+#
+# { 1 break 2 } 3   => empty
+#             ^
+#
+# { 1 break 2 } 3   => 1 3
+#               ^
+
 # break skips to next containing `}`
 fn test-eval-break {
   # in
diff --git a/baremetal/shell/word.mu b/baremetal/shell/word.mu
index 315a9cc1..ad57d040 100644
--- a/baremetal/shell/word.mu
+++ b/baremetal/shell/word.mu
@@ -101,6 +101,11 @@ fn copy-word-contents-before-cursor _src-ah: (addr handle word), _dest-ah: (addr
 
 fn word-equal? _self: (addr word), s: (addr array byte) -> _/eax: boolean {
   var self/esi: (addr word) <- copy _self
+  {
+    compare self, 0
+    break-if-!=
+    return 0/false
+  }
   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
   var data/eax: (addr gap-buffer) <- lookup *data-ah
   var result/eax: boolean <- gap-buffer-equal? data, s
@@ -127,19 +132,11 @@ fn word-length _self: (addr word) -> _/eax: int {
   return result
 }
 
-fn first-word _in: (addr handle word), out: (addr handle word) {
-  var curr-ah/esi: (addr handle word) <- copy _in
-  var curr/eax: (addr word) <- lookup *curr-ah
-  var prev/edi: (addr handle word) <- copy 0
-  {
-    prev <- get curr, prev
-    var curr/eax: (addr word) <- lookup *prev
-    compare curr, 0
-    break-if-=
-    copy-object prev, curr-ah
-    loop
-  }
-  copy-object curr-ah, out
+fn skip-one-word _in: (addr handle word), out: (addr handle word) {
+  var in/eax: (addr handle word) <- copy _in
+  var curr/eax: (addr word) <- lookup *in
+  var next/eax: (addr handle word) <- get curr, next
+  copy-object next, out  # modify 'out' right at the end, just in case it's same as 'in'
 }
 
 fn final-word _in: (addr handle word), out: (addr handle word) {