Really fix handling of ::keywords using aliases
With this patch, Marginalia installs a custom keyword reader during parsing. This reader reuses clojure.lang.LispReader's readToken and matchSymbol methods to read in either the whole keyword (when faced with a single-colon keyword) or the part following the first colon (a single-colon keyword, if we get to this case). Single-colon keywords may have arbitrary namespace parts, so no aliasing issues arise. The object returned depends on the type of keyword being read in: * :foo, :foo/bar => just the keyword * ::foo/bar => (DoubleColonKeyword. :foo/bar) DCK's print-method writes out a single colon followed by the string representation of the DCK's contents, for the genuine double-colon keyword look. Note that readToken and matchSymbol are private; this patch uses clojure.contrib.reflect/call-method to call them.
This commit is contained in:
parent
f7f63b1149
commit
0374c221d9
2 changed files with 34 additions and 2 deletions
|
@ -4,7 +4,7 @@
|
|||
(ns marginalia.parser
|
||||
"Provides the parsing facilities for Marginalia."
|
||||
(:refer-clojure :exclude [replace])
|
||||
(:use [clojure.contrib [reflect :only (get-field)]]
|
||||
(:use [clojure.contrib [reflect :only (get-field call-method)]]
|
||||
[clojure [string :only (join replace)]]))
|
||||
|
||||
(defrecord Comment [content])
|
||||
|
@ -39,6 +39,34 @@
|
|||
(int \;)
|
||||
reader))
|
||||
|
||||
(defrecord DoubleColonKeyword [content])
|
||||
|
||||
(defmethod print-method DoubleColonKeyword [dck ^java.io.Writer out]
|
||||
(.write out (str \: (.content dck))))
|
||||
|
||||
(letfn [(read-token [reader c]
|
||||
(call-method clojure.lang.LispReader :readToken
|
||||
[java.io.PushbackReader Character/TYPE]
|
||||
nil reader c))
|
||||
(match-symbol [s]
|
||||
(call-method clojure.lang.LispReader :matchSymbol
|
||||
[String]
|
||||
nil s))]
|
||||
(defn read-keyword [reader colon]
|
||||
(let [c (.read reader)]
|
||||
(if (= \: c)
|
||||
(-> (read-token reader c)
|
||||
match-symbol
|
||||
DoubleColonKeyword.)
|
||||
(do (.unread reader c)
|
||||
(-> (read-token reader colon)
|
||||
match-symbol))))))
|
||||
|
||||
(defn set-keyword-reader [reader]
|
||||
(aset (get-field clojure.lang.LispReader :macros nil)
|
||||
(int \:)
|
||||
reader))
|
||||
|
||||
(defn skip-spaces-and-comments [rdr]
|
||||
(loop [c (.read rdr)]
|
||||
(cond (= c -1) nil
|
||||
|
@ -263,11 +291,14 @@
|
|||
old-cmt-rdr (aget (get-field clojure.lang.LispReader :macros nil) (int \;))]
|
||||
(try
|
||||
(set-comment-reader read-comment)
|
||||
(set-keyword-reader read-keyword)
|
||||
(let [parsed-code (-> reader parse* doall)]
|
||||
(set-comment-reader old-cmt-rdr)
|
||||
(set-keyword-reader nil)
|
||||
(arrange-in-sections parsed-code lines))
|
||||
(catch Exception e
|
||||
(set-comment-reader old-cmt-rdr)
|
||||
(set-keyword-reader nil)
|
||||
(throw e)))))
|
||||
|
||||
(defn parse-file [file]
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
;(is (= (count (marginalia.parser/parse "(ns test)\n123")) 1)) still failing
|
||||
(is (= (count (marginalia.parser/parse "(ns test)\n123\n")) 1))
|
||||
(is (= (count (marginalia.parser/parse "(ns test)\n\"string\"")) 1))
|
||||
(is (= (count (marginalia.parser/parse "(ns test)\n\"some string\"")) 1)))
|
||||
(is (= (count (marginalia.parser/parse "(ns test)\n\"some string\"")) 1))
|
||||
(is (= (count (marginalia.parser/parse "(ns test (:require [marginalia.parser :as parser]))\n(defn foo [] ::parser/foo)")) 1)))
|
||||
|
|
Loading…
Reference in a new issue