about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-04-15 19:47:01 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-04-15 19:47:01 -0700
commit613b1d5734cf119494ef5921ec86bd6cf5e3e6ea (patch)
tree73f92581c4b272d34cea8862901a58f1dc1c99f8
parent2e06991834304f953be3c84d29c0083e9ecc286a (diff)
downloadmu-613b1d5734cf119494ef5921ec86bd6cf5e3e6ea.tar.gz
parse dotted lists
-rw-r--r--shell/parse.mu56
-rw-r--r--shell/sandbox.mu135
2 files changed, 191 insertions, 0 deletions
diff --git a/shell/parse.mu b/shell/parse.mu
index 357b48fb..1fc74214 100644
--- a/shell/parse.mu
+++ b/shell/parse.mu
@@ -57,6 +57,14 @@ fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace
       close-paren?, dot? <- parse-sexpression tokens, right-ah, trace
       return close-paren?, dot?
     }
+    # dot -> return
+    var dot?/eax: boolean <- dot-token? curr-token
+    compare dot?, 0/false
+    {
+      break-if-=
+      trace-higher trace
+      return 0/false, 1/true
+    }
     # not bracket -> parse atom
     var bracket-token?/eax: boolean <- bracket-token? curr-token
     compare bracket-token?, 0/false
@@ -78,6 +86,12 @@ fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace
         var close-paren?/eax: boolean <- copy 0/false
         var dot?/ecx: boolean <- copy 0/false
         close-paren?, dot? <- parse-sexpression tokens, left, trace
+        {
+          compare dot?, 0/false
+          break-if-=
+          error trace, "'.' cannot be at the start of a list"
+          return 1/true, dot?
+        }
         compare close-paren?, 0/false
         break-if-!=
         var curr-addr/eax: (addr cell) <- lookup *curr
@@ -88,6 +102,13 @@ fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace
           var close-paren?/eax: boolean <- copy 0/false
           var dot?/ecx: boolean <- copy 0/false
           close-paren?, dot? <- parse-sexpression tokens, tmp, trace
+          # '.' -> clean up right here and return
+          compare dot?, 0/false
+          {
+            break-if-=
+            parse-dot-tail tokens, curr, trace
+            return 0/false, 0/false
+          }
           allocate-pair curr
           # ')' -> return
           compare close-paren?, 0/false
@@ -170,3 +191,38 @@ fn parse-atom _curr-token: (addr cell), _out: (addr handle cell), trace: (addr t
     trace trace, "read", stream
   }
 }
+
+fn parse-dot-tail tokens: (addr stream cell), _out: (addr handle cell), trace: (addr trace) {
+  var out/edi: (addr handle cell) <- copy _out
+  var close-paren?/eax: boolean <- copy 0/false
+  var dot?/ecx: boolean <- copy 0/false
+  close-paren?, dot? <- parse-sexpression tokens, out, trace
+  compare close-paren?, 0/false
+  {
+    break-if-=
+    error trace, "'. )' makes no sense"
+    return
+  }
+  compare dot?, 0/false
+  {
+    break-if-=
+    error trace, "'. .' makes no sense"
+    return
+  }
+  #
+  var dummy: (handle cell)
+  var dummy-ah/edi: (addr handle cell) <- address dummy
+  close-paren?, dot? <- parse-sexpression tokens, dummy-ah, trace
+  compare close-paren?, 0/false
+  {
+    break-if-!=
+    error trace, "cannot have multiple expressions between '.' and ')'"
+    return
+  }
+  compare dot?, 0/false
+  {
+    break-if-=
+    error trace, "cannot have two dots in a single list"
+    return
+  }
+}
diff --git a/shell/sandbox.mu b/shell/sandbox.mu
index b127b642..0a34eb49 100644
--- a/shell/sandbox.mu
+++ b/shell/sandbox.mu
@@ -719,6 +719,141 @@ fn test-run-quote {
   check-screen-row screen, 2/y, "=> a ", "F - test-run-quote/2"
 }
 
+fn test-run-dotted-list {
+  var sandbox-storage: sandbox
+  var sandbox/esi: (addr sandbox) <- address sandbox-storage
+  initialize-sandbox sandbox, 0/no-screen-or-keyboard
+  # type "'(a . b)"
+  edit-sandbox sandbox, 0x27/quote, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x28/open-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x61/a, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x2e/dot, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x62/b, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x29/close-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # eval
+  edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # setup: screen
+  var screen-on-stack: screen
+  var screen/edi: (addr screen) <- address screen-on-stack
+  initialize-screen screen, 0x80/width, 0x10/height
+  #
+  render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height, 0/no-globals
+  check-screen-row screen, 0/y, "'(a . b)   ", "F - test-run-dotted-list/0"
+  check-screen-row screen, 1/y, "...        ", "F - test-run-dotted-list/1"
+  check-screen-row screen, 2/y, "=> (a . b) ", "F - test-run-dotted-list/2"
+}
+
+fn test-run-dot-and-list {
+  var sandbox-storage: sandbox
+  var sandbox/esi: (addr sandbox) <- address sandbox-storage
+  initialize-sandbox sandbox, 0/no-screen-or-keyboard
+  # type "'(a . (b))"
+  edit-sandbox sandbox, 0x27/quote, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x28/open-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x61/a, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x2e/dot, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x28/open-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x62/b, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x29/close-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x29/close-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # eval
+  edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # setup: screen
+  var screen-on-stack: screen
+  var screen/edi: (addr screen) <- address screen-on-stack
+  initialize-screen screen, 0x80/width, 0x10/height
+  #
+  render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height, 0/no-globals
+  check-screen-row screen, 0/y, "'(a . (b)) ", "F - test-run-dot-and-list/0"
+  check-screen-row screen, 1/y, "...        ", "F - test-run-dot-and-list/1"
+  check-screen-row screen, 2/y, "=> (a b)   ", "F - test-run-dot-and-list/2"
+}
+
+fn test-run-final-dot {
+  var sandbox-storage: sandbox
+  var sandbox/esi: (addr sandbox) <- address sandbox-storage
+  initialize-sandbox sandbox, 0/no-screen-or-keyboard
+  # type "'(a .)"
+  edit-sandbox sandbox, 0x27/quote, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x28/open-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x61/a, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x2e/dot, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x29/close-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # eval
+  edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # setup: screen
+  var screen-on-stack: screen
+  var screen/edi: (addr screen) <- address screen-on-stack
+  initialize-screen screen, 0x80/width, 0x10/height
+  #
+  render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height, 0/no-globals
+  check-screen-row screen, 0/y, "'(a .)               ", "F - test-run-final-dot/0"
+  check-screen-row screen, 1/y, "...                  ", "F - test-run-final-dot/1"
+  check-screen-row screen, 2/y, "'. )' makes no sense ", "F - test-run-final-dot/2"
+  # further errors may occur
+}
+
+fn test-run-double-dot {
+  var sandbox-storage: sandbox
+  var sandbox/esi: (addr sandbox) <- address sandbox-storage
+  initialize-sandbox sandbox, 0/no-screen-or-keyboard
+  # type "'(a . .)"
+  edit-sandbox sandbox, 0x27/quote, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x28/open-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x61/a, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x2e/dot, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x2e/dot, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x29/close-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # eval
+  edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # setup: screen
+  var screen-on-stack: screen
+  var screen/edi: (addr screen) <- address screen-on-stack
+  initialize-screen screen, 0x80/width, 0x10/height
+  #
+  render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height, 0/no-globals
+  check-screen-row screen, 0/y, "'(a . .)             ", "F - test-run-double-dot/0"
+  check-screen-row screen, 1/y, "...                  ", "F - test-run-double-dot/1"
+  check-screen-row screen, 2/y, "'. .' makes no sense ", "F - test-run-double-dot/2"
+  # further errors may occur
+}
+
+fn test-run-multiple-expressions-after-dot {
+  var sandbox-storage: sandbox
+  var sandbox/esi: (addr sandbox) <- address sandbox-storage
+  initialize-sandbox sandbox, 0/no-screen-or-keyboard
+  # type "'(a . b c)"
+  edit-sandbox sandbox, 0x27/quote, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x28/open-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x61/a, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x2e/dot, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x62/b, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x20/space, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x63/c, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  edit-sandbox sandbox, 0x29/close-paren, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # eval
+  edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-screen, 0/no-keyboard, 0/no-disk
+  # setup: screen
+  var screen-on-stack: screen
+  var screen/edi: (addr screen) <- address screen-on-stack
+  initialize-screen screen, 0x80/width, 0x10/height
+  #
+  render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height, 0/no-globals
+  check-screen-row screen, 0/y, "'(a . b c)                                           ", "F - test-run-multiple-expressions-after-dot/0"
+  check-screen-row screen, 1/y, "...                                                  ", "F - test-run-multiple-expressions-after-dot/1"
+  check-screen-row screen, 2/y, "cannot have multiple expressions between '.' and ')' ", "F - test-run-multiple-expressions-after-dot/2"
+  # further errors may occur
+}
+
 fn test-run-error-invalid-integer {
   var sandbox-storage: sandbox
   var sandbox/esi: (addr sandbox) <- address sandbox-storage