Skip to content

Commit

Permalink
Search for more fields via reflection. Update README. Support HostArg
Browse files Browse the repository at this point in the history
  • Loading branch information
frenchy64 committed Mar 13, 2013
1 parent 958c565 commit 211a69e
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 17 deletions.
194 changes: 187 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,193 @@
# clr.tools.analyzer
# Interface to ClojureCLR's Analyzer

A ClojureCLR library designed to ... well, that part is up to you.
ClojureCLR's analysis compilation phase holds rich information about Clojure forms, like type/reflection information.

## Usage
_analyze_ provides an interface to this phase, callable a la carte. The output is similar to ClojureScript's analyzer.

FIXME
Supports ClojureCLR 1.4.1 or later.

## License
# Contributing

Copyright © 2012 FIXME
Pull requests accepted from registered Clojure contributers

Distributed under the Eclipse Public License, the same as Clojure.
http://clojure.org/contributing

# Usage

## Generating AST from syntax

```clojure

clojure.clr.tools.analyzer=> (ast [1])
{:op :constant, :env {:locals {}, :ns {:name clojure.clr.tools.analyzer}}, :val [1]}

clojure.clr.tools.analyzer=> (-> (ast (if true 1 2)) clojure.pprint/pprint)
{:op :if,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:test
{:op :boolean,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val true},
:then
{:op :number,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val 1},
:else
{:op :number,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val 2}}
nil

clojure.clr.tools.analyzer=> (-> (ast (fn [x] (+ x 1))) clojure.pprint/pprint)
{:op :meta,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:meta
{:op :map,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:keyvals
({:op :keyword,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val :source-span}
{:op :map,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:keyvals
({:op :keyword,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val :start-line}
{:op :number,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val 12}
{:op :keyword,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val :start-column}
{:op :number,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val 10}
{:op :keyword,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val :end-line}
{:op :number,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val 12}
{:op :keyword,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val :end-column}
{:op :number,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val 25})})},
:expr
{:name clojure.clr.tools.analyzer$fn__3171,
:op :fn-expr,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:methods
({:op :fn-method,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:body
{:op :do,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:exprs
({:op :static-method,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:class clojure.lang.Numbers,
:method
{:name add,
:return-type System.Object,
:declaring-class clojure.lang.Numbers,
:parameter-types [System.Object System.Int64],
:flags #{:hide-by-sig :reuse-slot :static :public}},
:args
({:op :host-arg,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:expr
{:op :local-binding-expr,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:local-binding
{:op :local-binding,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:sym x,
:tag nil,
:init nil},
:tag nil}}
{:op :host-arg,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:expr
{:op :number,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:val 1}}),
:tag nil})},
:required-params
({:op :local-binding,
:env {:locals {}, :ns {:name clojure.clr.tools.analyzer}},
:sym x,
:tag nil,
:init nil}),
:rest-param nil}),
:variadic-method nil,
:tag nil}}
nil
```

## Syntax from AST


```clojure
clojure.jvm.tools.analyzer=> (require '[clojure.jvm.tools.analyzer.emit-form :as e])
nil
clojure.jvm.tools.analyzer=> (-> (ast 1) e/emit-form)
1
clojure.jvm.tools.analyzer=> (-> (ast [(+ 1 2)]) e/emit-form)
[(clojure.lang.Numbers/add 1 2)]
```

# Known Issues

## Evaluating forms

Currently the analyzer evaluates each form after it is analyzed.

## Incorrect handling of Var mappings within the same form

`analyze` is a thin wrapper over `clojure.lang.Compiler`, so to get our
hands on analysis results some compromises are made.

The following form normally evaluates to the Var `clojure.set/intersection`, but
analyses to `clojure.core/require`.


```clojure
;normal evaluation
(eval
'(do
(require '[clojure.set])
(refer 'clojure.set
:only '[intersection]
:rename '{intersection require})
require))
;=> #'clojure.set/intersection

;analysis result
(-> (ast
(do (require '[clojure.set])
(refer 'clojure.set
:only '[intersection]
:rename '{intersection require})
require))
:exprs last :var)
;=> #'clojure.core/require
```

# Todo

- analyze a leiningen `project.clj` file
- analyze `clojure.core`
- use :locals if necessary

# Examples

See `clojure.jvm.tools.analyzer.examples.*` namespaces.

# Contributors

- Jonas Enlund (jonase)
- Nicola Mometto (Bronsa)
- Chris Gray (chrismgray)
33 changes: 23 additions & 10 deletions src/clojure/clr/tools/analyzer.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
(ns clojure.clr.tools.analyzer
"Interface to Compiler's analyze.
Entry point `analyze-path` and `analyze-one`"
(:require [clojure.reflect :as reflect]
[clojure.clr.io :as io]
[clojure.repl :as repl]
[clojure.string :as string]
[clojure.set :as set]
[clojure.clr.tools.analyzer.util])
(:import (System.IO TextReader)
(System.Reflection BindingFlags)
(clojure.lang RT Compiler LineNumberingTextReader)
Expand All @@ -17,13 +23,8 @@
MapExpr IfExpr KeywordInvokeExpr InstanceFieldExpr InstanceOfExpr
CaseExpr Expr SetExpr MethodParamExpr KeywordExpr
ConstantExpr NumberExpr NilExpr BooleanExpr StringExpr
ObjMethod ParserContext RHC)
(clojure.reflect Field))
(:require [clojure.reflect :as reflect]
[clojure.clr.io :as io]
[clojure.repl :as repl]
[clojure.string :as string]
[clojure.clr.tools.analyzer.util]))
ObjMethod ParserContext RHC HostArg)
(clojure.reflect Field)))

(def CHILDREN (atom false))
(def JAVA-OBJ (atom false))
Expand Down Expand Up @@ -86,9 +87,10 @@
first)
_ (assert clj-field)
reflect-flags (.flags clj-field)
binding-flags (set (->> reflect-flags
(map reflect-flag->BindingFlags)
(remove nil?)))
binding-flags (set/union (set (->> reflect-flags
(map reflect-flag->BindingFlags)
(remove nil?)))
#{BindingFlags/NonPublic BindingFlags/Public})
binding-flags (if (:static reflect-flags)
binding-flags
(conj binding-flags BindingFlags/Instance))
Expand Down Expand Up @@ -807,6 +809,17 @@
:env env
:class (.ClrType expr)
:can-emit-primitive (.CanEmitPrimitive expr)}
(when @JAVA-OBJ
{:Expr-obj expr}))))

HostArg
(analysis->map
[expr env]
(let []
(merge
{:op :host-arg
:env env
:expr (analysis->map (.ArgExpr expr) env)}
(when @JAVA-OBJ
{:Expr-obj expr})))))

Expand Down

0 comments on commit 211a69e

Please sign in to comment.