about summary refs log tree commit diff stats
path: root/shell/global.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-06-09 09:16:52 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-06-09 09:16:52 -0700
commitb7e8c2810a5008f68446ef62770ff2ec2c06a813 (patch)
tree6ffefd69cea31763fa2437634c538f84095afab0 /shell/global.mu
parent8cff44fef442bab0b6c75ac0ef1e3616c5149139 (diff)
downloadmu-b7e8c2810a5008f68446ef62770ff2ec2c06a813.tar.gz
snapshot: attempt at modifying a function name
It turns out there's another problem, and it predates the ability to create
new definitions:

  ctrl-s triggers a call to `evaluate`, which inserts a new definition
  into globals. which has a null gap buffer.

All this happens long before the new code in this commit, resulting in a
null gap buffer by the time we get to word-at-cursor.

Which in turn happens because we perform a raw `evaluate`, which doesn't
update the gap buffer like `run` does (using `maybe-stash-gap-buffer-to-global`).

And arguably `evaluate` shouldn't mess with the gap buffer. Gap buffers
are a UI concern.

The hardest version of this immediate scenario: It's unclear how to guarantee
that every definition have a gap buffer, when two definitions may share
one (closures sharing a lexical environment).

New plan:
  - improve the logic for detecting definitions. Looking at the outermost
    layer isn't enough. And a single expression can create multiple definitions.
  - extract a helper to attach a single gap buffer to multiple definitions.
  - have the UI detect conflicts in gap buffers and prompt the user for
    a decision if a different gap buffer already exists for a definition.
Diffstat (limited to 'shell/global.mu')
-rw-r--r--shell/global.mu68
1 files changed, 57 insertions, 11 deletions
diff --git a/shell/global.mu b/shell/global.mu
index 9b68e91e..a76e7148 100644
--- a/shell/global.mu
+++ b/shell/global.mu
@@ -285,10 +285,41 @@ fn refresh-definition _self: (addr global-table), _index: int {
     var nil-ah/eax: (addr handle cell) <- address nil-h
     allocate-pair nil-ah
   }
-  var curr-value-ah/eax: (addr handle cell) <- get curr-global, value
+  var curr-value-ah/edi: (addr handle cell) <- get curr-global, value
   debug-print "GL", 4/fg, 0/bg
   evaluate read-result-ah, curr-value-ah, nil-h, self, trace, 0/no-screen-cell, 0/no-keyboard-cell, 1/call-number
   debug-print "GZ", 4/fg, 0/bg
+  {
+    var error?/eax: boolean <- has-errors? trace
+    compare error?, 0/false
+    break-if-=
+    return
+  }
+  # update definition name if necessary
+  var curr-global-name-ah/ecx: (addr handle array byte) <- get curr-global, name
+  var _curr-global-name/eax: (addr array byte) <- lookup *curr-global-name-ah
+  var curr-global-name/ebx: (addr array byte) <- copy _curr-global-name
+  var read-result/eax: (addr cell) <- lookup *read-result-ah
+  {
+    var is-definition?/eax: boolean <- is-definition? read-result
+    compare is-definition?, 0/false
+    break-if-!=
+    return
+  }
+  # (no error checking since it's a definition and there were no errors)
+  var rest-ah/eax: (addr handle cell) <- get read-result, right
+  var rest/eax: (addr cell) <- lookup *rest-ah
+  var correct-definition-symbol-ah/eax: (addr handle cell) <- get rest, left
+  var correct-definition-symbol/eax: (addr cell) <- lookup *correct-definition-symbol-ah
+  var correct-definition-name-ah/eax: (addr handle stream byte) <- get correct-definition-symbol, text-data
+  var correct-definition-name/eax: (addr stream byte) <- lookup *correct-definition-name-ah
+  {
+    var still-matches?/eax: boolean <- stream-data-equal? correct-definition-name, curr-global-name
+    compare still-matches?, 0/false
+    break-if-=
+    return
+  }
+  stream-to-array correct-definition-name, curr-global-name-ah
 }
 
 fn assign-or-create-global _self: (addr global-table), name: (addr array byte), value: (handle cell), trace: (addr trace) {
@@ -493,20 +524,14 @@ fn maybe-stash-gap-buffer-to-global _globals: (addr global-table), _expr-ah: (ad
     break-if-=
     return
   }
-  # if expr->left is neither "define" nor "set", return
-  var left-ah/eax: (addr handle cell) <- get expr, left
-  var _left/eax: (addr cell) <- lookup *left-ah
-  var left/ecx: (addr cell) <- copy _left
+  # if expr is not a definition, return
   {
-    var def?/eax: boolean <- symbol-equal? left, "define"
-    compare def?, 0/false
-    break-if-!=
-    var set?/eax: boolean <- symbol-equal? left, "set"
-    compare set?, 0/false
+    var is-definition?/eax: boolean <- is-definition? expr
+    compare is-definition?, 0/false
     break-if-!=
     return
   }
-  # locate the global for expr->right->left
+  # locate the global for definition->right->left
   var right-ah/eax: (addr handle cell) <- get expr, right
   var right/eax: (addr cell) <- lookup *right-ah
   var defined-symbol-ah/eax: (addr handle cell) <- get right, left
@@ -542,6 +567,27 @@ fn maybe-stash-gap-buffer-to-global _globals: (addr global-table), _expr-ah: (ad
   initialize-gap-buffer gap-addr, capacity
 }
 
+fn is-definition? _expr: (addr cell) -> _/eax: boolean {
+  var expr/eax: (addr cell) <- copy _expr
+  # if expr->left is neither "define" nor "set", return
+  var left-ah/eax: (addr handle cell) <- get expr, left
+  var _left/eax: (addr cell) <- lookup *left-ah
+  var left/ecx: (addr cell) <- copy _left
+  {
+    var def?/eax: boolean <- symbol-equal? left, "define"
+    compare def?, 0/false
+    break-if-=
+    return 1/true
+  }
+  {
+    var set?/eax: boolean <- symbol-equal? left, "set"
+    compare set?, 0/false
+    break-if-=
+    return 1/true
+  }
+  return 0/false
+}
+
 # Accepts an input s-expression, naively checks if it is a definition, and if
 # so saves the gap-buffer to the appropriate global.
 fn move-gap-buffer-to-global _globals: (addr global-table), _definition-ah: (addr handle cell), gap: (addr handle gap-buffer) {