Skip to content

Commit c3a7d21

Browse files
author
Yannick Scherer
committed
Added cljx example.
1 parent ff86d52 commit c3a7d21

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

examples/rewrite_clj/cljx.clj

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
(ns ^{ :doc "Implementation of lynaghk/cljx's basic semantics using rewrite-clj."}
2+
rewrite-clj.cljx
3+
(:require [rewrite-clj.parser :as p]
4+
[rewrite-clj.zip :as z]
5+
[rewrite-clj.printer :as prn]))
6+
7+
;; ## Semantics
8+
;;
9+
;; cljx allows for Clojure forms to be prefixed with reader macros of the form
10+
;; "#+<profile>" and "#-<profile>". If the given profile is active, everything with
11+
;; "+" will remain in the code (minus the prefix) and everything with '-' will be removed.
12+
;;
13+
;; (defn my-inc
14+
;; [x]
15+
;; #+debug (println "inc: x =" x)
16+
;; (+ x 1))
17+
;;
18+
;; If the profile 'debug' is active, the following result will be created:
19+
;;
20+
;; (defn my-inc
21+
;; [x]
22+
;; (println "inc: x = " x)
23+
;; (+ x 1))
24+
;;
25+
;; Whitespace has thus to be preserved.
26+
27+
;; ## Implementation
28+
29+
(defn- cljx-macro?
30+
"Check if the given zipper node contains a cljx reader macro ('#+...' or '#-...')."
31+
[loc]
32+
(when (= (z/tag loc) :reader-macro)
33+
(let [[t sym] (z/value loc)]
34+
(when (and (= t :token) (symbol? sym))
35+
(let [^String nm (name sym)]
36+
(or (.startsWith nm "+") (.startsWith nm "-")))))))
37+
38+
(defn- replace-with-spaces
39+
"Replace the given reader macro node with spaces."
40+
[zloc]
41+
(let [w (count (with-out-str (prn/print-edn (z/node zloc))))]
42+
(-> zloc (z/prepend-space w) z/remove)))
43+
44+
(defn- remove-reader-macro
45+
"Remove the macro part of the given reader macro node."
46+
[zloc]
47+
(-> zloc
48+
z/down replace-with-spaces ;; replace the '+...'/'-...' part with spaces
49+
z/up z/splice ;; remove the macro wrapper
50+
z/prepend-space)) ;; insert a space to make up for the missing '#'
51+
52+
(defn- handle-reader-macro
53+
"Handle a reader macro node by either removing it completely or only the macro part."
54+
[active-profiles zloc]
55+
(let [profile-node (-> zloc z/down)
56+
value-node (-> profile-node z/right)
57+
^String profile-string (-> profile-node z/sexpr name)
58+
profile-active? (contains? active-profiles (.substring profile-string 1))
59+
print? (.startsWith profile-string "+")]
60+
(if (or (and profile-active? (not print?)) (and (not profile-active?) print?))
61+
(replace-with-spaces zloc)
62+
(remove-reader-macro zloc))))
63+
64+
(defn cljx-walk
65+
"Replace all occurences of profile reader macros."
66+
[active-profiles root]
67+
(loop [loc root]
68+
(if-let [mloc (z/find loc z/next cljx-macro?)]
69+
(recur (handle-reader-macro active-profiles mloc))
70+
loc)))
71+
72+
;; ## Test
73+
74+
(comment
75+
(def data
76+
(z/edn
77+
(p/parse-string
78+
"(defn my-inc\n [x]\n #+debug (println \"inc: x =\" x #-nomark \"[debug]\")\n (+ x 1))")))
79+
80+
(println "Original Code:")
81+
(-> data z/root prn/print-edn)
82+
(println "\n")
83+
84+
(println "Processed Code:")
85+
(-> (cljx-walk #{"debug" "nomark"} data) z/root prn/print-edn)
86+
(println))

0 commit comments

Comments
 (0)