about summary refs log tree commit diff stats
path: root/075duplex_list.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-11-13 14:32:21 -0800
committerKartik K. Agaram <vc@akkartik.com>2015-11-13 14:36:18 -0800
commite36e7caffa6194135895844aae9df93d1af4b9f9 (patch)
tree9ed97c9ac3190034b8361c0937c4ba064eef4573 /075duplex_list.mu
parentc4f5d4cf0b6f0d33994aac9d5fa29da1a46f7831 (diff)
downloadmu-e36e7caffa6194135895844aae9df93d1af4b9f9.tar.gz
2432 - first stab at making ingredients immutable
The rule is, an address ingredient is only modifiable if:
  a) it's also a product
  b) it's /contained-in some other ingredient+product

Only if an ingredient is a modifiable can you:
  a) call get-address or index-address on it (the only way to write to it)
  b) call other recipes that also return it in a product

I still don't check copies of the address. That's next.

Core mu passes this check, but none of the example apps do. edit/ and
sandbox/ are known to fail.
Diffstat (limited to '075duplex_list.mu')
-rw-r--r--075duplex_list.mu97
1 files changed, 46 insertions, 51 deletions
diff --git a/075duplex_list.mu b/075duplex_list.mu
index 765a6a17..e98710ed 100644
--- a/075duplex_list.mu
+++ b/075duplex_list.mu
@@ -6,17 +6,20 @@ container duplex-list:_elem [
   prev:address:duplex-list:_elem
 ]
 
-recipe push-duplex x:_elem, in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
+recipe push-duplex x:_elem, in:address:duplex-list:_elem -> in:address:duplex-list:_elem [
   local-scope
   load-ingredients
-  result <- new {(duplex-list _elem): type}
+  result:address:duplex-list:_elem <- new {(duplex-list _elem): type}
   val:address:_elem <- get-address *result, value:offset
   *val <- copy x
   next:address:address:duplex-list:_elem <- get-address *result, next:offset
   *next <- copy in
-  reply-unless in
-  prev:address:address:duplex-list:_elem <- get-address *in, prev:offset
-  *prev <- copy result
+  {
+    break-unless in
+    prev:address:address:duplex-list:_elem <- get-address *in, prev:offset
+    *prev <- copy result
+  }
+  reply result  # needed explicitly because we need to replace 'in' with 'result'
 ]
 
 recipe first-duplex in:address:duplex-list:_elem -> result:_elem [
@@ -83,11 +86,11 @@ scenario duplex-list-handling [
   ]
 ]
 
-# Inserts 'x' after 'in'. Returns some pointer into the list.
-recipe insert-duplex x:_elem, in:address:duplex-list:_elem -> new-node:address:duplex-list:_elem [
+# insert 'x' after 'in'
+recipe insert-duplex x:_elem, in:address:duplex-list:_elem -> in:address:duplex-list:_elem [
   local-scope
   load-ingredients
-  new-node <- new {(duplex-list _elem): type}
+  new-node:address:duplex-list:_elem <- new {(duplex-list _elem): type}
   val:address:_elem <- get-address *new-node, value:offset
   *val <- copy x
   next-node:address:duplex-list:_elem <- get *in, next:offset
@@ -101,11 +104,10 @@ recipe insert-duplex x:_elem, in:address:duplex-list:_elem -> new-node:address:d
   y <- get-address *new-node, next:offset
   *y <- copy next-node
   # if next-node is not null
-  reply-unless next-node, new-node
+  reply-unless next-node
   # next-node.prev = new-node
   y <- get-address *next-node, prev:offset
   *y <- copy new-node
-  reply new-node  # just signalling something changed; don't rely on the result
 ]
 
 scenario inserting-into-duplex-list [
@@ -189,7 +191,7 @@ scenario inserting-after-start-of-duplex-list [
     1:address:duplex-list:character <- push-duplex 3, 1:address:duplex-list:character
     1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
     1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
-    2:address:duplex-list:character <- insert-duplex 6, 1:address:duplex-list:character
+    1:address:duplex-list:character <- insert-duplex 6, 1:address:duplex-list:character
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
     3:character <- first-duplex 2:address:duplex-list:character
@@ -219,38 +221,38 @@ scenario inserting-after-start-of-duplex-list [
   ]
 ]
 
-# Removes 'in' from its surrounding list. Returns some valid pointer into the
-# rest of the list.
+# remove 'x' from its surrounding list 'in'
 #
-# Returns null if and only if list is empty. Beware: in that case any pointers
-# to the head are now invalid.
-recipe remove-duplex in:address:duplex-list:_elem -> next-node:address:duplex-list:_elem [
+# Returns null if and only if list is empty. Beware: in that case any other
+# pointers to the head are now invalid.
+recipe remove-duplex x:address:duplex-list:_elem/contained-in:in, in:address:duplex-list:_elem -> in:address:duplex-list:_elem [
   local-scope
   load-ingredients
   # if 'in' is null, return
-  reply-unless in, in
-  next-node:address:duplex-list:_elem <- get *in, next:offset
-  prev-node:address:duplex-list:_elem <- get *in, prev:offset
-  # null in's pointers
-  x:address:address:duplex-list:_elem <- get-address *in, next:offset
-  *x <- copy 0
-  x <- get-address *in, prev:offset
-  *x <- copy 0
+  reply-unless x
+  next-node:address:duplex-list:_elem <- get *x, next:offset
+  prev-node:address:duplex-list:_elem <- get *x, prev:offset
+  # null x's pointers
+  tmp:address:address:duplex-list:_elem <- get-address *x, next:offset
+  *tmp <- copy 0
+  tmp <- get-address *x, prev:offset
+  *tmp <- copy 0
+  # if next-node is not null, set its prev pointer
   {
-    # if next-node is not null
     break-unless next-node
-    # next-node.prev = prev-node
-    x <- get-address *next-node, prev:offset
-    *x <- copy prev-node
+    tmp <- get-address *next-node, prev:offset
+    *tmp <- copy prev-node
   }
+  # if prev-node is not null, set its next pointer and return
   {
-    # if prev-node is not null
     break-unless prev-node
     # prev-node.next = next-node
-    x <- get-address *prev-node, next:offset
-    *x <- copy next-node
-    reply prev-node
+    tmp <- get-address *prev-node, next:offset
+    *tmp <- copy next-node
+    reply
   }
+  # if prev-node is null, then we removed the node at 'in'
+  # return the new head rather than the old 'in'
   reply next-node
 ]
 
@@ -261,7 +263,7 @@ scenario removing-from-duplex-list [
     1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
     1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
     2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character  # 2 points at second element
-    2:address:duplex-list:character <- remove-duplex 2:address:duplex-list:character
+    1:address:duplex-list:character <- remove-duplex 2:address:duplex-list:character, 1:address:duplex-list:character
     3:boolean <- equal 2:address:duplex-list:character, 0
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
@@ -289,8 +291,8 @@ scenario removing-from-start-of-duplex-list [
     1:address:duplex-list:character <- push-duplex 3, 1:address:duplex-list:character
     1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
     1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
-    # removing from head? return value matters.
-    1:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character
+    # remove from head
+    1:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character, 1:address:duplex-list:character
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
     3:character <- first-duplex 2:address:duplex-list:character
@@ -319,7 +321,7 @@ scenario removing-from-end-of-duplex-list [
     # delete last element
     2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
     2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- remove-duplex 2:address:duplex-list:character
+    1:address:duplex-list:character <- remove-duplex 2:address:duplex-list:character, 1:address:duplex-list:character
     3:boolean <- equal 2:address:duplex-list:character, 0
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
@@ -345,22 +347,15 @@ scenario removing-from-singleton-list [
   run [
     1:address:duplex-list:character <- copy 0  # 1 points to singleton list
     1:address:duplex-list:character <- push-duplex 3, 1:address:duplex-list:character
-    2:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character
-    3:address:duplex-list:character <- get *1:address:duplex-list:character, next:offset
-    4:address:duplex-list:character <- get *1:address:duplex-list:character, prev:offset
+    1:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character, 1:address:duplex-list:character
   ]
   memory-should-contain [
-    2 <- 0  # remove returned null
-    3 <- 0  # removed node is also detached
-    4 <- 0
+    1 <- 0  # back to an empty list
   ]
 ]
 
-# l:address:duplex-list <- remove-duplex-between start:address:duplex-list, end:address:duplex-list
-# Remove values between 'start' and 'end' (both exclusive). Returns some valid
-# pointer into the rest of the list.
-# Also clear pointers back out from start/end for hygiene.
-recipe remove-duplex-between start:address:duplex-list:_elem, end:address:duplex-list:_elem -> start:address:duplex-list:_elem [
+# remove values between 'start' and 'end' (both exclusive)
+recipe remove-duplex-between start:address:duplex-list:_elem, end:address:duplex-list:_elem/contained-in:start -> start:address:duplex-list:_elem [
   local-scope
   load-ingredients
   reply-unless start
@@ -470,8 +465,8 @@ scenario remove-range-empty [
   ]
 ]
 
-# Inserts list beginning at 'new' after 'in'. Returns some pointer into the list.
-recipe insert-duplex-range in:address:duplex-list:_elem, start:address:duplex-list:_elem -> in:address:duplex-list:_elem [
+# insert list beginning at 'new' after 'in'
+recipe insert-duplex-range in:address:duplex-list:_elem, start:address:duplex-list:_elem/contained-in:in -> in:address:duplex-list:_elem [
   local-scope
   load-ingredients
   reply-unless in
@@ -497,7 +492,7 @@ recipe insert-duplex-range in:address:duplex-list:_elem, start:address:duplex-li
   *dest <- copy in
 ]
 
-recipe append-duplex in:address:duplex-list:_elem, new:address:duplex-list:_elem -> in:address:duplex-list:_elem [
+recipe append-duplex in:address:duplex-list:_elem, new:address:duplex-list:_elem/contained-in:in -> in:address:duplex-list:_elem [
   local-scope
   load-ingredients
   last:address:duplex-list:_elem <- last-duplex in
@@ -547,7 +542,7 @@ recipe force-specialization-duplex-list-character [
   1:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
   1:address:duplex-list:character <- prev-duplex 1:address:duplex-list:character
   1:address:duplex-list:character <- insert-duplex 2:character, 1:address:duplex-list:character
-  1:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character
+  1:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character, 1:address:duplex-list:character
   1:address:duplex-list:character <- remove-duplex-between 1:address:duplex-list:character, 1:address:duplex-list:character
   1:address:duplex-list:character <- insert-duplex-range 1:address:duplex-list:character, 1:address:duplex-list:character
   1:address:duplex-list:character <- append-duplex 1:address:duplex-list:character, 1:address:duplex-list:character