Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

transform with multimethod (transform') #199

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 74 additions & 18 deletions src/instaparse/transform.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,59 @@ something that can have a metamap attached."
(let [transform (transform-map (:tag parse-tree))]
(cond
transform
(merge-meta
(apply transform (map (partial enlive-transform transform-map)
(:content parse-tree)))
(meta parse-tree))
(merge-meta
(apply transform (map (partial enlive-transform transform-map)
(:content parse-tree)))
(meta parse-tree))
(:tag parse-tree)
(assoc parse-tree :content (map (partial enlive-transform transform-map)
(:content parse-tree)))
:else
parse-tree)))

(defn- enlive-transform'
[transform parse-tree]
(cond
transform
(merge-meta
(apply transform (map (partial enlive-transform transform)
(:content parse-tree)))
(meta parse-tree))
(:tag parse-tree)
(assoc parse-tree :content (map (partial enlive-transform transform)
(:content parse-tree)))
:else
parse-tree))

(defn- hiccup-transform
[transform-map parse-tree]
(if (and (sequential? parse-tree) (seq parse-tree))
(if-let [transform (transform-map (first parse-tree))]
(merge-meta
(apply transform (map (partial hiccup-transform transform-map)
(next parse-tree)))
(meta parse-tree))
(with-meta
(into [(first parse-tree)]
(map (partial hiccup-transform transform-map)
(next parse-tree)))
(meta parse-tree)))
(apply transform (map (partial hiccup-transform transform-map)
(next parse-tree)))
(meta parse-tree))
(with-meta
(into [(first parse-tree)]
(map (partial hiccup-transform transform-map)
(next parse-tree)))
(meta parse-tree)))
parse-tree))

(defn- hiccup-transform'
[transform parse-tree]
(if (and (sequential? parse-tree) (seq parse-tree))
(merge-meta
(apply transform
(first parse-tree)
(map (partial hiccup-transform' transform)
(next parse-tree)))
(meta parse-tree))
parse-tree))

(defn transform
"Takes a transform map and a parse tree (or seq of parse-trees).
A transform map is a mapping from tags to
A transform map is a mapping from tags to
functions that take a node's contents and return
a replacement for the node, i.e.,
{:node-tag (fn [child1 child2 ...] node-replacement),
Expand All @@ -62,20 +87,51 @@ something that can have a metamap attached."
(and (map? parse-tree) (:tag parse-tree))
; This is an enlive tree-seq
(enlive-transform transform-map parse-tree)

(and (vector? parse-tree) (keyword? (first parse-tree)))
; This is a hiccup tree-seq
(hiccup-transform transform-map parse-tree)

(sequential? parse-tree)
; This is either a sequence of parse results, or a tree
; with a hidden root tag.
(map-preserving-meta (partial transform transform-map) parse-tree)

(instance? instaparse.gll.Failure parse-tree)
; pass failures through unchanged
parse-tree


:else
(throw-illegal-argument-exception
"Invalid parse-tree, not recognized as either enlive or hiccup format.")))

(defn transform'
"Takes a transform fn and a parse tree (or seq of parse-trees).
For hiccup format, transform fn is like (fn [tag & children] ...)"
[transform-fn parse-tree]
(cond
(string? parse-tree)
; This is a leaf of the tree that should pass through unchanged
parse-tree

;; TODO: how to handle enlive
#_(and (map? parse-tree) (:tag parse-tree))
; This is an enlive tree-seq
#_(enlive-transform' transform-fn parse-tree)

(and (vector? parse-tree) (keyword? (first parse-tree)))
; This is a hiccup tree-seq
(hiccup-transform' transform-fn parse-tree)

(sequential? parse-tree)
; This is either a sequence of parse results, or a tree
; with a hidden root tag.
(map-preserving-meta transform-fn parse-tree)

(instance? instaparse.gll.Failure parse-tree)
; pass failures through unchanged
parse-tree

:else
(throw-illegal-argument-exception
"Invalid parse-tree, not recognized as either enlive or hiccup format.")))
"Invalid parse-tree, not recognized as either enlive or hiccup format.")))