{"id":15010259,"url":"https://github.com/clojure/tools.analyzer","last_synced_at":"2025-05-15T09:07:56.539Z","repository":{"id":11001908,"uuid":"13325180","full_name":"clojure/tools.analyzer","owner":"clojure","description":"An analyzer for Clojure code, written in Clojure and producing AST in EDN","archived":false,"fork":false,"pushed_at":"2024-07-15T17:55:45.000Z","size":1656,"stargazers_count":262,"open_issues_count":0,"forks_count":33,"subscribers_count":51,"default_branch":"master","last_synced_at":"2025-04-11T19:55:31.868Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clojure.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-10-04T13:41:24.000Z","updated_at":"2025-04-02T09:24:20.000Z","dependencies_parsed_at":"2023-01-13T16:24:53.718Z","dependency_job_id":"922b8e6e-a7fb-4cb8-aaa4-8145228b4ea4","html_url":"https://github.com/clojure/tools.analyzer","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clojure%2Ftools.analyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clojure%2Ftools.analyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clojure%2Ftools.analyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clojure%2Ftools.analyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clojure","download_url":"https://codeload.github.com/clojure/tools.analyzer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254310520,"owners_count":22049470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T19:33:13.083Z","updated_at":"2025-05-15T09:07:51.529Z","avatar_url":"https://github.com/clojure.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tools.analyzer\n\nAn analyzer for host agnostic Clojure code, written in Clojure and producing AST in EDN.\n\nI gave a talk on tools.analyzer[.jvm] at ClojureX in December 2015. Video [here](https://www.youtube.com/watch?v=oZyt93lmF5s)\n\nTimothy Baldridge gave a talk on tools.analyzer[.jvm] at Clojure/West in\nMarch 2014. Video\n[here](https://www.youtube.com/watch?v=KhRQmT22SSg\u0026list=PLZdCLR02grLp__wRg5OTavVj4wefg69hM\u0026index=11).\n\nNote that the analyzer in this library should not to be used directly as it lacks any knowledge about host-specific special forms and it should only be considered as a building platform for host-specific analyzers.\nCurrently the following platform specific analyzers written on top of tools.analyzer exist: [tools.analyzer.jvm](https://github.com/clojure/tools.analyzer.jvm), [tools.analyzer.js](https://github.com/clojure/tools.analyzer.js)\n\n* [Example Usage](#example-usage)\n* [Quickref](#quickref)\n* [Releases and Dependency Information](#releases-and-dependency-information)\n* [Changelog](#changelog)\n* [API Index](#api-index)\n* [Developer Information](#developer-information)\n* [License](#license)\n\n[Quickref](https://clojure.github.io/tools.analyzer/spec/quickref.html)\n========================================\n\n## Example Usage\n`clojure.tools.analyzer/analyze` will not work out of the box, as it requires a number of entry-points to be set.\nHere's what could happen trying to use `clojure.tools.analyzer/analyze` directly:\n```clojure\nclojure.tools.analyzer\u003e (analyze 'a {})\nAttempting to call unbound fn: #'clojure.tools.analyzer/macroexpand-1\n  [Thrown class java.lang.IllegalStateException]\n```\n\nAt the moment there exist two official analyzers written on top of [tools.analyzer](https://github.com/clojure/tools.analyzer): [tools.analyzer.jvm](https://github.com/clojure/tools.analyzer.jvm) for clojure on the JVM and [tools.analyzer.js](https://github.com/clojure/tools.analyzer.js) for clojurescript.\nWe will use [tools.analyzer.jvm](https://github.com/clojure/tools.analyzer.jvm) for those examples.\n\nHere's a simplified version of how `clojure.tools.analyzer.jvm/analyze` is defined:\n```clojure\n(require '[clojure.tools.analyzer :as ana])\n(require '[clojure.tools.analyzer.env :as env])\n(defn analyze [form env]\n  (binding [ana/macroexpand-1 macroexpand-1\n            ana/create-var    create-var\n            ana/parse         parse\n            ana/var?          var?]\n       (env/ensure (global-env)\n         (run-passes (-analyze form env))))))\n```\n\nHere, `-analyze` is a multimethod that defaults to `ana/analyze` and defines analysis methods for the JVM specific special forms, `global-env` is a function that returns a global environment for the JVM analyzer and `run-passes` is a function that takes an AST and applies a number of passes to it.\n\nThe `tools.analyzer.jvm` [README](https://github.com/clojure/tools.analyzer.jvm#example-usage) contains more examples on how the `analyze` function works as well as a reference for all the nodes it can return.\n\nOne of the most important features of `tools.analyzer` is the ability to walk generically through the AST nodes, this has been immensely useful to write most of the passes used by the various analyzers.\nThe `tools.analyzer.ast` namespace provides a number of functions that implement various generic AST walking strategies.\n\nThe `children` function returns a vector of the children nodes of the current node (the output has been elided and pretty-printed for clarity):\n```clojure\nclojure.tools.analyzer.jvm\u003e (require '[clojure.tools.analyzer.ast :as ast])\nnil\nclojure.tools.analyzer.jvm\u003e (ast/children (analyze '(do 1 2 :foo)))\n[{:op   :const,\n  :id   0,\n  :type :number,\n  :val  1,\n  :form 1,\n  ...}\n {:op   :const,\n  :id   1,\n  :type :number,\n  :val  2,\n  :form 2,\n  ...}\n {:op   :const,\n  :id   3,\n  :type :keyword,\n  :val  :foo,\n  :form :foo,\n  ...}]\n```\n\nIf we want to access a flattened view of all the nodes of an AST, we can use the `nodes` function:\n```clojure\nclojure.tools.analyzer.jvm\u003e (ast/nodes (analyze '[1 (+ 1 2)]))\n({:op        :vector,\n  :top-level true,\n  :items\n  [{:op   :const,\n    :type :number,\n    :val  1,\n    ...}\n   {:op     :static-call,\n    :class  clojure.lang.Numbers,\n    :method add,\n    :form   (. clojure.lang.Numbers (add 1 2)),\n    :args   [{:op  :const,\n              :val 1,\n              ...}\n             {:op  :const,\n              :val 2,\n              ...}],\n   ...}]\n  :form [1 (+ 1 2)],\n  ...}\n {:op   :const,\n  :type :number,\n  :val  1,\n  ...}\n {:op    :static-call,\n  :class  clojure.lang.Numbers,\n  :method add,\n  :form   (. clojure.lang.Numbers (add 1 2)),\n  :args [{:op  :const,\n          :val 1,\n          ...}\n         {:op  :const,\n          :val 2,\n          ...}],\n  ...}\n  ..)\n```\n\nThe `update-children` function takes an AST node and a function and replaces the children nodes of the given node with the result of applying the function to each children node.\n```clojure\nclojure.tools.analyzer.jvm\u003e (ast/update-children (analyze '(do 1 (+ 1 2) :foo))\n                               #(assoc % :visited true))\n{:op :do\n :statements\n [{:op      :const,\n   :val     1,\n   :visited true,\n   ...}\n  {:op      :static-call,\n   :class   clojure.lang.Numbers,\n   :method  add,\n   :visited true,\n   :args   [{:op  :const\n             :val 1,\n             ...}\n            {:op  :const,\n             :val 2,\n             ...}],\n   ...}]\n :ret\n {:op      :const,\n  :val     :foo,\n  :visited true,\n  ...},\n ...}\n```\nIf it's desirable to walk all the AST applying a function to all the nodes and the children nodes, one of `walk`, `prewalk` or `postwalk` should be used, read the docstrings of the three functions to understand the differences.\nHere's the previous example using `prewalk` instead of `update-children`:\n```clojure\nclojure.tools.analyzer.jvm\u003e (ast/prewalk (analyze '(do 1 (+ 1 2) :foo))\n                               #(assoc % :visited true))\n{:op      :do\n :visited true,\n :statements\n [{:op      :const,\n   :val     1,\n   :visited true,\n   ...}\n  {:op      :static-call,\n   :class   clojure.lang.Numbers,\n   :method  add,\n   :visited true,\n   :args   [{:op      :const\n             :val     1,\n             :visited true,\n             ...}\n            {:op     :const,\n             :val     2,\n             :visited true,\n             ...}],\n   ...}]\n :ret\n {:op      :const,\n  :val     :foo,\n  :visited true,\n  ...},\n ...}\n```\nAs you can see, this time all the nodes have been marked `:visited`.\n\nSince version `0.6.0`, passes can be scheduled automatically using `clojure.tools.analyzer.passes/schedule` rather than having to compose them and sort out pass dependencies manually, refer to its docstrings and examples from `tools.analyzer.jvm` for more info.\n\n## SPONSORSHIP\n\n* Cognitect (https://cognitect.com/) has sponsored tools.analyzer development (https://groups.google.com/d/msg/clojure/iaP16MHpX0E/EMtnGmOz-rgJ)\n* Ambrose BS (https://twitter.com/ambrosebs) has sponsored tools.analyzer development in his typed clojure campaign (https://www.indiegogo.com/projects/typed-clojure).\n\n## YourKit\n\nYourKit has given an open source license for their profiler, greatly simplifying the profiling of tools.analyzer performance.\n\nYourKit is kindly supporting open source projects with its full-featured Java Profiler. YourKit, LLC is the creator of innovative and intelligent tools for profiling Java and .NET applications. Take a look at YourKit's leading software products:\n\n* \u003ca href=\"https://www.yourkit.com/java/profiler/index.jsp\"\u003eYourKit Java Profiler\u003c/a\u003e and\n* \u003ca href=\"https://www.yourkit.com/.net/profiler/index.jsp\"\u003eYourKit .NET Profiler\u003c/a\u003e.\n\nReleases and Dependency Information\n========================================\n\nLatest stable release: 1.2.0\n\n* [All Released Versions](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22tools.analyzer%22)\n* [Development Snapshot Versions](https://clojure.org/releases/downloads#_using_clojure_snapshot_releases)\n\n[Leiningen](https://github.com/technomancy/leiningen) dependency information:\n\n```clojure\n[org.clojure/tools.analyzer \"1.2.0\"]\n```\n[Maven](https://maven.apache.org/) dependency information:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.clojure\u003c/groupId\u003e\n  \u003cartifactId\u003etools.analyzer\u003c/artifactId\u003e\n  \u003cversion\u003e1.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n[Changelog](CHANGELOG.md)\n========================================\n\nAPI Index\n========================================\n\n* [API index](https://clojure.github.io/tools.analyzer)\n\nDeveloper Information\n========================================\n\n* [GitHub project](https://github.com/clojure/tools.analyzer)\n* [Bug Tracker](https://clojure.atlassian.net/browse/TANAL)\n* [Continuous Integration](https://github.com/clojure/tools.analyzer/actions/workflows/test.yml)\n\n## License\n\nCopyright © Nicola Mometto, Rich Hickey \u0026 contributors.\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclojure%2Ftools.analyzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclojure%2Ftools.analyzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclojure%2Ftools.analyzer/lists"}