pax_global_header00006660000000000000000000000064131224500030014500gustar00rootroot0000000000000052 comment=da99d3a414cc74501714c96d1c60595f5d328935 tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/000077500000000000000000000000001312245000300210415ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/.gitignore000066400000000000000000000001721312245000300230310ustar00rootroot00000000000000/target /lib /classes /checkouts *.jar *.class .lein-deps-sum .lein-failures .lein-plugins .lein-repl-history .nrepl-port tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/CHANGELOG.md000066400000000000000000000206501312245000300226550ustar00rootroot00000000000000Changelog ======================================== Since tools.analyzer.jvm version are usually cut simultaneously with a tools.analyzer version, check also the tools.analyzer [CHANGELOG](https://github.com/clojure/tools.analyzer/blob/master/CHANGELOG.md) for changes on the corresponding version, since changes in that library will reflect on this one. - - - * Release 0.7.0 on 14 Feb 2017 * Release 0.7.0-alpha1 on 26 Jan 2017 * Added handle-evaluation-exception opts to `analyze+eval` * Changed `analyze+eval`'s default behaviour on eval exception * Stop caching maybe-class-from-string as it implicitely relies on dynamic state * Make analyze work from nested invocations -- remove state mutation * Release 0.6.10 on 17 Jun 2016 * Fix ns munging * Release 0.6.9 on 10 Nov 2015 * Correctly check for recur on case :then branches * Release 0.6.8 on 3 Nov 2015 * Fixed eof check in tools.reader usage * Avoid reflection on catch local * Fix context in analyze+eval statement * Release 0.6.7 on 23 Apr 2015 * Add support for reader conditionals * Ensure *file* is correctly bound in analyze-ns * Fixed emit-form for :host-interop * Release 0.6.6 on 23 Feb 2015 * Small performance enhancements * Added validate-recur pass * Renamed annotate-methods to annotate-host-info * Fixed class resolution * Added macroexpand-all * Fixed ::resolved-op handling in analyze+eval * Release 0.6.5 on 20 Nov 2014 * Ensure *ns* is correctly bound during analysis * Removed analyze' and analyze+eval' * Improvements in class resolution * Release 0.6.4 on 03 Nov 2014 * Disallow def of a symbol that maps to a Class * Made the target of a host interop expression privilege classnames over the lexical scope, as in clojure * Preserve correct meta on emit-form * Validate the target of a new expression * Fixed bug that caused the symbols used as primitive type hints to be interpreted as classes in host interop expressions * Made update-ns-map! an optional global-env field * Enhanced source-info support on analyze+eval * Release 0.6.3 on 27 Oct 2014 * Better interop method matcher * Fixed a bug when using analyze+eval and lein uberjar caused by Compiler/LOADER being unbound during macroexpansion * Faster maybe-class impl * Release 0.6.1 on 13 Oct 2014 * Significant performance enhancements * Made Class literals shadow Vars * Fixed a bug in :arglists automatic tag qualification * :env :locals are no longer uniquified by default, can be changed via pass-opts * Fixed tag validation * Removed annotate-class-id, annotate-internal-name, ensure-tag, collect, collect-closed-overs and clear-locals, moved to tools.emiter.jvm * Fixed a bug in the method resolution code, caused some unnecessary reflection * Added opts and env args to analyze-ns, consistent with the other analyze functions * Made emit-form with :qualified-symbols qualify def symbol * Release 0.6.0 on 18 Sep 2014 * Started using clojure.tools.analyzer.passes/schedule to schedule the default passes and configured all the passes * Reduced the set of default passes, removed: annotate-class-id, annotate-internal-name, ensure-tag * Changed the interface of the collect pass * Added default-passes and default-passes-opts to the clojure.tools.analyzer.jvm namespace * Release 0.5.6 on 02 Sep 2014 * Fixed a bug in classify-invoke that caused default-exprs in keyword invoke expressions to be lost * Release 0.5.5 on 31 Aug 2014 * Fixed analyze-ns analysis caching * Qualify :arglists class names * Release 0.5.4 on 21 Aug 2014 * Added optional unresolved symbol handler, configurable via :passes-opts * Release 0.5.3 on 14 Aug 2014 * Compare contexts with isa? rather than = * Fixed a reflection warning * Fixed a bug in the :protocol-invoke nodes that caused ast/children to crash * Release 0.5.2 on 09 Aug 2014 * Fixed emit-form * Imported collect pass from tools.analyzer * Fixed infer-tag for :def * Release 0.5.1 on 09 Aug 2014 * Allow ^:const values to be unboxed * Made :keyword a children in :keyword-invoke * Added optional Var tag inference, configurable via :passes-opts * Added optional wrong tag handler, configurable via :passes-opts * Added optional mismatched arity handler, configurable via :passes-opts * Release 0.5.0 on 29 Jul 2014 * BREAKING CHANGE: changed :protocol-invoke and :keyword-invoke fields * Made :host-interop :assignable? * Release 0.4.0 on 26 Jul 2014 * BREAKING CHANGE: update to new :class field for :new and :catch nodes * Elide source info metadata on :reify, :fn * Fixed performance regression * Added :qualified-symbols option to emit-form, deprecate :qualified-vars * Don't promote :invoke to :keyword-invoke when the keyword is namespaced * Added analyze-ns * Fixed some wrong contexts * Fixed and enhanced :tag/:arglists inference for :try nodes * Fixed handling of void bodies in loops * Collect closed-overs on :try * Release 0.3.0 on 21 Jun 2014 * BREAKING API CHANGE: Updated to new :context * Fixed 1-arity macroexpand-1 * validate throws on Var not found * Release 0.2.2 on 13 Jun 2014 * Added 1-arity version of macroexpand-1 * Made analyze+eval handle exceptions via ExceptionThrown * Fixed a bug in the validate pass that caused some instance-methods to stay unresolved * Keep :raw-forms on analyze+eval * Update \*ns\* in each call to analyze+eval * Release 0.2.1 on 08 Jun 2014 * Made run-passes dynamic * Made analyze-host-expr and classify-invoke preserve the original AST fields * Release 0.2.0 on 05 Jun 2014 * BREAKING API CHANGE: Updated to new global env interface * Made analyze+eval attach the result of evaluating the form to the AST * Release 0.1.0-beta13 on 11 Mar 2014 * Don't run cleanup on analyze, added analyze' and analyze+eval' that run it * Added :top-level true to constructed :do nodes * Added 3-arity to analyze taking an optional map of options * Fixes regarding :fn-method :o-tag/:tag handling * Release 0.1.0-beta12 on 25 Apr 2014 * Default to (empty-env) if env not provided * Fix a bug in check-recur with case * Release 0.1.0-beta11 on 18 Apr 2014 * Performance enhancements on reflection utils * Workaround for a weird behaviour of clojure.reflect on interfaces * Fix for annotate-tag and validate-loop-locals interaction * Improve logic of try-best-match * Improve handling of Void tag * Fix handling of tag on constructor that defer to runtime reflection * Fix validate-loop-locals when the return type of the loop changed after the invalidation * Added :qualified-vars option to emit-form * Release 0.1.0-beta10 on 1 Apr 2014 * Fix validate-loop-locals handling of tag * merge &form meta into mfrom meta to preserve source info during macroexpansion * Release 0.1.0-beta9 on 29 Mar 2014 * Macroexpand evaluates :inline/:inline-arities to allow using the inlined version in the fn body * Fix fn name munging * Fix annotate-loops handling of statements * Update the ns map in the env after macroexpansion as some interning might happen at macroexpansion time * Added analyze+eval * Pass (:locals env) as &env instead of env, macros that use (keys &env) now work * Fix binding init tag * Fix create-var handling of meta * Release 0.1.0-beta8 on 11 Mar 2014 * Removed :name in env for the :fn name, moved in a tools.analyzer.jvm pass * Added docstrings * Add annotate-internal-name pass * Add warn-on-reflection pass * clear-locals is *compiler-options* aware * Release 0.1.0-beta7 on 28 Feb 2014 * Moved :should-not-clear annotation from annotate-branch to clear-locals * Release 0.1.0-beta6 on 27 Feb 2014 * Bind Compiler/LOADER to a new DynamicClassLoader on every analyze call to avoid problems regarding deftype redefinitions * Fix handling of meta by create-var * Release 0.1.0-beta5 on 26 Feb 2014 * Clear :catch locals * Added "this" clearing where possible (CLJ-1250) * Clear unused bindings * Attach the correct :tag on instance call/field instances * Fixes to clear-locals pass regarding nested loops * Release 0.1.0-beta4 on 17 Feb 2014 * Fix validate-loop-locals to short-circuit on nested loops * Added docstrings * Correctly clear closed-overs on :once fns * Correctly clear closed-overs used in closure creation * Release 0.1.0-beta3 on 15 Feb 2014 * Added annotate-class-id * clear-locals clears loop locals when possible * Release 0.1.0-beta2 on 14 Feb 2014 * Memoize only maybe-class and member*, a new deftype invalidates the cache * Release 0.1.0-beta1 on 11 Feb 2014 * First beta release tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/CONTRIBUTING.md000066400000000000000000000012211312245000300232660ustar00rootroot00000000000000This is a [Clojure contrib] project. Under the Clojure contrib [guidelines], this project cannot accept pull requests. All patches must be submitted via [JIRA]. See [Contributing] and the [FAQ] on the Clojure development [wiki] for more information on how to contribute. [Clojure contrib]: http://dev.clojure.org/display/doc/Clojure+Contrib [Contributing]: http://dev.clojure.org/display/community/Contributing [FAQ]: http://dev.clojure.org/display/community/Contributing+FAQ [JIRA]: http://dev.clojure.org/jira/browse/TANAL [guidelines]: http://dev.clojure.org/display/community/Guidelines+for+Clojure+Contrib+committers [wiki]: http://dev.clojure.org/ tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/README.md000066400000000000000000000151421312245000300223230ustar00rootroot00000000000000# tools.analyzer.jvm An analyzer for Clojure code, written on top of [tools.analyzer](https://github.com/clojure/tools.analyzer), providing additional jvm-specific passes. * [Example Usage](#example-usage) * [AST Quickref](#ast-quickref) * [Releases and Dependency Information](#releases-and-dependency-information) * [Changelog](#changelog) * [API Index](#api-index) * [Developer Information](#developer-information) * [License](#license) ## Note for REPL usage The AST `tools.analyzer.jvm` produces contains *a lot* of redundant information and while having this structure in memory will not require an excessive amount of memory thanks to structural sharing, attempting to print the AST of even a relatively small clojure expression can easily produce a several thousand lines output which might make your REPL irresponsive for several seconds or even crash it. For this reason, when exploring `tools.analyzer.jvm` ASTs on the REPL, I encourage you to: * set `*print-length*` and `*print-level*` to a small value, like 10 * interactively explore the AST structure, inspecting the `:children` and `:op` fields of a node and the `keys` function rather than printing it to see its content ## Example Usage Calling `analyze` on the form is all it takes to get its AST (the output has been pretty printed for clarity): ```clojure user> (require '[clojure.tools.analyzer.jvm :as ana.jvm]) nil user> (ana.jvm/analyze 1) {:op :const, :env {:context :ctx/expr, :locals {}, :ns user}, :form 1, :top-level true, :val 1, :type :number, :literal? true, :id 0, :tag long, :o-tag long} ``` To get a clojure form out of an AST, use the `emit-form` pass: ```clojure user> (require '[clojure.tools.analyzer.passes.jvm.emit-form :as e]) nil user> (e/emit-form (ana.jvm/analyze '(let [a 1] a))) (let* [a 1] a) ``` Note that the output will be fully macroexpanded. You can also get an hygienic form back, using the `emit-hygienic-form` pass: ```clojure user> (e/emit-hygienic-form (ana.jvm/analyze '(let [a 1 a a] a))) (let* [a__#0 1 a__#1 a__#0] a__#1) ``` As you can see the local names are renamed to resolve shadowing. The `analyze` function can take an environment arg (when not provided it uses the default empty-env) which allows for more advanced usages, like injecting locals from an outer scope: ```clojure user> (-> '(let [a a] a) (ana.jvm/analyze (assoc (ana.jvm/empty-env) :locals '{a {:op :binding :name a :form a :local :let}})) e/emit-hygienic-form) (let* [a__#0 a] a__#0) ``` There's also an `analyze+eval` function that, as the name suggests, evaluates the form after its analysis and stores the resulting value in the `:result` field of the AST, this function should be used when analyzing multiple forms, as the analysis of a clojure form might require the evaluation of a previous one to make sense. This would not work using `analyze` but works fine when using `analyze+eval`: ```clojure user> (ana.jvm/analyze+eval '(defmacro x [])) {:op :do, :top-level true, :form (do (clojure.core/defn x ([&form &env])) (. (var x) (setMacro)) (var x)), ... , :result #'user/x} user> (ana.jvm/analyze+eval '(x)) {:op :const, :env {:context :ctx/expr, :locals {}, :ns user}, :form nil, :top-level true, :val nil, :type :nil, :literal? true, :tag java.lang.Object, :o-tag java.lang.Object, :result nil} ``` To analyze a whole namespace, use `analyze-ns` which behaves like `analyze+eval` and puts the ASTs for each analyzed form in a vector, in order. ```clojure user> (ana.jvm/analyze-ns 'clojure.string) [{:op :do, :result nil, :top-level true, :form (do (clojure.core/in-ns (quote clojure.string)) ..), ...} ..] ``` [AST Quickref](http://clojure.github.io/tools.analyzer.jvm/spec/quickref.html) ======================================== Note that the quickref refers to the last stable release of t.a.jvm and might not be valid for the current SNAPSHOT version or for previous ones. Note also that the documented node fields refer to the output of t.a.jvm/analyze running the default passes and using the default configuration. ## SPONSORSHIP * Cognitect (http://cognitect.com/) has sponsored tools.analyzer.jvm development (https://groups.google.com/d/msg/clojure/iaP16MHpX0E/EMtnGmOz-rgJ) * Ambrose BS (https://twitter.com/ambrosebs) has sponsored tools.analyzer.jvm development in his typed clojure campaign (http://www.indiegogo.com/projects/typed-clojure). ## YourKit YourKit has given an open source license for their profiler, greatly simplifying the profiling of tools.analyzer.jvm performance. YourKit 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: * YourKit Java Profiler and * YourKit .NET Profiler. Releases and Dependency Information ======================================== Latest stable release: 0.7.0 * [All Released Versions](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22tools.analyzer.jvm%22) * [Development Snapshot Versions](https://oss.sonatype.org/index.html#nexus-search;gav%7Eorg.clojure%7Etools.analyzer.jvm%7E%7E%7E) [Leiningen](https://github.com/technomancy/leiningen) dependency information: ```clojure [org.clojure/tools.analyzer.jvm "0.7.0"] ``` [Maven](http://maven.apache.org/) dependency information: ```xml org.clojure tools.analyzer.jvm 0.7.0 ``` [Changelog](CHANGELOG.md) ======================================== API Index ======================================== * [CrossClj Documentation](http://crossclj.info/doc/org.clojure/tools.analyzer.jvm/lastest/index.html) * [API index](http://clojure.github.io/tools.analyzer.jvm) Developer Information ======================================== * [GitHub project](https://github.com/clojure/tools.analyzer.jvm) * [Bug Tracker](http://dev.clojure.org/jira/browse/TANAL) * [Continuous Integration](http://build.clojure.org/job/tools.analyzer.jvm/) * [Compatibility Test Matrix](http://build.clojure.org/job/tools.analyzer.jvm-test-matrix/) ## License Copyright © 2013-2017 Nicola Mometto, Rich Hickey & contributors. Distributed under the Eclipse Public License, the same as Clojure. tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/docs/000077500000000000000000000000001312245000300217715ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/docs/ClojureX_slides.pdf000066400000000000000000002776451312245000300256070ustar00rootroot00000000000000%PDF-1.3 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x}Tn0+(BM F/R P'v!YhKRKpmșݙN '6gB5;x Oqh fcɠ5C2>A1!b dE7H;ZR(~":I.AJILj@3W o|9Tm]SwǮ|I!%ߡx<&\NIWƗK.w\QJZTE> endobj 6 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs2 9 0 R /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 11 0 obj [ 12 0 R 13 0 R ] endobj 14 0 obj << /Length 15 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >> stream xWX>HJSF2dATbH!( --RZ(.nPPKz >|g|=@]ȕHq@8_N¤ @GIp = `Hr5q(|A:[? 'h %Bq* *k r!ܜ.љ-Mehɖ!6pvC| ŏ DIB bc" X HcF\s!X4қ/ Y3(. 6 Pٕ 4C1G=a(ΎDz!}JW0Y4QE!.JCK=!ɖ ƄN*ECiq!R4(b+Z+Hĸ@r<Ġ0A9\Z`[%M g,(π8ht832Yȅ о}}y㯁 B4t%оRˀxg#g-u4jɅ+r]#됗#@Š!䞓$ A,6)QrolL'ϑo·~|b|+ ='Zڝ5S4l$U19rR\O0!oQy!g o()W)(7tR K;{+>1`Y<">(/SF!׋8˖ʬ@ -2'x*hdh c:*gȄ5hv1% sP%FU2%?Ҙt"92E&&]HQ7|P%IwT{whl!zRATkr度Pj0`R:/(wr%ERQ0Ɇ#93YNLhcw!L'H%xj+7AA2LJadK2P*l;Pap p \.'`0:c&%f9c/E`X2e`bL`a:l+ þŚv?8ZnOq6 |>^x ^7Kx'ލ?@(:)@DBRb1QAT5D  ސTRd0d#瓋ɕVrH%o= BR(e&%RNRR KyIRu`~`ޒԅԕԃSkԇ!OТh\Z>VO;IN륽VPV0QpVVHQ+*T)W8p]°b"_Hq+JJJ>JJJ˔6+5(S\YYLC9FYTy!=oT4TlUTRUd*TRN[)|*z 5C0%jF#:㩪*[ujj+jjVjj\jjjԆ5՝ԣsWWާAӰki8P4 i~GfUZUeAm iډڅǵu+Nj:]:outٺ u_MU{_Li`kc`9IZ&&UL:<'C0pn!#c#3F:ƙOhL64yf̳ASCPS.˦ff ff+o0o30aQbq'KEKwK&vWVVIV˭YYYsX̷߳9:}r퓯.Bj+vn5{ؾۡCcc1ǧS,LY;}{ +~:i89:8lsv9>5x꒩MSM&cmM.]\tus6YmscV7=rm-̇˧ۗoׯgs#dv&t:kt< $C+/i%m zl| x0%daȩPJhx[#S s [v6\%<.|k҈g܋GQQGC5)$=N3nnWMI%%&&%J LZ=sE3/%$Rh)))Cfm՛Z5zv s d9>Wu.w4JZRw(n whg޶y&?_#X'x./'c}FOX%ef|7CvRf8K|680NR.9Ai6˛ה>T^HzȶhEѣ y JLK,b/ڵ[|7-] endstream endobj 15 0 obj 3367 endobj 9 0 obj [ /ICCBased 14 0 R ] endobj 16 0 obj << /Length 17 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xwTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf endstream endobj 17 0 obj 2612 endobj 7 0 obj [ /ICCBased 16 0 R ] endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode >> stream x}1o0w7ԥSNPuQQUpgw<ƈM543@smK<-G=iOtW "ۭQ'&N򑻄*h:'8/_:l:ZTq8ߦfoCw pic[b&S(|SS+X: jQcVAtڧ]e2kw}ra endstream endobj 20 0 obj 227 endobj 18 0 obj << /Type /Page /Parent 3 0 R /Resources 21 0 R /Contents 19 0 R /MediaBox [0 0 1024 768] >> endobj 21 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs2 9 0 R /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 24 0 obj << /Length 25 0 R /Filter /FlateDecode >> stream xUn0+(1ÇD=襧CӃ +*@ve)2&ցk{5.X 0|89JC W>m8W5q ½`2<|7 KǷ<>c@q ͞|@T{8*Cu?!aTkBhIUqf%C"s*> endobj 26 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT2 27 0 R /TT1 8 0 R >> >> endobj 30 0 obj << /Length 31 0 R /Filter /FlateDecode >> stream xSMo0WH. 4RDCzw1]5?y6) l,af޼-m^Fs,_{X2$ s V'ۆ(=|u*,yžJݍ~.tk֘T?y;z  I0ϒ22W h/CܿcB #&Z> endobj 32 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 35 0 obj << /Length 36 0 R /Filter /FlateDecode >> stream xSN0+(qns!!%C\66HONJ$$Zwvvg-v8Vi8ɰ+pOj('% _fh|gQdbʰspRڀkB9ݯݬ*\lU,CC~NAM)2U!x-6=;Qe="> endobj 37 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 40 0 obj << /Length 41 0 R /Filter /FlateDecode >> stream xN0w?7&v7"$$ K JS61w~>0 wCفӕ0ʇmE,;fJq 0O)tk|xl@P]SV4V+A\Kn $ZeQj`RO˨wC1(Y> Ii\d> endobj 42 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 45 0 obj << /Length 46 0 R /Filter /FlateDecode >> stream xVr0+ȤlY K.lBUm\lFx?b@]zyu7ppQqHR`Lx!4nOBi_e4?'IB[ n pnKķ:҂|1~wj.qgqķp Χ,eڞI{[5+8!8++f ! c]AE}E0:`Mb9W?# #|z' މ&N0ug7MdRrE2wd")|s QA[*Lr4BF[q$"Kd)F*rʪUɔ@VXhZ{ ]-B4gKZ&,w0 r󧻻& Ĵ"9u#*gt8wxaba7X1#l|؟v[ĩV߽Q;lI4x<ꮙ2 +bm$ < 4^޸kk N1ArS'B(g@A34.w 콎Fcm!b!K#ɬLnh w#ȬZ{tgoH)C9)qkJ> endobj 47 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT2 27 0 R /TT1 8 0 R >> >> endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream xVˎ@});;oXED @xcZ?ȏ?3`0l">0~S3k`[@(k{ +/P$q!ܳlJ_a$u?Sf|N4wti*+f > [2nR *N@qCL qEc4 {bs Y lW" `/k+Pf}HQh|_0&Ai3%LƈZaNAigZ=vwBidRKD 4C95ʵ\MݮP4yc $6BH.G=/8N]s-t0-$<< dkg27"^O%K8Z3jtT(Xg6G!c11J8Emu,Z n ߙOh2TI/pX|-}[CVeS]/p̣q5]2yM}؞-Oq47A^0eq0R^W.s9AAVLqmW޹Uck3n ]ǒ$|a-=0)T3+R\Fe%z @-ar?Hl6L&F'[/&JIWpx!6}zl8.(F}BJ<ƃ%7sVCkrzI$E}V= 諾,l"Xŭaڭζ'L֍6Vv_ѣhEeOoJ) ͔1waμD,k^{l8O&c2{%J\?&r)N# <;Baj8ouvfW̴8n{jloD endstream endobj 51 0 obj 888 endobj 49 0 obj << /Type /Page /Parent 3 0 R /Resources 52 0 R /Contents 50 0 R /MediaBox [0 0 1024 768] >> endobj 52 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT2 27 0 R /TT1 8 0 R >> >> endobj 56 0 obj << /Length 57 0 R /Filter /FlateDecode >> stream xVM0W&VUVBaw&J*D˪?c`BUof{3 _pj`xq&X[*<6(C> endobj 58 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 63 0 obj << /Length 64 0 R /Filter /FlateDecode >> stream xVn0+(%ʱAPrT; R~BKRh[v:Hٙ ba^ F[XW0~eh~Z!ESGa$s?.BYZdA> P.,]rא}z>rl=~֛q 0[(?e W$sȭosj=nI֌'w vJ*85ИL*d7fes*iΊ%,Wm#!hKA{ے2o~j:~`DPⅤ=DIn/ةB;]WwPB%ى|D%,fx5@#Lt="BV-77"Q E'y[Ne36 :.Z~O QaJ>&Ւ ״B sa!Fsj$,qFo%Lsm@ KCsBq]qAp4m !_DkP672B#!^a\h0]%yK'7;j+'xE*8oVĨIUs&d dp>k2l ڳt`$ B~aA|~ eByoEpEdC>pGKc{7P&۰c(58=0WPB=2`39caQ'y{oHz5mއ'}fw$6_@L[^﷘rdڣ"^V止6SzKh\ E^C[>PB9r4|9kz4G%ߵ/JhH*}1L뙺c{;Oo ~{HK2Β8 endstream endobj 64 0 obj 892 endobj 62 0 obj << /Type /Page /Parent 55 0 R /Resources 65 0 R /Contents 63 0 R /MediaBox [0 0 1024 768] >> endobj 65 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 68 0 obj << /Length 69 0 R /Filter /FlateDecode >> stream xV0[Ex|.) "8}4{[ɱUݙ٥/xTKksH 8Pw?*x>,Dp8R@Kx!):A#:";C(C8!l)zWld_slNn'OɩjhʗnZZ0e"6/ijCRFD*fM9zO&18^6}QTGa6ʲ 5Q`R)9nÆ_RR?7XPcIU+tF0\9 XTpa7FV]0t<(7گzݘ&y "Qs4LJzT)jjڈkvKNq!fhb`?:)!ԭE݄t5BZcpڟyt+QEmvMyJk2Hg7†};E5^Zٖx:o=eX]4K=_`c'RĖd,G3]_I$%DuIRE#xI\XЌ+kŒJڑLqݻM4(Z%hm?wW#];$1xl?1 ?`AKn+Zkz{%Rz endstream endobj 69 0 obj 672 endobj 67 0 obj << /Type /Page /Parent 55 0 R /Resources 70 0 R /Contents 68 0 R /MediaBox [0 0 1024 768] >> endobj 70 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 73 0 obj << /Length 74 0 R /Filter /FlateDecode >> stream xVM0W1=`Z!q@Z)CiSvm.Zs4IJC,~3fތúz ΄-J؆ w?á=ʨ? 쾃%]=zH>eAk =yW6TۢV-|Cy(Ok(dկTv G)tpȭ]v(r`ŏ(׹ZJ\W>7i,sƄTYaHnsZ^ a9T[WǻET~FZ99sD Ww srKJnVox>nVOeK9Х&yKI82>R.KR9bTiT~%.=ʛ49Ɣ0gGJB*乳HܥQ*8Tη t7(|0%Q205VK.v‚ ʍ$n a7i73Jl`5!6 1kI1* =`KZ(ۤAqAaok(0_Q24'tk `oab |qtֵ0[VǞIMGhHsn?`Q1Bj@;/=%smf\1 }ᰭ^bs)"/^1 yalPNwBi \W(qrn#S06S.ܢ~%v_౉?)P5f"*Tó&ٝ,<$]3R3K@hDi=9c>Yxh6%1l:/P87%<-T7"p'Jpw\sQ{+. x.<YW% endstream endobj 74 0 obj 833 endobj 72 0 obj << /Type /Page /Parent 55 0 R /Resources 75 0 R /Contents 73 0 R /MediaBox [0 0 1024 768] >> endobj 75 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 78 0 obj << /Length 79 0 R /Filter /FlateDecode >> stream xU=o0+n2&EQ[ "#.d,A{$Jl'`J"ݽ{t[8ͷCWWË3mmǣg Ÿ=$:.go?ᩀB90FBy _ 0b\) d?cK(6 תk <@pKώUR=!X'B1ʍ(`TI ׸bNckL(C 0,i[>vAV'*͂P*_~3օ58,Sү,JhWH.|YBij,UYk{$~/3L树,X ԕ^ uM6Ү頻;XƚR`C BqEU}mwy=5h+(ܢz&s#/Z8 =e AO2@*/G Ce5yx5P>D&{OyKXSO9Q6wK `LNV>+h|o!3R_ @RðACK'|(!156?L%L Nߏ-NS8K~ދDh({i Ykh,3L*a3xWX8]#ѽ|s9 endstream endobj 79 0 obj 660 endobj 77 0 obj << /Type /Page /Parent 55 0 R /Resources 80 0 R /Contents 78 0 R /MediaBox [0 0 1024 768] >> endobj 80 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 83 0 obj << /Length 84 0 R /Filter /FlateDecode >> stream xV=o0+n2&AP[ ,7ne˱ EП٣(Q#ML{wGGj i 0%maW²]vlVJ2:q -ۻ`*?P< n#jK Z (!#L5\乳//ܭ gqHwr+CsIx&(<|znf_.,(aZq%P"S)Q0|fXNRi3 49 xXU ܌i8 ,2ډhkq[d#׻Yk+FXE,dqӚcpu\ ?1Wz[/P]G[b[7[̘w]xFD "=Jzʫ(yIz=o~>I!f2S؈/jUe3r*y}U3Z*v5TH7Z0ZKE4 !K»=qsौKF5aD ۑK8jNzKPJQ=5$ TJQ l,~՘,^`SІʘA`rYדdž׋KGIGh ,Bz]~Zm[^FC¤ 9X !rx%̒@EFOc Z(qLR"!N}%CT'M b-U?SaWH6V3HY cLr?p60\ ) epNGATL{* έz=s V iwvӞɑ> endstream endobj 84 0 obj 818 endobj 82 0 obj << /Type /Page /Parent 55 0 R /Resources 85 0 R /Contents 83 0 R /MediaBox [0 0 1024 768] >> endobj 85 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 88 0 obj << /Length 89 0 R /Filter /FlateDecode >> stream xVK0W̑&VU"!-KT$4KޱM0Bjrr k 6pOgxK`L(A[6v VFs1"{HexɠkaY_O+#<KE(PKGȾTǪݗP /oU{~V W\\+Η峧lŏPF caTI ׸ƜF܎A,uJk *de]k +{8AAFtepl^3U實}Z 9,S!9ˤH.<6u&7D3E kmNdfXӂ-pYإ:g ŐNNs&sP, ZKoÑ%WAYM2z4x*JtACZq"GQ\Su\7?Wwg_(me[ Xo~.0)=3=!c 6%dlqHy'!<=vkʷ❠|+jυ %wѵĸw$1> endobj 90 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 93 0 obj << /Length 94 0 R /Filter /FlateDecode >> stream xVn0+(%ʱAPzHzpmq+[-~NKR%Y$>H`ٝ!ja0q&maWl6VF35q ]G22(=|  wy|ʂk1mh_5\之-$M[- A& ͟~^_:y 'w :Z+¨<<5fS~A1פWaU.w3b)S0 d +hb] lebqvwX\$**D e5U$co hKW0͊$(ֵ!|$'nq&rәLčK j-]ȩDFtVy Y7wLq_gɬei@ի2|Rj:v3y 4Z$j&pjjɅP ?4LQNbLFd])4~Q-C\jP P2ŭJf*M2+V Azw`U(63ަH, f'E,-Ujۉ9; >megb թW4f(`tk|ur̸ʻXӄxsQ2OoǩdB*_sa$=-n)Wb<]ig$YXeҺ \~ҿ}eiʴBfyZqF 6HfdV^q3ۈ>Zua:=Җ" 䙡> ;!&qwCCh%p7Ӽԍly ᄊtOE> endobj 95 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 99 0 obj << /Length 100 0 R /Filter /FlateDecode >> stream xV;o0+n2|آ(-IT~r({$%`=NG#}:qOuřP`Mxm q+C|ݥ06+!B|ʁ1XT]U,j}~o`OP}ܓ[p=|Xbha"*ɵטӈ1KYZAYׯoۗvA3 Qs8AAFts}hW96geJ""gTcsɅ&JKhB]0kk[ئONBn$$Xcwrx/,JQ&PevTb;;O%", 1L:l}&?@L.;Lphf%}:o!K&,!*]b } n4j:-a$eH4'v 5$C8{ä'mJ7.w AL@&~y"f s(gRfRpr$Oގ( 2mxT>%LeVKجվXWp#> endobj 101 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 104 0 obj << /Length 105 0 R /Filter /FlateDecode >> stream xWn0+(%ʱEPrHrpeqc[ ~NKR%Yr4>Ƞ!9{/3h u gKu[ܟāxwa6+:H~<>eAk Ŗ|A*KypɷrWdz\`7.HBj< \' y `ThJTטMnnE"h*ߒA)gz-$W`DV /_\^"?VQ) $B,k#ԿS@g D]z4~R$9__`SUOk-9q:if27)i>'9==TJ"r>VCJ'wGPꞨCd[r)׋{1C l۔AO?,0<F/u>Z{YWM+ρƩ0%qaR 7`X-p%2CRBs1BSC¦[oZM]K-Jp7I*dJZ 8MV80={I&@( @EרYܷe1NL.DT+s6w1@87Α@gU59>_ИdKIB1 /oSY}(R |ACiqGtEL8y,,2i݆Q{~,kϤz`9k rBDqL9:miz=!ǝJFhI1!W%Ǔ+f.3Q"1s(x&OJSj'NL3TJ{JbxLwo$鮤|l&$5klg ~Eة# /ݛFDMdk(TGR{4C,w@ ] QF=뉷wolo!! nc7/ endstream endobj 105 0 obj 949 endobj 103 0 obj << /Type /Page /Parent 98 0 R /Resources 106 0 R /Contents 104 0 R /MediaBox [0 0 1024 768] >> endobj 106 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT4 60 0 R /TT1 8 0 R >> >> endobj 109 0 obj << /Length 110 0 R /Filter /FlateDecode >> stream xYMo6WߢhmQA !p$[NEEvI# g{C\'='=w$ ~9ƒ݊o?M+1rF wC4n2:]wyKAdP8'{?0%g6<vŚ|W2#/_q)%j@nmv/l~k7#ܒ}n{,oAb<֨)I]ͤڿFr㵦RE զJ6pC]ek- 95MZjAT2j4|B2^7@j]C],fQKè"cHج%oR-ެn} :@ (`R-Ę-҇-A0دprx.%M^D1ʍyJrm\441o>9IB&EϷOXStus~NgGauIl<b˻ 2T e ז  TrWgHw*7+*(*/I8Vb7$ c;t]h6|_—xF'V02&RmT >`+-^^Ċiʌ>:&Y#>\GRZRSQI\'X3ќ: )V8D9<)xq21i9thuK^,<2e  0#٨]-"jn* 0 7֨Cy4|4@Rƭ5\@1IVx~;laL0~̏HHm7w,ORW|;l<8dAEΛҺuS{92K= l jqi9J5o mjN1wFh1gO)3 >V,&KikٞyԶ 5F#UM5w6#[4bjTB=~6AO/f{~p#pw;,JGiGG0 "sOer6{Mq;B.5s1 ƚM7f`'0p"qŖ IY}ɸHRaau Iň27c X*ƒ7"sjp0?ݳӊn:OM!RZ=4)Rg[䣃Q(ΪCۄQ0߮h)9Ի{Zo j2N"2qшN}g> endobj 111 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs2 9 0 R /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT1 8 0 R /TT4 60 0 R >> >> endobj 114 0 obj << /Length 115 0 R /Filter /FlateDecode >> stream xXKoFWQw (SA) %ْҢ ;|,VRDR&7/ /{=0/Q.h V׏$wZgN]1U}J+xDN$uS^>0AK u[5\P`[)wOK8w|9[‚,[eZfsȼٲ~0+adYT[9Yk=X- P!gV Ɲs("sDJKj2"Y_=vuaD J(A0dLlrhq%Ru {CoY@E(ahʱB" lZ[6 5 X(}(W=#H.G!);a' DWd} |g D Zv; DCH ^_q0vDh21DXZ˨1qiy}Dw$Eȟv{aS4 t<zT=lX3X9^-P\OQq w+r%HU^{1־D&'kd6^ǻo{li]c ߦ;$~kbv3>io8C)ǷzX(H,"T}œu4ed.)}yb,ޕ=K$=V#p<E(*f2 Y?8s7O؈_#O`Hm||ː<7Xˆl~òqaRN)Qsv}('E'YT6hϻ͡^CPHp\:{^vVX8F"pPըyb{7C}.cru=žɓ4zWW-CN^&SiFhA!v̤${ '7o-̷N^= v ֨~ >.o!sS+G endstream endobj 115 0 obj 1213 endobj 113 0 obj << /Type /Page /Parent 98 0 R /Resources 116 0 R /Contents 114 0 R /MediaBox [0 0 1024 768] >> endobj 116 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs2 9 0 R /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT1 8 0 R /TT4 60 0 R >> >> endobj 119 0 obj << /Length 120 0 R /Filter /FlateDecode >> stream xUK0WV=uU= j%j?;6aۤ`07 7[y ާ=xliVe˯& GW ]>Gs\ƣm$ 9ÑTK-<J[ڑx'9k}ΔjUK=z\*Ύk%MӔٽ y5louz9;<2/F_SEP'*JXwb W hĐu~py|sҙ endstream endobj 120 0 obj 680 endobj 118 0 obj << /Type /Page /Parent 98 0 R /Resources 121 0 R /Contents 119 0 R /MediaBox [0 0 1024 768] >> endobj 121 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT2 27 0 R /TT1 8 0 R >> >> endobj 124 0 obj << /Length 125 0 R /Filter /FlateDecode >> stream xTn0JUb 1r)Qrzud !R?~Kf-ɮ6U1-yxז~gQ,]x}ه=i8b klA2w}KQq̐:Z`5mEˢp'w /)< 'ˑE|e>nc>yB ĩ`/١jEXn*$QP`{13fCeW Q4DpU|NG%NTZҧ…pXeAo+*Q|>uh[Y*ڍԂrD o9'!9G&LwD>ol%e endstream endobj 125 0 obj 453 endobj 123 0 obj << /Type /Page /Parent 98 0 R /Resources 126 0 R /Contents 124 0 R /MediaBox [0 0 1024 768] >> endobj 126 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 129 0 obj << /Length 130 0 R /Filter /FlateDecode >> stream xTˎ0+*70{rY)RVC BcfiX 3nU#p͇V i!& .luSv+T5 V3L9/v>T$EbwѰc\Lc fsYU8alw&&~\8 dPڥ [m/ʺI[E{$/'45fx Jp?P""dQH҉RK$ʐ6B|TY/Ԉ^(*"s;PKB% Kɠ*]U#䫺8׺Jr Mj'˺6{tq 0O8񐑛N5`֩Ӏhu:GIGOS1CTEM.Mg'Мs}1CL YcW֣c:}_8mGg:uy9,5Y\wѴ"T]v˹yuRirqIeFR\7 endstream endobj 130 0 obj 531 endobj 128 0 obj << /Type /Page /Parent 98 0 R /Resources 131 0 R /Contents 129 0 R /MediaBox [0 0 1024 768] >> endobj 131 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT2 27 0 R /TT1 8 0 R >> >> endobj 134 0 obj << /Length 135 0 R /Filter /FlateDecode >> stream xTM0W#*qlW"gaeLa@BڰY8xd7o{.=?D%w@R=75O1b!LnscAZx` g~?RG#}nhOA`eHs6?kUCQr{kANFpإ! #]?)d2tpU.nR{5ꑁ ٷ8EKө.:OO|ZhOsp9,!C寢ӹD;}(EG>Lh-6I|5RPPEM 3Eыo"ӵBv̙֭|\6 b;H]ơ]5u+U T1֪o18~ĽG~)W{~#I T#+ьRЄ.T׭vw=ɄKcgq|?<Vb endstream endobj 135 0 obj 514 endobj 133 0 obj << /Type /Page /Parent 98 0 R /Resources 136 0 R /Contents 134 0 R /MediaBox [0 0 1024 768] >> endobj 136 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 140 0 obj << /Length 141 0 R /Filter /FlateDecode >> stream xXKS0WљN=L @h[zhHj#Cn99Tga2ͯ,bE$f VPWK(y͒A/P/aRfz_ ۮ׋ ^.GzɕbZf (]TvS?tg#/"8QCrYn o?}8%C*AU^ /HH* JĵaiqzВJ*3fA*;ƥ (~p g0}CIR!iΫ\A' s@[ܔ)#x"5.eYuA@LGDFĎb@L#R{v3p@Y[}Mo'aq?$b4b1E=/{N0j.P7"7 HLht%P2"cru$tdڂ%mʥ!r5"pIB gp| clFRWLyjnnMBV)nEy:"n҄'q;1ҿ9d8  ١(+bRhp`e<T// 2@8l.!"7Bb}? ߎdiA,ّ("]219r֬KPڤoKʬbBe(c % u> endobj 142 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT2 27 0 R /TT1 8 0 R >> >> endobj 144 0 obj [ 145 0 R ] endobj 147 0 obj << /Length 148 0 R /Filter /FlateDecode >> stream xn0w?o6 k,RPu@ ?R{6 4(Cp}|w hzLWg@b (Qc;RiOJ r_L9l)J/nIfy>X@"pb Jkw.)JBn=- gJ!b)Tlc0G0& xj\z,}$ݪ(NGEX(o5b'VSU,5+\ZUV\__*d]YomטZ 5n )wo$ȋ׆iMu`7~tpYr\7Iƒ endstream endobj 148 0 obj 321 endobj 146 0 obj << /Type /Page /Parent 139 0 R /Resources 149 0 R /Contents 147 0 R /MediaBox [0 0 1024 768] >> endobj 149 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 152 0 obj << /Length 153 0 R /Filter /FlateDecode >> stream xXr"GWdȇin^՚.9Lֈ -W,B~Y^u?(,O@i _0Z8X},?J%n̦~K`So a-$_?S>P@)mXfZ> ~8N[j }]>u?/f &L_ #fಙt"~^Z~.I2\(4QA3HJe&՟g"DM#r>z(*g9A2IxN!7$#9C<!Vu@"#58!x-t >y:$r\ cr1\`Tĵdؘxc[mXDf+I#.B-?,G#hHJ]Fe.FBgKrr,rߜny8fScXavxO00&w+ͬW5rUZ6<7$Rh|1q}$4CƩU|EU)% NuxK,zTw{- A3i.׻UdԕmQ樮vj{]LVLbWz򹨻r=H/9݇fcb}]Y)]^}HL-åWpIń&Hj{Ǧ'i(~-܇AM4^S\ ^Mz3һƑk-+b2pf [Ro/k9қY,䦪 IbBEec%hિy>G E8^1~>OpB\ucA]Db??~o݄Yqund();BetVtz >j/`hr{8%]NaHmty:ט܌M^V~|+$e:l endstream endobj 153 0 obj 1377 endobj 151 0 obj << /Type /Page /Parent 139 0 R /Resources 154 0 R /Contents 152 0 R /MediaBox [0 0 1024 768] >> endobj 154 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs2 9 0 R /Cs1 7 0 R >> /Font << /TT3 59 0 R /TT1 8 0 R /TT4 60 0 R >> >> endobj 157 0 obj << /Length 158 0 R /Filter /FlateDecode >> stream xTMo@+SDRBʡa/K"v*7͛a%v} oQGh6}'T,!r) d@Rӧz|0/Fbu 2GR6ILdo?ukl[i'Wqg|L,D@d.]H褘A@XZcT##LjlO fUPu]H+^ֱ.l})Q k\hq;p$B%I#G0}_uh}W?1З k*CZۃC2mFFO撼_$kd&ɋc''LJzDҿ9kG#Bk;oG+ZkZ}uy~d ztoMMy4RB`]])*U^WRw7IMƥ%`Aŭv)XpV1yoMW ڼLvuWo{`?ԕjUVijQ@w6Ii/8qv9~Z endstream endobj 158 0 obj 564 endobj 156 0 obj << /Type /Page /Parent 139 0 R /Resources 159 0 R /Contents 157 0 R /MediaBox [0 0 1024 768] >> endobj 159 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 162 0 obj << /Length 163 0 R /Filter /FlateDecode >> stream xN0%$Qs-jbŲ&^8/up>i[&iz~NGlp|P$ YMG- 8kGTg-.mHV#} !8)su~}IK,.7(e'HR@9>{ A)s#%G{Im5J \MS'b-چU5,t NE\6fe,[)Z֔[z>vдIb=ZWi"ix^TmU,uOR|!R;{J- τ`mf y:hG,5z'L2jFi endstream endobj 163 0 obj 374 endobj 161 0 obj << /Type /Page /Parent 139 0 R /Resources 164 0 R /Contents 162 0 R /MediaBox [0 0 1024 768] >> endobj 164 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 167 0 obj << /Length 168 0 R /Filter /FlateDecode >> stream x]M =xKءʤL6jQf123CTA45}(k'L(mv鴭J)w8G6.Q55z:szGsm 5#/?NCqD8/S/^+<_ endstream endobj 168 0 obj 158 endobj 166 0 obj << /Type /Page /Parent 139 0 R /Resources 169 0 R /Contents 167 0 R /MediaBox [0 0 1024 768] >> endobj 169 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R >> >> endobj 3 0 obj << /Type /Pages /Parent 171 0 R /Count 8 /Kids [ 2 0 R 18 0 R 23 0 R 29 0 R 34 0 R 39 0 R 44 0 R 49 0 R ] >> endobj 55 0 obj << /Type /Pages /Parent 171 0 R /Count 8 /Kids [ 54 0 R 62 0 R 67 0 R 72 0 R 77 0 R 82 0 R 87 0 R 92 0 R ] >> endobj 98 0 obj << /Type /Pages /Parent 171 0 R /Count 8 /Kids [ 97 0 R 103 0 R 108 0 R 113 0 R 118 0 R 123 0 R 128 0 R 133 0 R ] >> endobj 139 0 obj << /Type /Pages /Parent 171 0 R /Count 6 /Kids [ 138 0 R 146 0 R 151 0 R 156 0 R 161 0 R 166 0 R ] >> endobj 171 0 obj << /Type /Pages /MediaBox [0 0 1024 768] /Count 30 /Kids [ 3 0 R 55 0 R 98 0 R 139 0 R ] >> endobj 172 0 obj << /Type /Catalog /Pages 171 0 R >> endobj 112 0 obj [ 108 0 R /XYZ 0 768 0 ] endobj 170 0 obj [ 166 0 R /XYZ 0 768 0 ] endobj 10 0 obj [ 2 0 R /XYZ 0 768 0 ] endobj 81 0 obj [ 77 0 R /XYZ 0 768 0 ] endobj 160 0 obj [ 156 0 R /XYZ 0 768 0 ] endobj 137 0 obj [ 133 0 R /XYZ 0 768 0 ] endobj 38 0 obj [ 34 0 R /XYZ 0 768 0 ] endobj 48 0 obj [ 44 0 R /XYZ 0 768 0 ] endobj 61 0 obj [ 54 0 R /XYZ 0 768 0 ] endobj 33 0 obj [ 29 0 R /XYZ 0 768 0 ] endobj 43 0 obj [ 39 0 R /XYZ 0 768 0 ] endobj 117 0 obj [ 113 0 R /XYZ 0 768 0 ] endobj 76 0 obj [ 72 0 R /XYZ 0 768 0 ] endobj 155 0 obj [ 151 0 R /XYZ 0 768 0 ] endobj 96 0 obj [ 92 0 R /XYZ 0 768 0 ] endobj 143 0 obj [ 138 0 R /XYZ 0 768 0 ] endobj 71 0 obj [ 67 0 R /XYZ 0 768 0 ] endobj 86 0 obj [ 82 0 R /XYZ 0 768 0 ] endobj 28 0 obj [ 23 0 R /XYZ 0 768 0 ] endobj 122 0 obj [ 118 0 R /XYZ 0 768 0 ] endobj 150 0 obj [ 146 0 R /XYZ 0 768 0 ] endobj 165 0 obj [ 161 0 R /XYZ 0 768 0 ] endobj 132 0 obj [ 128 0 R /XYZ 0 768 0 ] endobj 107 0 obj [ 103 0 R /XYZ 0 768 0 ] endobj 66 0 obj [ 62 0 R /XYZ 0 768 0 ] endobj 127 0 obj [ 123 0 R /XYZ 0 768 0 ] endobj 102 0 obj [ 97 0 R /XYZ 0 768 0 ] endobj 53 0 obj [ 49 0 R /XYZ 0 768 0 ] endobj 91 0 obj [ 87 0 R /XYZ 0 768 0 ] endobj 22 0 obj [ 18 0 R /XYZ 0 768 0 ] endobj 145 0 obj << /A 173 0 R /Border [ 0 0 0 ] /Type /Annot /Subtype /Link /Rect [42.1875 44.5 958 85.5] >> endobj 173 0 obj << /Type /Action /S /URI /URI 174 0 R >> endobj 174 0 obj (http://clojure.github.io/tools.analyzer.jvm/spec/quickref.html) endobj 13 0 obj << /A 175 0 R /Border [ 0 0 0 ] /Type /Annot /Subtype /Link /Rect [349.6562 94 674.3438 128] >> endobj 175 0 obj << /Type /Action /S /URI /URI 176 0 R >> endobj 176 0 obj (https://github.com/Bronsa) endobj 12 0 obj << /A 177 0 R /Border [ 0 0 0 ] /Type /Annot /Subtype /Link /Rect [370.75 162 653.25 196] >> endobj 177 0 obj << /Type /Action /S /URI /URI 178 0 R >> endobj 178 0 obj (mailto:brobronsa@gmail.com?subject=) endobj 60 0 obj << /Type /Font /Subtype /TrueType /BaseFont /YYGIGK+CourierNewPS-BoldMT /FontDescriptor 179 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 121 /Widths [ 600 0 0 0 0 0 0 0 0 0 0 0 0 600 0 0 0 600 600 0 0 0 0 0 0 0 600 0 0 0 0 0 0 600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 600 600 0 0 0 0 0 0 0 0 0 0 0 0 600 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 ] >> endobj 179 0 obj << /Type /FontDescriptor /FontName /YYGIGK+CourierNewPS-BoldMT /Flags 33 /FontBBox [-192 -710 702 1222] /ItalicAngle 0 /Ascent 833 /Descent -300 /CapHeight 592 /StemV 0 /XHeight 443 /AvgWidth 600 /MaxWidth 600 /FontFile2 180 0 R >> endobj 180 0 obj << /Length 181 0 R /Length1 27444 /Filter /FlateDecode >> stream x |T?>s޳={f/{vslvsِBHnBИ h*% ZP-z. j@[Zlkh_XJvߙpQ|<̙3Ϝygl.^}2'D$, >荳\˦m+ X~A6u򕗟MzKݹ/ͦ1sMZs/l:g算"=ŗ蓿 p˲W _tq6}CKV/˕ )0K_5\Y-A|ADI"ƓTMHJB_kl:22r~3vvof+jyyvŮgǯ߲=LΥ'0{ F:r8Á尗χll.?G`$?~6BxrF7R-٨Pىċvü==zOlD|3  -Қ}Ͳx=z h>~s?p?rB 2 •q}(}#%))Q|Q%K! =CK1`l0A]A]wP;^׉(.zG0°\%pR v"QSpu SSRl#$;Ix" 77pJN@8x3tXT R%ȋ[۪"/]}]CU6д\$ +9( ؒ!6,,(fGoUz]8=z Hvva,l.B nRR &(l U%U~ҫN{ jeRHBy|_צ<_ H%RԦm^!AB FO؋0P "cxl'=*;2"g9WXɩ=Q#+,1Ē^"W[@ipr+!@k.9\sV"vB@?9#4qiF?hF?/ hA49~\V0A^p=C@߁;Pw߁;xw^#7FoD7Q#oDF߈QпE؜FhFN @ 1q1@ b@ b '@  c?cQ^(E?GQ(Q?GyQ^(E׿VXFzZlR29 }ŀ%< 9 [,9s89s,tAtA~~N_83=Fi?N?/El`>^qD,,^^NtzAtz9^^tzAW Cz9NPN:A:9NPNP:A:ASNPNN:D$A4(Ki$h$9$h$A# IN# IHFHF44bQi@#1Јq1ЈF 4bF 4bh@#i@#1Јq1 1 (h(hr1 1i(h(1 1 p}D:!%BZ< YY Yh@R 1qEQ9) HR⃴xԹ|DAD7h -mA8E;+;J?ZY PPe-`3 J!@xflͅ$vɧ4Q.mWޮi]]4|,ɿ?k\|M~5uh wvoyY#;#5w#¤>|R9{ME`~k;HwJ06G%>d@1w~Dk;},wIB)8@i{1\)I.Utuԓ"DG._ԕ-E_L<"},J*>O_n[ت($NjE@P!|XUtӋ.%.A,f!G.[1Kh_/HA5+@CvW:z#u;Wd-[ /$)C^!{)3ywe>'SR˗"_W nf"Dަŧ,>Lеb/5v2@~L. WϨ2f‘dÙWb\BF.ՙMs.AJEձN_ϼOG,, E$əuPŗec_3[P4z;=M>Sۊiƛy=Qw&J4@'BMxiNpdYNj(Oh-MЩTGIKxQSqZ%TA˩Lgй } uxu.qVrnH[QC^)+>͜+`TlOJ$02LmI<ߏӄ5b%!^%nQ,P&]W̃3e9L$@dzzYHN~Z_ /hNџ"5 }GBX')> Yq)HP5ӝ9[B#7;/#อmlQ"LPg OaqxxxxTR\xW&ݓ3-\ߔ'j$2&9J4񭧓T Vz}~L(ZYrKy bb>QoDiRMҼcO;vZH{2+SiN>GA`^!,3s+DŽ / i1OtAg }zN| (Še;O(^PU|lST^2nUm\mjQ@!p($fyN!c-Z~p/z}Pr$Ƀ=:r+| JzPmx0L І.w³ d9}ӛTR(#Ar1G)+ L*)Eam?t1Lo)aTQ-tԉsSAA^n͂T 9iFKŤΆ~$f þ.2-!N܋m#W%TG~JFN( 0kV!&AcId:3zc:ZpL7y=9W6+=Ƌz}AYIU+Ks3- *eүt(JUVNGJEB/~EOEgI<¿O#Z+2]I K:>~1?N}c/뱷m90rl .,ʜfܙ~n3 ;1.oBt*49Jm1إd^eе"%b̘0&gbe%̴/'3Q.2 oR_ZBO3n%[T6g [VIϏ 3Ӯ$VO[Ι9=9yRƆ ښx2Z)/+- q{j1$!_j*B(h N})E88}zYN-)%e<;%lIxI*HSvM F mjۗ:3y\|$~k;՗}Դ5o[t-eh٢C4Tap` -LyD(lm"M>1 NmM9ՈKS]Nuъm9;$E!EH 'RԜoE Cnmع,.>saJ\:ZSNM^Dd_wUվ _Η<{Inԁ{д@V 8|(ه.B}RÀ8קȜCN-8[}- SIW{Ԣ-V~8Jbd1Y^1^f9ޝ1؞GgВA҆'PА0?KB,!Riw-C47 uyzA * ٩taR̾0+ 1(PJIm!i)DZ 5m!RHMc$R4;b],.œO0 Bl~4jAnSAJe?袓?A S}b"1_8?0A C]AH&ai B!L-gW>A_(; ӂi/ . mMh|ґ[\iv;ϥPE%HoE7]p-A72oa|B0r\Ew)veB|-`OW&a' p-}\8C+~@/s 8r!}"EwGdS>8uG4׏ppH߻+/ +E  XX;vcE٧ߙOXM\rj IZݤr}>gR :sv"X^2({Tð\"ѩEQpjՊÔ843GfIGf5͒l)5dXxo M r'<&+ɷ8?*4+TRb>VG~y*N z1q!=qDs?83;eO:q^ !9jGpMo.Oo0JO|O;9axMk#r[*BV9V]kB$TIdUOja@8Q[WScR<:Ax͎dc.lE ₸~r,fF`MBz;&OlK\[\[|UH+ Fۊo,~YRzn>YI/ m _!M>zixraؘߙ;_QGGTl*XL GRGewMiKhGPҦc槆gTT,es KkIv":֫ـ Gx;g3V=`(֍ґஞGr46!|TzZlQ1e:潭ZV'& FZC0!LKԆJʍdEB؄cp|RW?m␨S3Lzcn=(۫BCQV˾P:V-Tʺ2c9͔#B9O卲BvN70{q7K?7>-s8,".y|GLVU\JT}6͚GzVa\u* r *(ŏ{W>2 1eQ6FzwQ#PVif+j/ T DTkI8`@U`EY ǧf:bUN' o^X_7Ǟ\:M(-KEE6}i&jt/;n+% ]οKw$ MµmV䎟_p1}4wNPyNPUc%DWۃ$ i.:;rꐩB8u$LU߷N8WOGL!&Sj4N a3*B\3StN* VtD(.ݘQ~%=4zfeAp;H$[Mc45=k+ TҔ$0BP(>!07)+4E~#tcq(f D+VK'#ɊI WJ_͋W}>R}Y[p笰<- Bo,ejf룘W+A!Ƀ:Aﭠ*Ga.3K~L7XKk|Q {4n֚gC0_6{>u\-gUd30k~J&T %9()DsClꃰ F!T6p,rE }m`qfQO䬯œA&qHB&ޙO{OT}3n5XN W{zWeeOw_U+B"6>m7Vn43[iQN7UJAg4/k>|UxI-1Ÿ?-?:Zc2bYWSvD\"Kua aKZ`+gfg^\=ߗ_jݠQR.JMYݥVt9m.vVZHl>[mvȖ7(7(fsDξ' ˌPVaǭ<0.egYϯ^/-"^Z)V^K].K<}X_T䅂DNrjX@PFL{(Ljb,A ,RRjLeZ^VͅRm*uժo6^ I!{Mo[/[yu'%Z 4VmP3/3-7/+8[*OO%ZjXtReql|I+keoJ25uZAeTug4d'9cZσ-Bwl$ "F:^_FCRF쐨䈴ob$6YaJq /2=E9hyIA 6$`Y *+ӗA  .}>W[qvIǃ\+&re9I2|OK`VnLiwpUU!Zyts>&Y7b>K{^]*QjucǿY:hS y"ln >}(#ϭVybՠ;k@fF8j{ .mF7&\=azF]NLُHQK۔oH ƚMIߦV<ψ7D.̓u88-1R,ݗGKaVLx-"k-PʬV$}]HfvA O{dx3 [K頙!0GaX,e`&w*Lz+` 0+ gMhj" YYXqY/oYYzOi _fz߱{W{oյXQZjPš N[f ѧwCЙ_*t&`5ٿ?T]U'8q ;"ZWUb˰]wlgfO{V[,Ϝ шXRFkhEde{>hWUƥZT#Q~L`_Tp>-V}_$=%DzSRHdRe\Ń>b_ h&`rX s* 7,YCMxg")虖/bfJeW,a%?/.9g&mbyŽI: gݸ[_vLbS/"!REo %B*w%_WI.o犅~ȑѪիi)GjPG.\r RAT(Ujp=°jsܶ c?+2Tԁ>*A&S7N>ƴZQ2:}~߀OG}~lFiUV1i +Y &d>%:Jv2|jJOx1SZZQA wFydfk^'IH}=LvjJeSDr=e告h,D=sf|䙅]w;RGVO{=e#=]VZj2I:ɪ0Al$~iV9:) a2a#j-(/qlwBSm 3eύ SG.eOg{2Y;sªd'*,>ƝM`MzD+QzQ/X<)O/tc1c!b_EI%/Į.-eTa+Sg{ 8r (yc8߉#eۅWw$"U^|VA >kg}#+Hކ-@ dBd,?ZDmE]` ~Y^o+GZ@ۃoZ5jK0wPGŸE9`?mfu܄H U^RT$˗e#-]s94#vd\77%|fTx7h{g7*vo|n20&sb'+ (Z;t7k_ĹBO{ܖ*}+S+rRȁ)JZYmBXlK) ,VmM+jmrC6Hlfp4ox*Yz&<~Bdt&{FZV X KkUU*\QF-G|{*e"ܽ$헾<܄X6ͺʈj%F(<|51qՈDNr~q@Fi4ΑwLa uSPnd-VUlu òPHYed8F4Os;\c9F$i؜4Hs`Q†.Ȃr@8k5`W!.`0ϜU3 2;1ؼz`(kSP< feY`R7 XT U,07c <,p(Άmo ̂R{uiza˙&.Z<] OEk<^)|VZCzV^ qDdBv>k;tRbDŽ"Z)k~y.w\]xB 6#SŲmHQ=~96sܯWhY9 ro/֚kk+7x7TnnV4m VZk-e6Q7qĦ ieޜӷFCk|3mHLu'w(k̖#G֛~+۳$dJ7MyڍP~-OP_WW\SOQ%jkCN`x&W'S& OcVg 6f=,<>o+xj+x3%0*p"+3aE\p{0j"J:$Mdj'6MƉ'N7D<"ɉdDyJ6Ħ@ '?&]S;ђ̹-XE"qgۆ'҉ۄ4iu72j a;=ALqʺNOӗwW!1acm m 9 ,7@ęmԚ*+zƧ5#Fݚ>zѨyn8ݢ=0ks$fh *dyr sڍdr C`>xzw(d!12f+ StXى Β'Ox1 C  UPk:'';[BI]?J'a]hMMT-x|fL@ñ}-]lw[Վza[#'VztGy$ZYJopVK>sr]Z3ʜlG]X%TeIQWhc5L' G|vgRsۡlQou.0W qj(+u)>WjS'fRyE+>nj9e 癗TV^%m1"/?5Q 9n,2lq$EsZl8#(`BBVV洄~eb ^cݚ!7ޔV*^mo럧Ou~xoӫϞ;0tIߣ]zެ?aRKȱ1XXHHJ҅g/=P?e(Zř=z 'өix,eܑl%a'7GnQen]U/q#C `'|"IA}>EG}:8 /: w9LDb› & 3\pr]Cx8Ix(Jqsmm+`橮-OMmi'X=%^ZDPx]=:i0^žWuPQh *+p}ƶs5Mʬ`&Ѕ}8dAy+Y3ͷ{B{Ǐl\b#2{Na{|+ a=-}g;SooѤoVS\YiU~Ǒ/lL+moˉ=#1]3£m-{//p*d}[a.c<LÔ. M<}$c/~=9q0T[#~sYu] 3!yY 3 T&Y.'v4*w{=cS#q|,·`;p+Y*u ^L)Ԣg4d U8A*@P OᷬKl5j,%AxNe"wY v+/u'{8=]C6 RƘ,khr};1Z8Uh)x3Z lw?{SM>gLql8Ѯ }UX濲6 _Hz^{UK9:C2UtIyK%9qHSC|18טMh$7!jM'(9~ꨥe<<70SGӇj#vJx`h ?ۄ*k͒cYȜ3qΘsV6XwY9ߘ J!4 L;0~.6eY%fXd&f&UY.{2u{7Bӵw5/=K GL4)>+{ ASjbTMxsnlz|.Į4j ܱ8 /8 _<ᵀ|.Nir_]+V/{ƀ9MfG;7ڮk oB^);ΨIƢ/87$;Z;eեe6{ivvaRW[압LYܮ~!?Bdo?6*Qߔ75ZVF\Y wV߰S@l {$֔uu0fddAnDZDXsM\aHܶN3v?$EP0bdwQ8e9n)eĞr|nqNUGޱ(7lJ)u:.ba <[I]N>-c N ߗ>epMx10X/wr;3݄ҩ@l dlͲIfpdlԟ|3P6SPu6Q_ C؇B!}TD;#-<]&Ӡz(?u[l\?6M'Y8[qOz,s_=[LJ i-_\yDÒVffΟQ7.y*w?Ż}3۸y݄9w{W^K{:pcdžj>>.o<-6W:6-ZfӺu$ȽvjYuc؅QZ(Z|Xc=N;TmAG 6( 4 `{n7jj|O-Rr}='Ie Y'ӀJ; .QM(ǝE'd6e]MΞerrsjX`H?^q7R s/[}fa㈆^_a `U!m{,Z {pqt?[rayyg(m]p3+/ś(#CÌJq& %Ƞ9mFz0@cvdu#\)Hft 6nm 5uvaZL\ۏ,ZߤQ`K7/!35͘8 hCzSHktjtz 5즣Q0h* Cd̊}(a8k1? ,L\+Pd.<|Cpqqh 7;m?=]̦\U,u6k#^Y[`E*plBr^ɖR* D&Z "Edq ~Fg.|@Lx5Ek9%m#d ̖i~~Ʀ!X0{V?7p.GI̽#'VCH7{#ZIq%{n{oRx-k` ?|lO v㕡j_du\6+ ^`0e{y-i`h40OM< 0Z4< {yy OiCy ,%XG?&7-˸nEd}CcGG9k3]Ɏ:"}Cl05R鳧3ô5w2A1l#lB4o^Ԓ0 юu[< O@VQi*5k7ƼE[Pv%n9Es(hɤ`͜^L+ z vxߦ>t}AfېTގZm:}௜75{5X~T#9m`5 톀XO&`M=g -'M(Q%=cHz~(+ZrOce;>Hx߉ ɎH\u"cAf!Vc8Ǹ9d Zx/Dedyi^B ӌ  r qƯ%YqE&Zv@<[v q7!A8"ԦG2t, |uX 6jci<{YpE_~=q?*{h0W=¹4ދw ~L0ľ?nE Zv źzȺ?3ÅZY/ܖ`d.f6ļAȡ;e#,&IͰ,(<+qV`|y:ͽU7wi3t~C^YUUN9MV4KrٖW[lt+mm=pGG:{:vHߦOg꺿?waz'oco~2dy ^{{?ԗk;i,?5H8yܢgw"[zo~*Eλ 6TAq[hb]٭&.]cܓNqaq:"6oKýA_q/` ŒpOY͞4^R i~/e~Y*b$;=߹%UB^0#QcLs?T5@yMP ߀ XIz!¶.&)5=LMR$&&rHSnR ^0B2QT XqG+NT.=2&S iW֔><;{Sԓ_؟Jo\,To[ 6?3Yxphy`2#PuMRG+-rG']Re>]-ɲR1P9ّmv5e#m\CVZhV:R犆4KYDi@F'pvzNҹ̮ϖ4i)gq_*LV6$7K Ք7syAkjߘk05ECw/\#h!gn6\fWpnԂL jgЪch!,M# Q["۱-@+. f2d;'M$TosiGo0pg2Hh6'}6Ga_f`ѭ-[Mqahl5?> FzK0u9 D$lz# $J+kHa0wS& -!,uBRas: T͒_]Ž4Ofuڿ3˵k\tZ(Ox߳mh ){fRWow{Aw hkZ&Y(^gV7Bt%,OG}Õ@la 7^=Cj-&W| w܁id>K& dM9ۜbIء$ 30l5Є:%9ӈVXēG9%5٤[db5Y+(LD2Ы\wޚ>8O,_lw4h11aI0e*#[ο۳?|qfc#!X9wnJz࡞l|u< ƫ t]^F7nTӚdag=ED~ "6^k9mÂ@j"۵ 5UAqcM.SGY!eИ]T(T]TRa-TQG?d[H<>[sPf` 1d~mwffCšdaS9-f7w傽Pz{xwuShw9TqS2]3.3bjD]6{ub)e d45&+M*rq=GHV|d}z!Nbh&` 8'}=G򽾩s[}TgbB&,'=)TWk+IVbltlb'I 6,Cu EJYD0QD1-!TAd8hT qՍqHj<vX;__X/#aUw `b>Q};-#z3H}$0Ix,&f}pWh5\ten[b9Pz ~S;FWɕß+Z كAkd8olѱE3Ym,~ \;๗޷OEQ<<Ė }y>YHEDf) b"y@8 ]$bLɌDkQݫWRukf*=6Ž(1a+'Zw4BGf)\ ֲؒә2UI> Lxd/) 2u;@$9)BDϓw.U־[kW^` <9;vR 5 u8:YChiEQD ;q}u$(K6@hJ]gY"SAg-'ʭeb/g"FKlo*WLΠe~S:, Ghr t^EjM|YY-f3bm ~6IQ^h7nI#r&R${z*M^/Va|c}sхmOGtڝwd̎ËwpyPpDyxeQ+'Ԉ!>Z $8^ A>X%GyQȥVo2=??sn pUnͯSzJ^&dپmdNuo vYk(z (؁%$p )Gڛ+ Ԯ`he5gWkڧYiW!qvKjD*'{Us艣'YbdF&#aI %ԃ"Ђi&!N Ms)Sc^Z ݳ/b)1.L+ C'B8^S#G(ZLxڽt,߉R}XTguQqIwj[duEOWQX8 Bu/=$\0`}H ~j@m+pe>.w"6eU" (gM154Rg)I߻~߾px޵{C|yTe;}4`?tLq E&g3޸4>HfxF ('2讇?l4ք IHz"z(BeAE&`3nP_(YjWb=KKf1s4^dg74;\;TtTewjO[.<?62"ypR.J{3Nb$X Ds@7R'10z`uC! :VNj1c%beS)B9҂GT)D݇l[I'TCsc#;*Y&S%Gy8g4A]v 8܉fPrpR!f} + K?zYZ[Н7S~S1966.w)[|e*++цJ93eL W?#JtN}gJϾyxݦҤҽk; oZt:>:nvG+A[Q?".s>e}%.aQ[,E@W3hg]Q{ =Z"CBOAcNȷ+DŦlՑ*QFDHNb&C}%E*=Y#!_9fLh2[,ʎ}xSQ=5+{=KV8?ɟ m~T#ބy<]R"N⿳IdEt[~RU<=s}nv/!1412^nd⥃fmz~P/%\%'=ϜXˁ&+Cߒs$nYcHG,>5+W5#,VD4%:*#||8~J'j1H mmЊvvP0┎fI`CcY-+K>L2,em'_1&S֡:yȿX-BVc(Ⱥ @?W>8'WI衹ÀFuCX+刧&喍1DTd=+rIu7k%w`a[&CV 9s\~5ee#nom<^̄"int> "v[]4N\"dI!()QDG Jɜ[Bdg /j)Vbi?Zհؿ\Qg):=m2E| dZ9.BJk6TÒp=K`$4`JqF-:'7wmb)ph{wG$m5Vbzo!ϢP7ŕDVQ!n<$n)!Q98d1؜= WcPUIXMD2׀vB!!"ޖr L1Ѻ(M\-V_//g˿ڮ=]7} p~Űbĺ{_V>e:i"ax gI(FmSE9Z TdT (G J29P:(dH!ҁ!I(g، Lcb`;)Jnj3Z'k@.=n/]cֶ#!s2kӹu$b d[!VtT3}-E)a|*%[@4xkc[[*0V~ڽHu31Q݌6P݂jLgQU80F_XOFG\#-\7^W0K@(,b π{|ݦDld2dYp]䌟ˣnR(RpzKd܀N :@NQI;v95,, r4t^R:rD+^=^$xrݴBԯ ^M-|P_PߔSو fLfw+&ؕ4S! b@ɠ(9L=h OxǮE <9ѳUhv]lҨ//lՍهa* =VWI? ;zAs_,fy+E:G}^-(rk-BLylퟋ9~}e>/htO_d6.G.YY(%yli5VC]܆gm?7&ȳ+ZQ'9R::N4.-8T픨TLAAѳRڇ,#cDŽ6Cچ =GI343_v;;v`h$Nux)2ykX Y咶!Sv aG1/;;56K{ T3zGa 5j_3!2 [5eO 6 lrPؐ$e5C'*ߞ*ڵ7`_9;ޮpK;ȭw4 , x൏=Q3+~e7i|G0KAS;v v\jkOYOb 7|u_||awQmXNyIy_mQ,*9Y۬Jd|jG_gӬo䗾TF;<=QA$ze¿ZQe;405fǾus!JsWeXjOSiDv,X;1ǟ9u?>Tjc4oжC8gރ$OM"Dpw(+Tn J]RրIMΡFXΥ"-&&*EDIiB?b# :v SE_4MJ.?ݏF\w"4_.%Պ-֊' |N"6^sU=@lAbXzےdjU04h/v+Z'2H[I>bgo,[ZL,- 2=|`bӕ+Q>}4zS[L6삀@Z $T2mPrdc?>0Wڟ>#~B\zZEvOtB_սt a[~3W@-_9D MȖ2l*[clvBWķMEav {XEhl̩[> endobj 185 0 obj << /Type /FontDescriptor /FontName /XOPHTS+CourierNewPSMT /Flags 33 /FontBBox [-122 -680 622 1021] /ItalicAngle 0 /Ascent 833 /Descent -300 /CapHeight 571 /StemV 0 /XHeight 423 /AvgWidth 600 /MaxWidth 600 /FontFile2 186 0 R >> endobj 186 0 obj << /Length 187 0 R /Length1 22340 /Filter /FlateDecode >> stream x |U?<3};w_s7BNH !6EZJuQ\+b+K0 Z7 .>jR>B}sM ty>>sΜ՗YLD^l 9Th$Ds+.Z*#DW^*!%/J)c"UH3,[T+"X|aݷ i#?lqWN{iϊvBۥ&6Ճ3!"%ω0"b2A"Uzy:2ʼ^2ǍIm :?qdž6"$O(!}$㔤ߜYփb}ba?Y H!^H^{;H{I/~7xAAM0@𴰫/3f}I wI K#GtAXW4PkIw{oJVl܏PWxzzz17~37~RPVҙ,t 2zC8tp^_Yh_c0ަ[Y߮xUZ*J~oP <[SqH[x,%yx a -$ (t0YI {P*)<f'Ӊ„PI 硍1fknG؂pDx-!AIf\MFq-2Wz-ux:IJP !.Fh@0a?›qX$%2BB7 )̫O( I&ap: $r FAV }*с~o1tykD؆% "Xk믭-S14J2KeB)< `yr^uBur>CG`1r9xQz~_Drk×&g EM.1_.bm#CmQݮ #0#79 c:֗4Vaݧ#mjnmn!vTn\yrp zqݎ6\p݊k=g*Wm*5{|\ݬ[ @}7 tǴo uyVo;DJewss:dzn{eEd* ׉/_&K's$@u sx|Z@, *KIo27gX% k1:K`Oүs~l)c8G|jhG™K|H&&{Hw t 1xK=!umއNZv-{%n^ĴIJ}dEr*pK%fzCq@; -yv%t9]AWҫ5XGLDfNS-d׳"{p.l]Mo$%T[RJLҾv}jЂ(J4'.MO'_a->8 󞊙ρt!%J3t?}#5}Plv!~? L(UэIK#SNTemBkb5Ѝ˗f:04&l+قv>uG3$L\xmab=}p Hi=`Y  7UZj3%o?W1m:ʄ? mc.V P ɠ?wC )Ϩ[Jl/-R zRr-]K.aw([zl2مDLl!9:7kz! cbSޡ\FO $|JfsT<15D`ǁAV=-%F2,V bPnҤ%ZUXNꁍCD.z!&YLGmGI75y+ K줵43+:~55O'5o$w &Cn`j2J]=4mmr:6d1NQDQRc&rl>*QFՄ}z||4)gS=呞T ג‚pK,zs,<@ϟюXGwPOU H-%^npu-ͅtAkZ/, d c+Sw=U22n;#Z^kn0Z/mD: zi؂^µ҅4)U7jDŽ/ې: qآs{GK56:9]͡otf_X8;[wSwˌ3#Ʋ &ѷRRe7tHY[/gu_ǖ%3|Qk 6cd+r;`dM-v%1,ƢڔҝZg,sMQ ØI{ TͣdjQ{uMqH{UYR,{ ~5f~F%}Ox#ǓTxo~>GM`9+‚űR "҆1pz{faGb nq-=-#ûcP"qjG,޲d\/uũsc3oNcmQT;_Pҹ^{Sg9V GnVzрF TjhxB=)w#4_QJrzX5zMMfTyY`9uGM3[nB,oզ{|GG:|G )ڠN_Gg"C؊T=F~1(1i-ykzGlgv yĉ>!܉Љq  $!`G )5 R<ͪzb@S=acXa1̑$.Xdh>~$$aV^A&"ِҹJH0.f~J^3SK#݇ FIS2;)[p<5ӛ{u`}F$=ܝqDHm !5ԸR%@j2t^v՞4xԡi҉کC<[#֬5rHNd9I~z;ymto7؍u|7In{s1lg=d=bڪ.sZ%>6:6K'JC'bR-VZB#ZfYa7)Y/NClY*ŪM^+ZUDJ[6{[Aǃmmm~D2);kr\UP8slXΖwNHV*If*P])&v5kT[h9oKaxK&l%ΪI6}UiVhMvCR9FmM.ZYY9&srf1+ڦ)vcg:[ގyJoo gط.u<kKD񯐦./?~p1I:Hq4{ JݙHˠc1JpPUV)/?3F(R#1Yao>_wZ#ټ4=B+Uzh&9v,nw' 7Nx=* (yD)~c?>ɒjXSNڤS`tZ E # g#`?#|܀u%NM3KL66Z.ޮٷ39b"꽁Seԡ㵀Ǝ7y$I\?w:$ R s!N9j[ l82EcHNeSL:ȁvf֙%C@J' mVgERNëR?9ٹy٢`uFQcT5S&aOqu ]X1KD~/lcL"U/u:%);A%s>zmGwK%_qWN|H~"b߿pJəS/#굑謁Gw:^wWb+`<ϵ Řb s }8l+HwԱ1$uB 0V+uOcUjW{hO )@ǎM>>O̡1t AI.bYSL3PQewL*L3+em2hIujRR*&)a]^6p` RR4L#)a(W_ҿYܒ/yVu5s,gΕ?b_~>DI˪Wn<]y -YM,,LRYgs}Dm KDi0xBL [mm*!D‚i< >"NcCe~1q%j>YY!=M u}%,IUTtX=u<ߍu%lVV*D3RmS Ϙk-4ped1]'^=bU}L:~L(,b[Myicke-lARv18p5HxkXk2Q6YR-]>sȘK~K5- ZNk%YE*Ø*NߜϨI!"n:ϟ ~Y^(6wL6!V'6̘Qؼ`yJhuw$f j kTa%l!eU}Gi֠6B3uDߦ^{- aq@()jMO畜<)ϖ['m{ƲmVQ p[LDH/uGbscKn @ޒM-١5_<Π Mv\0B[ZEy6JA mpXO]9) SBJDC*+Hyggmz{_xg:/~ՃpyT\Op[/+)<.\ Zb?59I>p02T+LT*_=hP FAb484Ѕ{%J}Yx~O+I Lc9"Nk+Mf,4]䫾#{FǴ5"b ?=3PYd)sǗuo^{{@2[~G鑫^0yGmHֶ^śz&'+cLylCۇޏiGT9CKCoo l >q (h;8Tk_aHPkFĭ#Vqf +@AS К-ܱqH#ӬhA]+  rv ѫ#gPahĥaLQV#.xn>HWߠ9w및W-^U*Cuzb0Tx>0dcGsu[}z֢3*IQ]E)L 9Z%fʲҨ637J"82z:> \c`g}ԼG6;e N\8vM=ޅ>S|f|RiיBs~HܟpG(پ6Z6=ʜzT1UrM'nrǡrO(44#%l7ǵ<Һl6^ڲ6w1ĵRNric}y'ȱK.,^X~隼*y[L˹AT*.H0^ K0`iU rWF[`*܌0 nW'Xtuttt*(덉bbGcĘ"(dU)7- cr5TR4Cag`^gj }yeb/)\hnuh,vι&3Yp]JezV̝wo\'O|ݛn?npz1v_pA.c=gr~ݔII^_-;3qh^&n 3:"Fz7BfQ?١کyYOZ ߶8Bq8ܞ5W D$=/idRJ5dMeK4ZMy pWQ#鵺BN<$ƑHt_ɡV2@;1 JdJ|8h Q@Sهo .sꫀC$_QgUi)MSliyw!GJ]\*|sXGM[V..-4Йmwu.e!7 ~fncy) jS(z9[n>:* _1pJ+\*+dyeLBj/Ijw@Uu*U xqB^b];/ fYUatux3f=maSZٖn8 e 3>Ŕw*ްbX׬S{y)?%fnpmdGZZy IB#.CzhioǾ*@*v>K f7ͮ5XKa}g4 y* YybN^U!18OrS݂.0G96>w""hS~VNZ%vvv3CkTR0}(*;Vt4l4U>mqҥ "իu8iE6NPK ꚔOxE` Zj9h';Cp"GӜEi XX>X^MoUe/_Բ}>Rӣa 5f#jvu`B tI߃A VZ!'sN:ovx'31SlG) ,,)%MRbZMУ$ ˞56>tz0ad KbwC r>5gchQ{Fv*02u@k3R8_rw!i {@/%Ocшso^ݩ\(M~ٹWSgOŌQ*l3Noq22^%iiDMyŖgyAwRgG,Zs8hɘ1/cy-;U)TיִQxVa1k,ZR!C9KٞqRoEro o}b5oJ =)bzMoaaι]3|:w%.Лx`=p"$+WbLb ]l<0DOÌݕLqw&)Nf Wטinە[leMCX(E~6eYxgq";-377+37G** 8̒>3 Y~E #iRob꘷`]զrv;29Pi60l)Km椼hg#"~:]o*UՊ7XXpً}v؄1_DdwTϯG}m5;Cl6.j+|Y4%e%1hŌhܽ5uuؽkWr.E^9=&!5c#Ӄ#|JgjuAhI#i/31(6ţqٯ0ԡ!A!kwͧrK۠j-Ȳg!RUaD(Ls6lUDo+u5dfGQ5ɉf.bl}2\p(5 sΏ?>A5_Ssm qoeENvfvj^ezML(q[yoZٻmZ3|Ở(>6zl67`{bLw/$Y*iyZqqbIR+&JU#I 9󤟚>?{XS1r{̏_6gPT9S+mJj6k`Mfg#^fyLvy@8"^i!7 88(;لEf_o0t!C8ýNŦYS{g8Գ+=)) uU΂kV~a=^x<ӎO|ӌE)oͤ/%n׸ @CM•@QUZPZ9yFTu@UeC<6O4n+iuIvoԠڧD%֟~stYff-%&SdQ@ ipS4+űԎEWqˆҲḫKmTR:J|~;M8G}L^,'8cQ{YY8u` lvB`R l.Z;j|>P4ԙ558>o& [<kJm*|&ªoTj<ptk%tޕ#J/Ci6ؐ>=юl}[ >|FYőf,]ҨJZʮH9SJ:F#dy-M\ LNgVRT!( xL5 )y:۞B! i A;MG֛˂jzl1|AS,h4ջi[vu)09=3S&nXv5}~9Fjz֤WDe)%El@ƂQ18*lNI~~i(O Xvp߹8pMFO% gna H)Cu^g^{ppv2J};ߵe0٧h ZD^v fYm`Qt P*g' k;elx H"aQi;2#a|-q7O|OGQ}Ґ7E҅T9u Ǎx bk)e۪1cP4j5z٘2{|iHoyWN_p?t\]v>id3m,KZE尻.gͨTS5LZݍ*klϏҫ~@AVaK6#E⑛C)F8W9LmS֢ NuM%a VVV7)u3R^R"cqap4`/=XNk*"+{(2Xܑl(?ʮȑԺeO/"9WnBu&bbSW^Q?tIQ'6Oy}BB'BmFª_0j_"i_*Q7"0_L׭?|CNA?A$ endstream endobj 187 0 obj 15555 endobj 27 0 obj << /Type /Font /Subtype /TrueType /BaseFont /FSQQEN+Helvetica-Bold /FontDescriptor 188 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 122 /Widths [ 278 0 0 0 0 0 0 0 0 0 0 584 0 333 0 278 0 556 0 0 0 0 0 0 0 0 333 0 0 0 0 611 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 556 611 556 333 611 611 278 278 556 278 889 611 611 611 0 389 556 333 611 556 778 556 556 500 ] >> endobj 188 0 obj << /Type /FontDescriptor /FontName /FSQQEN+Helvetica-Bold /Flags 32 /FontBBox [-1018 -481 1436 1159] /ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight 720 /StemV 149 /XHeight 532 /StemH 124 /AvgWidth 621 /MaxWidth 1500 /FontFile2 189 0 R >> endobj 189 0 obj << /Length 190 0 R /Length1 12144 /Filter /FlateDecode >> stream xz tSU9$mҼӦI;}B//hlk+- 0kyMPEGD|⨡0䃏ϩ3ƊU)fXk<9>sY}cҠMF-݋!jѴ%MwlE48jϖ{BMK::"EK #zYM ܴEcƽ._ѱvtΕ+3 Lt;ݫ&5!׉#%ZBZCj7b}3{] bKF:d 7{ _i7(ZEB `) b$%ǐ;#ǵ D!l-M*ͭ]lg!aݵ M`D͗Dڹ].we =w%iyuS.ZBŽ:wWEsw\ I\wA4|bp8Q|f}m﫦UI!}Mk)'}"}"}Ջr_K{gPٙrdG(6;$"ٗ GFhn8=xUt+<t&;Ȇv^o|SNڌ~EQ7*fMBF6D|$.( 9~@Oavt|mcȷ@$C-6@obNx~lcKyh\+M=.Z$FhBm%t}F7 g?fOd}T:`M|Oy@qU/  ! r1@3G#;m?|6@e r~xn;7CM$PV>LmŐ'.gzp08c DגC#+4<ω?n<Gȱ H|iP sHCzd JͰ>;vv؝::+@pv9T u {niK6}=>'rrP!Q 'ohy4UtE o2vlJcdU(¡Ѭ@tҀ6\Jårsu.hP)阮 b4ʔ('v%q 4'(hfdU/dҎFQ88>enZt̀cK὘cNL?>Lȸ\bJ} :ɘ5ܦ=@hQSPH_! l~j x7z 0EѠ#K 聆+ a5.>p>8uQoybbg) ~IɨժCH9ɩQjF[n~i=EUHp[djD:C{Si^s s12ĩtE# J"nM;*7cx9>BY4E伊}vbդrnC6t#[82 T7M -9iIC_n,0|#~χFFe:kT\ <9]Sq8 Ӿc;Θz^3<ޞ}gcԽyzssQcqViJ75u}{@(4*Lbvqv UXơ8ϦѰpZeN2xUR)sOTy dO.Lb+BkIa+ئts"6] HR @Q{9b|g'MikJOe*?cE'$H/h$s7n*NgTfӖ~^OK.ugu`TMkrU}Ϸi~+5=b cSܒº/ 1WO7jSjA-uDTgfeGGd5ґVH)^P 32J. TȌi•ӵ0!!WJo)Zxؔ6m=O }c+bOݶb95씖FfGPi9h/cs؊4D=ˆ}>R@dZ#LNB8q2)Z'){{[Om:5k{qwG. xq۟_pE0Ah_zLQ7 ,emlv|slCMYoқku: [b;a>֩-Z ]b111'ś2U&J՛Ԕ1n@1&0?ځD0('qOZg%6r99z[^,eQ572)2aޅOII)*tVO!}I -xpB 8(RUicUyvvmgo+(U hfq$fn[lcvӻG'#:~r36fb}N.B* r*W! h( ަbTVUdKb?ik4oBq8ZE)_XUmZb:flp*="]α/uAAz`nxXpɐg9 %87' ګQ[҂]4R@70<ހH9'_42N%1,2KֲK`<͌u3uOUG, XnQzѝ 'Kr.ӆR"/H5p0 雷_yƦ3ރm&]03^"Α^~1|r Y>G=rԉقfJ7M2x+g,olkl bO !21';2`^/Yހ'Z2~]}g>g}_5Ly6_Cs6O_D1;`gw |¡ߊ\#=ޑsXKUCz^pxgwgb?c%doco4Q,|є` a LQa| '<j= )eG jJq2Uwt2ΓHIS~S~ #>Ck:dXd@!_ PaSňOPQ8MyqM8tv]8A.WQ@0g; 0@{)¥ E_dffasp?py?& 1/232f0,퍣(̰fq' JRzxBPY 3 )NXɃCcA`( #GkGPKy4c[gL6!g(dZlFxۯPp[><#U؆{ n@7uJ,. _QQȧo^aX%^i4YS3m> endobj xref 0 195 0000000000 65535 f 0000094042 00000 n 0000000642 00000 n 0000037181 00000 n 0000000022 00000 n 0000000623 00000 n 0000000762 00000 n 0000007168 00000 n 0000058993 00000 n 0000004396 00000 n 0000037929 00000 n 0000000870 00000 n 0000039536 00000 n 0000039321 00000 n 0000000904 00000 n 0000004375 00000 n 0000004432 00000 n 0000007147 00000 n 0000007527 00000 n 0000007204 00000 n 0000007507 00000 n 0000007635 00000 n 0000039031 00000 n 0000008539 00000 n 0000007744 00000 n 0000008519 00000 n 0000008647 00000 n 0000085335 00000 n 0000038578 00000 n 0000009318 00000 n 0000008757 00000 n 0000009298 00000 n 0000009426 00000 n 0000038212 00000 n 0000010033 00000 n 0000009524 00000 n 0000010013 00000 n 0000010141 00000 n 0000038092 00000 n 0000010671 00000 n 0000010239 00000 n 0000010651 00000 n 0000010779 00000 n 0000038252 00000 n 0000011814 00000 n 0000010877 00000 n 0000011794 00000 n 0000011922 00000 n 0000038132 00000 n 0000013016 00000 n 0000012032 00000 n 0000012996 00000 n 0000013124 00000 n 0000038951 00000 n 0000014014 00000 n 0000037305 00000 n 0000013234 00000 n 0000013994 00000 n 0000014123 00000 n 0000068964 00000 n 0000039758 00000 n 0000038172 00000 n 0000015233 00000 n 0000014245 00000 n 0000015213 00000 n 0000015342 00000 n 0000038828 00000 n 0000016232 00000 n 0000015464 00000 n 0000016212 00000 n 0000016341 00000 n 0000038498 00000 n 0000017392 00000 n 0000016463 00000 n 0000017372 00000 n 0000017501 00000 n 0000038334 00000 n 0000018379 00000 n 0000017623 00000 n 0000018359 00000 n 0000018488 00000 n 0000037968 00000 n 0000019524 00000 n 0000018610 00000 n 0000019504 00000 n 0000019633 00000 n 0000038538 00000 n 0000020594 00000 n 0000019755 00000 n 0000020574 00000 n 0000020703 00000 n 0000038991 00000 n 0000021831 00000 n 0000020825 00000 n 0000021811 00000 n 0000021940 00000 n 0000038416 00000 n 0000022922 00000 n 0000037431 00000 n 0000022062 00000 n 0000022901 00000 n 0000023032 00000 n 0000038910 00000 n 0000024203 00000 n 0000023155 00000 n 0000024182 00000 n 0000024315 00000 n 0000038786 00000 n 0000026107 00000 n 0000024438 00000 n 0000026085 00000 n 0000026219 00000 n 0000037845 00000 n 0000027666 00000 n 0000026353 00000 n 0000027644 00000 n 0000027778 00000 n 0000038292 00000 n 0000028691 00000 n 0000027912 00000 n 0000028670 00000 n 0000028803 00000 n 0000038618 00000 n 0000029466 00000 n 0000028914 00000 n 0000029445 00000 n 0000029578 00000 n 0000038868 00000 n 0000030307 00000 n 0000029677 00000 n 0000030286 00000 n 0000030419 00000 n 0000038744 00000 n 0000031143 00000 n 0000030530 00000 n 0000031122 00000 n 0000031255 00000 n 0000038050 00000 n 0000032527 00000 n 0000037564 00000 n 0000031354 00000 n 0000032505 00000 n 0000032656 00000 n 0000038456 00000 n 0000032767 00000 n 0000039071 00000 n 0000033216 00000 n 0000032796 00000 n 0000033195 00000 n 0000033329 00000 n 0000038660 00000 n 0000034905 00000 n 0000033428 00000 n 0000034883 00000 n 0000035018 00000 n 0000038374 00000 n 0000035815 00000 n 0000035152 00000 n 0000035794 00000 n 0000035928 00000 n 0000038008 00000 n 0000036500 00000 n 0000036027 00000 n 0000036479 00000 n 0000036613 00000 n 0000038702 00000 n 0000036969 00000 n 0000036712 00000 n 0000036948 00000 n 0000037082 00000 n 0000037887 00000 n 0000037683 00000 n 0000037792 00000 n 0000039181 00000 n 0000039239 00000 n 0000039433 00000 n 0000039491 00000 n 0000039645 00000 n 0000039703 00000 n 0000040185 00000 n 0000040434 00000 n 0000058970 00000 n 0000059705 00000 n 0000059963 00000 n 0000068942 00000 n 0000069420 00000 n 0000069664 00000 n 0000085312 00000 n 0000085757 00000 n 0000086017 00000 n 0000093859 00000 n 0000093881 00000 n 0000093918 00000 n 0000093972 00000 n 0000093999 00000 n trailer << /Size 195 /Root 172 0 R /Info 1 0 R /ID [ <0875988bdb4806ea7ba420b8003d054e> <0875988bdb4806ea7ba420b8003d054e> ] >> startxref 94152 %%EOF tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/epl.html000066400000000000000000000305361312245000300225160ustar00rootroot00000000000000 Eclipse Public License - Version 1.0

Eclipse Public License - v 1.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

"Contribution" means:

a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and

b) in the case of each subsequent Contributor:

i) changes to the Program, and

ii) additions to the Program;

where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.

"Contributor" means any person or entity that distributes the Program.

"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

"Program" means the Contributions distributed in accordance with this Agreement.

"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.

2. GRANT OF RIGHTS

a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.

b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.

c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.

d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.

3. REQUIREMENTS

A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:

a) it complies with the terms and conditions of this Agreement; and

b) its license agreement:

i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;

ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;

iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and

iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.

When the Program is made available in source code form:

a) it must be made available under this Agreement; and

b) a copy of this Agreement must be included with each copy of the Program.

Contributors may not remove or alter any copyright notices contained within the Program.

Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.

This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/pom.xml000066400000000000000000000033051312245000300223570ustar00rootroot00000000000000 4.0.0 tools.analyzer.jvm 0.7.1 tools.analyzer.jvm Additional jvm-specific passes for tools.analyzer org.clojure pom.contrib 0.2.2 1.5.1 bronsa Nicola Mometto org.clojure tools.analyzer 0.6.9 org.clojure core.memoize 0.5.9 org.ow2.asm asm-all 4.2 org.clojure tools.reader 1.0.0-beta4 scm:git:git://github.com/clojure/tools.analyzer.jvm.git scm:git:git://github.com/clojure/tools.analyzer.jvm.git http://github.com/clojure/tools.analyzer.jvm tools.analyzer.jvm-0.7.1 tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/project.clj000066400000000000000000000014451312245000300232050ustar00rootroot00000000000000(defproject org.clojure/tools.analyzer.jvm "0.7.1-SNAPSHOT" :description "Additional jvm-specific passes for tools.analyzer." :url "https://github.com/clojure/tools.analyzer.jvm" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :source-paths ["src/main/clojure"] :test-paths ["src/test/clojure"] :dependencies [[org.clojure/clojure "1.9.0-master-SNAPSHOT"] [org.clojure/core.memoize "0.5.9"] [org.clojure/tools.reader "1.0.0-beta4"] [org.clojure/tools.analyzer "0.6.9"] [org.ow2.asm/asm "5.2"]] :repositories [["sonatype" "http://oss.sonatype.org/content/repositories/releases"] ["snapshots" "http://oss.sonatype.org/content/repositories/snapshots"]]) tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/spec/000077500000000000000000000000001312245000300217735ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/spec/ast-ref.edn000066400000000000000000000546151312245000300240370ustar00rootroot00000000000000{:all-keys [[:op "The node op"] [:form "The clojure form from which the node originated"] [:env "The environment map"] ^:optional [:children "A vector of keywords, representing the children nodes of this node, in order of evaluation"] ^:optional [:raw-forms "If this node's :form has been macroexpanded, a sequence of all the intermediate forms from the original form to the macroexpanded form"] ^:optional [:top-level "`true` if this is the root node"] [:tag "The tag this expression is required to have"] [:o-tag "The tag of this expression, based on the node's children"] ^:optional [:ignore-tag "`true` if this node returns a statement rather than an expression"] ^:optional [:loops "A set of the loop-ids that might cause this node to recur"]] :node-keys [{:op :binding :doc "Node for a binding symbol" :keys [[:form "The binding symbol"] [:name "The uniquified binding symbol"] [:local "One of :arg, :catch, :fn, :let, :letfn, :loop, :field or :this"] ^:optional [:arg-id "When :local is :arg, the parameter index"] ^:optional [:variadic? "When :local is :arg, a boolean indicating whether this parameter binds to a variable number of arguments"] ^:optional ^:children [:init "When :local is :let, :letfn or :loop, an AST node representing the bound value"] [:atom "An atom shared by this :binding node and all the :local nodes that refer to this binding"] #_ ^:optional [:to-clear? "When :local is :let, :loop, :catch or :arg, a boolean indicating whether this binding is never used and this is immediately eligible for clearing"]]} {:op :case :doc "Node for a case* special-form expression" :keys [[:form "`(case* expr shift maks default case-map switch-type test-type skip-check?)`"] ^:children [:test "The AST node for the expression to test against"] ^:children [:tests "A vector of :case-test AST nodes, each node has a corresponding :case-then node in the :thens field"] ^:children [:thens "A vector of :case-then AST nodes, each node has a corresponding :case-test node in the :tests field"] ^:children [:default "An AST node representing the default value of the case expression"] [:shift] [:mask] [:low] [:high] [:switch-type "One of :sparse or :compact"] [:test-type "One of :int, :hash-equiv or :hash-identity"] [:skip-check? "A set of case ints for which equivalence checking should not be done"]]} {:op :case-test :doc "Node for a test value in a case* expression" :keys [^:children [:test "A :const AST node representing the test value"] [:hash]]} {:op :case-then :doc "Node for a then expression in a case* expression" :keys [^:children [:then "An AST node representing the expression the case will evaluate to when the :test expression matches this node's corresponding :case-test value"] [:hash]]} {:op :catch :doc "Node for a catch expression" :keys [[:form "`(catch class local body*)`"] ^:children [:class "A :const AST node with :type :class representing the type of exception to catch"] ^:children [:local "The :binding AST node for the caught exception"] ^:children [:body "Synthetic :do AST node (with :body? `true`) representing the body of the catch clause"]]} {:op :const :doc "Node for a constant literal or a quoted collection literal" :keys [[:form "A constant literal or a quoted collection literal"] [:literal? "`true`"] [:type "one of :nil, :bool, :keyword, :symbol, :string, :number, :type, :record, :map, :vector, :set, :seq, :char, :regex, :class, :var, or :unknown"] [:val "The value of the constant node"] ^:optional ^:children [:meta "An AST node representing the metadata of the constant value, if present. The node will be either a :map node or a :const node with :type :map"] #_ ^:optional [:id "A numeric id for the constant value, will be the same for every instance of this constant inside the same compilation unit, not present if :type is :nil or :bool"]]} {:op :def :doc "Node for a def special-form expression" :keys [[:form "`(def name docstring? init?)`"] [:name "The var symbol to define in the current namespace"] [:var "The Var object created (or found, if it already existed) named by the symbol :name in the current namespace"] ^:optional ^:children [:meta "An AST node representing the metadata attached to :name, if present. The node will be either a :map node or a :const node with :type :map"] ^:optional ^:children [:init "An AST node representing the initial value of the var"] ^:optional [:doc "The docstring for this var"] #_ [:id "A numeric id for this var, will be the same for every instance of this var inside the same compilation unit"]]} {:op :deftype :doc "Node for a deftype* special-form expression" :keys [[:form "`(deftype* name class.name [arg*] :implements [interface*] method*)`"] [:interfaces "A set of the interfaces implemented by the type"] [:name "The symbol name of the deftype"] [:class-name "A class for the deftype, should *never* be instantiated or used on instance? checks as this will not be the same class the deftype will evaluate to after compilation"] ^:children [:fields "A vector of :binding AST nodes with :local :field representing the deftype fields"] ^:children [:methods "A vector :method AST nodes representing the deftype methods"] #_#_#_#_ [:closed-overs "A map of field name -> :binding AST node of the field"] [:protocol-callsites "A map of protocol Vars that appear in the bodies of the deftype methods"] [:keyword-callsites "A map of keywords that appear in keyword-invoke position in the bodies of the deftype methods"] [:constants "A map of the constants that appear in the bodies of the deftype methods. The mapping is from a map with :form, :meta and :tag fields to a map with :id, :tag :val and :type fields, the :id will be the same for all every instance of this constant inside the same compilation unit."]]} {:op :do :doc "Node for a do special-form expression or for another special-form's body" :keys [[:form "`(do statement* ret)`"] ^:children [:statements "A vector of AST nodes representing all but the last expression in the do body"] ^:children [:ret "An AST node representing the last expression in the do body (the block's return value)"] ^:optional [:body? "`true` if this node is a synthetic body"]]} {:op :fn :doc "Node for a fn* special-form expression" :keys [[:form "`(fn* name? [arg*] body*)` or `(fn* name? method*)`"] [:variadic? "`true` if this function contains a variadic arity method"] [:max-fixed-arity "The number of arguments taken by the fixed-arity method taking the most arguments"] #_#_ [:internal-name "The internal name symbol used for the fn"] [:class-id "A unique id representing this function"] ^:optional ^:children [:local "A :binding AST node with :local :fn representing the function's local name, if one is supplied"] ^:children [:methods "A vector of :fn-method AST nodes representing the fn method arities"] [:once "`true` if the fn is marked as `^:once fn*`, meaning it will only be executed once and thus allowing for the clearing of closed-over locals"] #_#_#_#_ [:closed-overs "A map of uniquified local name -> :binding AST node of the local, containing all the locals closed-over by this fn"] [:protocol-callsites "A map of protocol Vars that appear in the bodies of the fn methods"] [:keyword-callsites "A map of keywords that appear in keyword-invoke position in the bodies of the fn methods"] [:constants "A map of the constants that appear in the bodies of the fn methods. The mapping is from a map with :form, :meta and :tag fields to a map with :id, :tag :val and :type fields, the :id will be the same for all every instance of this constant inside the same compilation unit."]]} {:op :fn-method :doc "Node for an arity method in a fn* expression" :keys [[:form "`([arg*] body*)`"] [:loop-id "Unique symbol identifying this method as a target for recursion"] [:variadic? "`true` if this fn-method takes a variable number of arguments"] ^:children [:params "A vector of :binding AST nodes with :local :arg representing this fn-method args"] [:fixed-arity "The number of non-variadic args this fn-method takes"] ^:children [:body "Synthetic :do node (with :body? `true`) representing the body of this fn-method"]]} {:op :host-interop :doc "Node for a no-arg instance-call or for an instance-field that couldn't be resolved at compile time" :keys [[:form "`(. target m-or-f)`"] ^:children [:target "An AST node representing the target object"] [:m-or-f "Symbol naming the no-arg method or field to lookup in the target"] [:assignable? "`true`"]]} {:op :if :doc "Node for an if special-form expression" :keys [[:form "`(if test then else?)`"] ^:children [:test "An AST node representing the test expression"] ^:children [:then "An AST node representing the expression's return value if :test evaluated to a truthy value"] ^:children [:else "An AST node representing the expression's return value if :test evaluated to a falsey value, if not supplied it will default to a :const node representing nil"]]} {:op :import :doc "Node for a clojure.core/import* special-form expression" :keys [[:form "`(clojure.core/import* \"qualified.class\")`"] [:class "String representing the qualified class to import"]]} {:op :instance-call :doc "Node for an instance method call" :keys [[:form "`(.method instance arg*)`"] [:method "Symbol naming the invoked method"] ^:children [:instance "An AST node representing the instance to call the method on"] ^:children [:args "A vector of AST nodes representing the args passed to the method call"] ^:optional [:validated? "`true` if the method call could be resolved at compile time"] ^:optional [:class "If :validated? the class or interface the method belongs to"]]} {:op :instance-field :doc "Node for an instance field access" :keys [[:form "`(.-field instance)`"] [:field "Symbol naming the field to access"] ^:children [:instance "An AST node representing the instance to lookup the symbol on"] [:assignable? "`true` if the field is set!able"] [:class "The class the field belongs to"]]} {:op :instance? :doc "Node for a clojure.core/instance? call where the Class is known at compile time" :keys [[:form "`(clojure.core/instance? Class x)`"] [:class "The Class to test the :target for instanceability"] ^:children [:target "An AST node representing the object to test for instanceability"]]} {:op :invoke :doc "Node for an invoke expression" :keys [[:form "`(f arg*)`"] ^:children [:fn "An AST node representing the function to invoke"] ^:children [:args "A vector of AST nodes representing the args to the function"] ^:optional [:meta "Map of metadata attached to the invoke :form"]]} {:op :keyword-invoke :doc "Node for an invoke expression where the fn is a not-namespaced keyword and thus a keyword callsite can be emitted" :keys [[:form "`(:k instance)`"] ^:children [:keyword "An AST node representing the keyword to lookup in the instance"] ^:children [:target "An AST node representing the instance to lookup the keyword in"]]} {:op :let :doc "Node for a let* special-form expression" :keys [[:form "`(let* [binding*] body*)`"] ^:children [:bindings "A vector of :binding AST nodes with :local :let"] ^:children [:body "Synthetic :do node (with :body? `true`) representing the body of the let expression"]]} {:op :letfn :doc "Node for a letfn* special-form expression" :keys [[:form "`(letfn* [binding*] body*)`"] ^:children [:bindings "A vector of :binding AST nodes with :local :letfn"] ^:children [:body "Synthetic :do node (with :body? `true`) representing the body of the letfn expression"]]} {:op :local :doc "Node for a local symbol" :keys [[:form "The local symbol"] [:assignable? "`true` if the corresponding :binding AST node is :local :field and is declared either ^:volatile-mutable or ^:unsynchronized-mutable"] [:name "The uniquified local symbol"] [:local "One of :arg, :catch, :fn, :let, :letfn, :loop, :field or :this"] ^:optional [:arg-id "When :local is :arg, the parameter index"] ^:optional [:variadic? "When :local is :arg, a boolean indicating whether this parameter binds to a variable number of arguments"] [:atom "An atom shared by this :local node, the :binding node this local refers to and all the other :local nodes that refer to this same local"] #_ ^:optional [:to-clear? "When :local is :let, :loop, :catch or :arg, a boolean indicating whether this local is eligible for locals clearing"]]} {:op :loop :doc "Node a loop* special-form expression" :keys [[:form "`(loop* [binding*] body*)`"] ^:children [:bindings "A vector of :binding AST nodes with :local :loop"] ^:children [:body "Synthetic :do node (with :body? `true`) representing the body of the loop expression"] [:loop-id "Unique symbol identifying this loop as a target for recursion"] #_ [:closed-overs "A map of uniquified local name -> :binding AST node of the local, containing all the locals closed-over by this loop"]]} {:op :map :doc "Node for a map literal with attached metadata and/or non literal elements" :keys [[:form "`{[key val]*}`"] ^:children [:keys "A vector of AST nodes representing the keys of the map"] ^:children [:vals "A vector of AST nodes representing the vals of the map"]]} {:op :method :doc "Node for a method in a deftype* or reify* special-form expression" :keys [[:form "`(method [this arg*] body*)`"] [:bridges "A list of signature for bridge methods to emit"] [:interface "The interface (or Object) this method belongs to"] ^:children [:this "A :binding AST node with :local :this representing the \"this\" local"] [:loop-id "Unique symbol identifying this method as a target for recursion"] [:name "The symbol name of this method"] ^:children [:params "A vector of AST :binding nodes with :local :arg representing the arguments of the method"] [:fixed-arity "The number of args this method takes"] ^:children [:body "Synthetic :do node (with :body? `true`) representing the body of this method"]]} {:op :monitor-enter :doc "Node for a monitor-enter special-form statement" :keys [[:form "`(monitor-enter target)`"] ^:children [:target "An AST node representing the monitor-enter sentinel"]]} {:op :monitor-exit :doc "Node for a monitor-exit special-form statement" :keys [[:form "`(monitor-exit target)`"] ^:children [:target "An AST node representing the monitor-exit sentinel"]]} {:op :new :doc "Node for a new special-form expression" :keys [[:form "`(new Class arg*)`"] ^:children [:class "A :const AST node with :type :class representing the Class to instantiate"] ^:children [:args "A vector of AST nodes representing the arguments passed to the Class constructor"] ^:optional [:validated? "`true` if the constructor call could be resolved at compile time"]]} {:op :primitive-invoke :doc "Node for an invoke expression that can be optimized using one of the primitive interfaces in IFn" :keys [[:form "`(prim-f arg*)`"] ^:children [:fn "An AST node representing the function to invoke"] ^:children [:args "A vector of AST nodes representing the args to the function"] [:prim-interface "The primitive interface in IFn that will be used"] ^:optional [:meta "Map of metadata attached to the invoke :form"]]} {:op :protocol-invoke :doc "Node for an invoke expression where the function is a protocol function var" :keys [[:form "`(proto-fn target arg*)`"] ^:children [:protocol-fn "An AST node representing the protocol function var to invoke"] ^:children [:target "An AST node representing the target of the protocol function call"] ^:children [:args "A vector of AST nodes representing the args to the protocol function"]]} {:op :quote :doc "Node for a quote special-form expression" :keys [[:form "`(quote expr)`"] ^:children [:expr "A :const AST node representing the quoted value"] [:literal? "`true`"]]} {:op :recur :doc "Node for a recur special-form expression" :keys [[:form "`(recur expr*)`"] ^:children [:exprs "A vector of AST nodes representing the new bound values for the loop binding on the next loop iteration"] [:loop-id "Unique symbol identifying the enclosing loop target"]]} {:op :reify :doc "Node for a reify* special-form expression" :keys [[:form "`(reify* [interface*] method*)`"] [:interfaces "A set of the interfaces implemented by the generated type"] [:class-name "The generated class for the reify, should *never* be instantiated or used on instance? checks"] ^:children [:methods "A vector :method AST nodes representing the reify methods"] #_#_#_#_#_ [:class-id "A unique id representing this reify"] [:closed-overs "A map of uniquified local name -> :binding AST node of the local, containing all the locals closed-over by this reify"] [:protocol-callsites "A map of protocol Vars that appear in the bodies of the reify methods"] [:keyword-callsites "A map of keywords that appear in keyword-invoke position in the bodies of the reify methods"] [:constants "A map of the constants that appear in the bodies of the reify methods. The mapping is from a map with :form, :meta and :tag fields to a map with :id, :tag :val and :type fields, the :id will be the same for all every instance of this constant inside the same compilation unit."]]} {:op :set :doc "Node for a set literal with attached metadata and/or non literal elements" :keys [[:form "`#{item*}`"] ^:children [:items "A vector of AST nodes representing the items of the set"]]} {:op :set! :doc "Node for a set! special-form expression" :keys [[:form "`(set! target val)`"] ^:children [:target "An AST node representing the target of the set! expression, must be :assignable?"] ^:children [:val "An AST node representing the new value for the target"]]} {:op :static-call :doc "Node for a static method call" :keys [[:form "`(Class/method arg*)`"] [:class "The Class the static method belongs to"] [:method "The symbol name of the static method"] ^:children [:args "A vector of AST nodes representing the args to the method call"] ^:optional [:validated? "`true` if the static method could be resolved at compile time"]]} {:op :static-field :doc "Node for a static field access" :keys [[:form "`Class/field`"] [:class "The Class the static field belongs to"] [:field "The symbol name of the static field"] ^:optional [:assignable? "`true` if the static field is set!able"]]} {:op :the-var :doc "Node for a var special-form expression" :keys [[:form "`(var var-name)`"] [:var "The Var object this expression refers to"] #_ [:id "A numeric id for this var, will be the same for every instance of this var inside the same compilation unit"]]} {:op :throw :doc "Node for a throw special-form statement" :keys [[:form "`(throw exception)`"] ^:children [:exception "An AST node representing the exception to throw"]]} {:op :try :doc "Node for a try special-form expression" :keys [[:form "`(try body* catch* finally?)`"] ^:children [:body "Synthetic :do AST node (with :body? `true`) representing the body of this try expression"] ^:children [:catches "A vector of :catch AST nodes representing the catch clauses of this try expression"] ^:optional ^:children [:finally "Synthetic :do AST node (with :body? `true`) representing the final clause of this try expression"]]} {:op :var :doc "Node for a var symbol" :keys [[:form "A symbol naming the var"] [:var "The Var object this symbol refers to"] ^:optional [:assignable? "`true` if the Var is :dynamic"] #_ [:id "A numeric id for this var, will be the same for every instance of this var inside the same compilation unit"]]} {:op :vector :doc "Node for a vector literal with attached metadata and/or non literal elements" :keys [[:form "`[item*]`"] ^:children [:items "A vector of AST nodes representing the items of the vector"]]} {:op :with-meta :doc "Node for a non quoted collection literal or fn/reify expression with attached metadata" :keys [[:form "Non quoted collection literal or fn/reify expression with attached metadata"] ^:children [:meta "An AST node representing the metadata of expression. The node will be either a :map node or a :const node with :type :map"] ^:children [:expr "The expression this metadata is attached to, :op is one of :vector, :map, :set, :fn or :reify"]]}]} tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/spec/buildref.sh000077500000000000000000000004311312245000300241240ustar00rootroot00000000000000#!/bin/sh java -cp .:`lein cp` clojure.main < (str x) (replace #"`(.*?)`" "$1") (replace #":([a-zA-Z\?!\-]*)" ":$1"))) (defn build-children [children] (if (some #(:optional (meta %)) children) (let [[c & rest] children] (let [k (build-children rest) kc (mapv (fn [x] (cons c x)) k)] (if (:optional (meta c)) (into k kc) kc))) (if (seq children) [children] [[]]))) (defn children [keys] (when-let [children (seq (filter #(:children (meta %)) keys))] (mapv #(mapv first %) (build-children children)))) (def nodes (apply str (for [{:keys [op doc keys]} (:node-keys tej-ref) :let [op (name op)]] (str "
" "

" "#" op "

" "

" doc "

" "
" "
:op
:" op "
" (apply str (for [[k d :as f] keys] (str "
" k "
" "
" (if (:optional (meta f)) "optional ") (fix d) "
"))) (if-let [c (children keys)] (str "
:children
" (join ", " (mapv (fn [c] (str "" c "")) c)) "
")) "
" "
\n")))) (def nav (apply str (for [{op :op} (:node-keys tej-ref) :let [op (name op)]] (str "
  • " op "
  • \n")))) (def common (apply str (str "
    " "
    " (apply str (for [[k d :as f] (:all-keys tej-ref)] (str "
    " k "
    " "
    " (if (:optional (meta f)) "optional ") (fix d) "
    "))) "
    " "
    \n"))) (spit "quickref.html" (-> html (replace "{nav}" nav) (replace "{common}" common) (replace "{nodes}" nodes))) tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/spec/quickref.html.tpl000066400000000000000000000040221312245000300252660ustar00rootroot00000000000000 tools.analyzer.jvm AST Quickref

    tools.analyzer.jvm AST Quickref

    Common AST fields

    {common}

    Nodes reference

    {nodes}
    tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/000077500000000000000000000000001312245000300216305ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/000077500000000000000000000000001312245000300225545ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/000077500000000000000000000000001312245000300242175ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/000077500000000000000000000000001312245000300256625ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/000077500000000000000000000000001312245000300270225ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/000077500000000000000000000000001312245000300306475ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/jvm.clj000066400000000000000000000563641312245000300321530ustar00rootroot00000000000000;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.jvm "Analyzer for clojure code, extends tools.analyzer with JVM specific passes/forms" (:refer-clojure :exclude [macroexpand-1 macroexpand]) (:require [clojure.tools.analyzer :as ana :refer [analyze analyze-in-env wrapping-meta analyze-fn-method] :rename {analyze -analyze}] [clojure.tools.analyzer [utils :refer [ctx resolve-sym -source-info resolve-ns obj? dissoc-env butlast+last mmerge]] [ast :refer [walk prewalk postwalk] :as ast] [env :as env :refer [*env*]] [passes :refer [schedule]]] [clojure.tools.analyzer.jvm.utils :refer :all :as u :exclude [box specials]] [clojure.tools.analyzer.passes [source-info :refer [source-info]] [trim :refer [trim]] [elide-meta :refer [elide-meta elides]] [warn-earmuff :refer [warn-earmuff]] [uniquify :refer [uniquify-locals]]] [clojure.tools.analyzer.passes.jvm [analyze-host-expr :refer [analyze-host-expr]] [box :refer [box]] [constant-lifter :refer [constant-lift]] [classify-invoke :refer [classify-invoke]] [validate :refer [validate]] [infer-tag :refer [infer-tag]] [validate-loop-locals :refer [validate-loop-locals]] [warn-on-reflection :refer [warn-on-reflection]] [emit-form :refer [emit-form]]] [clojure.java.io :as io] [clojure.tools.reader :as reader] [clojure.tools.reader.reader-types :as readers] [clojure.core.memoize :refer [memo-clear!]]) (:import (clojure.lang IObj RT Compiler Var) java.net.URL)) (def specials "Set of the special forms for clojure in the JVM" (into ana/specials '#{monitor-enter monitor-exit clojure.core/import* reify* deftype* case*})) (defn build-ns-map [] (into {} (mapv #(vector (ns-name %) {:mappings (merge (ns-map %) {'in-ns #'clojure.core/in-ns 'ns #'clojure.core/ns}) :aliases (reduce-kv (fn [a k v] (assoc a k (ns-name v))) {} (ns-aliases %)) :ns (ns-name %)}) (all-ns)))) (defn update-ns-map! [] ((get (env/deref-env) :update-ns-map! #()))) (defn global-env [] (atom {:namespaces (build-ns-map) :update-ns-map! (fn update-ns-map! [] (swap! *env* assoc-in [:namespaces] (build-ns-map)))})) (defn empty-env "Returns an empty env map" [] {:context :ctx/expr :locals {} :ns (ns-name *ns*)}) (defn desugar-symbol [form env] (let [sym-ns (namespace form)] (if-let [target (and sym-ns (not (resolve-ns (symbol sym-ns) env)) (maybe-class-literal sym-ns))] ;; Class/field (with-meta (list '. target (symbol (str "-" (name form)))) ;; transform to (. Class -field) (meta form)) form))) (defn desugar-host-expr [form env] (let [[op & expr] form] (if (symbol? op) (let [opname (name op) opns (namespace op)] (if-let [target (and opns (not (resolve-ns (symbol opns) env)) (maybe-class-literal opns))] ; (class/field ..) (let [op (symbol opname)] (with-meta (list '. target (if (zero? (count expr)) op (list* op expr))) (meta form))) (cond (.startsWith opname ".") ; (.foo bar ..) (let [[target & args] expr target (if-let [target (maybe-class-literal target)] (with-meta (list 'do target) {:tag 'java.lang.Class}) target) args (list* (symbol (subs opname 1)) args)] (with-meta (list '. target (if (= 1 (count args)) ;; we don't know if (.foo bar) is (first args) args)) ;; a method call or a field access (meta form))) (.endsWith opname ".") ;; (class. ..) (with-meta (list* 'new (symbol (subs opname 0 (dec (count opname)))) expr) (meta form)) :else form))) form))) (defn macroexpand-1 "If form represents a macro form or an inlineable function,returns its expansion, else returns form." ([form] (macroexpand-1 form (empty-env))) ([form env] (env/ensure (global-env) (cond (seq? form) (let [[op & args] form] (if (specials op) form (let [v (resolve-sym op env) m (meta v) local? (-> env :locals (get op)) macro? (and (not local?) (:macro m)) ;; locals shadow macros inline-arities-f (:inline-arities m) inline? (and (not local?) (or (not inline-arities-f) (inline-arities-f (count args))) (:inline m)) t (:tag m)] (cond macro? (let [res (apply v form (:locals env) (rest form))] ; (m &form &env & args) (update-ns-map!) (if (obj? res) (vary-meta res merge (meta form)) res)) inline? (let [res (apply inline? args)] (update-ns-map!) (if (obj? res) (vary-meta res merge (and t {:tag t}) (meta form)) res)) :else (desugar-host-expr form env))))) (symbol? form) (desugar-symbol form env) :else form)))) (defn qualify-arglists [arglists] (vary-meta arglists merge (when-let [t (:tag (meta arglists))] {:tag (if (or (string? t) (u/specials (str t)) (u/special-arrays (str t))) t (if-let [c (maybe-class t)] (let [new-t (-> c .getName symbol)] (if (= new-t t) t (with-meta new-t {::qualified? true}))) t))}))) (defn create-var "Creates a Var for sym and returns it. The Var gets interned in the env namespace." [sym {:keys [ns]}] (let [v (get-in (env/deref-env) [:namespaces ns :mappings (symbol (name sym))])] (if (and v (or (class? v) (= ns (ns-name (.ns ^Var v) )))) v (let [meta (dissoc (meta sym) :inline :inline-arities :macro) meta (if-let [arglists (:arglists meta)] (assoc meta :arglists (qualify-arglists arglists)) meta)] (intern ns (with-meta sym meta)))))) (defn parse-monitor-enter [[_ target :as form] env] (when-not (= 2 (count form)) (throw (ex-info (str "Wrong number of args to monitor-enter, had: " (dec (count form))) (merge {:form form} (-source-info form env))))) {:op :monitor-enter :env env :form form :target (-analyze target (ctx env :ctx/expr)) :children [:target]}) (defn parse-monitor-exit [[_ target :as form] env] (when-not (= 2 (count form)) (throw (ex-info (str "Wrong number of args to monitor-exit, had: " (dec (count form))) (merge {:form form} (-source-info form env))))) {:op :monitor-exit :env env :form form :target (-analyze target (ctx env :ctx/expr)) :children [:target]}) (defn parse-import* [[_ class :as form] env] (when-not (= 2 (count form)) (throw (ex-info (str "Wrong number of args to import*, had: " (dec (count form))) (merge {:form form} (-source-info form env))))) {:op :import :env env :form form :class class}) (defn analyze-method-impls [[method [this & params :as args] & body :as form] env] (when-let [error-msg (cond (not (symbol? method)) (str "Method method must be a symbol, had: " (class method)) (not (vector? args)) (str "Parameter listing should be a vector, had: " (class args)) (not (first args)) (str"Must supply at least one argument for 'this' in: " method))] (throw (ex-info error-msg (merge {:form form :in (:this env) :method method :args args} (-source-info form env))))) (let [meth (cons (vec params) body) ;; this is an implicit arg this-expr {:name this :env env :form this :op :binding :o-tag (:this env) :tag (:this env) :local :this} env (assoc-in (dissoc env :this) [:locals this] (dissoc-env this-expr)) method-expr (analyze-fn-method meth env)] (assoc (dissoc method-expr :variadic?) :op :method :form form :this this-expr :name (symbol (name method)) :children (into [:this] (:children method-expr))))) ;; HACK (defn -deftype [name class-name args interfaces] (doseq [arg [class-name name]] (memo-clear! members* [arg]) (memo-clear! members* [(str arg)])) (let [interfaces (mapv #(symbol (.getName ^Class %)) interfaces)] (eval (list 'let [] (list 'deftype* name class-name args :implements interfaces) (list 'import class-name))))) (defn parse-reify* [[_ interfaces & methods :as form] env] (let [interfaces (conj (disj (set (mapv maybe-class interfaces)) Object) IObj) name (gensym "reify__") class-name (symbol (str (namespace-munge *ns*) "$" name)) menv (assoc env :this class-name) methods (mapv #(assoc (analyze-method-impls % menv) :interfaces interfaces) methods)] (-deftype name class-name [] interfaces) (wrapping-meta {:op :reify :env env :form form :class-name class-name :methods methods :interfaces interfaces :children [:methods]}))) (defn parse-opts+methods [methods] (loop [opts {} methods methods] (if (keyword? (first methods)) (recur (assoc opts (first methods) (second methods)) (nnext methods)) [opts methods]))) (defn parse-deftype* [[_ name class-name fields _ interfaces & methods :as form] env] (let [interfaces (disj (set (mapv maybe-class interfaces)) Object) fields-expr (mapv (fn [name] {:env env :form name :name name :mutable (let [m (meta name)] (or (and (:unsynchronized-mutable m) :unsynchronized-mutable) (and (:volatile-mutable m) :volatile-mutable))) :local :field :op :binding}) fields) menv (assoc env :context :ctx/expr :locals (zipmap fields (map dissoc-env fields-expr)) :this class-name) [opts methods] (parse-opts+methods methods) methods (mapv #(assoc (analyze-method-impls % menv) :interfaces interfaces) methods)] (-deftype name class-name fields interfaces) {:op :deftype :env env :form form :name name :class-name class-name ;; internal, don't use as a Class :fields fields-expr :methods methods :interfaces interfaces :children [:fields :methods]})) (defn parse-case* [[_ expr shift mask default case-map switch-type test-type & [skip-check?] :as form] env] (let [[low high] ((juxt first last) (keys case-map)) ;;case-map is a sorted-map e (ctx env :ctx/expr) test-expr (-analyze expr e) [tests thens] (reduce (fn [[te th] [min-hash [test then]]] (let [test-expr (ana/analyze-const test e) then-expr (-analyze then env)] [(conj te {:op :case-test :form test :env e :hash min-hash :test test-expr :children [:test]}) (conj th {:op :case-then :form then :env env :hash min-hash :then then-expr :children [:then]})])) [[] []] case-map) default-expr (-analyze default env)] {:op :case :form form :env env :test (assoc test-expr :case-test true) :default default-expr :tests tests :thens thens :shift shift :mask mask :low low :high high :switch-type switch-type :test-type test-type :skip-check? skip-check? :children [:test :tests :thens :default]})) (defn parse "Extension to tools.analyzer/-parse for JVM special forms" [form env] ((case (first form) monitor-enter parse-monitor-enter monitor-exit parse-monitor-exit clojure.core/import* parse-import* reify* parse-reify* deftype* parse-deftype* case* parse-case* #_:else ana/-parse) form env)) (def default-passes "Set of passes that will be run by default on the AST by #'run-passes" #{#'warn-on-reflection #'warn-earmuff #'uniquify-locals #'source-info #'elide-meta #'constant-lift #'trim #'box #'analyze-host-expr #'validate-loop-locals #'validate #'infer-tag #'classify-invoke}) (def scheduled-default-passes (schedule default-passes)) (defn ^:dynamic run-passes "Function that will be invoked on the AST tree immediately after it has been constructed, by default runs the passes declared in #'default-passes, should be rebound if a different set of passes is required. Use #'clojure.tools.analyzer.passes/schedule to get a function from a set of passes that run-passes can be bound to." [ast] (scheduled-default-passes ast)) (def default-passes-opts "Default :passes-opts for `analyze`" {:collect/what #{:constants :callsites} :collect/where #{:deftype :reify :fn} :collect/top-level? false :collect-closed-overs/where #{:deftype :reify :fn :loop :try} :collect-closed-overs/top-level? false}) (defn analyze "Analyzes a clojure form using tools.analyzer augmented with the JVM specific special ops and returns its AST, after running #'run-passes on it. If no configuration option is provides, analyze will setup tools.analyzer using the extension points declared in this namespace. If provided, opts should be a map of options to analyze, currently the only valid options are :bindings and :passes-opts (if not provided, :passes-opts defaults to the value of `default-passes-opts`). If provided, :bindings should be a map of Var->value pairs that will be merged into the default bindings for tools.analyzer, useful to provide custom extension points. If provided, :passes-opts should be a map of pass-name-kw->pass-config-map pairs that can be used to configure the behaviour of each pass. E.g. (analyze form env {:bindings {#'ana/macroexpand-1 my-mexpand-1}})" ([form] (analyze form (empty-env) {})) ([form env] (analyze form env {})) ([form env opts] (with-bindings (merge {Compiler/LOADER (RT/makeClassLoader) #'ana/macroexpand-1 macroexpand-1 #'ana/create-var create-var #'ana/parse parse #'ana/var? var? #'elides (merge {:fn #{:line :column :end-line :end-column :file :source} :reify #{:line :column :end-line :end-column :file :source}} elides) #'*ns* (the-ns (:ns env))} (:bindings opts)) (env/ensure (global-env) (doto (env/with-env (mmerge (env/deref-env) {:passes-opts (get opts :passes-opts default-passes-opts)}) (run-passes (-analyze form env))) (do (update-ns-map!))))))) (deftype ExceptionThrown [e ast]) (defn ^:private throw! [e] (throw (.e ^ExceptionThrown e))) (defn analyze+eval "Like analyze but evals the form after the analysis and attaches the returned value in the :result field of the AST node. If evaluating the form will cause an exception to be thrown, the exception will be caught and wrapped in an ExceptionThrown object, containing the exception in the `e` field and the AST in the `ast` field. The ExceptionThrown object is then passed to `handle-evaluation-exception`, which by defaults throws the original exception, but can be used to provide a replacement return value for the evaluation of the AST. Unrolls `do` forms to handle the Gilardi scenario. Useful when analyzing whole files/namespaces." ([form] (analyze+eval form (empty-env) {})) ([form env] (analyze+eval form env {})) ([form env {:keys [handle-evaluation-exception] :or {handle-evaluation-exception throw!} :as opts}] (env/ensure (global-env) (update-ns-map!) (let [env (merge env (-source-info form env)) [mform raw-forms] (with-bindings {Compiler/LOADER (RT/makeClassLoader) #'*ns* (the-ns (:ns env)) #'ana/macroexpand-1 (get-in opts [:bindings #'ana/macroexpand-1] macroexpand-1)} (loop [form form raw-forms []] (let [mform (ana/macroexpand-1 form env)] (if (= mform form) [mform (seq raw-forms)] (recur mform (conj raw-forms (if-let [[op & r] (and (seq? form) form)] (if (or (u/macro? op env) (u/inline? op r env)) (vary-meta form assoc ::ana/resolved-op (resolve-sym op env)) form) form)))))))] (if (and (seq? mform) (= 'do (first mform)) (next mform)) ;; handle the Gilardi scenario (let [[statements ret] (butlast+last (rest mform)) statements-expr (mapv (fn [s] (analyze+eval s (-> env (ctx :ctx/statement) (assoc :ns (ns-name *ns*))) opts)) statements) ret-expr (analyze+eval ret (assoc env :ns (ns-name *ns*)) opts)] {:op :do :top-level true :form mform :statements statements-expr :ret ret-expr :children [:statements :ret] :env env :result (:result ret-expr) :raw-forms raw-forms}) (let [a (analyze mform env opts) frm (emit-form a) result (try (eval frm) ;; eval the emitted form rather than directly the form to avoid double macroexpansion (catch Exception e (handle-evaluation-exception (ExceptionThrown. e a))))] (merge a {:result result :raw-forms raw-forms}))))))) (defn analyze-ns "Analyzes a whole namespace, returns a vector of the ASTs for all the top-level ASTs of that namespace. Evaluates all the forms." ([ns] (analyze-ns ns (empty-env))) ([ns env] (analyze-ns ns env {})) ([ns env opts] (env/ensure (global-env) (let [res ^URL (ns-url ns)] (assert res (str "Can't find " ns " in classpath")) (let [filename (str res) path (.getPath res)] (when-not (get-in (env/deref-env) [::analyzed-clj path]) (binding [*ns* *ns* *file* filename] (with-open [rdr (io/reader res)] (let [pbr (readers/indexing-push-back-reader (java.io.PushbackReader. rdr) 1 filename) eof (Object.) read-opts {:eof eof :features #{:clj :t.a.jvm}} read-opts (if (.endsWith filename "cljc") (assoc read-opts :read-cond :allow) read-opts)] (loop [] (let [form (reader/read read-opts pbr)] (when-not (identical? form eof) (swap! *env* update-in [::analyzed-clj path] (fnil conj []) (analyze+eval form (assoc env :ns (ns-name *ns*)) opts)) (recur)))))))) (get-in @*env* [::analyzed-clj path])))))) (defn macroexpand-all "Like clojure.walk/macroexpand-all but correctly handles lexical scope" ([form] (macroexpand-all form (empty-env) {})) ([form env] (macroexpand-all form env {})) ([form env opts] (binding [run-passes emit-form] (analyze form env opts)))) tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/jvm/000077500000000000000000000000001312245000300314435ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj000066400000000000000000000307301312245000300333000ustar00rootroot00000000000000;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.jvm.utils (:require [clojure.tools.analyzer.utils :as u] [clojure.tools.analyzer.env :as env] [clojure.reflect :as reflect] [clojure.string :as s] [clojure.core.memoize :refer [lru]] [clojure.java.io :as io]) (:import (clojure.lang RT Symbol Var) org.objectweb.asm.Type)) (defn ^:private type-reflect [typeref & options] (apply reflect/type-reflect typeref :reflector (reflect/->JavaReflector (RT/baseLoader)) options)) (defn macro? [sym env] (when-let [v (u/resolve-sym sym env)] (and (not (-> env :locals (get sym))) (u/macro? v) v))) (defn inline? [sym args env] (when-let [v (u/resolve-sym sym env)] (let [inline-arities-f (:inline-arities (meta v))] (and (not (-> env :locals (get sym))) (or (not inline-arities-f) (inline-arities-f (count args))) (:inline (meta v)))))) (defn specials [c] (case c "byte" Byte/TYPE "boolean" Boolean/TYPE "char" Character/TYPE "int" Integer/TYPE "long" Long/TYPE "float" Float/TYPE "double" Double/TYPE "short" Short/TYPE "void" Void/TYPE "object" Object nil)) (defn special-arrays [c] (case c "bytes" (Class/forName "[B") "booleans" (Class/forName "[Z") "chars" (Class/forName "[C") "ints" (Class/forName "[I") "longs" (Class/forName "[J") "floats" (Class/forName "[F") "doubles" (Class/forName "[D") "shorts" (Class/forName "[S") "objects" (Class/forName "[Ljava.lang.Object;") nil)) (defmulti ^Class maybe-class "Takes a Symbol, String or Class and tires to resolve to a matching Class" class) (defn array-class [element-type] (RT/classForName (str "[" (-> element-type maybe-class Type/getType .getDescriptor (.replace \/ \.))))) (defn maybe-class-from-string [^String s] (or (when-let [maybe-class (and (neg? (.indexOf s ".")) (not= \[ (first s)) (if env/*env* (u/resolve-sym (symbol s) {:ns (ns-name *ns*)}) ((ns-map *ns*) (symbol s))))] (when (class? maybe-class) maybe-class)) (try (RT/classForName s) (catch ClassNotFoundException _)))) (defmethod maybe-class :default [_] nil) (defmethod maybe-class Class [c] c) (defmethod maybe-class String [s] (maybe-class (symbol s))) (defmethod maybe-class Symbol [sym] (when-not (namespace sym) (let [sname (name sym) snamec (count sname)] (if-let [base-type (and (.endsWith sname "<>") (maybe-class (subs sname 0 (- snamec 2))))] (array-class base-type) (if-let [ret (or (specials sname) (special-arrays sname))] ret (maybe-class-from-string sname)))))) (defn maybe-class-literal [x] (cond (class? x) x (symbol? x) (and (not (namespace x)) (maybe-class-from-string (name x))) (string? x) (maybe-class-from-string x))) (def primitive? "Returns non-nil if the argument represents a primitive Class other than Void" #{Double/TYPE Character/TYPE Byte/TYPE Boolean/TYPE Short/TYPE Float/TYPE Long/TYPE Integer/TYPE}) (def ^:private convertible-primitives "If the argument is a primitive Class, returns a set of Classes to which the primitive Class can be casted" {Integer/TYPE #{Integer Long/TYPE Long Short/TYPE Byte/TYPE Object Number} Float/TYPE #{Float Double/TYPE Object Number} Double/TYPE #{Double Float/TYPE Object Number} Long/TYPE #{Long Integer/TYPE Short/TYPE Byte/TYPE Object Number} Character/TYPE #{Character Object} Short/TYPE #{Short Object Number} Byte/TYPE #{Byte Object Number} Boolean/TYPE #{Boolean Object} Void/TYPE #{Void}}) (defn ^Class box "If the argument is a primitive Class, returns its boxed equivalent, otherwise returns the argument" [c] ({Integer/TYPE Integer Float/TYPE Float Double/TYPE Double Long/TYPE Long Character/TYPE Character Short/TYPE Short Byte/TYPE Byte Boolean/TYPE Boolean Void/TYPE Void} c c)) (defn ^Class unbox "If the argument is a Class with a primitive equivalent, returns that, otherwise returns the argument" [c] ({Integer Integer/TYPE, Long Long/TYPE, Float Float/TYPE, Short Short/TYPE, Boolean Boolean/TYPE, Byte Byte/TYPE, Character Character/TYPE, Double Double/TYPE, Void Void/TYPE} c c)) (defn numeric? "Returns true if the given class is numeric" [c] (when c (.isAssignableFrom Number (box c)))) (defn subsumes? "Returns true if c2 is subsumed by c1" [c1 c2] (let [c1 (maybe-class c1) c2 (maybe-class c2)] (and (not= c1 c2) (or (and (not (primitive? c1)) (primitive? c2)) (.isAssignableFrom c2 c1))))) (defn convertible? "Returns true if it's possible to convert from c1 to c2" [c1 c2] (let [c1 (maybe-class c1) c2 (maybe-class c2)] (if (nil? c1) (not (primitive? c2)) (or (= c1 c2) (.isAssignableFrom c2 c1) (and (primitive? c2) ((convertible-primitives c2) c1)) (and (primitive? c1) (.isAssignableFrom (box c1) c2)))))) (def wider-than "If the argument is a numeric primitive Class, returns a set of primitive Classes that are narrower than the given one" {Long/TYPE #{Integer/TYPE Short/TYPE Byte/TYPE} Integer/TYPE #{Short/TYPE Byte/TYPE} Float/TYPE #{Integer/TYPE Short/TYPE Byte/TYPE Long/TYPE} Double/TYPE #{Integer/TYPE Short/TYPE Byte/TYPE Long/TYPE Float/TYPE} Short/TYPE #{Byte/TYPE} Byte/TYPE #{}}) (defn wider-primitive "Given two numeric primitive Classes, returns the wider one" [from to] (if ((wider-than from) to) from to)) (defn wider-tag* "Given two Classes returns the wider one" [from to] (if (not= from to) (if (primitive? from) (if (primitive? to) (wider-primitive from to) (or (and (numeric? from) (numeric? to) to) ((convertible-primitives from) to))) (if (primitive? to) (or (and (numeric? from) (numeric? to) from) ((convertible-primitives to) from)) (if (convertible? from to) to (when (convertible? to from) from)))) from)) (defn wider-tag "Given a collection of Classes returns the wider one" [tags] (let [tags* (filter identity tags) wider (loop [wider (first tags*) tags* (rest tags*)] (if (seq tags*) (if-let [t (wider-tag* wider (first tags*))] (recur t (rest tags*))) wider))] (when (or (= tags* tags) (not (primitive? wider))) wider))) (defn name-matches? [member] (let [member-name (str member) i (.lastIndexOf member-name ".") member-name* (when (pos? i) (str (s/replace (subs member-name 0 i) "-" "_") (subs member-name i))) member-name** (s/replace member-name "-" "_") member-name*** (munge member-name)] (fn [name] (let [name (str name)] (or (= member-name name) (= member-name* name) (= member-name** name) (= member-name*** name)))))) (def object-members (:members (type-reflect Object))) (def members* (lru (fn members* ([class] (into object-members (remove (fn [{:keys [flags]}] (not-any? #{:public :protected} flags)) (-> class maybe-class ^Class (box) .getName symbol (type-reflect :ancestors true) :members))))))) (defn members ([class] (members* class)) ([class member] (when-let [members (filter #((name-matches? member) (:name %)) (members* class))] members))) (defn static-members [class f] (when-let [members (members class f)] (when-let [statics (filter (comp :static :flags) members)] statics))) (defn instance-members [class f] (when-let [members (members class f)] (when-let [i-members (remove (comp :static :flags) members)] i-members))) (defn static-methods [class method argc] (filter #(= argc (count (:parameter-types %))) (filter :return-type (static-members class method)))) (defn instance-methods [class method argc] (filter #(= argc (count (:parameter-types %))) (filter :return-type (instance-members class method)))) (defn static-field [class f] (when-let [statics (static-members class f)] (when-let [[member] (filter (every-pred (comp nil? seq :parameter-types) (comp nil? :return-type)) statics)] member))) (defn instance-field [class f] (when-let [i-members (instance-members class f)] (when-let [[member] (filter (every-pred (comp nil? seq :parameter-types) (comp nil? :return-type)) i-members)] member))) (defn static-method [class method] (first (static-methods class method 0))) (defn instance-method [class method] (first (instance-methods class method 0))) (defn prim-or-obj "If the given Class is a primitive, returns that Class, otherwise returns Object" [tag] (if (and tag (primitive? tag)) tag java.lang.Object)) (defn prim-interface [tags] (when (some primitive? tags) (let [sig (apply str (mapv #(.toUpperCase (subs (.getSimpleName ^Class %) 0 1)) tags))] (maybe-class (str "clojure.lang.IFn$" sig))))) (defn tag-match? [arg-tags meth] (every? identity (map convertible? arg-tags (:parameter-types meth)))) (defn try-best-match "Given a vector of arg tags and a collection of methods, tries to return the subset of methods that match best the given tags" [tags methods] (let [o-tags (mapv #(or (maybe-class %) Object) tags)] (if-let [methods (or (seq (filter #(= o-tags (mapv maybe-class (:parameter-types %))) methods)) (seq (filter #(tag-match? tags %) methods)))] (reduce (fn [[prev & _ :as p] next] (let [prev-params (mapv maybe-class (:parameter-types prev)) next-params (mapv maybe-class (:parameter-types next)) prev-ret (maybe-class (:return-type prev)) next-ret (maybe-class (:return-type next)) prev-decl (maybe-class (:declaring-class prev)) next-decl (maybe-class (:declaring-class next))] (cond (not prev) [next] (= prev-params next-params) (cond (= prev-ret next-ret) (cond (.isAssignableFrom prev-decl next-decl) [next] (.isAssignableFrom next-decl prev-decl) p :else (conj p next)) (.isAssignableFrom prev-ret next-ret) [next] (.isAssignableFrom next-ret prev-ret) p :else (conj p next)) (and (some true? (map subsumes? next-params prev-params)) (not-any? true? (map subsumes? prev-params next-params))) [next] :else (conj p next)))) [] methods) methods))) (defn ns->relpath [s] (-> s str (s/replace \. \/) (s/replace \- \_) (str ".clj"))) (defn ns-url [ns] (let [f (ns->relpath ns)] (or (io/resource f) (io/resource (str f "c"))))) tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/000077500000000000000000000000001312245000300321455ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm/000077500000000000000000000000001312245000300327415ustar00rootroot00000000000000analyze_host_expr.clj000066400000000000000000000162751312245000300371250ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.analyze-host-expr (:require [clojure.tools.analyzer :as ana] [clojure.tools.analyzer.utils :refer [ctx source-info merge']] [clojure.tools.analyzer.jvm.utils :refer :all])) (defn maybe-static-field [[_ class sym]] (when-let [{:keys [flags type name]} (static-field class sym)] {:op :static-field :assignable? (not (:final flags)) :class class :field name :o-tag type :tag type})) (defn maybe-static-method [[_ class sym]] (when-let [{:keys [name return-type]} (static-method class sym)] {:op :static-call :tag return-type :o-tag return-type :class class :method name})) (defn maybe-instance-method [target-expr class sym] (when-let [{:keys [return-type]} (instance-method class sym)] {:op :instance-call :tag return-type :o-tag return-type :instance target-expr :class class :method sym :children [:instance]})) (defn maybe-instance-field [target-expr class sym] (when-let [{:keys [flags name type]} (instance-field class sym)] {:op :instance-field :assignable? (not (:final flags)) :class class :instance target-expr :field name :tag type :o-tag type :children [:instance]})) (defn analyze-host-call [target-type method args target-expr class env] (let [op (case target-type :static :static-call :instance :instance-call)] (merge {:op op :method method :args args} (case target-type :static {:class class :children [:args]} :instance {:instance target-expr :class (maybe-class (:tag target-expr)) :children [:instance :args]})))) (defn analyze-host-field [target-type field target-expr class env] (if class (case target-type :static (or (maybe-static-field (list '. class field)) (throw (ex-info (str "Cannot find field " field " for class " class) (merge {:class class :field field} (source-info env))))) :instance (or (maybe-instance-field target-expr class field) {:op :host-interop :target (dissoc target-expr :tag :validated?) :m-or-f field :assignable? true :children [:target]} (when (:literal? target-expr) (throw (ex-info (str "Cannot find field " field " for class " class) (merge {:instance (dissoc target-expr :env) :field field} (source-info env))))))) {:op :host-interop :target target-expr :m-or-f field :assignable? true :children [:target]})) (defn -analyze-host-expr [target-type m-or-f target-expr class env] (let [target-class (-> target-expr :tag) [field method] (if class [(maybe-static-field (list '. class m-or-f)) (maybe-static-method (list '. class m-or-f))] (when target-class [(maybe-instance-field target-expr target-class m-or-f) (maybe-instance-method target-expr target-class m-or-f)]))] (cond (not (or class target-class)) {:op :host-interop :target target-expr :m-or-f m-or-f :assignable? true :children [:target]} method method field field class (throw (ex-info (str "Cannot find field or no-arg method call " m-or-f " for class " class) (merge {:class class :m-or-f m-or-f} (source-info env)))) target-class {:op :host-interop :target (dissoc target-expr :tag :validated?) :m-or-f m-or-f :assignable? true :children [:target]} :else (when (:literal? target-expr) (throw (ex-info (str "Cannot find field or no-arg method call " m-or-f " for class " target-class) (merge {:instance (dissoc target-expr :env) :m-or-f m-or-f} (source-info env)))))))) (defn analyze-host-expr "Performing some reflection, transforms :host-interop/:host-call/:host-field nodes in either: :static-field, :static-call, :instance-call, :instance-field or :host-interop nodes, and a :var or :maybe-class node in a :const :class node, if necessary (class literals shadow Vars). A :host-interop node represents either an instance-field or a no-arg instance-method. " {:pass-info {:walk :post :depends #{}}} [{:keys [op target form tag env class] :as ast}] (case op (:host-interop :host-call :host-field) (let [target (if-let [the-class (and (= :local (:op target)) (maybe-class-literal (:form target)))] (merge target (assoc (ana/analyze-const the-class env :class) :tag Class :o-tag Class)) target) class? (and (= :const (:op target)) (= :class (:type target)) (:form target)) target-type (if class? :static :instance)] (merge' (dissoc ast :assignable? :target :args :children) (case op :host-call (analyze-host-call target-type (:method ast) (:args ast) target class? env) :host-field (analyze-host-field target-type (:field ast) target (or class? (:tag target)) env) :host-interop (-analyze-host-expr target-type (:m-or-f ast) target class? env)) (when tag {:tag tag}))) :var (if-let [the-class (and (not (namespace form)) (pos? (.indexOf (str form) ".")) (maybe-class-literal form))] (assoc (ana/analyze-const the-class env :class) :form form) ast) :maybe-class (if-let [the-class (maybe-class-literal class)] (assoc (ana/analyze-const the-class env :class) :form form) ast) ast)) annotate_branch.clj000066400000000000000000000026371312245000300365120ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.annotate-branch) (defmulti annotate-branch "Adds :branch? to branch AST nodes (if/case), :test? to the test children node of the branching op and :path? to the branching paths. Example: {:op if :branch? true :test {:test? true ..} :then {:path? true ..} ..}" {:pass-info {:walk :any :depends #{}}} :op) (defmethod annotate-branch :if [ast] (-> ast (assoc :branch? true) (assoc-in [:test :test?] true) (assoc-in [:then :path?] true) (assoc-in [:else :path?] true))) (defmethod annotate-branch :fn-method [ast] (assoc ast :path? true)) (defmethod annotate-branch :method [ast] (assoc ast :path? true)) (defmethod annotate-branch :case [ast] (-> ast (assoc :branch? true) (assoc-in [:test :test?] true) (assoc-in [:default :path?] true))) (defmethod annotate-branch :case-then [ast] (assoc ast :path? true)) (defmethod annotate-branch :default [ast] ast) annotate_host_info.clj000066400000000000000000000130061312245000300372350ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.annotate-host-info (:require [clojure.tools.analyzer :as ana] [clojure.tools.analyzer.ast :refer [prewalk]] [clojure.tools.analyzer.passes [cleanup :refer [cleanup]] [elide-meta :refer [elide-meta]]] [clojure.tools.analyzer.utils :refer [source-info]] [clojure.tools.analyzer.jvm.utils :refer [members name-matches? try-best-match] :as u])) (defn annotate-host-info "Adds a :methods key to reify/deftype :methods info representing the reflected informations for the required methods, replaces (catch :default ..) forms with (catch Throwable ..)" {:pass-info {:walk :pre :depends #{} :after #{#'elide-meta}}} [{:keys [op methods interfaces class env] :as ast}] (case op (:reify :deftype) (let [all-methods (into #{} (mapcat (fn [class] (mapv (fn [method] (dissoc method :exception-types)) (filter (fn [{:keys [flags return-type]}] (and return-type (not-any? #{:final :static} flags))) (members class)))) (conj interfaces Object)))] (assoc ast :methods (mapv (fn [ast] (let [name (:name ast) argc (count (:params ast))] (assoc ast :methods (filter #(and ((name-matches? name) (:name %)) (= argc (count (:parameter-types %)))) all-methods)))) methods))) :catch (let [the-class (cond (and (= :const (:op class)) (= :default (:form class))) Throwable (= :maybe-class (:op class)) (u/maybe-class-literal (:class class))) ast (if the-class (-> ast (assoc :class (assoc (ana/analyze-const the-class env :class) :form (:form class) :tag Class :o-tag Class))) ast)] (assoc-in ast [:local :tag] (-> ast :class :val))) :method ;; this should actually be in validate but it's here since it needs to be prewalked ;; for infer-tag purposes (let [{:keys [name class tag form params fixed-arity env]} ast] (if interfaces (let [tags (mapv (comp u/maybe-class :tag meta :form) params) methods-set (set (mapv (fn [x] (dissoc x :declaring-class :flags)) methods))] (let [[m & rest :as matches] (try-best-match tags methods)] (if m (let [ret-tag (u/maybe-class (:return-type m)) i-tag (u/maybe-class (:declaring-class m)) arg-tags (mapv u/maybe-class (:parameter-types m)) params (mapv (fn [{:keys [atom] :as arg} tag] (assoc arg :tag tag :o-tag tag)) params arg-tags)] (if (or (empty? rest) (every? (fn [{:keys [return-type parameter-types]}] (and (= (u/maybe-class return-type) ret-tag) (= arg-tags (mapv u/maybe-class parameter-types)))) rest)) (assoc (dissoc ast :interfaces :methods) :bridges (filter #(and (= arg-tags (mapv u/maybe-class (:parameter-types %))) (.isAssignableFrom (u/maybe-class (:return-type %)) ret-tag)) (disj methods-set (dissoc m :declaring-class :flags))) :methods methods :interface i-tag :tag ret-tag :o-tag ret-tag :params params) (throw (ex-info (str "Ambiguous method signature for method: " name) (merge {:method name :interfaces interfaces :form form :params (mapv (fn [x] (prewalk x cleanup)) params) :matches matches} (source-info env)))))) (throw (ex-info (str "No such method found: " name " with given signature in any of the" " provided interfaces: " interfaces) (merge {:method name :methods methods :interfaces interfaces :form form :params params} (source-info env))))))) ast)) ast)) annotate_loops.clj000066400000000000000000000100441312245000300364000ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.annotate-loops (:require [clojure.tools.analyzer.ast :refer [update-children]])) (defmulti annotate-loops "Adds a :loops field to nodes that represent a code path that might be visited more than once because of a recur. The field is a set of loop-ids representing the loops that might recur into that path Note that because (recur expr) is equivalent to (let [e expr] (recur e)) the node corresponting to expr will have the same :loops field as the nodes in the same code path of the recur" {:pass-info {:walk :pre :depends #{}}} :op) (defmulti check-recur :op) (defn -check-recur [ast k] (let [ast (update-in ast [k] check-recur)] (if (:recurs (k ast)) (assoc ast :recurs true) ast))) (defmethod check-recur :do [ast] (let [ast (-check-recur ast :ret)] (if (:recurs ast) (assoc ast :statements (mapv (fn [s] (assoc s :recurs true)) (:statements ast))) ast))) (defmethod check-recur :let [ast] (-check-recur ast :body)) (defmethod check-recur :letfn [ast] (-check-recur ast :body)) (defmethod check-recur :if [ast] (-> ast (-check-recur :then) (-check-recur :else))) (defmethod check-recur :case [ast] (let [ast (-> ast (-check-recur :default) (update-in [:thens] #(mapv check-recur %)))] (if (some :recurs (:thens ast)) (assoc ast :recurs true) ast))) (defmethod check-recur :case-then [ast] (-check-recur ast :then)) (defmethod check-recur :recur [ast] (assoc ast :recurs true)) (defmethod check-recur :default [ast] ast) (defn -loops [ast loop-id] (update-in ast [:loops] (fnil conj #{}) loop-id)) (defmethod annotate-loops :loop [{:keys [loops loop-id] :as ast}] (let [ast (if loops (update-children ast #(assoc % :loops loops)) ast) ast (update-in ast [:body] check-recur)] (if (-> ast :body :recurs) (update-in ast [:body] -loops loop-id) ast))) (defmethod annotate-loops :default [{:keys [loops] :as ast}] (if loops (update-children ast #(assoc % :loops loops)) ast)) (defmethod annotate-loops :if [{:keys [loops test then else env] :as ast}] (if loops (let [loop-id (:loop-id env) loops-no-recur (disj loops loop-id) branch-recurs? (or (:recurs then) (:recurs else)) then (if (or (:recurs then) ;; the recur is inside the then branch ;; the recur is in the same code path of the if expression (not branch-recurs?)) (assoc then :loops loops) (assoc then :loops loops-no-recur)) else (if (or (:recurs else) (not branch-recurs?)) (assoc else :loops loops) (assoc else :loops loops-no-recur))] (assoc ast :then then :else else :test (assoc test :loops loops))) ast)) (defmethod annotate-loops :case [{:keys [loops test default thens env] :as ast}] (if loops (let [loop-id (:loop-id env) loops-no-recur (disj loops loop-id) branch-recurs? (some :recurs (conj thens default)) default (if (or (:recurs default) (not branch-recurs?)) (assoc default :loops loops) (assoc default :loops loops-no-recur)) thens (mapv #(if (or (:recurs %) (not branch-recurs?)) (assoc % :loops loops) (assoc % :loops loops-no-recur)) thens)] (assoc ast :thens thens :default default :test (assoc test :loops loops))) ast)) annotate_tag.clj000066400000000000000000000062451312245000300360270ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.annotate-tag (:require [clojure.tools.analyzer.jvm.utils :refer [unbox maybe-class]] [clojure.tools.analyzer.passes.jvm.constant-lifter :refer [constant-lift]]) (:import (clojure.lang ISeq Var AFunction))) (defmulti -annotate-tag :op) (defmethod -annotate-tag :default [ast] ast) (defmethod -annotate-tag :map [{:keys [val form] :as ast}] (let [t (class (or val form))] (assoc ast :o-tag t :tag t))) (defmethod -annotate-tag :set [{:keys [val form] :as ast}] (let [t (class (or val form))] (assoc ast :o-tag t :tag t))) (defmethod -annotate-tag :vector [{:keys [val form] :as ast}] (let [t (class (or val form))] (assoc ast :o-tag t :tag t))) (defmethod -annotate-tag :the-var [ast] (assoc ast :o-tag Var :tag Var)) (defmethod -annotate-tag :const [ast] (case (:type ast) ;; char and numbers are unboxed by default :number (let [t (unbox (class (:val ast)))] (assoc ast :o-tag t :tag t)) :char (assoc ast :o-tag Character/TYPE :tag Character/TYPE) :seq (assoc ast :o-tag ISeq :tag ISeq) (let [t (class (:val ast))] (assoc ast :o-tag t :tag t)))) (defmethod -annotate-tag :binding [{:keys [form tag atom o-tag init local name variadic?] :as ast}] (let [o-tag (or (:tag init) ;; should defer to infer-tag? (and (= :fn local) AFunction) (and (= :arg local) variadic? ISeq) o-tag Object) o-tag (if (#{Void Void/TYPE} o-tag) Object o-tag)] (if-let [tag (or (:tag (meta form)) tag)] (let [ast (assoc ast :tag tag :o-tag tag)] (if init (assoc-in ast [:init :tag] (maybe-class tag)) ast)) (assoc ast :tag o-tag :o-tag o-tag)))) (defmethod -annotate-tag :local [{:keys [name form tag atom case-test] :as ast}] (let [o-tag (@atom :tag)] (assoc ast :o-tag o-tag :tag o-tag))) ;; TODO: move binding/local logic to infer-tag (defn annotate-tag "If the AST node type is a constant object or contains :tag metadata, attach the appropriate :tag and :o-tag to the node." {:pass-info {:walk :post :depends #{} :after #{#'constant-lift}}} [{:keys [op tag o-tag atom] :as ast}] (let [ast (if (and atom (:case-test @atom)) (update-in ast [:form] vary-meta dissoc :tag) ast) ast (if (and o-tag tag) ast (if-let [tag (or tag (-> ast :val meta :tag) (-> ast :form meta :tag))] (assoc (-annotate-tag ast) :tag tag) (-annotate-tag ast)))] (when (= op :binding) (swap! atom assoc :tag (:tag ast))) ast)) box.clj000066400000000000000000000130371312245000300341500ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.box (:require [clojure.tools.analyzer.jvm.utils :as u] [clojure.tools.analyzer.utils :refer [protocol-node? arglist-for-arity]] [clojure.tools.analyzer.passes.jvm [validate :refer [validate]] [infer-tag :refer [infer-tag]]])) (defmulti box "Box the AST node tag where necessary" {:pass-info {:walk :pre :depends #{#'infer-tag} :after #{#'validate}}} :op) (defmacro if-let-box [class then else] `(let [c# ~class ~class (u/box c#)] (if (u/primitive? c#) ~then ~else))) (defn -box [ast] (let [tag (:tag ast)] (if (u/primitive? tag) (assoc ast :tag (u/box tag)) ast))) (defn boxed? [tag expr] (and (or (nil? tag) (not (u/primitive? tag))) (u/primitive? (:tag expr)))) (defmethod box :instance-call [{:keys [args class validated? tag] :as ast}] (let [ast (if-let-box class (assoc (update-in ast [:instance :tag] u/box) :class class) ast)] (if validated? ast (assoc ast :args (mapv -box args) :o-tag Object :tag (if (not (#{Void Void/TYPE} tag)) tag Object))))) (defmethod box :static-call [{:keys [args validated? tag] :as ast}] (if validated? ast (assoc ast :args (mapv -box args) :o-tag Object :tag (if (not (#{Void Void/TYPE} tag)) tag Object)))) (defmethod box :new [{:keys [args validated?] :as ast}] (if validated? ast (assoc ast :args (mapv -box args) :o-tag Object))) (defmethod box :instance-field [{:keys [class] :as ast}] (if-let-box class (assoc (update-in ast [:instance :tag] u/box) :class class) ast)) (defmethod box :def [{:keys [init] :as ast}] (if (and init (u/primitive? (:tag init))) (update-in ast [:init] -box) ast)) (defmethod box :vector [ast] (assoc ast :items (mapv -box (:items ast)))) (defmethod box :set [ast] (assoc ast :items (mapv -box (:items ast)))) (defmethod box :map [ast] (let [keys (mapv -box (:keys ast)) vals (mapv -box (:vals ast))] (assoc ast :keys keys :vals vals))) (defmethod box :do [ast] (if (boxed? (:tag ast) (:ret ast)) (-> ast (update-in [:ret] -box) (update-in [:o-tag] u/box)) ast)) (defmethod box :quote [ast] (if (boxed? (:tag ast) (:ret ast)) (-> ast (update-in [:expr] -box) (update-in [:o-tag] u/box)) ast)) (defmethod box :protocol-invoke [ast] (assoc ast :args (mapv -box (:args ast)))) (defmethod box :let [{:keys [tag body] :as ast}] (if (boxed? tag body) (-> ast (update-in [:body] -box) (update-in [:o-tag] u/box)) ast)) (defmethod box :letfn [ast] (if (boxed? (:tag ast) (:body ast)) (-> ast (update-in [:body] -box) (update-in [:o-tag] u/box)) ast)) (defmethod box :loop [ast] (if (boxed? (:tag ast) (:body ast)) (-> ast (update-in [:body] -box) (update-in [:o-tag] u/box)) ast)) (defmethod box :fn-method [{:keys [params tag] :as ast}] (let [ast (if (u/primitive? tag) ast (-> ast (update-in [:body] -box) (update-in [:o-tag] u/box)))] (assoc ast :params (mapv (fn [{:keys [o-tag] :as p}] (assoc p :o-tag (u/prim-or-obj o-tag))) params) :tag (u/prim-or-obj tag) :o-tag (u/prim-or-obj tag)))) (defmethod box :if [{:keys [test then else tag o-tag] :as ast}] (let [test-tag (:tag test) test (if (and (u/primitive? test-tag) (not= Boolean/TYPE test-tag)) (assoc test :tag (u/box test-tag)) test) [then else o-tag] (if (or (boxed? tag then) (boxed? tag else) (not o-tag)) (conj (mapv -box [then else]) (u/box o-tag)) [then else o-tag])] (merge ast {:test test :o-tag o-tag :then then :else else}))) (defmethod box :case [{:keys [tag default tests thens test-type] :as ast}] (let [ast (if (and tag (u/primitive? tag)) ast (-> ast (assoc-in [:thens] (mapv (fn [t] (update-in t [:then] -box)) thens)) (update-in [:default] -box) (update-in [:o-tag] u/box)))] (if (= :hash-equiv test-type) (-> ast (update-in [:test] -box) (assoc-in [:tests] (mapv (fn [t] (update-in t [:test] -box)) tests))) ast))) (defmethod box :try [{:keys [tag] :as ast}] (let [ast (if (and tag (u/primitive? tag)) ast (-> ast (update-in [:catches] #(mapv -box %)) (update-in [:body] -box) (update-in [:o-tag] u/box)))] (-> ast (update-in [:finally] -box)))) (defmethod box :invoke [ast] (assoc ast :args (mapv -box (:args ast)) :o-tag Object)) (defmethod box :default [ast] ast) classify_invoke.clj000066400000000000000000000075411312245000300365530ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.classify-invoke (:require [clojure.tools.analyzer.utils :refer [arglist-for-arity protocol-node? source-info]] [clojure.tools.analyzer.jvm.utils :refer [specials prim-interface]] [clojure.tools.analyzer.passes.jvm.validate :refer [validate]])) (defn classify-invoke "If the AST node is an :invoke, check the node in function position, * if it is a keyword, transform the node in a :keyword-invoke node; * if it is the clojure.core/instance? var and the first argument is a literal class, transform the node in a :instance? node to be inlined by the emitter * if it is a protocol function var, transform the node in a :protocol-invoke node * if it is a regular function with primitive type hints that match a clojure.lang.IFn$[primitive interface], transform the node in a :prim-invoke node" {:pass-info {:walk :post :depends #{#'validate}}} [{:keys [op args tag env form] :as ast}] (if-not (= op :invoke) ast (let [argc (count args) the-fn (:fn ast) op (:op the-fn) var? (= :var op) the-var (:var the-fn)] (cond (and (= :const op) (= :keyword (:type the-fn))) (if (<= 1 argc 2) (if (and (not (namespace (:val the-fn))) (= 1 argc)) (merge (dissoc ast :fn :args) {:op :keyword-invoke :target (first args) :keyword the-fn :children [:keyword :target]}) ast) (throw (ex-info (str "Cannot invoke keyword with " argc " arguments") (merge {:form form} (source-info env))))) (and (= 2 argc) var? (= #'clojure.core/instance? the-var) (= :const (:op (first args))) (= :class (:type (first args)))) (merge (dissoc ast :fn :args) {:op :instance? :class (:val (first args)) :target (second args) :form form :env env :o-tag Boolean/TYPE :tag (or tag Boolean/TYPE) :children [:target]}) (and var? (protocol-node? the-var (:meta the-fn))) (if (>= argc 1) (merge (dissoc ast :fn) {:op :protocol-invoke :protocol-fn the-fn :target (first args) :args (vec (rest args)) :children [:protocol-fn :target :args]}) (throw (ex-info "Cannot invoke protocol method with no args" (merge {:form form} (source-info env))))) :else (let [arglist (arglist-for-arity the-fn argc) arg-tags (mapv (comp specials str :tag meta) arglist) ret-tag (-> arglist meta :tag str specials) tags (conj arg-tags ret-tag)] (if-let [prim-interface (prim-interface (mapv #(if (nil? %) Object %) tags))] (merge ast {:op :prim-invoke :prim-interface prim-interface :args (mapv (fn [arg tag] (assoc arg :tag tag)) args arg-tags) :o-tag ret-tag :tag (or tag ret-tag)}) ast)))))) constant_lifter.clj000066400000000000000000000021071312245000300365520ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm(ns clojure.tools.analyzer.passes.jvm.constant-lifter (:require [clojure.tools.analyzer.passes.constant-lifter :as orig] [clojure.tools.analyzer :refer [analyze-const]] [clojure.tools.analyzer.utils :refer [constant? classify]] [clojure.tools.analyzer.passes.jvm.analyze-host-expr :refer [analyze-host-expr]] [clojure.tools.analyzer.passes.elide-meta :refer [elide-meta]])) (defn constant-lift* [ast] (if (= :var (:op ast)) (let [{:keys [var env form meta]} ast] (if (constant? var meta) (let [val @var] (assoc (analyze-const val env (classify val)) :form form)) ast)) (orig/constant-lift ast))) (defn constant-lift "Like clojure.tools.analyzer.passes.constant-lifter/constant-lift but transforms also :var nodes where the var has :const in the metadata into :const nodes and preserves tag info" {:pass-info {:walk :post :depends #{} :after #{#'elide-meta #'analyze-host-expr}}} [ast] (merge (constant-lift* ast) (select-keys ast [:tag :o-tag :return-tag :arglists]))) emit_form.clj000066400000000000000000000130021312245000300353310ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.emit-form (:require [clojure.tools.analyzer.passes [emit-form :as default] [uniquify :refer [uniquify-locals]]])) (defmulti -emit-form (fn [{:keys [op]} _] op)) (defn -emit-form* [{:keys [form] :as ast} opts] (let [expr (-emit-form ast opts)] (if-let [m (and (instance? clojure.lang.IObj expr) (meta form))] (with-meta expr (merge m (meta expr))) expr))) ;; TODO: use pass opts infr (defn emit-form "Return the form represented by the given AST Opts is a set of options, valid options are: * :hygienic * :qualified-vars (DEPRECATED, use :qualified-symbols instead) * :qualified-symbols" {:pass-info {:walk :none :depends #{#'uniquify-locals} :compiler true}} ([ast] (emit-form ast #{})) ([ast opts] (binding [default/-emit-form* -emit-form*] (-emit-form* ast opts)))) (defn emit-hygienic-form "Return an hygienic form represented by the given AST" {:pass-info {:walk :none :depends #{#'uniquify-locals} :compiler true}} [ast] (binding [default/-emit-form* -emit-form*] (-emit-form* ast #{:hygienic}))) (defmethod -emit-form :default [ast opts] (default/-emit-form ast opts)) (defmethod -emit-form :const [{:keys [type val] :as ast} opts] (if (and (= type :class) (:qualified-symbols opts)) (symbol (.getName ^Class val)) (default/-emit-form ast opts))) (defmethod -emit-form :monitor-enter [{:keys [target]} opts] `(monitor-enter ~(-emit-form* target opts))) (defmethod -emit-form :monitor-exit [{:keys [target]} opts] `(monitor-exit ~(-emit-form* target opts))) (defmethod -emit-form :import [{:keys [class]} opts] `(clojure.core/import* ~class)) (defmethod -emit-form :the-var [{:keys [^clojure.lang.Var var]} opts] `(var ~(symbol (name (ns-name (.ns var))) (name (.sym var))))) (defmethod -emit-form :method [{:keys [params body this name form]} opts] (let [params (into [this] params)] `(~(with-meta name (meta (first form))) ~(with-meta (mapv #(-emit-form* % opts) params) (meta (second form))) ~(-emit-form* body opts)))) (defn class->str [class] (if (symbol? class) (name class) (.getName ^Class class))) (defn class->sym [class] (if (symbol? class) class (symbol (.getName ^Class class)))) (defmethod -emit-form :catch [{:keys [class local body]} opts] `(catch ~(-emit-form* class opts) ~(-emit-form* local opts) ~(-emit-form* body opts))) (defmethod -emit-form :deftype [{:keys [name class-name fields interfaces methods]} opts] `(deftype* ~name ~(class->sym class-name) ~(mapv #(-emit-form* % opts) fields) :implements ~(mapv class->sym interfaces) ~@(mapv #(-emit-form* % opts) methods))) (defmethod -emit-form :reify [{:keys [interfaces methods]} opts] `(reify* ~(mapv class->sym (disj interfaces clojure.lang.IObj)) ~@(mapv #(-emit-form* % opts) methods))) (defmethod -emit-form :case [{:keys [test default tests thens shift mask low high switch-type test-type skip-check?]} opts] `(case* ~(-emit-form* test opts) ~shift ~mask ~(-emit-form* default opts) ~(apply sorted-map (mapcat (fn [{:keys [hash test]} {:keys [then]}] [hash [(-emit-form* test opts) (-emit-form* then opts)]]) tests thens)) ~switch-type ~test-type ~skip-check?)) (defmethod -emit-form :static-field [{:keys [class field]} opts] (symbol (class->str class) (name field))) (defmethod -emit-form :static-call [{:keys [class method args]} opts] `(~(symbol (class->str class) (name method)) ~@(mapv #(-emit-form* % opts) args))) (defmethod -emit-form :instance-field [{:keys [instance field]} opts] `(~(symbol (str ".-" (name field))) ~(-emit-form* instance opts))) (defmethod -emit-form :instance-call [{:keys [instance method args]} opts] `(~(symbol (str "." (name method))) ~(-emit-form* instance opts) ~@(mapv #(-emit-form* % opts) args))) (defmethod -emit-form :prim-invoke [{:keys [fn args]} opts] `(~(-emit-form* fn opts) ~@(mapv #(-emit-form* % opts) args))) (defmethod -emit-form :protocol-invoke [{:keys [protocol-fn target args]} opts] `(~(-emit-form* protocol-fn opts) ~(-emit-form* target opts) ~@(mapv #(-emit-form* % opts) args))) (defmethod -emit-form :keyword-invoke [{:keys [target keyword]} opts] (list (-emit-form* keyword opts) (-emit-form* target opts))) (defmethod -emit-form :instance? [{:keys [class target]} opts] `(instance? ~class ~(-emit-form* target opts))) (defmethod -emit-form :var [{:keys [form ^clojure.lang.Var var]} opts] (if (or (:qualified-symbols opts) (:qualified-vars opts)) (with-meta (symbol (-> var .ns ns-name name) (-> var .sym name)) (meta form)) form)) (defmethod -emit-form :def [ast opts] (let [f (default/-emit-form ast opts)] (if (:qualified-symbols opts) `(def ~(with-meta (symbol (-> ast :env :ns name) (str (second f))) (meta (second f))) ~@(nthrest f 2)) f))) fix_case_test.clj000066400000000000000000000016101312245000300361720ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.fix-case-test (:require [clojure.tools.analyzer.passes.add-binding-atom :refer [add-binding-atom]])) (defn fix-case-test "If the node is a :case-test, annotates in the atom shared by the binding and the local node with :case-test" {:pass-info {:walk :pre :depends #{#'add-binding-atom}}} [ast] (when (:case-test ast) (swap! (:atom ast) assoc :case-test true)) ast) infer_tag.clj000066400000000000000000000232771312245000300353250ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.infer-tag (:require [clojure.tools.analyzer.utils :refer [arglist-for-arity]] [clojure.tools.analyzer.jvm.utils :as u] [clojure.tools.analyzer.env :as env] [clojure.set :refer [rename-keys]] [clojure.tools.analyzer.passes.trim :refer [trim]] [clojure.tools.analyzer.passes.jvm [annotate-tag :refer [annotate-tag]] [annotate-host-info :refer [annotate-host-info]] [analyze-host-expr :refer [analyze-host-expr]] [fix-case-test :refer [fix-case-test]]])) (defmulti -infer-tag :op) (defmethod -infer-tag :default [ast] ast) (defmethod -infer-tag :binding [{:keys [init atom] :as ast}] (if init (let [info (select-keys init [:return-tag :arglists])] (swap! atom merge info) (merge ast info)) ast)) (defmethod -infer-tag :local [ast] (let [atom @(:atom ast)] (merge atom ast {:o-tag (:tag atom)}))) (defmethod -infer-tag :var [{:keys [var form] :as ast}] (let [{:keys [tag arglists]} (:meta ast) arglists (if (= 'quote (first arglists)) (second arglists) arglists) form-tag (:tag (meta form))] ;;if (not dynamic) (merge ast {:o-tag Object} (when-let [tag (or form-tag tag)] (if (fn? @var) {:tag clojure.lang.AFunction :return-tag tag} {:tag tag})) (when arglists {:arglists arglists})))) (defmethod -infer-tag :def [{:keys [var init name] :as ast}] (let [info (merge (select-keys init [:return-tag :arglists :tag]) (select-keys (meta name) [:tag :arglists]))] (when (and (seq info) (not (:dynamic (meta name))) (= :global (-> (env/deref-env) :passes-opts :infer-tag/level))) (alter-meta! var merge (rename-keys info {:return-tag :tag}))) (merge ast info {:tag clojure.lang.Var :o-tag clojure.lang.Var}))) (defmethod -infer-tag :quote [ast] (let [tag (-> ast :expr :tag)] (assoc ast :tag tag :o-tag tag))) (defmethod -infer-tag :new [ast] (let [t (-> ast :class :val)] (assoc ast :o-tag t :tag t))) (defmethod -infer-tag :with-meta [{:keys [expr] :as ast}] (merge ast (select-keys expr [:return-tag :arglists]) {:tag (or (:tag expr) Object) :o-tag Object})) ;;trying to be smart here (defmethod -infer-tag :recur [ast] (assoc ast :ignore-tag true)) (defmethod -infer-tag :do [{:keys [ret] :as ast}] (merge ast (select-keys ret [:return-tag :arglists :ignore-tag :tag]) {:o-tag (:tag ret)})) (defmethod -infer-tag :let [{:keys [body] :as ast}] (merge ast (select-keys body [:return-tag :arglists :ignore-tag :tag]) {:o-tag (:tag body)})) (defmethod -infer-tag :letfn [{:keys [body] :as ast}] (merge ast (select-keys body [:return-tag :arglists :ignore-tag :tag]) {:o-tag (:tag body)})) (defmethod -infer-tag :loop [{:keys [body] :as ast}] (merge ast (select-keys body [:return-tag :arglists]) {:o-tag (:tag body)} (let [tag (:tag body)] (if (#{Void Void/TYPE} tag) (assoc ast :tag Object) (assoc ast :tag tag))))) (defn =-arglists? [a1 a2] (let [tag (fn [x] (-> x meta :tag u/maybe-class))] (and (= a1 a2) (every? true? (mapv (fn [a1 a2] (and (= (tag a1) (tag a2)) (= (mapv tag a1) (mapv tag a2)))) a1 a2))))) (defmethod -infer-tag :if [{:keys [then else] :as ast}] (let [then-tag (:tag then) else-tag (:tag else) ignore-then? (:ignore-tag then) ignore-else? (:ignore-tag else)] (cond (and then-tag (or ignore-else? (= then-tag else-tag))) (merge ast {:tag then-tag :o-tag then-tag} (when-let [return-tag (:return-tag then)] (when (or ignore-else? (= return-tag (:return-tag else))) {:return-tag return-tag})) (when-let [arglists (:arglists then)] (when (or ignore-else? (=-arglists? arglists (:arglists else))) {:arglists arglists}))) (and else-tag ignore-then?) (merge ast {:tag else-tag :o-tag else-tag} (when-let [return-tag (:return-tag else)] {:return-tag return-tag}) (when-let [arglists (:arglists else)] {:arglists arglists})) (and (:ignore-tag then) (:ignore-tag else)) (assoc ast :ignore-tag true) :else ast))) (defmethod -infer-tag :throw [ast] (assoc ast :ignore-tag true)) (defmethod -infer-tag :case [{:keys [thens default] :as ast}] (let [thens (conj (mapv :then thens) default) exprs (seq (remove :ignore-tag thens)) tag (:tag (first exprs))] (cond (and tag (every? #(= (:tag %) tag) exprs)) (merge ast {:tag tag :o-tag tag} (when-let [return-tag (:return-tag (first exprs))] (when (every? #(= (:return-tag %) return-tag) exprs) {:return-tag return-tag})) (when-let [arglists (:arglists (first exprs))] (when (every? #(=-arglists? (:arglists %) arglists) exprs) {:arglists arglists}))) (every? :ignore-tag thens) (assoc ast :ignore-tag true) :else ast))) (defmethod -infer-tag :try [{:keys [body catches] :as ast}] (let [{:keys [tag return-tag arglists]} body catches (remove :ignore-tag (mapv :body catches))] (merge ast (when (and tag (every? #(= % tag) (mapv :tag catches))) {:tag tag :o-tag tag}) (when (and return-tag (every? #(= % return-tag) (mapv :return-tag catches))) {:return-tag return-tag}) (when (and arglists (every? #(=-arglists? % arglists) (mapv :arglists catches))) {:arglists arglists})))) (defmethod -infer-tag :fn-method [{:keys [form body params local] :as ast}] (let [annotated-tag (or (:tag (meta (first form))) (:tag (meta (:form local)))) body-tag (:tag body) tag (or annotated-tag body-tag) tag (if (#{Void Void/TYPE} tag) Object tag)] (merge (if (not= tag body-tag) (assoc-in ast [:body :tag] (u/maybe-class tag)) ast) (when tag {:tag tag :o-tag tag}) {:arglist (with-meta (vec (mapcat (fn [{:keys [form variadic?]}] (if variadic? ['& form] [form])) params)) (when tag {:tag tag}))}))) (defmethod -infer-tag :fn [{:keys [local methods] :as ast}] (merge ast {:arglists (seq (mapv :arglist methods)) :tag clojure.lang.AFunction :o-tag clojure.lang.AFunction} (when-let [tag (or (:tag (meta (:form local))) (and (apply = (mapv :tag methods)) (:tag (first methods))))] {:return-tag tag}))) (defmethod -infer-tag :invoke [{:keys [fn args] :as ast}] (if (:arglists fn) (let [argc (count args) arglist (arglist-for-arity fn argc) tag (or (:tag (meta arglist)) (:return-tag fn) (and (= :var (:op fn)) (:tag (:meta fn))))] (merge ast (when tag {:tag tag :o-tag tag}))) (if-let [tag (:return-tag fn)] (assoc ast :tag tag :o-tag tag) ast))) (defmethod -infer-tag :method [{:keys [form body params] :as ast}] (let [tag (or (:tag (meta (first form))) (:tag (meta (second form)))) body-tag (:tag body)] (assoc ast :tag (or tag body-tag) :o-tag body-tag))) (defmethod -infer-tag :reify [{:keys [class-name] :as ast}] (assoc ast :tag class-name :o-tag class-name)) (defmethod -infer-tag :set! [ast] (let [t (:tag (:target ast))] (assoc ast :tag t :o-tag t))) (defn infer-tag "Performs local type inference on the AST adds, when possible, one or more of the following keys to the AST: * :o-tag represents the current type of the expression represented by the node * :tag represents the type the expression represented by the node is required to have, possibly the same as :o-tag * :return-tag implies that the node will return a function whose invocation will result in a object of this type * :arglists implies that the node will return a function with this arglists * :ignore-tag true when the node is untyped, does not imply that all untyped node will have this Passes opts: * :infer-tag/level If :global, infer-tag will perform Var tag inference" {:pass-info {:walk :post :depends #{#'annotate-tag #'annotate-host-info #'fix-case-test #'analyze-host-expr} :after #{#'trim}}} [{:keys [tag form] :as ast}] (let [tag (or tag (:tag (meta form))) ast (-infer-tag ast)] (merge ast (when tag {:tag tag}) (when-let [o-tag (:o-tag ast)] {:o-tag o-tag})))) validate.clj000066400000000000000000000301711312245000300351470ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.validate (:require [clojure.tools.analyzer.ast :refer [prewalk]] [clojure.tools.analyzer.env :as env] [clojure.tools.analyzer.passes.cleanup :refer [cleanup]] [clojure.tools.analyzer.passes.jvm [validate-recur :refer [validate-recur]] [infer-tag :refer [infer-tag]] [analyze-host-expr :refer [analyze-host-expr]]] [clojure.tools.analyzer.utils :refer [arglist-for-arity source-info resolve-sym resolve-ns merge']] [clojure.tools.analyzer.jvm.utils :as u :refer [tag-match? try-best-match]]) (:import (clojure.lang IFn ExceptionInfo))) (defmulti -validate :op) (defmethod -validate :maybe-class [{:keys [class env] :as ast}] (if-let [handle (-> (env/deref-env) :passes-opts :validate/unresolvable-symbol-handler)] (handle nil class ast) (if (not (.contains (str class) ".")) (throw (ex-info (str "Could not resolve var: " class) (merge {:var class} (source-info env)))) (throw (ex-info (str "Class not found: " class) (merge {:class class} (source-info env))))))) (defmethod -validate :maybe-host-form [{:keys [class field form env] :as ast}] (if-let [handle (-> (env/deref-env) :passes-opts :validate/unresolvable-symbol-handler)] (handle class field ast) (if (resolve-ns class env) (throw (ex-info (str "No such var: " class) (merge {:form form} (source-info env)))) (throw (ex-info (str "No such namespace: " class) (merge {:ns class :form form} (source-info env))))))) (defmethod -validate :set! [{:keys [target form env] :as ast}] (when (not (:assignable? target)) (throw (ex-info "Cannot set! non-assignable target" (merge {:target (prewalk target cleanup) :form form} (source-info env))))) ast) (defmethod -validate :new [{:keys [args] :as ast}] (if (:validated? ast) ast (if-not (= :class (-> ast :class :type)) (throw (ex-info (str "Unable to resolve classname: " (:form (:class ast))) (merge {:class (:form (:class ast)) :ast ast} (source-info (:env ast))))) (let [^Class class (-> ast :class :val) c-name (symbol (.getName class)) argc (count args) tags (mapv :tag args)] (let [[ctor & rest] (->> (filter #(= (count (:parameter-types %)) argc) (u/members class c-name)) (try-best-match tags))] (if ctor (if (empty? rest) (let [arg-tags (mapv u/maybe-class (:parameter-types ctor)) args (mapv (fn [arg tag] (assoc arg :tag tag)) args arg-tags)] (assoc ast :args args :validated? true)) ast) (throw (ex-info (str "no ctor found for ctor of class: " class " and given signature") (merge {:class class :args (mapv (fn [a] (prewalk a cleanup)) args)} (source-info (:env ast))))))))))) (defn validate-call [{:keys [class instance method args tag env op] :as ast}] (let [argc (count args) instance? (= :instance-call op) f (if instance? u/instance-methods u/static-methods) tags (mapv :tag args)] (if-let [matching-methods (seq (f class method argc))] (let [[m & rest :as matching] (try-best-match tags matching-methods)] (if m (let [all-ret-equals? (apply = (mapv :return-type matching))] (if (or (empty? rest) (and all-ret-equals? ;; if the method signature is the same just pick the first one (apply = (mapv #(mapv u/maybe-class (:parameter-types %)) matching)))) (let [ret-tag (:return-type m) arg-tags (mapv u/maybe-class (:parameter-types m)) args (mapv (fn [arg tag] (assoc arg :tag tag)) args arg-tags) class (u/maybe-class (:declaring-class m))] (merge' ast {:method (:name m) :validated? true :class class :o-tag ret-tag :tag (or tag ret-tag) :args args} (if instance? {:instance (assoc instance :tag class)}))) (if all-ret-equals? (let [ret-tag (:return-type m)] (assoc ast :o-tag Object :tag (or tag ret-tag))) ast))) (if instance? (assoc (dissoc ast :class) :tag Object :o-tag Object) (throw (ex-info (str "No matching method: " method " for class: " class " and given signature") (merge {:method method :class class :args (mapv (fn [a] (prewalk a cleanup)) args)} (source-info env))))))) (if instance? (assoc (dissoc ast :class) :tag Object :o-tag Object) (throw (ex-info (str "No matching method: " method " for class: " class " and arity: " argc) (merge {:method method :class class :argc argc} (source-info env)))))))) (defmethod -validate :static-call [ast] (if (:validated? ast) ast (validate-call (assoc ast :class (u/maybe-class (:class ast)))))) (defmethod -validate :static-field [ast] (if (:validated? ast) ast (assoc ast :class (u/maybe-class (:class ast))))) (defmethod -validate :instance-call [{:keys [class validated? instance] :as ast}] (let [class (or class (:tag instance))] (if (and class (not validated?)) (validate-call (assoc ast :class (u/maybe-class class))) ast))) (defmethod -validate :instance-field [{:keys [instance class] :as ast}] (let [class (u/maybe-class class)] (assoc ast :class class :instance (assoc instance :tag class)))) (defmethod -validate :import [{:keys [^String class validated? env form] :as ast}] (if-not validated? (let [class-sym (-> class (subs (inc (.lastIndexOf class "."))) symbol) sym-val (resolve-sym class-sym env)] (if (and (class? sym-val) (not= (.getName ^Class sym-val) class)) ;; allow deftype redef (throw (ex-info (str class-sym " already refers to: " sym-val " in namespace: " (:ns env)) (merge {:class class :class-sym class-sym :sym-val sym-val :form form} (source-info env)))) (assoc ast :validated? true))) ast)) (defmethod -validate :def [ast] (when-not (var? (:var ast)) (throw (ex-info (str "Cannot def " (:name ast) " as it refers to the class " (.getName ^Class (:var ast))) (merge {:ast (prewalk ast cleanup)} (source-info (:env ast)))))) (merge ast (when-let [tag (-> ast :name meta :tag)] (when (and (symbol? tag) (or (u/specials (str tag)) (u/special-arrays (str tag)))) ;; we cannot validate all tags since :tag might contain a function call that returns ;; a valid tag at runtime, however if tag is one of u/specials or u/special-arrays ;; we know that it's a wrong tag as it's going to be evaluated as a clojure.core function (if-let [handle (-> (env/deref-env) :passes-opts :validate/wrong-tag-handler)] (handle :name/tag ast) (throw (ex-info (str "Wrong tag: " (eval tag) " in def: " (:name ast)) (merge {:ast (prewalk ast cleanup)} (source-info (:env ast)))))))))) (defmethod -validate :invoke [{:keys [args env fn form] :as ast}] (let [argc (count args)] (when (and (= :const (:op fn)) (not (instance? IFn (:form fn)))) (throw (ex-info (str (class (:form fn)) " is not a function, but it's used as such") (merge {:form form} (source-info env))))) (if (and (:arglists fn) (not (arglist-for-arity fn argc))) (if (-> (env/deref-env) :passes-opts :validate/throw-on-arity-mismatch) (throw (ex-info (str "No matching arity found for function: " (:name fn)) {:arity (count args) :fn fn})) (assoc ast :maybe-arity-mismatch true)) ast))) (defn validate-interfaces [{:keys [env form interfaces]}] (when-not (every? #(.isInterface ^Class %) (disj interfaces Object)) (throw (ex-info "only interfaces or Object can be implemented by deftype/reify" (merge {:interfaces interfaces :form form} (source-info env)))))) (defmethod -validate :deftype [{:keys [class-name] :as ast}] (validate-interfaces ast) (assoc ast :class-name (u/maybe-class class-name))) (defmethod -validate :reify [{:keys [class-name] :as ast}] (validate-interfaces ast) (assoc ast :class-name (u/maybe-class class-name))) (defmethod -validate :default [ast] ast) (defn validate-tag [t {:keys [env] :as ast}] (let [tag (ast t)] (if-let [the-class (u/maybe-class tag)] {t the-class} (if-let [handle (-> (env/deref-env) :passes-opts :validate/wrong-tag-handler)] (handle t ast) (throw (ex-info (str "Class not found: " tag) (merge {:class tag :ast (prewalk ast cleanup)} (source-info env)))))))) (defn validate "Validate tags, classes, method calls. Throws exceptions when invalid forms are encountered, replaces class symbols with class objects. Passes opts: * :validate/throw-on-arity-mismatch If true, validate will throw on potential arity mismatch * :validate/wrong-tag-handler If bound to a function, will invoke that function instead of throwing on invalid tag. The function takes the tag key (or :name/tag if the node is :def and the wrong tag is the one on the :name field meta) and the originating AST node and must return a map (or nil) that will be merged into the AST, possibly shadowing the wrong tag with Object or nil. * :validate/unresolvable-symbol-handler If bound to a function, will invoke that function instead of throwing on unresolvable symbol. The function takes three arguments: the namespace (possibly nil) and name part of the symbol, as symbols and the originating AST node which can be either a :maybe-class or a :maybe-host-form, those nodes are documented in the tools.analyzer quickref. The function must return a valid tools.analyzer.jvm AST node." {:pass-info {:walk :post :depends #{#'infer-tag #'analyze-host-expr #'validate-recur}}} [{:keys [tag form env] :as ast}] (let [ast (merge (-validate ast) (when tag {:tag tag}))] (merge ast (when (:tag ast) (validate-tag :tag ast)) (when (:o-tag ast) (validate-tag :o-tag ast)) (when (:return-tag ast) (validate-tag :return-tag ast))))) validate_loop_locals.clj000066400000000000000000000142601312245000300375360ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.validate-loop-locals (:require [clojure.tools.analyzer.ast :refer [postwalk children update-children]] [clojure.tools.analyzer.jvm.utils :refer [wider-tag maybe-class primitive?]] [clojure.tools.analyzer.passes.jvm [validate :refer [validate]] [classify-invoke :refer [classify-invoke]] [infer-tag :refer [infer-tag]] [analyze-host-expr :refer [analyze-host-expr]]])) (def ^:dynamic ^:private validating nil) (def ^:dynamic ^:private mismatch?) (def ^:dynamic ^:private *loop-locals* []) (defn find-mismatches [{:keys [op exprs] :as ast} bindings] (case op :recur (when (some true? (mapv (fn [e {:keys [tag init form]}] (and (or (primitive? tag) (not (or (:tag (meta form)) (:tag (meta (:form init)))))) (not= (:tag e) tag))) exprs bindings)) (swap! mismatch? conj (mapv :tag exprs))) :do (doseq [child (children ast)] (find-mismatches child bindings)) (:let :letfn) (find-mismatches (:body ast) bindings) :if (do (find-mismatches (:then ast) bindings) (find-mismatches (:else ast) bindings)) :case (do (find-mismatches (:default ast) bindings) (doseq [child (:thens ast)] (find-mismatches child bindings))) nil) ast) (defmulti -validate-loop-locals (fn [_ {:keys [op]}] op)) (defmulti -cleanup-dirty-nodes :op) (defmethod -cleanup-dirty-nodes :local [{:keys [form name atom env] :as ast}] (if-let [cast ((:loop-locals-casts env) name)] (assoc ast :dirty? true :o-tag cast :tag (or (:tag (meta form)) cast)) (if (and (:dirty? @atom) (not (:tag (meta form)))) (dissoc (assoc ast :dirty? true) :o-tag :tag) ast))) (defn dirty [ast] (when-let [atom (:atom ast)] (swap! atom assoc :dirty? true)) (assoc (update-children ast (fn [ast] (dissoc ast :dirty?))) :dirty? true)) (defmethod -cleanup-dirty-nodes :do [{:keys [op ret] :as ast}] (if (:dirty? ret) (dissoc (dirty ast) :tag) ast)) ;; should check for :tag meta form (defmethod -cleanup-dirty-nodes :default [{:keys [op] :as ast}] (if (some :dirty? (children ast)) (dissoc (dirty ast) :tag :validated? (when (= :instance-call op) :class)) ast)) (defn -validate-loop-locals* [analyze {:keys [body env loop-id] :as ast} key] (if validating ast (binding [mismatch? (atom #{})] (let [bindings (key ast)] (find-mismatches body bindings) (if-let [mismatches (seq @mismatch?)] (let [bindings-form (apply mapv (fn [{:keys [form tag]} & mismatches] (when-not (every? #{tag} mismatches) (let [tags (conj mismatches tag)] (with-meta form {:tag (or (and (some primitive? tags) (wider-tag tags)) Object)})))) bindings mismatches) loop-locals (mapv :name bindings) binds (zipmap loop-locals (mapv (comp maybe-class :tag meta) bindings-form)) analyze* (fn [ast] (analyze (postwalk ast (fn [ast] (when-let [atom (:atom ast)] (swap! atom dissoc :dirty?)) ast))))] (binding [validating loop-id *loop-locals* loop-locals] (analyze* (dissoc (postwalk (assoc ast key (mapv (fn [{:keys [atom] :as bind} f] (if f (do (swap! atom assoc :dirty? true) (assoc (dissoc bind :tag) :form f)) bind)) (key ast) bindings-form)) (comp -cleanup-dirty-nodes (fn [ast] (assoc-in ast [:env :loop-locals-casts] binds)))) :dirty?)))) ast))))) (defmethod -validate-loop-locals :loop [analyze ast] (-validate-loop-locals* analyze ast :bindings)) (defmethod -validate-loop-locals :fn-method [analyze ast] (-validate-loop-locals* analyze ast :params)) (defmethod -validate-loop-locals :method [analyze ast] (-validate-loop-locals* analyze ast :params)) (defmethod -validate-loop-locals :recur [_ {:keys [exprs env loop-id] :as ast}] (if (= validating loop-id) (let [casts (:loop-locals-casts env)] (assoc ast :exprs (mapv (fn [{:keys [env form] :as e} n] (if-let [c (casts n)] (assoc e :tag c) e)) exprs *loop-locals*))) ast)) (defmethod -validate-loop-locals :default [_ ast] ast) (defn validate-loop-locals "Returns a pass that validates the loop locals, calling analyze on the loop AST when a mismatched loop-local is found" {:pass-info {:walk :post :depends #{#'validate} :affects #{#'analyze-host-expr #'infer-tag #'validate} :after #{#'classify-invoke}}} [analyze] (fn [ast] (-validate-loop-locals analyze ast))) validate_recur.clj000066400000000000000000000030331312245000300363440ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.validate-recur (:require [clojure.tools.analyzer.ast :refer [update-children]] [clojure.tools.analyzer.utils :refer [-source-info]])) (defmulti validate-recur "Ensures recurs don't cross try boundaries" {:pass-info {:walk :pre :depends #{}}} :op) (defmethod validate-recur :default [ast] (if (-> ast :env :no-recur) (update-children ast (fn [ast] (update-in ast [:env] assoc :no-recur true))) ast)) (defmethod validate-recur :try [ast] (update-children ast (fn [ast] (update-in ast [:env] assoc :no-recur true)))) (defmethod validate-recur :fn-method [ast] (update-in ast [:env] dissoc :no-recur)) (defmethod validate-recur :method [ast] (update-in ast [:env] dissoc :no-recur)) (defmethod validate-recur :loop [ast] (update-in ast [:env] dissoc :no-recur)) (defmethod validate-recur :recur [ast] (when (-> ast :env :no-recur) (throw (ex-info "Cannot recur accross try" (merge {:form (:form ast)} (-source-info (:form ast) (:env ast)))))) ast) warn_on_reflection.clj000066400000000000000000000043721312245000300372370ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/main/clojure/clojure/tools/analyzer/passes/jvm;; Copyright (c) Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns clojure.tools.analyzer.passes.jvm.warn-on-reflection (:require [clojure.tools.analyzer.passes.jvm [validate-loop-locals :refer [validate-loop-locals]] [validate :refer [validate]]])) (defn warn [what {:keys [file line column]}] (when *warn-on-reflection* (binding [*err* *out*] (println (str "Reflection warning: " (when file (str file ":")) (when line (str line ":")) (when column (str column " ")) "- " what))))) (defmulti warn-on-reflection "Prints a warning to *err* when *warn-on-reflection* is true and a node requires runtime reflection" {:pass-info {:walk :pre :depends #{#'validate} :after #{#'validate-loop-locals}}} :op) (defmethod warn-on-reflection :instance-call [ast] (when-not (:validated? ast) (warn (str "call to method " (:method ast) (when-let [class (:class ast)] (str " on " (.getName ^Class class))) " cannot be resolved") (:env ast))) ast) (defmethod warn-on-reflection :static-call [ast] (when-not (:validated? ast) (warn (str "call to static method " (:method ast) " on " (.getName ^Class (:class ast)) " cannot be resolved") (:env ast))) ast) (defmethod warn-on-reflection :host-interop [ast] (warn (str "reference to field or no args method call " (:m-or-f ast) " cannot be resolved") (:env ast)) ast) (defmethod warn-on-reflection :new [ast] (when-not (:validated? ast) (warn (str "call to " (.getName ^Class (:val (:class ast))) " ctor cannot be resolved") (:env ast))) ast) (defmethod warn-on-reflection :default [ast] ast) tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/000077500000000000000000000000001312245000300226075ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/clojure/000077500000000000000000000000001312245000300242525ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/clojure/clojure/000077500000000000000000000000001312245000300257155ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/clojure/clojure/tools/000077500000000000000000000000001312245000300270555ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/clojure/clojure/tools/analyzer/000077500000000000000000000000001312245000300307025ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/clojure/clojure/tools/analyzer/jvm/000077500000000000000000000000001312245000300314765ustar00rootroot00000000000000core_test.clj000066400000000000000000000100331312245000300340750ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/clojure/clojure/tools/analyzer/jvm(ns clojure.tools.analyzer.jvm.core-test (:refer-clojure :exclude [macroexpand-1]) (:require [clojure.tools.analyzer :as ana] [clojure.tools.analyzer.jvm :as ana.jvm] [clojure.tools.analyzer.env :as env] [clojure.tools.analyzer.passes.elide-meta :refer [elides elide-meta]] [clojure.tools.analyzer.ast :refer [postwalk]] [clojure.test :refer [deftest is]])) (defprotocol p (f [_])) (defn f1 [^long x]) (def e (ana.jvm/empty-env)) (defmacro ast [form] `(binding [ana/macroexpand-1 ana.jvm/macroexpand-1 ana/create-var ana.jvm/create-var ana/parse ana.jvm/parse ana/var? var? elides {:all #{:line :column :file}}] (env/with-env (ana.jvm/global-env) (postwalk (ana/analyze '~form e) elide-meta)))) (defmacro ast1 [form] `(binding [ana/macroexpand-1 ana.jvm/macroexpand-1 ana/create-var ana.jvm/create-var ana/parse ana.jvm/parse ana/var? var? elides {:all #{:line :column :file}}] (ana.jvm/analyze '~form e))) (defmacro mexpand [form] `(ana.jvm/macroexpand-1 '~form e)) (deftest macroexpander-test (is (= (list '. (list 'do java.lang.Object) 'toString) (mexpand (.toString Object)))) (is (= (list '. java.lang.Integer '(parseInt "2")) (mexpand (Integer/parseInt "2"))))) (deftest analyzer-test (let [v-ast (ast #'+)] (is (= :the-var (:op v-ast))) (is (= #'+ (:var v-ast)))) (let [mn-ast (ast (monitor-enter 1))] (is (= :monitor-enter (:op mn-ast))) (is (= 1 (-> mn-ast :target :form)))) (let [mx-ast (ast (monitor-exit 1))] (is (= :monitor-exit (:op mx-ast))) (is (= 1 (-> mx-ast :target :form)))) (let [i-ast (ast (clojure.core/import* "java.lang.String"))] (is (= :import (:op i-ast))) (is (= "java.lang.String" (:class i-ast)))) (let [r-ast (ast ^:foo (reify Object (toString [this] "") Appendable (^Appendable append [this ^char x] this)))] (is (= :with-meta (-> r-ast :op))) ;; line/column info (is (= :reify (-> r-ast :expr :op))) (is (= #{Appendable clojure.lang.IObj} (-> r-ast :expr :interfaces))) (is (= '#{toString append} (->> r-ast :expr :methods (mapv :name) set)))) (let [dt-ast (ast (deftype* x user.x [a b] :implements [Appendable] (^Appendable append [this ^char x] this)))] (is (= :deftype (-> dt-ast :op))) (is (= '[a b] (->> dt-ast :fields (mapv :name)))) (is (= '[append] (->> dt-ast :methods (mapv :name)))) (is (= 'user.x (-> dt-ast :class-name)))) (let [c-ast (ast (case* 1 0 0 :number {2 [2 :two] 3 [3 :three]} :compact :int))] (is (= :number (-> c-ast :default :form))) (is (= #{2 3} (->> c-ast :tests (mapv (comp :form :test)) set))) (is (= #{:three :two} (->> c-ast :thens (mapv (comp :form :then)) set))) (is (= 3 (-> c-ast :high))) (is (= :int (-> c-ast :test-type))) (is (= :compact (-> c-ast :switch-type))) (is (= 2 (-> c-ast :low))) (is (= 0 (-> c-ast :shift))) (is (= 0 (-> c-ast :mask)))) (is (= Throwable (-> (ast1 (try (catch :default e))) :catches first :class :val))) (is (= Exception (-> (ast1 (try (catch Exception e e))) :catches first :body :tag)))) (deftest doseq-chunk-hint (let [tree (ast1 (doseq [item (range 10)] (println item))) {[_ chunk] :bindings} tree] (is (= :loop (:op tree))) (is (.startsWith (name (:name chunk)) "chunk")) (is (= clojure.lang.IChunk (:tag chunk))))) (def ^:dynamic x) (deftest set!-dynamic-var (is (ast1 (set! x 1)))) (deftest analyze-proxy (is (ast1 (proxy [Object] [])))) (deftest analyze-record (is (ast1 (defrecord TestRecord [x y])))) (deftest eq-no-reflection (is (:validated? (-> (ast1 (fn [s] (= s \f))) :methods first :body)))) (deftest analyze+eval-context-test (let [do-ast (ana.jvm/analyze+eval '(do 1 2 3))] (is (= :ctx/statement (-> do-ast :statements first :env :context))))) passes_test.clj000066400000000000000000000175131312245000300344550ustar00rootroot00000000000000tools.analyzer.jvm-tools.analyzer.jvm-0.7.1/src/test/clojure/clojure/tools/analyzer/jvm(ns clojure.tools.analyzer.jvm.passes-test (:refer-clojure :exclude [macroexpand-1]) (:require [clojure.tools.analyzer.ast :refer :all] [clojure.tools.analyzer.jvm :as ana.jvm] [clojure.tools.analyzer.env :as env] [clojure.tools.analyzer.passes :refer [schedule]] [clojure.test :refer [deftest is]] [clojure.set :as set] [clojure.tools.analyzer.passes.add-binding-atom :refer [add-binding-atom]] [clojure.tools.analyzer.passes.collect-closed-overs :refer [collect-closed-overs]] [clojure.tools.analyzer.jvm.core-test :refer [ast ast1 e f f1]] [clojure.tools.analyzer.passes.jvm.emit-form :refer [emit-form emit-hygienic-form]] [clojure.tools.analyzer.passes.jvm.validate :as v] [clojure.tools.analyzer.passes.jvm.annotate-tag :refer [annotate-tag]] [clojure.tools.analyzer.passes.jvm.infer-tag :refer [infer-tag]] [clojure.tools.analyzer.passes.jvm.annotate-branch :refer [annotate-branch]] [clojure.tools.analyzer.passes.jvm.annotate-host-info :refer [annotate-host-info]] [clojure.tools.analyzer.passes.jvm.annotate-loops :refer [annotate-loops]] [clojure.tools.analyzer.passes.jvm.fix-case-test :refer [fix-case-test]] [clojure.tools.analyzer.passes.jvm.analyze-host-expr :refer [analyze-host-expr]] [clojure.tools.analyzer.passes.jvm.classify-invoke :refer [classify-invoke]]) (:import (clojure.lang Keyword Var Symbol AFunction PersistentVector PersistentArrayMap PersistentHashSet ISeq) java.util.regex.Pattern)) (defn validate [ast] (env/with-env (ana.jvm/global-env) (v/validate ast))) (deftest emit-form-test (is (= '(monitor-enter 1) (emit-form (ast (monitor-enter 1))))) (is (= '(monitor-exit 1) (emit-form (ast (monitor-exit 1))))) (is (= '(clojure.core/import* "java.lang.String") (emit-form (validate (ast (clojure.core/import* "java.lang.String")))))) (is (= '(var clojure.core/+) (emit-form (ast #'+)))) (is (= '(:foo {}) (emit-form (ast (:foo {}))))) (is (= '(try 1 (catch Exception e nil)) (emit-form (ana.jvm/analyze '(try 1 (catch Exception e)))))) (is (= '(try 1 (catch Exception e nil)) (emit-form (ana.jvm/analyze '(try 1 (catch Exception e))) {:qualifed-symbols true}))) (is (= '(f [] 1) (emit-form (ast (f [] 1)))))) (deftest annotate-branch-test (let [i-ast (annotate-branch (ast (if 1 2 3)))] (is (:branch? i-ast)) (is (= true (-> i-ast :test :test?))) (is (= true (-> i-ast :then :path?))) (is (= true (-> i-ast :else :path?)))) (let [fn-ast (prewalk (ast (fn ([]) ([x]))) annotate-branch)] (is (every? :path? (-> fn-ast :methods)))) (let [r-ast (prewalk (ast (reify Object (toString [this] x))) annotate-branch)] (is (every? :path? (-> r-ast :methods)))) (let [c-ast (-> (ast (case 1 0 0 2 2 1)) :body :ret (prewalk annotate-branch))] (is (:branch? c-ast)) (is (= true (-> c-ast :test :test?))) (is (= true (-> c-ast :default :path?))) (is (every? :path? (-> c-ast :thens))))) (deftest fix-case-test-test (let [c-ast (-> (ast (case 1 1 1)) add-binding-atom (prewalk fix-case-test))] (is (= true (-> c-ast :body :ret :test :atom deref :case-test))))) (deftest annotate-tag-test (is (= PersistentVector (-> {:op :const :form [] :val []} annotate-tag :tag))) (is (= PersistentVector (-> (ast []) annotate-tag :tag))) (is (= PersistentArrayMap(-> (ast {}) annotate-tag :tag))) (is (= PersistentHashSet (-> (ast #{}) annotate-tag :tag))) (is (= Class (-> {:op :const :type :class :form Object :val Object} annotate-tag :tag))) (is (= String (-> (ast "foo") annotate-tag :tag))) (is (= Keyword (-> (ast :foo) annotate-tag :tag))) (is (= Character/TYPE (-> (ast \f) annotate-tag :tag))) (is (= Long/TYPE (-> (ast 1) annotate-tag :tag))) (is (= Pattern (-> (ast #"foo") annotate-tag :tag))) (is (= Var (-> (ast #'+) annotate-tag :tag))) (is (= Boolean (-> (ast true) annotate-tag :tag))) (let [b-ast (-> (ast (let [a 1] a)) add-binding-atom (postwalk annotate-tag))] (is (= Long/TYPE (-> b-ast :body :ret :tag))))) (deftest classify-invoke-test (is (= :keyword-invoke (-> (ast (:foo {})) classify-invoke :op))) (is (= :invoke (-> (ast (:foo {} 1)) classify-invoke :op))) (is (= :protocol-invoke (-> (ast (f nil)) classify-invoke :op))) (is (= :instance? (-> (ast (instance? String "")) (prewalk analyze-host-expr) classify-invoke :op))) (is (= :prim-invoke (-> (ast (f1 1)) (prewalk infer-tag) classify-invoke :op)))) (deftest annotate-host-info-test (let [r-ast (-> (ast ^:foo (reify Object (toString [_] ""))) (prewalk annotate-host-info))] (is (= 'toString (-> r-ast :expr :methods first :name))) (is (= [] (-> r-ast :expr :methods first :params))) (is (= '_ (-> r-ast :expr :methods first :this :name))))) ;; TODO: test primitives, tag matching, throwing validation, method validation (deftest validate-test (is (= Exception (-> (ast (try (catch Exception e))) (prewalk (comp validate analyze-host-expr)) :catches first :class :val))) (is (-> (ast (set! *warn-on-reflection* true)) validate)) (is (= true (-> (ast (String. "foo")) (postwalk (comp validate annotate-tag analyze-host-expr)) :validated?))) (let [s-ast (-> (ast (Integer/parseInt "7")) (prewalk annotate-tag) analyze-host-expr validate)] (is (:validated? s-ast)) (is (= Integer/TYPE (:tag s-ast))) (is (= [String] (mapv :tag (:args s-ast))))) (let [i-ast (-> (ast (.hashCode "7")) (prewalk annotate-tag) analyze-host-expr validate)] (is (:validated? i-ast)) (is (= Integer/TYPE (:tag i-ast))) (is (= [] (mapv :tag (:args i-ast)))) (is (= String (:class i-ast)))) (is (= true (-> (ast (import java.lang.String)) (prewalk validate) :ret :validated?)))) ;; we need all or most those passes to perform those tests (deftest all-passes-test (let [t-ast (ast1 (let [a 1 b 2 c (str a) d (Integer/parseInt c b)] (Integer/getInteger c d)))] (is (= Integer (-> t-ast :body :tag))) (is (= Integer (-> t-ast :tag))) (is (= Long/TYPE (->> t-ast :bindings (filter #(= 'a (:form %))) first :tag))) (is (= String (->> t-ast :bindings (filter #(= 'c (:form %))) first :tag))) (is (= Integer/TYPE (->> t-ast :bindings (filter #(= 'd (:form %))) first :tag)))) (is (= Void/TYPE (:tag (ast1 (.println System/out "foo"))))) (is (= String (-> (ast1 String) :val))) (is (= 'String (-> (ast1 String) :form))) (is (= PersistentVector (-> (ast1 '[]) :tag))) (is (= ISeq (-> (ast1 '()) :tag))) (let [d-ast (ast1 (Double/isInfinite 2))] (is (= Boolean/TYPE (-> d-ast :tag))) (is (= Double/TYPE (->> d-ast :args first :tag))))) ;; checks for specific bugs that have surfaced (deftest annotate-case-loop (is (ast1 (loop [] (case 1 :a (recur) :b 42))))) (deftest var-tag-inference (let [ast (ana.jvm/analyze '(def a "foo") (ana.jvm/empty-env) {:passes-opts (merge ana.jvm/default-passes-opts {:infer-tag/level :global})})] (is (= String (-> ast :var meta :tag))))) (deftest validate-handlers ;; test for tanal-24, without the handler analysis would throw ;; with an handler that ignores the tag, we can simulate the current behaviour ;; of the clojure compiler (is (ana.jvm/analyze '(defn ^long a [] 1) (ana.jvm/empty-env) {:passes-opts (merge ana.jvm/default-passes-opts {:validate/wrong-tag-handler (fn [t ast] {t nil})})})))