Created
December 8, 2012 18:40
-
-
Save kanaka/4241273 to your computer and use it in GitHub Desktop.
cljs_in_cljs patch 3 (https://github.com/kanaka/clojurescript)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- /dev/null 2012-11-30 09:18:52.404117001 -0600 | |
| +++ src/cljs/cljs/analyzer_macros.clj 2012-12-08 11:13:03.441968192 -0600 | |
| @@ -0,0 +1,4 @@ | |
| +(ns cljs.analyzer-macros) | |
| + | |
| +(defmacro disallowing-recur [& body] | |
| + `(binding [cljs.analyzer/*recur-frames* (cons nil cljs.analyzer/*recur-frames*)] ~@body)) | |
| --- /dev/null 2012-11-30 09:18:52.404117001 -0600 | |
| +++ src/cljs/cljs/compiler_macros.clj 2012-11-17 13:40:55.000000000 -0600 | |
| @@ -0,0 +1,8 @@ | |
| +(ns cljs.compiler-macros) | |
| + | |
| +(defmacro emit-wrap [env & body] | |
| + `(let [env# ~env] | |
| + (when (= :return (:context env#)) (cljs.compiler/emits "return ")) | |
| + ~@body | |
| + (when-not (= :expr (:context env#)) (cljs.compiler/emitln ";")))) | |
| + | |
| --- src/clj/cljs/analyzer.clj 2012-12-08 11:13:03.441968192 -0600 | |
| +++ src/cljs/cljs/analyzer.cljs 2012-12-08 11:39:19.068577065 -0600 | |
| @@ -6,14 +6,26 @@ | |
| ; the terms of this license. | |
| ; You must not remove this notice, or any other, from this software. | |
| -(set! *warn-on-reflection* true) | |
| +;; (set! *warn-on-reflection* true) | |
| (ns cljs.analyzer | |
| (:refer-clojure :exclude [macroexpand-1]) | |
| - (:require [clojure.java.io :as io] | |
| + (:require ;; [clojure.java.io :as io] | |
| [clojure.string :as string] | |
| - [cljs.tagged-literals :as tags]) | |
| - (:import java.lang.StringBuilder)) | |
| + ;;[cljs.tagged-literals :as tags] | |
| + ) | |
| + (:use-macros [cljs.analyzer-macros :only [disallowing-recur]]) | |
| + ;;(:import java.lang.StringBuilder) | |
| + ) | |
| + | |
| +;; Stubs just to make it work | |
| +(declare ^:dynamic *out*) | |
| +(declare ^:dynamic *ns*) | |
| + | |
| +;;(defn create-ns [ns-sym] nil) | |
| +(defn create-ns [ns-sym] #_(.log js/console ns-sym) | |
| + (js/eval (str "try { " ns-sym "; } catch (e) { " ns-sym " = {}; }"))) | |
| + | |
| (declare resolve-var) | |
| (declare resolve-existing-var) | |
| @@ -28,8 +40,12 @@ | |
| (def ^:dynamic *reader-ns-name* (gensym)) | |
| (def ^:dynamic *reader-ns* (create-ns *reader-ns-name*)) | |
| -(defonce namespaces (atom '{cljs.core {:name cljs.core} | |
| - cljs.user {:name cljs.user}})) | |
| +;; (defonce namespaces (atom '{cljs.core {:name cljs.core} | |
| +;; cljs.user {:name cljs.user}})) | |
| +;; (def namespaces (atom '{cljs.core {:name cljs.core} | |
| +;; cljs.user {:name cljs.user}})) | |
| +;; "refer" it from somehwere that it will be from the start | |
| +(set! cljs.analyzer/namespaces cljs.core/namespaces) | |
| (defn reset-namespaces! [] | |
| (reset! namespaces | |
| @@ -63,29 +79,29 @@ | |
| (load *cljs-macros-path*) | |
| (load-file *cljs-macros-path*)))) | |
| -(defmacro with-core-macros | |
| - [path & body] | |
| - `(do | |
| - (when (not= *cljs-macros-path* ~path) | |
| - (reset! -cljs-macros-loaded false)) | |
| - (binding [*cljs-macros-path* ~path] | |
| - ~@body))) | |
| - | |
| -(defmacro with-core-macros-file | |
| - [path & body] | |
| - `(do | |
| - (when (not= *cljs-macros-path* ~path) | |
| - (reset! -cljs-macros-loaded false)) | |
| - (binding [*cljs-macros-path* ~path | |
| - *cljs-macros-is-classpath* false] | |
| - ~@body))) | |
| +;;(defmacro with-core-macros | |
| +;; [path & body] | |
| +;; `(do | |
| +;; (when (not= *cljs-macros-path* ~path) | |
| +;; (reset! -cljs-macros-loaded false)) | |
| +;; (binding [*cljs-macros-path* ~path] | |
| +;; ~@body))) | |
| +;; | |
| +;;(defmacro with-core-macros-file | |
| +;; [path & body] | |
| +;; `(do | |
| +;; (when (not= *cljs-macros-path* ~path) | |
| +;; (reset! -cljs-macros-loaded false)) | |
| +;; (binding [*cljs-macros-path* ~path | |
| +;; *cljs-macros-is-classpath* false] | |
| +;; ~@body))) | |
| (defn empty-env [] | |
| {:ns (@namespaces *cljs-ns*) :context :statement :locals {}}) | |
| -(defmacro ^:private debug-prn | |
| - [& args] | |
| - `(.println System/err (str ~@args))) | |
| +;;(defmacro ^:private debug-prn | |
| +;; [& args] | |
| +;; `(.println System/err (str ~@args))) | |
| (defn warning [env s] | |
| (binding [*out* *err*] | |
| @@ -128,7 +144,7 @@ | |
| {:name (symbol (str full-ns) (str (name sym))) | |
| :ns full-ns})) | |
| - (.contains s ".") | |
| + (>= (.indexOf s ".") 0) | |
| (let [idx (.indexOf s ".") | |
| prefix (symbol (subs s 0 idx)) | |
| suffix (subs s (inc idx)) | |
| @@ -173,7 +189,7 @@ | |
| ns (if (= "clojure.core" ns) "cljs.core" ns)] | |
| {:name (symbol (str (resolve-ns-alias env ns)) (name sym))}) | |
| - (.contains s ".") | |
| + (>= (.indexOf s ".") 0) | |
| (let [idx (.indexOf s ".") | |
| prefix (symbol (subs s 0 idx)) | |
| suffix (subs s idx) | |
| @@ -213,8 +229,8 @@ | |
| (def ^:dynamic *recur-frames* nil) | |
| (def ^:dynamic *loop-lets* nil) | |
| -(defmacro disallowing-recur [& body] | |
| - `(binding [*recur-frames* (cons nil *recur-frames*)] ~@body)) | |
| +;;(defmacro disallowing-recur [& body] | |
| +;; `(binding [*recur-frames* (cons nil *recur-frames*)] ~@body)) | |
| (defn analyze-keyword | |
| [env sym] | |
| @@ -472,7 +488,7 @@ | |
| bindings (seq (partition 2 bindings))] | |
| (if-let [[name init] (first bindings)] | |
| (do | |
| - (assert (not (or (namespace name) (.contains (str name) "."))) (str "Invalid local name: " name)) | |
| + (assert (not (or (namespace name) (>= (.indexOf (str name) ".") 0))) (str "Invalid local name: " name)) | |
| (let [init-expr (analyze env init) | |
| be {:name name | |
| :init init-expr | |
| @@ -589,12 +605,12 @@ | |
| (declare analyze-file) | |
| -(defn analyze-deps [deps] | |
| - (doseq [dep deps] | |
| - (when-not (:defs (@namespaces dep)) | |
| - (let [relpath (ns->relpath dep)] | |
| - (when (io/resource relpath) | |
| - (analyze-file relpath)))))) | |
| +;; (defn analyze-deps [deps] | |
| +;; (doseq [dep deps] | |
| +;; (when-not (:defs (@namespaces dep)) | |
| +;; (let [relpath (ns->relpath dep)] | |
| +;; (when (io/resource relpath) | |
| +;; (analyze-file relpath)))))) | |
| (defmethod parse 'ns | |
| [_ env [_ name & args :as form] _] | |
| @@ -666,7 +682,9 @@ | |
| (apply merge-with merge m (map (spec-parsers k) libs))) | |
| {} (remove (fn [[r]] (= r :refer-clojure)) args))] | |
| (when (seq @deps) | |
| - (analyze-deps @deps)) | |
| + ;; (analyze-deps @deps) | |
| + (println "**** Skipping analyze-deps ****") | |
| + ) | |
| (set! *cljs-ns* name) | |
| (load-core) | |
| (doseq [nsym (concat (vals requires-macros) (vals uses-macros))] | |
| @@ -846,25 +864,19 @@ | |
| (assoc ret :op :var :info lb) | |
| (assoc ret :op :var :info (resolve-existing-var env sym))))) | |
| +(defn is-macro? [sym] | |
| + (let [var (resolve-existing-var (empty-env) sym) | |
| + ns (:ns var) | |
| + name (symbol (name (:name var)))] | |
| + (get-in @namespaces [:macros ns name]))) | |
| + | |
| (defn get-expander [sym env] | |
| - (let [mvar | |
| - (when-not (or (-> env :locals sym) ;locals hide macros | |
| - (and (or (-> env :ns :excludes sym) | |
| - (get-in @namespaces [(-> env :ns :name) :excludes sym])) | |
| - (not (or (-> env :ns :uses-macros sym) | |
| - (get-in @namespaces [(-> env :ns :name) :uses-macros sym]))))) | |
| - (if-let [nstr (namespace sym)] | |
| - (when-let [ns (cond | |
| - (= "clojure.core" nstr) (find-ns 'cljs.core) | |
| - (.contains nstr ".") (find-ns (symbol nstr)) | |
| - :else | |
| - (-> env :ns :requires-macros (get (symbol nstr))))] | |
| - (.findInternedVar ^clojure.lang.Namespace ns (symbol (name sym)))) | |
| - (if-let [nsym (-> env :ns :uses-macros sym)] | |
| - (.findInternedVar ^clojure.lang.Namespace (find-ns nsym) sym) | |
| - (.findInternedVar ^clojure.lang.Namespace (find-ns 'cljs.core) sym))))] | |
| - (when (and mvar (.isMacro ^clojure.lang.Var mvar)) | |
| - @mvar))) | |
| + (let [var (resolve-existing-var (empty-env) sym) | |
| + ns (:ns var) | |
| + name (symbol (name (:name var)))] | |
| + ;(println "// get-expander:" sym ns name) | |
| + (when (is-macro? sym) | |
| + (js/eval (str ns "." name))))) | |
| (defn macroexpand-1 [env form] | |
| (let [op (first form)] | |
| @@ -944,10 +956,10 @@ | |
| facilitate code walking without knowing the details of the op set." | |
| ([env form] (analyze env form nil)) | |
| ([env form name] | |
| - (let [form (if (instance? clojure.lang.LazySeq form) | |
| + (let [form (if (instance? cljs.core.LazySeq form) | |
| (or (seq form) ()) | |
| form)] | |
| - (load-core) | |
| + ;;(load-core) | |
| (cond | |
| (symbol? form) (analyze-symbol env form) | |
| (and (seq? form) (seq form)) (analyze-seq env form name) | |
| @@ -957,19 +969,19 @@ | |
| (keyword? form) (analyze-keyword env form) | |
| :else {:op :constant :env env :form form})))) | |
| -(defn analyze-file | |
| - [^String f] | |
| - (let [res (if (re-find #"^file://" f) (java.net.URL. f) (io/resource f))] | |
| - (assert res (str "Can't find " f " in classpath")) | |
| - (binding [*cljs-ns* 'cljs.user | |
| - *cljs-file* (.getPath ^java.net.URL res) | |
| - *ns* *reader-ns*] | |
| - (with-open [r (io/reader res)] | |
| - (let [env (empty-env) | |
| - pbr (clojure.lang.LineNumberingPushbackReader. r) | |
| - eof (Object.)] | |
| - (loop [r (read pbr false eof false)] | |
| - (let [env (assoc env :ns (get-namespace *cljs-ns*))] | |
| - (when-not (identical? eof r) | |
| - (analyze env r) | |
| - (recur (read pbr false eof false)))))))))) | |
| +;; (defn analyze-file | |
| +;; [^String f] | |
| +;; (let [res (if (re-find #"^file://" f) (java.net.URL. f) (io/resource f))] | |
| +;; (assert res (str "Can't find " f " in classpath")) | |
| +;; (binding [*cljs-ns* 'cljs.user | |
| +;; *cljs-file* (.getPath ^java.net.URL res) | |
| +;; *ns* *reader-ns*] | |
| +;; (with-open [r (io/reader res)] | |
| +;; (let [env (empty-env) | |
| +;; pbr (clojure.lang.LineNumberingPushbackReader. r) | |
| +;; eof (Object.)] | |
| +;; (loop [r (read pbr false eof false)] | |
| +;; (let [env (assoc env :ns (get-namespace *cljs-ns*))] | |
| +;; (when-not (identical? eof r) | |
| +;; (analyze env r) | |
| +;; (recur (read pbr false eof false)))))))))) | |
| diff --git a/src/clj/cljs/compiler.clj b/src/clj/cljs/compiler.clj | |
| index 4f5e1e4..965b2ed 100644 | |
| --- a/src/clj/cljs/compiler.clj | |
| +++ b/src/clj/cljs/compiler.clj | |
| @@ -778,6 +778,15 @@ | |
| (ana/analyze-file "cljs/core.cljs")) | |
| ~@body)) | |
| +(defn ns-snap [ns] | |
| + (let [nss1 (dissoc (get @ana/namespaces ns) :requires-macros) | |
| + nss2 (read-string (pr-str (update-in nss1 | |
| + [:defs] dissoc '/)))] | |
| + (apply str | |
| + (emit (ana/analyze (ana/empty-env) | |
| + (list 'swap! 'cljs.core/namespaces 'assoc (list 'quote ns) (list 'quote nss2))))))) | |
| + | |
| + | |
| (defn compile-file* [src dest] | |
| (with-core-cljs | |
| (with-open [out ^java.io.Writer (io/make-writer dest {})] | |
| @@ -797,10 +806,13 @@ | |
| (if (= (:op ast) :ns) | |
| (recur (rest forms) (:name ast) (merge (:uses ast) (:requires ast))) | |
| (recur (rest forms) ns-name deps)))) | |
| - {:ns (or ns-name 'cljs.user) | |
| - :provides [ns-name] | |
| - :requires (if (= ns-name 'cljs.core) (set (vals deps)) (conj (set (vals deps)) 'cljs.core)) | |
| - :file dest})))))) | |
| + (do | |
| + (println "\n// Analyzer namespace snapshot:") | |
| + (ns-snap ns-name) | |
| + {:ns (or ns-name 'cljs.user) | |
| + :provides [ns-name] | |
| + :requires (if (= ns-name 'cljs.core) (set (vals deps)) (conj (set (vals deps)) 'cljs.core)) | |
| + :file dest}))))))) | |
| (defn requires-compilation? | |
| "Return true if the src file requires compilation." | |
| diff --git a/src/cljs/cljs/core.cljs b/src/cljs/cljs/core.cljs | |
| index 3bb58ef..c4eb5a6 100644 | |
| --- a/src/cljs/cljs/core.cljs | |
| +++ b/src/cljs/cljs/core.cljs | |
| @@ -1453,6 +1453,7 @@ reduces them without incurring seq initialization" | |
| ([x] (cond | |
| (symbol? x) (. x (substring 2 (alength x))) | |
| (keyword? x) (str* ":" (. x (substring 2 (alength x)))) | |
| + (regexp? x) (.-source x) | |
| (nil? x) "" | |
| :else (. x (toString)))) | |
| ([x & ys] | |
| @@ -7210,3 +7211,92 @@ reduces them without incurring seq initialization" | |
| (-hash [this] | |
| (goog.string/hashCode (pr-str this)))) | |
| + | |
| +;;;;;;;;;;;;;;;;;; PushbackReader ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| + | |
| +(defprotocol PushbackReader | |
| + (read-char [reader] "Returns the next char from the Reader, | |
| +nil if the end of stream has been reached") | |
| + (unread [reader ch] "Push back a single character on to the stream")) | |
| + | |
| +; Using two atoms is less idomatic, but saves the repeat overhead of map creation | |
| +(deftype StringPushbackReader [s index-atom buffer-atom] | |
| + PushbackReader | |
| + (read-char [reader] | |
| + (if (empty? @buffer-atom) | |
| + (let [idx @index-atom] | |
| + (swap! index-atom inc) | |
| + (aget s idx)) | |
| + (let [buf @buffer-atom] | |
| + (swap! buffer-atom rest) | |
| + (first buf)))) | |
| + (unread [reader ch] (swap! buffer-atom #(cons ch %)))) | |
| + | |
| +(defn push-back-reader [s] | |
| + "Creates a StringPushbackReader from a given string" | |
| + (StringPushbackReader. s (atom 0) (atom nil))) | |
| + | |
| +;;;;;;;;;;;;;;;;;; Namespace/Vars/Macro hackery ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| + | |
| +(def namespaces (atom '{cljs.core {:name cljs.core} | |
| + cljs.user {:name cljs.user}})) | |
| + | |
| +(defn setMacro [sym] | |
| + (let [ns (symbol (or (namespace sym) | |
| + (try cljs.analyzer/*cljs-ns* | |
| + (catch js/Error e 'cljs.core)))) | |
| + name (symbol (name sym))] | |
| + (swap! namespaces assoc-in [:macros ns name] true)) | |
| + nil) | |
| + | |
| +(def | |
| + | |
| + ^{:doc "Like defn, but the resulting function name is declared as a | |
| + macro and will be used as a macro by the compiler when it is | |
| + called." | |
| + :arglists '([name doc-string? attr-map? [params*] body] | |
| + [name doc-string? attr-map? ([params*] body)+ attr-map?]) | |
| + :added "1.0"} | |
| + defmacro (fn [&form &env | |
| + name & args] | |
| + (let [prefix (loop [p (list name) args args] | |
| + (let [f (first args)] | |
| + (if (string? f) | |
| + (recur (cons f p) (next args)) | |
| + (if (map? f) | |
| + (recur (cons f p) (next args)) | |
| + p)))) | |
| + fdecl (loop [fd args] | |
| + (if (string? (first fd)) | |
| + (recur (next fd)) | |
| + (if (map? (first fd)) | |
| + (recur (next fd)) | |
| + fd))) | |
| + fdecl (if (vector? (first fdecl)) | |
| + (list fdecl) | |
| + fdecl) | |
| + add-implicit-args (fn [fd] | |
| + (let [args (first fd)] | |
| + (cons (vec (cons '&form (cons '&env args))) (next fd)))) | |
| + add-args (fn [acc ds] | |
| + (if (nil? ds) | |
| + acc | |
| + (let [d (first ds)] | |
| + (if (map? d) | |
| + (conj acc d) | |
| + (recur (conj acc (add-implicit-args d)) (next ds)))))) | |
| + fdecl (seq (add-args [] fdecl)) | |
| + decl (loop [p prefix d fdecl] | |
| + (if p | |
| + (recur (next p) (cons (first p) d)) | |
| + d))] | |
| + (list 'do | |
| + (list 'def (first decl) (cons `fn* (first (rest decl)))) | |
| + #_(cons `defn decl) | |
| + #_(list '. (list 'var name) '(setMacro)) | |
| + (list 'cljs.core/setMacro (list 'quote name)) | |
| + #_(list 'var name))))) | |
| + | |
| +#_(. (var defmacro) (setMacro)) | |
| +(setMacro 'cljs.core/defmacro) | |
| + | |
| diff --git a/src/cljs/cljs/reader.cljs b/src/cljs/cljs/reader.cljs | |
| index 36c1592..0ec9dcd 100644 | |
| --- a/src/cljs/cljs/reader.cljs | |
| +++ b/src/cljs/cljs/reader.cljs | |
| @@ -7,29 +7,8 @@ | |
| ; You must not remove this notice, or any other, from this software. | |
| (ns cljs.reader | |
| - (:require [goog.string :as gstring])) | |
| - | |
| -(defprotocol PushbackReader | |
| - (read-char [reader] "Returns the next char from the Reader, | |
| -nil if the end of stream has been reached") | |
| - (unread [reader ch] "Push back a single character on to the stream")) | |
| - | |
| -; Using two atoms is less idomatic, but saves the repeat overhead of map creation | |
| -(deftype StringPushbackReader [s index-atom buffer-atom] | |
| - PushbackReader | |
| - (read-char [reader] | |
| - (if (empty? @buffer-atom) | |
| - (let [idx @index-atom] | |
| - (swap! index-atom inc) | |
| - (aget s idx)) | |
| - (let [buf @buffer-atom] | |
| - (swap! buffer-atom rest) | |
| - (first buf)))) | |
| - (unread [reader ch] (swap! buffer-atom #(cons ch %)))) | |
| - | |
| -(defn push-back-reader [s] | |
| - "Creates a StringPushbackReader from a given string" | |
| - (StringPushbackReader. s (atom 0) (atom nil))) | |
| + (:require [goog.string :as gstring] | |
| + [cljs.analyzer :as ana])) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; predicates | |
| @@ -368,6 +347,136 @@ nil if the end of stream has been reached") | |
| (with-meta o (merge (meta o) m)) | |
| (reader-error rdr "Metadata can only be applied to IWithMetas"))))) | |
| +(def UNQUOTE :__thisInternalKeywordRepresentsUnquoteToTheReader__) | |
| +(def UNQUOTE-SPICING :__thisInternalKeywordRepresentsUnquoteSplicingToTheReader__) | |
| + | |
| +(declare syntaxQuote) | |
| +(def ^:dynamic *gensym-env* (atom nil)) | |
| + | |
| +(defn isUnquote? [form] | |
| + (and (satisfies? ISeq form) (= (first form) UNQUOTE))) | |
| + | |
| +(defn isUnquoteSplicing? [form] | |
| + (and (satisfies? ISeq form) (= (first form) UNQUOTE-SPLICING))) | |
| + | |
| +(defn sqExpandList [sq] | |
| + (doall | |
| + (for [item sq] | |
| + (cond | |
| + (isUnquote? item) | |
| + (list 'list (second item)) | |
| + | |
| + (isUnquoteSplicing? item) | |
| + (second item) | |
| + | |
| + :else | |
| + (list 'list (syntaxQuote item)) | |
| + )))) | |
| + | |
| +(defn syntaxQuote [form] | |
| + (cond | |
| + ;; (Compiler.isSpecial(form)) | |
| + (get ana/specials form) | |
| + (list 'quote form) | |
| + | |
| + ;; (form instanceof Symbol) | |
| + (symbol? form) | |
| + (let [sym form | |
| + name (name sym) | |
| + ns (namespace sym) | |
| + var (ana/resolve-existing-var (ana/empty-env) sym)] | |
| + (cond | |
| + ;; no namespace and name ends with # | |
| + (and (not ns) (= "#" (last name))) | |
| + (let [new-name (subs name 0 (- (count name) 1)) | |
| + gmap @*gensym-env*] | |
| + (when (not gmap) | |
| + (reader-error nil "Gensym literal not in syntax-quote")) | |
| + (let [gs (or (get gmap sym) | |
| + (gensym (str new-name "__auto__")))] | |
| + (swap! *gensym-env* assoc sym gs) | |
| + (list 'quote gs))) | |
| + | |
| + ;; no namespace and name ends with . | |
| + (and (not ns) (= "." (last name))) | |
| + (let [new-name (subs name 0 (- (count name) 1)) | |
| + new-var (ana/resolve-existing-var | |
| + (ana/empty-env) (symbol new-name))] | |
| + (list 'quote (:name new-var))) | |
| + | |
| + ;; no namespace and name begins with . | |
| + (and (not ns) (= "." (first name))) | |
| + (list 'quote sym) | |
| + | |
| + ;; resolve symbol | |
| + :else | |
| + (list 'quote | |
| + (:name | |
| + (cljs.analyzer/resolve-existing-var (cljs.analyzer/empty-env) sym))))) | |
| + | |
| + ;; (isUnquote(form)) | |
| + (isUnquote? form) | |
| + (second form) | |
| + | |
| + ;; (isUnquoteSplicing(form)) | |
| + (isUnquoteSplicing? form) | |
| + (reader-error rdr "Reader ~@ splice not in list") | |
| + | |
| + ;; (form instanceof IPersistentCollection) | |
| + (satisfies? ICollection form) | |
| + (cond | |
| + (satisfies? IRecord form) | |
| + form | |
| + | |
| + (satisfies? IMap form) | |
| + (list 'apply 'hash-map (list 'seq (cons 'concat (sqExpandList (apply concat (seq form)))))) | |
| + | |
| + (satisfies? IVector form) | |
| + (list 'apply 'vector (list 'seq (cons 'concat (sqExpandList form)))) | |
| + | |
| + (satisfies? ISet form) | |
| + (list 'apply 'hash-set (list 'seq (cons 'concat (sqExpandList (seq form))))) | |
| + | |
| + (or (satisfies? ISeq form) (satisfies? IList form)) | |
| + (if-let [sq (seq form)] | |
| + (list 'seq (cons 'concat (sqExpandList sq))) | |
| + (cons 'list nil)) | |
| + | |
| + :else | |
| + (reader-error rdr "Unknown Collection type")) | |
| + | |
| + ;; (form instanceof Keyword || form instanceof Number || | |
| + ;; form instanceof Character || form instanceof String) | |
| + (or (keyword? form) (number? form) (string? form)) | |
| + form | |
| + | |
| + :else | |
| + (list 'quote form) | |
| + )) | |
| + | |
| +(defn read-syntax-quote | |
| + [rdr _] | |
| + (binding [*gensym-env* (atom {})] | |
| + (let [form (read rdr true nil true)] | |
| + (syntaxQuote form)))) | |
| + | |
| +(defn read-unquote | |
| + [rdr _] | |
| + (let [ch (read-char rdr)] | |
| + (cond | |
| + (= nil ch) | |
| + (reader-error rdr "EOF while reading character") | |
| + | |
| + (= "@" ch) | |
| + (let [o (read rdr true nil true)] | |
| + (list UNQUOTE-SPLICING o)) | |
| + | |
| + :else | |
| + (do | |
| + (unread rdr ch) | |
| + (let [o (read rdr true nil true)] | |
| + (list UNQUOTE o)))))) | |
| + | |
| (defn read-set | |
| [rdr _] | |
| (set (read-delimited-list "}" rdr true))) | |
| @@ -389,8 +498,8 @@ nil if the end of stream has been reached") | |
| (identical? c \') (wrapping-reader 'quote) | |
| (identical? c \@) (wrapping-reader 'deref) | |
| (identical? c \^) read-meta | |
| - (identical? c \`) not-implemented | |
| - (identical? c \~) not-implemented | |
| + (identical? c \`) read-syntax-quote | |
| + (identical? c \~) read-unquote | |
| (identical? c \() read-list | |
| (identical? c \)) read-unmatched-delimiter | |
| (identical? c \[) read-vector | |
| diff --git a/src/cljs/goog.js b/src/cljs/goog.js | |
| new file mode 100644 | |
| index 0000000..9be0a56 | |
| --- /dev/null | |
| +++ b/src/cljs/goog.js | |
| @@ -0,0 +1,37 @@ | |
| +// Simple module wrapper around Google Closure Library | |
| +// goog/ directory should be in the same directory as this file | |
| + | |
| +goog = exports; | |
| +path_ = require("path"); | |
| +googDir_ = path_.join(path_.dirname(module.filename), "goog"); | |
| + | |
| +rawLoaded_ = {}; | |
| +rawLoad_ = function(file) { | |
| + var path = path_.resolve(googDir_, file); | |
| + //console.log("rawLoad_ file:", file, "path:", path); | |
| + | |
| + if (rawLoaded_[path]) { return; } | |
| + rawLoaded_[path] = true; | |
| + | |
| + var contents = require('fs').readFileSync(path); | |
| + // TODO: cljs.nodejscli needs require, but this is gross | |
| + global.require = require; | |
| + process.binding('evals').NodeScript. | |
| + runInThisContext.call(global, contents, file); | |
| +}; | |
| + | |
| +rawLoad_('base.js'); | |
| +goog.global = goog.window = global.top = global; | |
| +rawLoad_('deps.js'); | |
| + | |
| +// Override goog.require script loader/evaluator | |
| +goog.writeScriptTag_ = function(file) { | |
| + try { | |
| + rawLoad_(file); | |
| + } catch (exc) { | |
| + console.error('Could not goog.require("' + file + '")\n' + exc.stack); | |
| + process.exit(1); | |
| + } | |
| + return false; | |
| +}; | |
| + |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment