From 3fff515edbb1f334c8111e7ccf3ecbe0722613a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Marczyk?= Date: Wed, 14 Sep 2011 12:04:59 +0800 Subject: [PATCH] Fix handling of ::keywords using aliases This patch introduces namespace tracking to Marginalia's parser: ns, in-ns, require, use and alias forms are now evaluated in the proper namespace at read-time. This is necessary to handle ::keywords in full generality, since ::foo/bar is a valid token iff the symbol 'foo can be resolved to a namespace at read time: (in-ns 'test) ::foo/bar ; => invalid token results in read-time error (require '[some.namespace :as foo]) ::foo/bar ; => :some.namespace/foo NB. only top-level #{ns in-ns require use alias} forms are recognized. --- src/marginalia/parser.clj | 15 ++++++++++++++- test/marginalia/test/parse.clj | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/marginalia/parser.clj b/src/marginalia/parser.clj index b8bac3a..d675da8 100644 --- a/src/marginalia/parser.clj +++ b/src/marginalia/parser.clj @@ -15,6 +15,9 @@ (def top-level-comments (atom [])) (def sub-level-comments (atom [])) +(def user-ns (the-ns 'user)) +(def current-namespace (atom user-ns)) + (def *comments* nil) (defn read-comment [reader semicolon] @@ -49,6 +52,14 @@ (recur (.read rdr)) :else (.unread rdr c)))) +(defn maybe-change-namespace [form] + (when (and (seq? form) + ('#{ns in-ns require use alias} (first form))) + (binding [*ns* @current-namespace] + (eval form)) + (when ('#{ns in-ns} (first form)) + (reset! current-namespace (the-ns (second form)))))) + (defn parse* [reader] (take-while :form @@ -58,12 +69,14 @@ (binding [*comments* top-level-comments] (skip-spaces-and-comments reader)) (let [start (.getLineNumber reader) - form (binding [*comments* sub-level-comments] + form (binding [*comments* sub-level-comments + *ns* @current-namespace] (. clojure.lang.LispReader (read reader false nil false))) end (.getLineNumber reader) code {:form form :start start :end end} comments @top-level-comments] + (maybe-change-namespace form) (swap! top-level-comments (constantly [])) (if (empty? comments) [code] diff --git a/test/marginalia/test/parse.clj b/test/marginalia/test/parse.clj index 7da8a75..5ca2928 100644 --- a/test/marginalia/test/parse.clj +++ b/test/marginalia/test/parse.clj @@ -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)))