summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-03-10 03:21:38 +0000
committerRich Hickey <richhickey@gmail.com>2008-03-10 03:21:38 +0000
commit26f727ea9444d84a0a3d8c4928b1b7bd25dbf658 (patch)
tree35b801e8f62f2387f9993f2b3de3ba7c24cc327b /src
parentcbc24c18cb0a5986abc2e34bfa2b76aed5f00833 (diff)
moving to new metadata/docstrings
Diffstat (limited to 'src')
-rw-r--r--src/zip.clj394
1 files changed, 194 insertions, 200 deletions
diff --git a/src/zip.clj b/src/zip.clj
index f9e66075..1e33fc44 100644
--- a/src/zip.clj
+++ b/src/zip.clj
@@ -12,208 +12,202 @@
(in-ns 'zip)
(clojure/refer 'clojure)
-(defn
- #^{:doc "Creates a new zipper structure.
-
- branch? is a fn that, given a node, returns true if can
- have children, even if it currently doesn't.
-
- children is a fn that, given a branch node, returns a seq
- of its children.
-
- make-node is a fn that, given an existing node and a seq
- of children, returns a new branch node with the supplied
- children. root is the root node."}
-zipper [branch? children make-node root]
- #^{:zip/branch? branch? :zip/children children :zip/make-node make-node} [root nil])
-
-(defn
- #^{:doc "Returns a zipper for nested sequences, given a root sequence"}
-seq-zip [root]
- (zipper seq? identity (fn [node children] children) root))
-
-(defn
- #^{:doc "Returns a zipper for nested vectors, given a root vector"}
-vector-zip [root]
- (zipper vector? seq (fn [node children] (apply vector children)) root))
-
-(defn
- #^{:doc "Returns a zipper for xml elements (as from xml/parse),
- given a root element"}
-xml-zip [root]
- (zipper (complement string?)
- (comp seq :content)
- (fn [node children]
- (assoc node :content (and children (apply vector children))))
- root))
-
-(defn
- #^{:doc "Returns the node at loc"}
-node [loc]
- (loc 0))
-
-(defn
- #^{:doc "Returns true if the node at loc is a branch"}
-branch? [loc]
- ((:zip/branch? ^loc) (node loc)))
-
-(defn
- #^{:doc "Returns a seq of the children of node at loc,
- which must be a branch"}
-children [loc]
- ((:zip/children ^loc) (node loc)))
-
-(defn
- #^{:doc "Returns a new branch node, given an existing node and new
- children. The loc is only used to supply the constructor."}
-make-node [loc node children]
- ((:zip/make-node ^loc) node children))
-
-(defn
- #^{:doc "Returns a seq of nodes leading to this loc"}
-path [loc]
- (:pnodes (loc 1)))
-
-(defn
- #^{:doc "Returns a seq of the left siblings of this loc"}
-lefts [loc]
- (seq (:l (loc 1))))
-
-(defn
- #^{:doc "Returns a seq of the right siblings of this loc"}
-rights [loc]
- (:r (loc 1)))
-
-
-(defn
- #^{:doc "Returns the loc of the leftmost child of the node
- at this loc, or nil if no children"}
-down [loc]
- (let [[node path] loc
- [c & crest :as cs] (children loc)]
- (when cs
- (with-meta [c {:l []
- :pnodes (if path (conj (:pnodes path) node) [node])
- :ppath path
- :r crest}] ^loc))))
-
-(defn
- #^{:doc "Returns the loc of the parent of the node at this loc, or nil
- if at the top"}
-up [loc]
- (let [[node {l :l, ppath :ppath, pnodes :pnodes r :r, changed? :changed?, :as path}] loc]
- (when path
- (let [pnode (peek pnodes)]
- (with-meta (if changed?
- [(make-node loc pnode (concat l (cons node r)))
+(defn zipper
+ "Creates a new zipper structure.
+
+ branch? is a fn that, given a node, returns true if can have
+ children, even if it currently doesn't.
+
+ children is a fn that, given a branch node, returns a seq of its
+ children.
+
+ make-node is a fn that, given an existing node and a seq of
+ children, returns a new branch node with the supplied children.
+ root is the root node."
+ [branch? children make-node root]
+ #^{:zip/branch? branch? :zip/children children :zip/make-node make-node}
+ [root nil])
+
+(defn seq-zip
+ "Returns a zipper for nested sequences, given a root sequence"
+ [root]
+ (zipper seq? identity (fn [node children] children) root))
+
+(defn vector-zip
+ "Returns a zipper for nested vectors, given a root vector"
+ [root]
+ (zipper vector? seq (fn [node children] (apply vector children)) root))
+
+(defn xml-zip
+ "Returns a zipper for xml elements (as from xml/parse),
+ given a root element"
+ [root]
+ (zipper (complement string?)
+ (comp seq :content)
+ (fn [node children]
+ (assoc node :content (and children (apply vector children))))
+ root))
+
+(defn node
+ "Returns the node at loc"
+ [loc] (loc 0))
+
+(defn branch?
+ "Returns true if the node at loc is a branch"
+ [loc]
+ ((:zip/branch? ^loc) (node loc)))
+
+(defn children
+ "Returns a seq of the children of node at loc, which must be a branch"
+ [loc]
+ ((:zip/children ^loc) (node loc)))
+
+(defn make-node
+ "Returns a new branch node, given an existing node and new
+ children. The loc is only used to supply the constructor."
+ [loc node children]
+ ((:zip/make-node ^loc) node children))
+
+(defn path
+ "Returns a seq of nodes leading to this loc"
+ [loc]
+ (:pnodes (loc 1)))
+
+(defn lefts
+ "Returns a seq of the left siblings of this loc"
+ [loc]
+ (seq (:l (loc 1))))
+
+(defn rights
+ "Returns a seq of the right siblings of this loc"
+ [loc]
+ (:r (loc 1)))
+
+
+(defn down
+ "Returns the loc of the leftmost child of the node at this loc, or
+ nil if no children"
+ [loc]
+ (let [[node path] loc
+ [c & crest :as cs] (children loc)]
+ (when cs
+ (with-meta [c {:l []
+ :pnodes (if path (conj (:pnodes path) node) [node])
+ :ppath path
+ :r crest}] ^loc))))
+
+(defn up
+ "Returns the loc of the parent of the node at this loc, or nil if at
+ the top"
+ [loc]
+ (let [[node {l :l, ppath :ppath, pnodes :pnodes r :r, changed? :changed?, :as path}] loc]
+ (when path
+ (let [pnode (peek pnodes)]
+ (with-meta (if changed?
+ [(make-node loc pnode (concat l (cons node r)))
+ (and ppath (assoc ppath :changed? true))]
+ [pnode ppath])
+ ^loc)))))
+
+(defn root
+ "zips all the way up and returns the root node, reflecting any
+ changes."
+ [loc]
+ (if (= :end (loc 1))
+ (node loc)
+ (let [p (up loc)]
+ (if p
+ (recur p)
+ (node loc)))))
+
+(defn right
+ "Returns the loc of the right sibling of the node at this loc, or nil"
+ [loc]
+ (let [[node {l :l [r & rrest :as rs] :r :as path}] loc]
+ (when (and path rs)
+ (with-meta [r (assoc path :l (conj l node) :r rrest)] ^loc))))
+
+(defn left
+ "Returns the loc of the left sibling of the node at this loc, or nil"
+ [loc]
+ (let [[node {l :l r :r :as path}] loc]
+ (when (and path (seq l))
+ (with-meta [(peek l) (assoc path :l (pop l) :r (cons node r))] ^loc))))
+
+(defn insert-left
+ "Inserts the item as the left sibling of the node at this loc,
+ without moving"
+ [loc item]
+ (let [[node {l :l :as path}] loc]
+ (if (nil? path)
+ (throw (new Exception "Insert at top"))
+ (with-meta [node (assoc path :l (conj l item) :changed? true)] ^loc))))
+
+(defn insert-right
+ "Inserts the item as the right sibling of the node at this loc,
+ without moving"
+ [loc item]
+ (let [[node {r :r :as path}] loc]
+ (if (nil? path)
+ (throw (new Exception "Insert at top"))
+ (with-meta [node (assoc path :r (cons item r) :changed? true)] ^loc))))
+
+(defn replace
+ "Replaces the node at this loc, without moving"
+ [loc node]
+ (let [[_ path] loc]
+ (with-meta [node (assoc path :changed? true)] ^loc)))
+
+(defn edit
+ "Replaces the node at this loc with the value of (f node args)"
+ [loc f & args]
+ (replace loc (apply f (node loc) args)))
+
+(defn insert-child
+ "Inserts the item as the leftmost child of the node at this loc,
+ without moving"
+ [loc item]
+ (replace loc (make-node loc (node loc) (cons item (children loc)))))
+
+(defn append-child
+ "Inserts the item as the rightmost child of the node at this loc,
+ without moving"
+ [loc item]
+ (replace loc (make-node loc (node loc) (concat (children loc) [item]))))
+
+(defn next
+ "Moves to the next loc in the hierarchy, depth-first. When reaching
+ the end, returns a distinguished loc detectable via end?. If already
+ at the end, stays there."
+ [loc]
+ (if (= :end (loc 1))
+ loc
+ (or
+ (and (branch? loc) (down loc))
+ (right loc)
+ (loop [p loc]
+ (if (up p)
+ (or (right (up p)) (recur (up p)))
+ [(node p) :end])))))
+
+(defn end?
+ "Returns true if loc represents the end of a depth-first walk"
+ [loc]
+ (= :end (loc 1)))
+
+(defn remove
+ "Removes the node at loc, returning the loc that would have preceded
+ it in a depth-first walk."
+ [loc]
+ (let [[node {l :l, ppath :ppath, pnodes :pnodes, rs :r, :as path}] loc]
+ (if (nil? path)
+ (throw (new Exception "Remove at top"))
+ (if (pos? (count l))
+ (with-meta [(peek l) (assoc path :l (pop l) :changed? true)] ^loc)
+ (with-meta [(make-node loc (peek pnodes) rs)
(and ppath (assoc ppath :changed? true))]
- [pnode ppath])
- ^loc)))))
-
-(defn
- #^{:doc "zips all the way up and returns the root node,
- reflecting any changes."}
-root [loc]
- (if (= :end (loc 1))
- (node loc)
- (let [p (up loc)]
- (if p
- (recur p)
- (node loc)))))
-
-(defn
- #^{:doc "Returns the loc of the right sibling of the node at this loc,
- or nil"}
-right [loc]
- (let [[node {l :l [r & rrest :as rs] :r :as path}] loc]
- (when (and path rs)
- (with-meta [r (assoc path :l (conj l node) :r rrest)] ^loc))))
-
-(defn
- #^{:doc "Returns the loc of the left sibling of the node at this loc, or
- nil"}
-left [loc]
- (let [[node {l :l r :r :as path}] loc]
- (when (and path (seq l))
- (with-meta [(peek l) (assoc path :l (pop l) :r (cons node r))] ^loc))))
-
-(defn
- #^{:doc "Inserts the item as the left sibling of the node at this loc,
- without moving"}
-insert-left [loc item]
- (let [[node {l :l :as path}] loc]
- (if (nil? path)
- (throw (new Exception "Insert at top"))
- (with-meta [node (assoc path :l (conj l item) :changed? true)] ^loc))))
-
-(defn
- #^{:doc "Inserts the item as the right sibling of the node at this loc,
- without moving"}
-insert-right [loc item]
- (let [[node {r :r :as path}] loc]
- (if (nil? path)
- (throw (new Exception "Insert at top"))
- (with-meta [node (assoc path :r (cons item r) :changed? true)] ^loc))))
-
-(defn
- #^{:doc "Replaces the node at this loc, without moving"}
-replace [loc node]
- (let [[_ path] loc]
- (with-meta [node (assoc path :changed? true)] ^loc)))
-
-(defn
- #^{:doc "Replaces the node at this loc with the value of (f node args)"}
-edit [loc f & args]
- (replace loc (apply f (node loc) args)))
-
-(defn
- #^{:doc "Inserts the item as the leftmost child of the node at this loc,
- without moving"}
-insert-child [loc item]
- (replace loc (make-node loc (node loc) (cons item (children loc)))))
-
-(defn
- #^{:doc "Inserts the item as the rightmost child of the node at this
- loc, without moving"}
-append-child [loc item]
- (replace loc (make-node loc (node loc) (concat (children loc) [item]))))
-
-(defn
- #^{:doc "Moves to the next loc in the hierarchy, depth-first. When
- reaching the end, returns a distinguished loc detectable
- via end?. If already at the end, stays there."}
-next [loc]
- (if (= :end (loc 1))
- loc
- (or
- (and (branch? loc) (down loc))
- (right loc)
- (loop [p loc]
- (if (up p)
- (or (right (up p)) (recur (up p)))
- [(node p) :end])))))
-
-(defn
- #^{:doc "Returns true if loc represents the end of a depth-first walk"}
-end? [loc]
- (= :end (loc 1)))
-
-(defn
- #^{:doc "Removes the node at loc, returning the loc that would have
- preceded it in a depth-first walk."}
-remove [loc]
- (let [[node {l :l, ppath :ppath, pnodes :pnodes, rs :r, :as path}] loc]
- (if (nil? path)
- (throw (new Exception "Remove at top"))
- (if (pos? (count l))
- (with-meta [(peek l) (assoc path :l (pop l) :changed? true)] ^loc)
- (with-meta [(make-node loc (peek pnodes) rs)
- (and ppath (assoc ppath :changed? true))]
- ^loc)))))
+ ^loc)))))
-
-
-
(comment
(load-file "/Users/rich/dev/clojure/src/zip.clj")