前書き
Clojureのソースコードを読んでいく過程を書いていきたいと思います。
2014年9月10日のmasterブランチから読み進めていきます。
https://github.com/clojure/clojure
追加された変更に関しては余裕があったら見ていきたいと思っています。
環境の準備
ひとまず、現状のコードをローカルにcloneする。
トップレベルのディレクトリにpom.xmlがあるので、ディレクトリ構造的にはmavenのプロジェクトに準じているようだ。
ディレクトリ構造はおおまかに以下のような感じになっている。
├── pom.xml
├── src
│ ├── clj
│ │ └── clojure
│ │ ├── core
│ │ ├── java
│ │ ├── pprint
│ │ ├── reflect
│ │ └── test
│ ├── jvm
│ │ └── clojure
│ │ ├── asm
│ │ │ └── commons
│ │ ├── java
│ │ │ └── api
│ │ └── lang
│ ├── resources
│ └── script
└── test
├── clojure
│ └── test_clojure
└── java
├── clojure
└── compilationd
Javaの中核となるコードはsrc/jvm/clojure/lang
にあるようなので、まずはここから読み始めた方が良さそう。
リポジトリのファイル内に.idea
ディレクトリがあることや.gitignore
に.ipr、.iwsが含まれることから開発にはIntelliJ IDEAが使われているようだ。
Community Editionをダウンロードしてインストールした。
http://www.jetbrains.com/idea/
インストール直後だとClojureのコードがシンタックスハイライトされないので、pluginのCursive Clojureをインストール。
https://cursiveclojure.com/
ひとまず、コードを読む環境は整ったと思う。
build.xmlもあるのでantでのビルドにも対応しているのだろうか。
clojure.langを読み込む
$ cd clojure/src/jvm/clojure/lang
$ ls -1 | wc -l
124
clojure.langパッケージ内にはファイルが124ある。
まずはどこから読めば良いか、分類し、確認していく。
それぞれのファイルのコード量がどの程度か見てみる。
$ find . -type f | xargs wc -l | sort
13 ./Sequential.java
14 ./IRecord.java
14 ./IType.java
15 ./IPending.java
16 ./Fn.java
16 ./IPersistentList.java
16 ./IndexedSeq.java
17 ./IBlockingDeref.java
17 ./IDeref.java
17 ./IEditableCollection.java
17 ./IHashEq.java
17 ./IKeywordLookup.java
17 ./IMeta.java
17 ./MapEquivalence.java
17 ./Reversible.java
17 ./Seqable.java
18 ./Counted.java
18 ./IObj.java
18 ./IReference.java
18 ./ITransientAssociative.java
18 ./Settable.java
19 ./Associative.java
19 ./ILookup.java
19 ./ILookupSite.java
19 ./ILookupThunk.java
19 ./IMapEntry.java
19 ./IPersistentSet.java
19 ./IPersistentStack.java
19 ./IReduce.java
19 ./ITransientSet.java
19 ./Indexed.java
19 ./Named.java
20 ./IChunk.java
20 ./IExceptionInfo.java
20 ./IPersistentVector.java
20 ./ITransientCollection.java
20 ./ITransientVector.java
21 ./IProxy.java
21 ./package.html
22 ./Box.java
22 ./ITransientMap.java
22 ./Repl.java
22 ./Script.java
22 ./WarnBoxedMath.java
23 ./IChunkedSeq.java
23 ./IPersistentCollection.java
23 ./IPersistentMap.java
23 ./Reduced.java
25 ./Sorted.java
26 ./Binding.java
27 ./IRef.java
29 ./ISeq.java
29 ./Volatile.java
32 ./ArityException.java
33 ./SeqEnumeration.java
34 ./LazilyPersistentVector.java
35 ./Obj.java
37 ./ChunkBuffer.java
40 ./AReference.java
40 ./MapEntry.java
42 ./ExceptionInfo.java
53 ./Delay.java
54 ./ATransientSet.java
54 ./StringSeq.java
55 ./Cons.java
55 ./SeqIterator.java
57 ./KeywordLookupSite.java
59 ./AFunction.java
64 ./Range.java
67 ./ChunkedCons.java
69 ./ArrayChunk.java
72 ./ProxyHandler.java
75 ./FnLoaderThunk.java
75 ./IteratorSeq.java
76 ./DynamicClassLoader.java
78 ./Compile.java
78 ./EnumerationSeq.java
78 ./Ratio.java
85 ./ARef.java
86 ./ATransientMap.java
88 ./MethodImplCache.java
89 ./XMLHandler.java
90 ./PersistentTreeSet.java
95 ./LineNumberingPushbackReader.java
104 ./Atom.java
128 ./PersistentHashSet.java
136 ./Intrinsics.java
136 ./Symbol.java
149 ./AMapEntry.java
151 ./Murmur3.java
176 ./APersistentSet.java
181 ./TransactionalHashMap.java
182 ./BigInt.java
233 ./PersistentStructMap.java
242 ./LazySeq.java
243 ./Namespace.java
248 ./Util.java
258 ./Keyword.java
262 ./ASeq.java
278 ./ArrayIter.java
287 ./Agent.java
309 ./PersistentQueue.java
316 ./PersistentList.java
351 ./LazyTransformer.java
369 ./Ref.java
406 ./APersistentMap.java
431 ./AFn.java
450 ./PersistentArrayMap.java
455 ./IFn.java
529 ./Reflector.java
586 ./MultiFn.java
597 ./APersistentVector.java
653 ./LockingTransaction.java
702 ./ArraySeq.java
715 ./Var.java
737 ./EdnReader.java
821 ./PersistentVector.java
1029 ./PersistentTreeMap.java
1180 ./PersistentHashMap.java
1281 ./LispReader.java
2295 ./RT.java
4104 ./RestFn.java
4131 ./Numbers.java
8563 ./Compiler.java
37385 total
LispReader、EdnReader、Compilerあたりがそれっぽい。
RTはおそらくリテラル。
RTはRuntimeクラス。(Practical Clojure参照 P.149 Clojureはインタプリタ持っていないとか重要なことが書いてあった。)
I〜がインターフェースでA〜が抽象クラスという命名規則かと思ったら、一部違ったりしている。
全体像がまだよくわからないのでjavadocを生成してみる。
$ mvn clean
$ mvn javadoc:javadoc
$ cd target/site/apidocs
$ open index.html
jarの生成は以下で問題なくできた。
$ mvn clean
$ mvn package
生成したjarの実行は以下のようになる。
$ java -cp ./target/clojure-1.7.0-master-SNAPSHOT.jar clojure.main