diff --git a/src/deuce-loadup.el b/src/deuce-loadup.el index f6dc8fd..dd1010f 100644 --- a/src/deuce-loadup.el +++ b/src/deuce-loadup.el @@ -153,18 +153,7 @@ ;; DEUCE: minibuffer implements completion, the actual minibuffer is (not yet) in minibuf.clj ;; Autoloads (but fails) pcase, which is a pattern matcher utterly confused by Deuce's concept of cons. -;; Also, a minor mode macro which many files use is blowing up, next thing to investigate. -;; cl-macs and autoloads seem to be the main things from actually compiling and loading the rest of the needed files. -;; PersistentList instead of Cons and syntax-quoted deuce.emacs-lisp.cons/pair are known issues. -;; (Running properly is another matter altogether.) -;; The pcase issue is not really solved, but autoloads are now delayed until actually called. ;; Pcase is pretty new in Emacs terms, seems to be more of it in 24.3. -;; This enters a never ending loop in pcase.clj, works in pcase.el, something with and: -;; Emacs Lisp: -;; (pcase '(current-time . 1) (`(,(and (pred functionp) x) . ,_) (funcall x))) -;; Same in Clojure: -;; (pcase '(current-time . 1) ((#el/sym "\\`" ((#el/sym "\\," (and (pred functionp) x)) . (#el/sym "\\," _))) (funcall x))) -;; Pcase currently fails with Don't know how to create ISeq from: clojure.lang.Symbol in an odd way. ;; The problem is this: `(match ,sym ,@upat) both sym and upat are x. ;; An atom is allowed at a the tail as unquote-splicing in an Emacs Lisp, which basically uses setcdr: ;; '(match x . x) diff --git a/src/deuce/emacs/frame.clj b/src/deuce/emacs/frame.clj index a92db2d..d7edc2b 100644 --- a/src/deuce/emacs/frame.clj +++ b/src/deuce/emacs/frame.clj @@ -151,7 +151,7 @@ (defun frame-parameter (frame parameter) "Return FRAME's value for parameter PARAMETER. If FRAME is nil, describe the currently selected frame." - ) + nil) (defun framep (object) "Return non-nil if OBJECT is a frame. diff --git a/src/deuce/emacs_lisp.clj b/src/deuce/emacs_lisp.clj index f1d67e1..ab17ff8 100644 --- a/src/deuce/emacs_lisp.clj +++ b/src/deuce/emacs_lisp.clj @@ -79,7 +79,10 @@ (c/defmacro el-var-get [name] (c/let [name (sym name)] (if (c/and (symbol? name) (name &env)) - `(if (var? ~name) @~name ~name) + `(if (var? ~name) + (if (bound? ~name)@~name + (throw* '~'void-variable '~name)) + ~name) `(el-var-get* '~name)))) ;; split these out into el-var-set-** and get rid of eval in deuce.emacs.data/set(-default) @@ -95,7 +98,7 @@ `(c/let [value# ~value] (if-let [^Var v# (c/or ~(c/and (symbol? name) (name &env) name) ((some-fn *dynamic-vars* el-var-buffer-local) '~name))] - (if (c/and (.hasRoot v#) (not (.getThreadBinding v#))) + (if (c/or (c/and (.hasRoot v#) (not (.getThreadBinding v#))) (not (bound? v#))) (alter-var-root v# (constantly value#)) (var-set v# value#)) (el-var-set-default ~name value#))))) @@ -159,7 +162,9 @@ (map el->clj rst)))))))) symbol? (if (namespace x) (if (-> (resolve x) meta :macro) (resolve x) x) - (list `el-var-get x)) + (if (= '. x) + x + (list `el-var-get x))) x)) (defn ^Throwable cause [^Throwable e] @@ -177,18 +182,29 @@ (defn syntax-quote* [form] (.invoke clojure-syntax-quote nil (into-array [form]))) +;; Emacs Lisp allows an atom to be spliced if it is in the last position, like this: +;; (let ((upat 'x) (sym 'x)) +;; `(match ,sym ,@upat)) +;; => (match x . x) +(defn maybe-splice-dotted-list [x] + (if ((some-fn seq? nil?) x) x `(. ~x))) + ;; There's a version of this already defined as macro in backquote.el, use it / override it? ;; What's their relationship? (defn emacs-lisp-backquote [form] (w/postwalk #(c/cond + (c/and (seq? %) (seq? (last %)) (= `unquote-splicing (first (last %)))) + (concat (butlast %) `((unquote-splicing (maybe-splice-dotted-list ~(second (last %)))))) + (c/and (seq? %) (= '#el/sym "\\`" (first %))) (w/postwalk cons/maybe-seq (el->clj (syntax-quote* (second %)))) + (= '#el/sym "\\," %) `unquote (= '#el/sym "\\,@" %) `unquote-splicing :else %) form)) -;; Explore to either get rid of or just using the macro, not both el->clj and it +;; Explore to either get rid of or just using the macro, not both el->clj and it. ;; (c/defmacro #el/sym "\\`" [form] ;; (emacs-lisp-backquote (list '#el/sym "\\`" form))) @@ -288,15 +304,20 @@ BODY should be a list of Lisp expressions." {:arglists '([ARGS [DOCSTRING] [INTERACTIVE] BODY])} [& cdr] + (println cdr) (c/let [[args & body] cdr [docstring body] (parse-doc-string body) doc (apply str docstring) vars (remove #(re-find #"__\d+" (name %)) (keys &env)) vars (vec (remove (c/set args) vars))] ;; This is wrong as it won't share updates between original definition and the lambda var. - ;; Yet to see if this ends up being a real issue. + ;; Yet to see if this ends up being a real issue. A few days later: Indeed it is! `(c/let [closure# (zipmap '~vars - (map #(doto (Var/create (if (var? %) (deref %) %)) .setDynamic) + (map #(doto + (if (dynamic-binding?) ;; Temporary hack. + (if (var? %) % (Var/create %)) + (Var/create (if (var? %) (deref %) %))) + .setDynamic) ~vars))] (with-meta (def-helper* fn nil lambda ~args @@ -459,6 +480,10 @@ [arg] `(quote ~arg)) +;; Bindings refering to other bindings and modifying them don't work properly. +;; The vars must be created here instead of in with-local-el-vars (which might be removed). +;; Everytime you make a 'sane' assumption you're bound to find some Emacs Lisp breaking it. +;; (let* ((x 2) (y (setq x 4))) (+ x y)) => 8 (c/defmacro let-helper* [can-refer? varlist & body] (c/let [varlist (map #(if (symbol? %) [% nil] %) varlist) all-vars (map (comp sym first) varlist)