Explodes Clojure functions and macros into dependency graphs
Pull request Compare This branch is even with aphyr:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
doc
src/meitner
test/meitner
.gitignore
README.md
project.clj

README.md

Lise Meitner

Meitner

Meitner infers the static dependency graph of Clojure functions, macros, and other vars through syntactic analysis of their source. Meitner uses Riddley for macroexpansion and analysis of lexical scope. Relies on clojure.repl/source-fn, so I'm not sure how to use it outside the repl right now.

Install

Via Clojars

Try me

user=> (require ['meitner.core :refer '[deps unfold]])
nil

Here's a function:

user=> (source second)
(def
 ^{:doc "Same as (first (next x))"
   :arglists '([x])
   :added "1.0"
   :static true}
 second (fn ^:static second [x] (first (next x))))
nil

What's it depend on?

user=> (deps 'second)
#{clojure.core/next clojure.core/first}

How about a recursive function?

user=> (source last)
(def 
 ^{:arglists '([coll])
   :doc "Return the last item in coll, in linear time"
   :added "1.0"
   :static true}
 last (fn ^:static last [s]
        (if (next s)
          (recur (next s))
          (first s))))
user=> (deps 'last)
#{clojure.core/next clojure.core/last clojure.core/first}

What about the full dependency tree, pruning cycles?

user=> (pprint (unfold deps 'partition))
{partition
 {clojure.core/cons {},
  clojure.core/doall
  {clojure.core/dorun
   {clojure.core/next {},
    clojure.core/dorun :recursive,
    clojure.core/seq {}}},
  clojure.core/nthrest
  {clojure.core/nthrest :recursive,
   clojure.core/seq {},
   clojure.core/rest {}},
  clojure.core/list {},
  clojure.core/concat
  {clojure.core/cons {},
   clojure.core/first {},
   clojure.core/chunk-rest {},
   clojure.core/chunk-cons {},
   clojure.core/next {},
   clojure.core/chunked-seq? {clojure.core/instance? {}},
   clojure.core/chunk-first {},
   clojure.core/seq {},
   clojure.core/rest {}},
  clojure.core/count {},
  clojure.core/seq {},
  clojure.core/take
  {clojure.core/cons {},
   clojure.core/first {},
   clojure.core/seq {},
   clojure.core/rest {}}}}
nil

So partition depends on cons, doall (which in turn depends on dorun, which depends on next, seq, and dorun recursively), and so on.

License

Copyright © 2013 Kyle Kingsbury

Distributed under the Eclipse Public License, the same as Clojure.