about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-04-21 21:19:23 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-04-21 21:34:55 -0700
commit4afe53d8344f091dff02583913af57080f745f68 (patch)
tree451c0a3caec351c9ef60d8b9e35efb36b84936be
parenta5e1a220fde080c0eb7ef2a09ee0a7e9362e5de4 (diff)
downloadmu-4afe53d8344f091dff02583913af57080f745f68.tar.gz
shell: non-recursive 'while'
-rw-r--r--shell/evaluate.mu72
1 files changed, 58 insertions, 14 deletions
diff --git a/shell/evaluate.mu b/shell/evaluate.mu
index e41459a4..79204bd7 100644
--- a/shell/evaluate.mu
+++ b/shell/evaluate.mu
@@ -286,6 +286,45 @@ fn evaluate _in: (addr handle cell), out: (addr handle cell), env-h: (handle cel
     trace-higher trace
     return
   }
+  $evaluate:while: {
+    # trees starting with "while" are loops
+    var expr/esi: (addr cell) <- copy in-addr
+    # if its first elem is not "while", break
+    var first-ah/ecx: (addr handle cell) <- get in-addr, left
+    var rest-ah/edx: (addr handle cell) <- get in-addr, right
+    var first/eax: (addr cell) <- lookup *first-ah
+    var first-type/ecx: (addr int) <- get first, type
+    compare *first-type, 2/symbol
+    break-if-!=
+    var sym-data-ah/eax: (addr handle stream byte) <- get first, text-data
+    var sym-data/eax: (addr stream byte) <- lookup *sym-data-ah
+    var while?/eax: boolean <- stream-data-equal? sym-data, "while"
+    compare while?, 0/false
+    break-if-=
+    #
+    trace-text trace, "eval", "while"
+    var rest/eax: (addr cell) <- lookup *rest-ah
+    var first-arg-ah/ecx: (addr handle cell) <- get rest, left
+    rest-ah <- get rest, right
+    var guard-h: (handle cell)
+    var guard-ah/esi: (addr handle cell) <- address guard-h
+    {
+      trace-text trace, "eval", "loop termination check"
+      debug-print "V", 4/fg, 0/bg
+      increment call-number
+      evaluate first-arg-ah, guard-ah, env-h, globals, trace, screen-cell, keyboard-cell, call-number
+      debug-print "W", 4/fg, 0/bg
+      var guard-a/eax: (addr cell) <- lookup *guard-ah
+      var done?/eax: boolean <- nil? guard-a
+      compare done?, 0/false
+      break-if-!=
+      evaluate-exprs rest-ah, out, env-h, globals, trace, screen-cell, keyboard-cell, call-number
+      loop
+    }
+    trace-text trace, "eval", "loop terminated"
+    trace-higher trace
+    return
+  }
   trace-text trace, "eval", "function call"
   trace-text trace, "eval", "evaluating list elements"
   trace-lower trace
@@ -388,31 +427,36 @@ fn apply _f-ah: (addr handle cell), args-ah: (addr handle cell), out: (addr hand
   error trace, "unknown function"
 }
 
-fn apply-function params-ah: (addr handle cell), args-ah: (addr handle cell), _body-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), globals: (addr global-table), trace: (addr trace), screen-cell: (addr handle cell), keyboard-cell: (addr handle cell), call-number: int {
+fn apply-function params-ah: (addr handle cell), args-ah: (addr handle cell), body-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), globals: (addr global-table), trace: (addr trace), screen-cell: (addr handle cell), keyboard-cell: (addr handle cell), call-number: int {
   # push bindings for params to env
-  var new-env-storage: (handle cell)
-  var new-env-ah/esi: (addr handle cell) <- address new-env-storage
+  var new-env-h: (handle cell)
+  var new-env-ah/esi: (addr handle cell) <- address new-env-h
   push-bindings params-ah, args-ah, env-h, new-env-ah, trace
-  # eval all expressions in body, writing result to `out` each time
-  var body-ah/ecx: (addr handle cell) <- copy _body-ah
-  $apply-function:body: {
-    var body/eax: (addr cell) <- lookup *body-ah
-    # stop when body is nil
+  #
+  evaluate-exprs body-ah, out, new-env-h, globals, trace, screen-cell, keyboard-cell, call-number
+}
+
+fn evaluate-exprs _exprs-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), globals: (addr global-table), trace: (addr trace), screen-cell: (addr handle cell), keyboard-cell: (addr handle cell), call-number: int {
+  # eval all exprs, writing result to `out` each time
+  var exprs-ah/ecx: (addr handle cell) <- copy _exprs-ah
+  $evaluate-exprs:loop: {
+    var exprs/eax: (addr cell) <- lookup *exprs-ah
+    # stop when exprs is nil
     {
-      var body-nil?/eax: boolean <- nil? body
-      compare body-nil?, 0/false
-      break-if-!= $apply-function:body
+      var exprs-nil?/eax: boolean <- nil? exprs
+      compare exprs-nil?, 0/false
+      break-if-!= $evaluate-exprs:loop
     }
     # evaluate each expression, writing result to `out`
     {
-      var curr-ah/eax: (addr handle cell) <- get body, left
+      var curr-ah/eax: (addr handle cell) <- get exprs, left
       debug-print "E", 7/fg, 0/bg
       increment call-number
-      evaluate curr-ah, out, *new-env-ah, globals, trace, screen-cell, keyboard-cell, call-number
+      evaluate curr-ah, out, env-h, globals, trace, screen-cell, keyboard-cell, call-number
       debug-print "X", 7/fg, 0/bg
     }
     #
-    body-ah <- get body, right
+    exprs-ah <- get exprs, right
     loop
   }
   # `out` contains result of evaluating final expression