Permalink
Browse files

add rough implementation of dalap clj->cljs transforms

inspired by cljx / kibit
  • Loading branch information...
1 parent 6245478 commit 50b1b77cd8afb1a03598235b89f8fff8f3434775 @tavisrudd tavisrudd committed Jun 1, 2012
Showing with 199 additions and 0 deletions.
  1. +168 −0 test/dalap/test/cljsrc_walk.clj
  2. +31 −0 test/dalap/test/cljsrc_walk_sample.clj
@@ -0,0 +1,168 @@
+(ns dalap.test.cljsrc-walk
+ (:use [clojure.test :only [deftest is]])
+ (:use [clojure.java.io :only [reader make-parents]])
+ (:require [clojure.string :as string])
+ (:import [clojure.lang LineNumberingPushbackReader])
+ (:import [java.io File])
+
+ (:use dalap.html.selector)
+ (:use [dalap.walk :only [walk]]))
+
+(defn visit-form [form w]
+ ;; a modified version of clojure.walk with the ability to drop forms
+ (letfn [(filter-map [f form] (remove #(= % ::drop) (map f form)))]
+ (cond
+ (list? form) (apply list (filter-map w form))
+ (instance? clojure.lang.IMapEntry form) (vec (filter-map w form))
+ (seq? form) (doall (filter-map w form))
+ (coll? form) (into (empty form) (filter-map w form))
+ :else form)))
+
+(def clj-forms-to-drop #{'defmacro 'comment})
+(def cljs-core-transform-rules
+ [(fn [form w] (contains? (meta form) :cljs))
+ (comp :cljs meta)
+ ;;
+ (fn [form w] (contains? (meta form) :clj))
+ (constantly ::drop)
+ ;;
+ (fn [form w] (and (list? form) (clj-forms-to-drop (first form))))
+ (constantly ::drop)])
+
+(def cljs-type-transform-rules
+ ['clojure.lang.Atom 'cljs.core.Atom
+ 'clojure.lang.PersistentVector 'cljs.core.PersistentVector
+ 'Object 'default
+
+ 'String 'string
+ 'java.lang.String 'string
+
+ 'Number 'number
+ 'java.lang.Number 'number
+
+ 'Error 'js/Error
+ 'Error. 'js/Error.])
+
+(def cljs-default-transform-rules
+ (concat cljs-core-transform-rules
+ cljs-type-transform-rules))
+
+(defn cljs-transform
+ ([forms]
+ (cljs-transform forms cljs-default-transform-rules))
+ ([forms rules]
+ (walk forms ((gen-decorator rules) visit-form))))
+
+(defn read-file
+ ;; see https://github.com/jonase/kibit/blob/master/src/kibit/check.clj
+ "Gen a lazy sequence of top level forms from a LineNumberingPushbackReader"
+ [^LineNumberingPushbackReader r]
+ (lazy-seq
+ (let [form (try
+ (read r false ::eof)
+ (catch Exception e
+ (throw (Exception.
+ (str "Dalap's reader crashed"
+ (.getMessage e)) e))))]
+ (when-not (= form ::eof)
+ (cons form (read-file r))))))
+
+(defn read-clj?s [file-or-path]
+ (read-file
+ (LineNumberingPushbackReader.
+ (java.io.StringReader.
+ (string/replace (slurp file-or-path) #"\#_\(\s*cljs\b" "(do ")))))
+
+(defn warning-str [orig-path]
+ (str ";;This file autogenerated from \n;;\n;; " orig-path
+ " @ " (java.util.Date.)
+ "\n;;\n"))
+
+(defn transform-file
+ ([file-or-path rules-vector-fn-or-map]
+ (let [f (File. file-or-path)
+ path (.getPath f)
+ rules (if (or (fn? rules-vector-fn-or-map)
+ (map? rules-vector-fn-or-map))
+ (rules-vector-fn-or-map path)
+ rules-vector-fn-or-map)
+ munged-forms (cljs-transform (read-clj?s file-or-path) rules)]
+ (str (warning-str path)
+ (string/join "\n" munged-forms)))))
+
+;;; ;Taken from clojure.tools.namespace
+(defn clj-source-file?
+ "Returns true if file is a normal file with a .clj extension."
+ [^File file]
+ (and (.isFile file)
+ (.endsWith (.getName file) ".clj")))
+
+(defn find-clj-sources-in-dir
+ "Searches recursively under dir for CLJ files.
+Returns a sequence of File objects, in breadth-first sort order."
+ [^File dir]
+ ;; Use sort by absolute path to get breadth-first search.
+ (sort-by #(.getAbsolutePath ^File %)
+ (filter clj-source-file? (file-seq dir))))
+
+(defn transform-directory
+ ([clj-path output-path]
+ (transform-directory
+ clj-path output-path "cljs" cljs-default-transform-rules
+ (constantly true)))
+
+ ([clj-path output-path extension rules file-filter]
+ (doseq [f (find-clj-sources-in-dir (File. clj-path))]
+ (if (file-filter f)
+ (let [generated-f (File. (-> (.getPath f)
+ (string/replace clj-path output-path)
+ (string/replace #"clj$" extension)))]
+ (make-parents generated-f)
+ (spit generated-f
+ (transform-file f rules)))))))
+
+(comment
+ (transform-directory "src/dalap" ".generated")
+ (print (string/join
+ "\n"
+ (cljs-transform (read-clj?s
+ "test/dalap/test/cljsrc_walk_sample.clj")))))
+
+;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(deftest test-source-transformation
+ (let [visitor ((gen-decorator
+ (concat
+ ['something 'something-else
+ 'dalap.html.selector 'dalap.cljs.selector
+ ] cljs-core-transform-rules))
+ visit-form)
+ vis #(walk % visitor)
+ ]
+ (is (= (vis '(something ^{:cljs something-else-cljs}
+ foobar))
+ '(something-else something-else-cljs)))
+
+ (is (= (vis '(abcd ^:clj foobar))
+ '(abcd)))
+
+ (is (= (vis '(ns dalap.test.html.selector
+ (:use clojure.test)
+ (:use [clojure.pprint :only (pprint)])
+
+ (:require [dalap.html :as html])
+
+ ^{:cljs (:require [dalap.cljs.defaults :as defaults])}
+ (:require [dalap.defaults :as defaults])
+
+ (:use dalap.html.selector)
+ (:use [dalap.walk :only [walk]])
+ (:use [dalap.html :only [add-class]])))
+ '(ns dalap.test.html.selector
+ (:use clojure.test)
+ (:use [clojure.pprint :only (pprint)])
+
+ (:require [dalap.html :as html])
+ (:require [dalap.cljs.defaults :as defaults])
+ (:use dalap.cljs.selector)
+ (:use [dalap.walk :only [walk]])
+ (:use [dalap.html :only [add-class]]))))))
@@ -0,0 +1,31 @@
+^{:cljs
+ (ns dalap.cljs.test.cljsrc-walk)}
+(ns dalap.test.cljsrc-walk)
+
+^:clj
+(do
+ (defn only-in-clj [] true)
+ (defn only-in-clj2 [i] (* i 2))
+ )
+(defmacro clj-only-macro [sadf]
+ nil)
+(comment
+ 'asdf)
+(defn foo []
+ ^{:cljs something-else-cljs}
+ foobar
+ (Error. "asdf")
+ (Error "Fooe")
+ clojure.lang.Atom
+ something)
+
+#_(cljs
+ (just-testing something)
+
+ (defn cljs-func []
+ nil)
+ )
+
+#_(
+ (read-file (LineNumberingPushbackReader. reader))
+ )

0 comments on commit 50b1b77

Please sign in to comment.