pax_global_header00006660000000000000000000000064137540131070014513gustar00rootroot0000000000000052 comment=bebdbc81924ebf967583284bd31d3853e920f230 tools.reader-tools.reader-1.3.4/000077500000000000000000000000001375401310700165205ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/.gitignore000066400000000000000000000001331375401310700205050ustar00rootroot00000000000000/target /lib /classes /checkouts *.jar *.class .lein-deps-sum .lein-failures .lein-plugins tools.reader-tools.reader-1.3.4/CHANGELOG.md000066400000000000000000000201631375401310700203330ustar00rootroot00000000000000Changelog ======================================== * Release 1.3.3 on 9 Aug 2020 * Fix tagged literals returning non truthy values in EDN reader (#TRDR-62) * Refer to `cljs.tools.reader` instead of `clojure.tools.reader` in docstrings (#TRDR-56) * Release 1.3.2 on 26 Oct 2018 * Fix bad arities for read+string * Release 1.3.1 on 22 Oct 2018 * Changes to read+string 2-arity to match new clojure arity (#CLJ-2358) * Fix buffer overflow when reading files with consecutive carriage returns (#TRDR-54) * Release 1.3.0 on 5 Jul 2018 * Fix private var warning in cljs impl * Release 1.3.0-alpha3 on 25 Feb 2018 * Improve memory footprint of source-logging-pushback-reader * Trim output of read+string to match clojure impl * Workaround for bad read+string 2-arity * Release 1.3.0-alpha2 on 25 Feb 2018 * Reduce memory footprint of source-logging-pushback-reader by cleaning up buffer after use * Exclude read+string from import to remove warning when using clojure 1.9.0 * Release 1.3.0-alpha1 on 24 Feb 2018 * Implement read+string * Attach metadata to all IObjs instead of requiring IMeta * Release 1.2.2 on 18 Feb 2018 * Exclude reader-conditional and tagged-literal import to remove warning when using newer versions of clojure * Release 1.2.1 on 25 Jan 2018 * Fix potential stack overflow introduced by previous release * Release 1.2.0 on 25 Jan 2018 * Fixed wrong recurson point in read, that caused source logging issues * Release 1.1.3.1 on 19 Jan 2017 * Fix malformed error message for cljs reader (#TRDR-51) * Release 1.1.2 on 17 Jan 2017 * Fixed cljs edn reader wrt unicode limits (#TRDR-50) * Release 1.1.1 on 07 Nov 2017 * Fix typo in cljs inspector (#TRDR-46) * Fix typo in octal string validation (#TRDR-47) * Release 1.1.0 on 09 Sept 2017 * Remove +-Inf/NaN experimental feature * Add support for ##Inf ##-Inf and ##NaN (#CLJ-1074) * Release 1.0.6 on 29 Aug 2017 * Disallow non-aliases after :: * Release 1.0.5 on 03 Aug 2017 * Syntax-quote delegates `Foo.` symbols to `resolve-symbol`, cljs needs to resolve namespaces while clj classes * Release 1.0.3 on 19 Jul 2017 * ALl errors throw ex-info, add :ex-kind :eof for EOF errors * Release 1.0.2 on 11 Jul 2017 * Improved error messages (#TRDR-44) * Duplicate checks for sets in CLJS port * Release 1.0.1 on 08 Jul 2017 * More informative error messages for tagged literals * Ported the Fix for #TRDR-44 in the edn namespace * Release 1.0.0 on 08 Jun 2017 * Release 1.0.0-RC1 on 24 May 2017 * Throw on nil ns in namespaced map (#CLJ-2152) * Better map keys duplicate checks in cljs port * Release 1.0.0-beta4 on 13 Dec 2016 * Respect array-map/hash-map in cljs port (#TRDR-40) * Release 1.0.0-beta3 on 25 Jun 2016 * Initial implementation of new namespaced maps support * Removed further boxed math * Droped clojure 1.4.0 support * Release 1.0.0-beta2 on 10 Jun 2016 * Removed some boxed math * Release 1.0.0-beta1 on 30 Mar 2016 * Error out on invalid numbers * Release 1.0.0-alpha4 on 29 Feb 2016 * Throw exception on duplicate keys in sets/maps in cljs port * Release 1.0.0-alpha3 on 05 Jan 2016 * Auto qualify symbols in cljs syntax-quote * Release 1.0.0-alpha2 on 05 Dec 2015 * Renamed pushback-reader to push-back-reader * Added Closeable type hint to reader ctor functions * Release 1.0.0-alpha1 on 02 Nov 2015 * Reader types implement Closeable * Added pushback-reader * Improved interoperability between reader types and java readers * Release 0.10.0 on 09 Oct 2015 * Better error for invalid octal literal * Release 0.10.0-alpha3 on 28 Jul 2015 * Updated cljs port for self-hosted cljs * Release 0.10.0-alpha2 on 27 Jun 2015 * Re-added *alias-map* support in cljs port * Added support for auto-qualifying symbols and keywords inside backtick in cljs port * Removed a reflection instance * Allow returning nil in reader-conditionals (#TRDR-30) * Release 0.10.0-alpha1 on 09 Jun 2015 * Initial cljs port * Removed support for clojure 1.3.0 * Release 0.9.2 on 23 Apr 2015 * Allow sym->sym mapping in *alias-map* * Release 0.9.1 on 09 Apr 2015 * Fixed tagged literals inside read-cond * Release 0.9.0 on 09 Apr 2015 * Implemented reader conditionals * Fixed column metadata on sets * Disallowed reading keywords and symbols ending with colon * Made ExceptionInfo extend RuntimeException * Release 0.8.16 on 06 Mar 2015 * Added new output jar with "aot" classifier * Release 0.8.15 on 21 Feb 2015 * Fixed line-start? offset * Release 0.8.14 on 20 Feb 2015 * Added line-start? predicate * Removed support for \xHH chars * Fixed column metadata handling for set literals * Release 0.8.13 on 04 Dec 2014 * Fixed column number handling in source info * Release 0.8.12 on 03 Nov 2014 * Fixed a bug when reading syntax-quoted map literals containing a :val key * Release 0.8.11 on 31 Oct 2014 * Ensure metadata is not lost in syntax-quoted forms * Release 0.8.10 on 23 Oct 2014 * Reverted hack to allow `{~@foo} and `#{~(gensym) ~(gensym)} * Fixed error reporting for keywords starting with macro-starting chars * Release 0.8.9 on 18 Sep 2014 * Don't attach metadata on syntax-quoted forms if it's composed only by source-info * Release 0.8.8 on 31 Aug 2014 * Made resolve-symbol a public ^:dynamic function * Release 0.8.7 on 23 Aug 2014 * Fixed a bug introduced in 0.8.6 in syntax-quote * Cleaned up read-eval implementation * Release 0.8.6 on 16 Aug 2014 (BROKEN) * Allow for `{~@foo} and `#{~(gensym) ~(gensym)} * Performance enhancements in the code emitted by syntax-quote * Release 0.8.5 on 12 Jun 2014 * Attach source info on literal sets too * Fixed how syntax-quoting handles splicing empty seqs into a list * Release 0.8.4 on 04 Apr 2014 * Fixed misplaced docstring * Added file metadata info * Fixed end-column offset * Release 0.8.3 on 20 Dec 2013 * Fixed a typo that caused syntax-quote to keep unqualified the classes in static calls * Release 0.8.2 on 11 Dec 2013 * Fixed read-line implementation fallbacking to c.c/read-line * Richer error reporting * Release 0.8.1 on 05 Dec 2013 * Fixed possible stack overflow in read (#TRDR-11) * Release 0.8.0 on 20 Nov 2013 * Added SourceLoggingPushbackReader (#TRDR-9) * Added end-line/column-line metadata info (#TRDR-10) * Release 0.7.10 on 24 Oct 2013 * Added \*alias-map\* * Release 0.7.9 on 11 Oct 2013 * Fixed \r\n handling * Release 0.7.8 on 27 Sep 2013 * Added missing whitespace in exception message * Added get-file-name to IndexingReader * Release 0.7.7 on 13 Sep 2013 * Fixed #TRDR-8 * Fixed out-of-bound exception in ctor-reader args mismatch * Release 0.7.6 on 14 Aug 2013 * Fixed #TRDR-7 * Release 0.7.5 on 03 Jun 2013 * Removed all reflection for clojure 1.3 * Fixed :column metadata handling on symbols * Release 0.7.4 on 19 Apr 2013 * Fixed docstrings position and typos * Fixed a bug that would have prevented future alpha versions of clojure to have column metadata * Made symbols containing two consecutive ':' illegal, as per [clojure.org](http://clojure.org/reader#The%20Reader--Reader%20forms) * Made symbols containing two consecutive '/' illegal * Removed reflection warnings * Release 0.7.3 on Mar 08, 2013 * AOT compile only ExceptionInfo. * Release 0.7.2 on 02 Mar 2013 * Fixed evaling read objects for clojure 1.5 * Release 0.7.1 on 02 Mar 2013 * Added the syntax-quote macro to the public API * Release 0.7.0 on 14 Feb 2013 * Fixed #TRDR-1 by @jafingerhut * Made compatible with clojure-1.3.0 * Decoupled from clojure.core vars (\*read-eval\*, \*default-data-reader-fn\*, \*data-readers\*) * clojure.tools.reader/read-string and clojure.tools.reader.edn/read-string return nil if string is nil or empty * Added comprehensive docstrings * Release 0.6.5 on 09 Feb 2013 * Fixed reading \@ \~ and \` * Release 0.6.4 on 08 Feb 2013 * Fixed Unicode char reading * Added \*default-data-reader-fn\* support * Added an EDN-only reader * Disabled record literals reading when \*read-eval\* is bound to false * Made \% a symbol constituent char * Made the EDN reader API match the clojure.edn one * Release 0.6.2 on 04 Feb 2013 * Added line/column metadata on vectors, maps and symbols * Release 0.6.0 on 03 Feb 2013 * Initial release. tools.reader-tools.reader-1.3.4/CONTRIBUTING.md000066400000000000000000000007341375401310700207550ustar00rootroot00000000000000This 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] on the Clojure website for more information on how to contribute. [Clojure contrib]: https://clojure.org/community/contrib_libs [Contributing]: https://clojure.org/community/contributing [JIRA]: http://dev.clojure.org/jira/browse/TRDR [guidelines]: https://clojure.org/community/contrib_howto tools.reader-tools.reader-1.3.4/LICENSE000066400000000000000000000263741375401310700175410ustar00rootroot00000000000000Eclipse 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.reader-tools.reader-1.3.4/README.md000066400000000000000000000152031375401310700200000ustar00rootroot00000000000000clojure.tools.reader ======================================== A complete Clojure reader and an EDN-only reader, works with Clojure versions >= 1.4.0 and Clojurescript >=0.5308 and since version 0.10.0-alpha1 * [Rationale](#rationale) * [Releases and Dependency Information](#releases-and-dependency-information) * [Changelog](#changelog) * [API Index](#api-index) * [Developer Information](#developer-information) * [Example Usage](#example-usage) * [Differences from LispReader.java](#differences-from-lispreaderjava) * [License](#license) Rationale ======================================== clojure.tools.reader offers all functionality of the reader from clojure-1.9.0, and more. For a list of additional features of the reader, read [Differences from LispReader.java](#differences-from-lispreaderjava) Moreover, by using reader types from `clojure.tools.reader.reader-types`, if using an IndexingReader, column info is available and both line and column metadata is attached not only to lists, but to symbols, vectors and maps too, when additional debugging info is needed (note that the edn reader doesn't add any line/column metadata at all). YourKit ======================================== YourKit has given an open source license for their profiler, greatly simplifying the profiling of tools.reader 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: 1.3.3 * [All Released Versions](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22tools.reader%22) * [Development Snapshot Versions](https://oss.sonatype.org/index.html#nexus-search;gav%7Eorg.clojure%7Etools.reader%7E%7E%7E) [clj](https://clojure.org/guides/getting_started) dependency information: ```clojure org.clojure/tools.reader {:mvn/version "1.3.3"} ``` [Leiningen](https://github.com/technomancy/leiningen) dependency information: ```clojure [org.clojure/tools.reader "1.3.3"] ``` [Maven](http://maven.apache.org/) dependency information: ```xml org.clojure tools.reader 1.3.3 ``` [Changelog](CHANGELOG.md) ======================================== API Index ======================================== * [API index](http://clojure.github.io/tools.reader) Developer Information ======================================== * [GitHub project](https://github.com/clojure/tools.reader) * [Bug Tracker](http://dev.clojure.org/jira/browse/TRDR) * [Continuous Integration](http://build.clojure.org/job/tools.reader/) * [Compatibility Test Matrix](http://build.clojure.org/job/tools.reader-test-matrix/) Example Usage ======================================== To read data structures, functions from `clojure.tools.reader.edn` should be used, since those are **safe** and don't allow any code execution at all. Remember that when using `read` you *need* to use a reader that implements `IPushbackReader` such as `string-push-back-reader`. Note that since no code-execution is permitted, reader literals are also disabled. ```clojure (require '[clojure.tools.reader.edn :as edn]) ;=> nil (edn/read-string "1") ;=> 1 (edn/read-string "#inst \"2010-11-12T13:14:15.666\"") ;=> #inst "2010-11-12T13:14:15.666-00:00" (let [my-unknown (fn [tag val] {:unknown-tag tag :value val})] (edn/read-string {:default my-unknown} "#foo bar")) ;=> {:unknown-tag foo, :value bar} (edn/read-string {:readers {'foo (constantly 1)}} "#foo bar") ;=> 1 ``` To switch from using `clojure.core/read-string` to `clojure.tools.reader.edn/read-string` in your projects, put this in your namespace declaration: ```clojure (:refer-clojure :exclude [read read-string]) (:use [clojure.tools.reader.edn :only [read read-string]]) ``` If (and only if) reading from a **trusted** source, and advanced features that need some level of code-execution during read are needed, functions from `clojure.tools.reader` should be used. ```clojure (require '[clojure.tools.reader :as r]) ;=> nil (r/read-string "1") ;=> 1 ;; WARNING! (r/read-string "#=(+ 1 2)") ;=> 3 (binding [r/*read-eval* false] (r/read-string "#=(+ 1 2)")) => ExceptionInfo #= not allowed when *read-eval* is false ``` To switch from using `clojure.core/read-string` to `clojure.tools.reader/read-string` in your projects, put this in your namespace declaration: ```clojure (:refer-clojure :exclude [read read-string *default-data-reader-fn* *read-eval* *data-readers*]) (:use [clojure.tools.reader :only [read read-string *default-data-reader-fn* *read-eval* *data-readers*]]) ``` Reader types example usage: ```clojure (require '[clojure.tools.reader.reader-types :as t]) ;=> nil (def reader (t/string-push-back-reader "1")) ;=> #'user/reader (t/read-char reader) ;=> \1 (t/unread reader \a) ;=> \a (t/peek-char reader) ;=> \a (t/read-char reader) ;=> \a (t/read-char reader) ;=> nil ``` Note that the pushback buffer is of dimension 1 by default, and an exception will be thrown if trying to unread more chars than the pushback buffer dimension. Every predefined reader type has an additional arity that allows to specify the pushback buffer dimension. ```clojure (def reader (t/string-push-back-reader "" 2)) ;=> nil (t/unread reader \a) ;=> \a (t/unread reader \b) ;=> \b (t/read-char reader) ;=> \b (t/read-char reader) ;=> \a (t/read-char reader) ;=> nil ``` Differences from LispReader.java ======================================== There are small differences from clojure.lang.LispReader: * `read` throws an `ex-info` for almost every exception, whereas `clojure.lang.LispReader/read` throws a `ReaderException` wrapping the causing exception. * `read` is capable of reading literal tags containing periods, fixing [#CLJ-1100](http://dev.clojure.org/jira/browse/CLJ-1100) * `clojure.tools.reader/read` checks if `clojure.tools.reader/*alias-map*` is bound, if that's the case, aliases will be resolved by querying it (must be a map), otherwhise (ns-aliases \*ns\*) will be used * `clojure.tools.reader/read` adds additional line/column info to symbols, vectors and maps when possible * `clojure.tools.reader.reader-types/read-line` has an additional arity with which is possible to specify the reader to read from ## License Copyright © 2013-2018 Nicola Mometto, Rich Hickey & contributors. Licensed under the EPL. (See the file epl.html.) tools.reader-tools.reader-1.3.4/epl.html000066400000000000000000000305361375401310700201750ustar00rootroot00000000000000 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.reader-tools.reader-1.3.4/pom.xml000066400000000000000000000077211375401310700200440ustar00rootroot00000000000000 4.0.0 tools.reader 1.3.4 tools.reader A Clojure reader in Clojure https://github.com/clojure/tools.reader src/main/clojure src/main/cljs com.theoryinpractise clojure-maven-plugin 1.7.1 false clojure-compile compile compile true clojure.tools.reader clojure.tools.reader.default-data-readers clojure.tools.reader.edn clojure.tools.reader.impl.commons clojure.tools.reader.impl.utils clojure.tools.reader.reader-types maven-jar-plugin 2.4 default-jar package jar **/*.clj **/*.cljs maven-assembly-plugin 2.4 aot-jar package single src/assembly/aot.xml Eclipse Public License 1.0 http://opensource.org/licenses/eclipse-1.0.php repo org.clojure pom.contrib 0.2.2 org.clojure clojure 1.5.1 org.clojure clojurescript 1.9.946 provided Bronsa Nicola Mometto +1 scm:git:git://github.com/clojure/tools.reader.git scm:git:git://github.com/clojure/tools.reader.git http://github.com/clojure/tools.reader tools.reader-1.3.4 tools.reader-tools.reader-1.3.4/project.clj000066400000000000000000000051111375401310700206560ustar00rootroot00000000000000(defproject org.clojure/tools.reader "1.0.0-SNAPSHOT" :description "A Clojure reader in Clojure" :parent [org.clojure/pom.contrib "0.2.0"] :url "https://github.com/clojure/tools.reader" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :source-paths ["src/main/clojure" "src/main/cljs"] :test-paths ["src/test/clojure"] :repositories {"sonatype-oss-public" "https://oss.sonatype.org/content/groups/public/"} :dependencies [[org.clojure/clojure "1.10.0-master-SNAPSHOT"] [org.clojure/clojurescript "1.9.946" :scope "provided"]] :profiles {:1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]} :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]} :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]} :1.10 {:dependencies [[org.clojure/clojure "1.10.0-master-SNAPSHOT"]]}} :aliases {"test-all" ["with-profile" "test,1.5:test,1.6:test,1.7:test,1.8:test,1.9:test,1.10" "test"] "check-all" ["with-profile" "1.5:1.6:1.7:1.8:1.9" "check"]} :min-lein-version "2.0.0" :global-vars {*warn-on-reflection* true *unchecked-math* :warn-on-boxed} :plugins [[lein-cljsbuild "1.1.4"]] :cljsbuild {:builds [{:id "dev" :source-paths ["src/main/cljs"] :compiler {:output-to "out/main.js" :output-dir "out" :optimizations :simple :pretty-print true}} {:id "whitespace" :source-paths ["src/main/cljs" "src/test/cljs"] :compiler {:output-to "target/test/tests-whitespace.js" :output-dir "target/test/out-whitespace" :optimizations :whitespace}} {:id "simple" :source-paths ["src/main/cljs" "src/test/cljs"] :notify-command ["node" "target/test/tests-simple.js"] :compiler {:optimizations :simple :output-to "target/test/tests-simple.js" :output-dir "target/test/out-simple"}} {:id "advanced" :source-paths ["src/main/cljs" "src/test/cljs"] :compiler {:optimizations :advanced :output-to "target/test/tests-advanced.js" :output-dir "target/test/out-advanced"}}] :test-commands {"simple" ["node" "target/test/tests-simple.js"] "advanced" ["node" "target/test/tests-advanced.js"]}}) tools.reader-tools.reader-1.3.4/src/000077500000000000000000000000001375401310700173075ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/assembly/000077500000000000000000000000001375401310700211265ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/assembly/aot.xml000066400000000000000000000006571375401310700224430ustar00rootroot00000000000000 aot jar false src/resources / true target/classes / tools.reader-tools.reader-1.3.4/src/main/000077500000000000000000000000001375401310700202335ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/cljs/000077500000000000000000000000001375401310700211665ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/000077500000000000000000000000001375401310700221215ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/000077500000000000000000000000001375401310700232615ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader.cljs000066400000000000000000001022341375401310700254020ustar00rootroot00000000000000;; 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 ^{:doc "A clojure reader in clojure" :author "Bronsa"} cljs.tools.reader (:refer-clojure :exclude [read read-line read-string char read+string default-data-readers *default-data-reader-fn* *data-readers* *suppress-read*]) (:require-macros [cljs.tools.reader.reader-types :refer [log-source]]) (:require [cljs.tools.reader.reader-types :refer [read-char unread peek-char indexing-reader? get-line-number get-column-number get-file-name string-push-back-reader]] [cljs.tools.reader.impl.utils :refer [char ex-info? whitespace? numeric? desugar-meta next-id namespace-keys second' ReaderConditional reader-conditional reader-conditional? char-code]] [cljs.tools.reader.impl.commons :refer [number-literal? read-past match-number parse-symbol read-comment throwing-reader]] [cljs.tools.reader.impl.errors :as err] [goog.array :as garray] [goog.string :as gstring]) (:import goog.string.StringBuffer)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (declare ^:private read* macros dispatch-macros ^:dynamic *data-readers* ^:dynamic *default-data-reader-fn* ^:dynamic *suppress-read* default-data-readers) (defn- ^boolean macro-terminating? [ch] (case ch (\" \; \@ \^ \` \~ \( \) \[ \] \{ \} \\) true false)) (def sb (StringBuffer.)) (defn- read-token "Read in a single logical token from the reader" [^not-native rdr kind initch] (if (nil? initch) (err/throw-eof-at-start rdr kind) (do (.clear sb) (loop [ch initch] (if (or (whitespace? ch) (macro-terminating? ch) (nil? ch)) (do (when-not (nil? ch) (unread rdr ch)) (.toString sb)) (do (.append sb ch) (recur (read-char rdr)))))))) (declare read-tagged) (defn- read-dispatch [^not-native rdr _ opts pending-forms] (if-let [ch (read-char rdr)] (if-let [dm (dispatch-macros ch)] (dm rdr ch opts pending-forms) (read-tagged (doto rdr (unread ch)) ch opts pending-forms)) ;; ctor reader is implemented as a tagged literal (err/throw-eof-at-dispatch rdr))) (defn- read-unmatched-delimiter [rdr ch opts pending-forms] (err/throw-unmatch-delimiter rdr ch)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; readers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn read-regex [^not-native rdr ch opts pending-forms] (let [sb (StringBuffer.)] (loop [ch (read-char rdr)] (if (identical? \" ch) (re-pattern (str sb)) (if (nil? ch) (err/throw-eof-reading rdr :regex sb) (do (.append sb ch ) (when (identical? \\ ch) (let [ch (read-char rdr)] (if (nil? ch) (err/throw-eof-reading rdr :regex sb)) (.append sb ch))) (recur (read-char rdr)))))))) (defn- read-unicode-char ([token offset length base] (let [l (+ offset length)] (when-not (== (count token) l) (err/throw-invalid-unicode-literal nil token)) (loop [i offset uc 0] (if (== i l) (js/String.fromCharCode uc) (let [d (char-code (nth token i) base)] (if (== d -1) (err/throw-invalid-unicode-digit-in-token nil (nth token i) token) (recur (inc i) (+ d (* uc base))))))))) ([^not-native rdr initch base length exact?] (loop [i 1 uc (char-code initch base)] (if (== uc -1) (err/throw-invalid-unicode-digit rdr initch) (if-not (== i length) (let [ch (peek-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (if exact? (err/throw-invalid-unicode-len rdr i length) (js/String.fromCharCode uc)) (let [d (char-code ch base)] (read-char rdr) (if (== d -1) (err/throw-invalid-unicode-digit rdr ch) (recur (inc i) (+ d (* uc base))))))) (js/String.fromCharCode uc)))))) (def ^:private ^:const upper-limit (.charCodeAt \uD7ff 0)) (def ^:private ^:const lower-limit (.charCodeAt \uE000 0)) (defn- valid-octal? [token base] (<= (js/parseInt token base) 0377)) (defn- read-char* "Read in a character literal" [^not-native rdr backslash opts pending-forms] (let [ch (read-char rdr)] (if-not (nil? ch) (let [token (if (or (macro-terminating? ch) (whitespace? ch)) (str ch) (read-token rdr :character ch)) token-len (. token -length)] (cond (== 1 token-len) (.charAt token 0) ;;; no char type - so can't ensure/cache char (= token "newline") \newline (= token "space") \space (= token "tab") \tab (= token "backspace") \backspace (= token "formfeed") \formfeed (= token "return") \return (gstring/startsWith token "u") (let [c (read-unicode-char token 1 4 16) ic (.charCodeAt c 0)] (if (and (> ic upper-limit) (< ic lower-limit)) (err/throw-invalid-character-literal rdr (.toString ic 16)) c)) (gstring/startsWith token "o") (let [len (dec token-len)] (if (> len 3) (err/throw-invalid-octal-len rdr token) (let [offset 1 base 8 uc (read-unicode-char token offset len base)] (if-not (valid-octal? (subs token offset) base) (err/throw-bad-octal-number rdr) uc)))) :else (err/throw-unsupported-character rdr token))) (err/throw-eof-in-character rdr)))) (defn- starting-line-col-info [^not-native rdr] (when (indexing-reader? rdr) [(get-line-number rdr) (int (dec (get-column-number rdr)))])) (defn- ending-line-col-info [^not-native rdr] (when (indexing-reader? rdr) [(get-line-number rdr) (get-column-number rdr)])) (defonce ^:private READ_EOF (js/Object.)) (defonce ^:private READ_FINISHED (js/Object.)) (def ^:dynamic *read-delim* false) (defn- read-delimited-internal [kind delim rdr opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) delim (char delim)] (loop [a (transient [])] (let [form (read* rdr false READ_EOF delim opts pending-forms)] (if (identical? form READ_FINISHED) (persistent! a) (if (identical? form READ_EOF) (err/throw-eof-delimited rdr kind start-line start-column (count a)) (recur (conj! a form)))))))) (defn- read-delimited "Reads and returns a collection ended with delim" [kind delim rdr opts pending-forms] (binding [*read-delim* true] (read-delimited-internal kind delim rdr opts pending-forms))) (defn- read-list "Read in a list, including its location if the reader is an indexing reader" [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) the-list (read-delimited :list \) rdr opts pending-forms) [end-line end-column] (ending-line-col-info rdr)] (with-meta (if (empty? the-list) '() (apply list the-list)) (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-vector "Read in a vector, including its location if the reader is an indexing reader" [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) the-vector (read-delimited :vector \] rdr opts pending-forms) [end-line end-column] (ending-line-col-info rdr)] (with-meta the-vector (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-map "Read in a map, including its location if the reader is an indexing reader" [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) the-map (read-delimited :map \} rdr opts pending-forms) map-count (count the-map) ks (take-nth 2 the-map) key-set (set ks) [end-line end-column] (ending-line-col-info rdr)] (when (odd? map-count) (err/throw-odd-map rdr start-line start-column the-map)) (when-not (= (count key-set) (count ks)) (err/throw-dup-keys rdr :map ks)) (with-meta (if (<= map-count (* 2 (.-HASHMAP-THRESHOLD cljs.core/PersistentArrayMap))) (.fromArray cljs.core/PersistentArrayMap (to-array the-map) true true) (.fromArray cljs.core/PersistentHashMap (to-array the-map) true)) (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-number [^not-native rdr initch] (loop [sb (doto (StringBuffer.) (.append initch)) ch (read-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (let [s (str sb)] (unread rdr ch) (or (match-number s) (err/throw-invalid-number rdr s))) (recur (doto sb (.append ch)) (read-char rdr))))) (defn- escape-char [sb ^not-native rdr] (let [ch (read-char rdr)] (case ch \t "\t" \r "\r" \n "\n" \\ "\\" \" "\"" \b "\b" \f "\f" \u (let [ch (read-char rdr)] (if (== -1 (js/parseInt (int ch) 16)) (err/throw-invalid-unicode-escape rdr ch) (read-unicode-char rdr ch 16 4 true))) (if (numeric? ch) (let [ch (read-unicode-char rdr ch 8 3 false)] (if (> (int ch) 0377) (err/throw-bad-octal-number rdr) ch)) (err/throw-bad-escape-char rdr ch))))) (defn- read-string* [^not-native reader _ opts pending-forms] (loop [sb (StringBuffer.) ch (read-char reader)] (if (nil? ch) (err/throw-eof-reading reader :string \" sb) (case ch \\ (recur (doto sb (.append (escape-char sb reader))) (read-char reader)) \" (str sb) (recur (doto sb (.append ch)) (read-char reader)))))) (defn- loc-info [rdr line column] (when-not (nil? line) (let [file (get-file-name rdr) filem (when-not (nil? file) {:file file}) [end-line end-column] (ending-line-col-info rdr) lcm {:line line :column column :end-line end-line :end-column end-column}] (merge filem lcm)))) (defn- read-symbol [rdr initch] (let [[line column] (starting-line-col-info rdr) token (read-token rdr :symbol initch)] (when-not (nil? token) (case token ;; special symbols "nil" nil "true" true "false" false "/" '/ (let [^not-native p (parse-symbol token)] (if-not (nil? p) (let [^not-native sym (symbol (-nth p 0) (-nth p 1))] (-with-meta sym (loc-info rdr line column))) (err/throw-invalid rdr :symbol token))))))) (def ^:dynamic *alias-map* "Map from ns alias to ns, if non-nil, it will be used to resolve read-time ns aliases. Defaults to nil" nil) (defn- resolve-alias [sym] (get *alias-map* sym)) (defn- resolve-ns [sym] (or (resolve-alias sym) (when-let [ns (find-ns sym)] (symbol (ns-name ns))))) (defn- read-keyword [^not-native reader initch opts pending-forms] (let [ch (read-char reader)] (if-not (whitespace? ch) (let [token (read-token reader :keyword ch) ^not-native s (parse-symbol token)] (if-not (nil? s) (let [ns (-nth s 0) name (-nth s 1)] (if (identical? \: (.charAt token 0)) (if-not (nil? ns) (if-let [ns (resolve-alias (symbol (subs ns 1)))] (keyword (str ns) name) (err/throw-invalid reader :keyword (str \: token))) (if-let [ns *ns*] (keyword (str ns) (subs name 1)) (err/reader-error reader "Invalid token: :" token))) (keyword ns name))) (err/throw-invalid reader :keyword (str \: token)))) (err/throw-single-colon reader)))) (defn- wrapping-reader "Returns a function which wraps a reader in a call to sym" [sym] (fn [rdr _ opts pending-forms] (list sym (read* rdr true nil opts pending-forms)))) (defn- read-meta "Read metadata and return the following object with the metadata applied" [rdr _ opts pending-forms] (log-source rdr (let [[line column] (starting-line-col-info rdr) m (desugar-meta (read* rdr true nil opts pending-forms))] (when-not (map? m) (err/throw-bad-metadata rdr m)) (let [o (read* rdr true nil opts pending-forms)] (if (implements? IMeta o) (let [m (if (and line (seq? o)) (assoc m :line line :column column) m)] (if (implements? IWithMeta o) (with-meta o (merge (meta o) m)) (reset-meta! o m))) (err/throw-bad-metadata-target rdr o)))))) (defn- read-set [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) ;; subtract 1 from start-column so it includes the # in the leading #{ start-column (if start-column (int (dec start-column))) coll (read-delimited :set \} rdr opts pending-forms) the-set (set coll) [end-line end-column] (ending-line-col-info rdr)] (when-not (= (count coll) (count the-set)) (err/reader-error rdr (err/throw-dup-keys rdr :set coll))) (with-meta the-set (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-discard "Read and discard the first object from rdr" [rdr _ opts pending-forms] (doto rdr (read* true nil opts pending-forms))) (defn- read-symbolic-value [rdr _ opts pending-forms] (let [sym (read* rdr true nil opts pending-forms)] (case sym NaN js/Number.NaN -Inf js/Number.NEGATIVE_INFINITY Inf js/Number.POSITIVE_INFINITY (err/reader-error rdr (str "Invalid token: ##" sym))))) (def ^:private RESERVED_FEATURES #{:else :none}) (defn- has-feature? [rdr feature opts] (if (keyword? feature) (or (= :default feature) (contains? (get opts :features) feature)) (err/reader-error rdr "Feature should be a keyword: " feature))) (defn- check-eof-error [form rdr first-line] (when (identical? form READ_EOF) (err/throw-eof-error rdr (and (< first-line 0) first-line)))) (defn- check-reserved-features [rdr form] (when (get RESERVED_FEATURES form) (err/reader-error rdr "Feature name " form " is reserved"))) (defn- check-invalid-read-cond [form rdr first-line] (when (identical? form READ_FINISHED) (if (< first-line 0) (err/reader-error rdr "read-cond requires an even number of forms") (err/reader-error rdr "read-cond starting on line " first-line " requires an even number of forms")))) (defn- read-suppress "Read next form and suppress. Return nil or READ_FINISHED." [first-line rdr opts pending-forms] (binding [*suppress-read* true] (let [form (read* rdr false READ_EOF \) opts pending-forms)] (check-eof-error form rdr first-line) (when (identical? form READ_FINISHED) READ_FINISHED)))) (defonce ^:private NO_MATCH (js/Object.)) (defn- match-feature "Read next feature. If matched, read next form and return. Otherwise, read and skip next form, returning READ_FINISHED or nil." [first-line rdr opts pending-forms] (let [feature (read* rdr false READ_EOF \) opts pending-forms)] (check-eof-error feature rdr first-line) (if (= feature READ_FINISHED) READ_FINISHED (do (check-reserved-features rdr feature) (if (has-feature? rdr feature opts) ;; feature matched, read selected form (doto (read* rdr false READ_EOF \) opts pending-forms) (check-eof-error rdr first-line) (check-invalid-read-cond rdr first-line)) ;; feature not matched, ignore next form (or (read-suppress first-line rdr opts pending-forms) NO_MATCH)))))) (defn- read-cond-delimited [rdr splicing opts pending-forms] (let [first-line (if (indexing-reader? rdr) (get-line-number rdr) -1) result (loop [matched NO_MATCH finished nil] (cond ;; still looking for match, read feature+form (identical? matched NO_MATCH) (let [match (match-feature first-line rdr opts pending-forms)] (if (identical? match READ_FINISHED) READ_FINISHED (recur match nil))) ;; found match, just read and ignore the rest (not (identical? finished READ_FINISHED)) (recur matched (read-suppress first-line rdr opts pending-forms)) :else matched))] (if (identical? result READ_FINISHED) rdr (if splicing (do (if (implements? ISequential result) (do (garray/insertArrayAt pending-forms (to-array result) 0) rdr) (err/reader-error rdr "Spliced form list in read-cond-splicing must implement ISequential"))) result)))) (defn- read-cond [^not-native rdr _ opts pending-forms] (when (not (and opts (#{:allow :preserve} (:read-cond opts)))) (throw (ex-info "Conditional read not allowed" {:type :runtime-exception}))) (if-let [ch (read-char rdr)] (let [splicing (= ch \@) ch (if splicing (read-char rdr) ch)] (when splicing (when-not *read-delim* (err/reader-error rdr "cond-splice not in list"))) (if-let [ch (if (whitespace? ch) (read-past whitespace? rdr) ch)] (if (not= ch \() (throw (ex-info "read-cond body must be a list" {:type :runtime-exception})) (binding [*suppress-read* (or *suppress-read* (= :preserve (:read-cond opts)))] (if *suppress-read* (reader-conditional (read-list rdr ch opts pending-forms) splicing) (read-cond-delimited rdr splicing opts pending-forms)))) (err/throw-eof-in-character rdr))) (err/throw-eof-in-character rdr))) (def ^:private ^:dynamic arg-env nil) (defn- garg "Get a symbol for an anonymous ?argument?" [n] (symbol (str (if (== -1 n) "rest" (str "p" n)) "__" (next-id) "#"))) (defn- read-fn [rdr _ opts pending-forms] (if arg-env (throw (ex-info "Nested #()s are not allowed" {:type :illegal-state}))) (binding [arg-env (sorted-map)] (let [form (read* (doto rdr (unread \()) true nil opts pending-forms) ;; this sets bindings rargs (rseq arg-env) args (if rargs (let [higharg (key (first rargs))] (let [args (loop [i 1 args (transient [])] (if (> i higharg) (persistent! args) (recur (inc i) (conj! args (or (get arg-env i) (garg i)))))) args (if (arg-env -1) (conj args '& (arg-env -1)) args)] args)) [])] (list 'fn* args form)))) (defn- register-arg "Registers an argument to the arg-env" [n] (if arg-env (if-let [ret (arg-env n)] ret (let [g (garg n)] (set! arg-env (assoc arg-env n g)) g)) (throw (ex-info "Arg literal not in #()" {:type :illegal-state})))) ;; should never hit this (declare read-symbol) (defn- read-arg [^not-native rdr pct opts pending-forms] (if (nil? arg-env) (read-symbol rdr pct) (let [ch (peek-char rdr)] (cond (or (whitespace? ch) (macro-terminating? ch) (nil? ch)) (register-arg 1) (= ch \&) (do (read-char rdr) (register-arg -1)) :else (let [n (read* rdr true nil opts pending-forms)] (if-not (integer? n) (throw (ex-info "Arg literal must be %, %& or %integer" {:type :illegal-state})) (register-arg n))))))) (def ^:private ^:dynamic gensym-env nil) (defn- read-unquote [^not-native rdr comma opts pending-forms] (if-let [ch (peek-char rdr)] (if (= \@ ch) ((wrapping-reader 'clojure.core/unquote-splicing) (doto rdr read-char) \@ opts pending-forms) ((wrapping-reader 'clojure.core/unquote) rdr \~ opts pending-forms)))) (declare syntax-quote*) (defn- unquote-splicing? [form] (and (seq? form) (= (first form) 'clojure.core/unquote-splicing))) (defn- unquote? [form] (and (seq? form) (= (first form) 'clojure.core/unquote))) (defn- expand-list "Expand a list by resolving its syntax quotes and unquotes" [s] (loop [s (seq s) r (transient [])] (if s (let [item (first s) ret (conj! r (cond (unquote? item) (list 'clojure.core/list (second item)) (unquote-splicing? item) (second item) :else (list 'clojure.core/list (syntax-quote* item))))] (recur (next s) ret)) (seq (persistent! r))))) (defn- flatten-map "Flatten a map into a seq of alternate keys and values" [form] (loop [s (seq form) key-vals (transient [])] (if s (let [e (first s)] (recur (next s) (-> key-vals (conj! (key e)) (conj! (val e))))) (seq (persistent! key-vals))))) (defn- register-gensym [sym] (if-not gensym-env (throw (ex-info "Gensym literal not in syntax-quote" {:type :illegal-state}))) (or (get gensym-env sym) (let [gs (symbol (str (subs (name sym) 0 (dec (count (name sym)))) "__" (next-id) "__auto__"))] (set! gensym-env (assoc gensym-env sym gs)) gs))) (defn- add-meta [form ret] (if (and (implements? IWithMeta form) (seq (dissoc (meta form) :line :column :end-line :end-column :file :source))) (list 'cljs.core/with-meta ret (syntax-quote* (meta form))) ret)) (defn- syntax-quote-coll [type coll] (let [res (list 'cljs.core/sequence (cons 'cljs.core/concat (expand-list coll)))] (if type (list 'cljs.core/apply type res) res))) (defn map-func "Decide which map type to use, array-map if less than 16 elements" [coll] (if (>= (count coll) 16) 'cljs.core/hash-map 'cljs.core/array-map)) (defn bool? [x] (or (instance? js/Boolean x) (true? x) (false? x))) (defn ^:dynamic resolve-symbol "Resolve a symbol s into its fully qualified namespace version" [s] (throw (ex-info "resolve-symbol is not implemented" {:sym s}))) (defn- syntax-quote* [form] (->> (cond (special-symbol? form) (list 'quote form) (symbol? form) (list 'quote (if (and (not (namespace form)) (gstring/endsWith (name form) "#")) (register-gensym form) (let [sym (str form)] (if (gstring/endsWith sym ".") (let [csym (symbol (subs sym 0 (dec (count sym))))] (symbol (str (resolve-symbol csym) "."))) (resolve-symbol form))))) (unquote? form) (second form) (unquote-splicing? form) (throw (ex-info "unquote-splice not in list" {:type :illegal-state})) (coll? form) (cond (implements? IRecord form) form (map? form) (syntax-quote-coll (map-func form) (flatten-map form)) (vector? form) (list 'cljs.core/vec (syntax-quote-coll nil form)) (set? form) (syntax-quote-coll 'cljs.core/hash-set form) (or (seq? form) (list? form)) (let [seq (seq form)] (if seq (syntax-quote-coll nil seq) '(cljs.core/list))) :else (throw (ex-info "Unknown Collection type" {:type :unsupported-operation}))) (or (keyword? form) (number? form) (string? form) (nil? form) (bool? form) (instance? js/RegExp form)) form :else (list 'quote form)) (add-meta form))) (defn- read-syntax-quote [rdr backquote opts pending-forms] (binding [gensym-env {}] (-> (read* rdr true nil opts pending-forms) syntax-quote*))) (defn- read-namespaced-map [rdr _ opts pending-forms] (let [token (read-token rdr :namespaced-map (read-char rdr))] (if-let [ns (cond (= token ":") (ns-name *ns*) (= \: (first token)) (some-> token (subs 1) parse-symbol second' symbol resolve-ns) :else (some-> token parse-symbol second'))] (let [ch (read-past whitespace? rdr)] (if (identical? ch \{) (let [items (read-delimited :namespaced-map \} rdr opts pending-forms)] (when (odd? (count items)) (err/throw-odd-map rdr nil nil items)) (let [keys (namespace-keys (str ns) (take-nth 2 items)) vals (take-nth 2 (rest items))] (when-not (= (count (set keys)) (count keys)) (err/throw-dup-keys rdr :namespaced-map keys)) (zipmap keys vals))) (err/throw-ns-map-no-map rdr token))) (err/throw-bad-ns rdr token)))) (defn- macros [ch] (case ch \" read-string* \: read-keyword \; read-comment \' (wrapping-reader 'quote) \@ (wrapping-reader 'clojure.core/deref) \^ read-meta \` read-syntax-quote \~ read-unquote \( read-list \) read-unmatched-delimiter \[ read-vector \] read-unmatched-delimiter \{ read-map \} read-unmatched-delimiter \\ read-char* \% read-arg \# read-dispatch nil)) (defn- dispatch-macros [ch] (case ch \^ read-meta ;; deprecated \' (wrapping-reader 'var) \( read-fn \{ read-set \< (throwing-reader "Unreadable form") \= (throwing-reader "read-eval not supported") \" read-regex \! read-comment \_ read-discard \? read-cond \: read-namespaced-map \# read-symbolic-value nil)) (defn- read-tagged [^not-native rdr initch opts pending-forms] (let [tag (read* rdr true nil opts pending-forms)] (if-not (symbol? tag) (err/throw-bad-reader-tag rdr tag)) (if *suppress-read* (tagged-literal tag (read* rdr true nil opts pending-forms)) (if-let [f (or (*data-readers* tag) (default-data-readers tag))] (f (read* rdr true nil opts pending-forms)) (if-let [f *default-data-reader-fn*] (f tag (read* rdr true nil opts pending-forms)) (err/throw-unknown-reader-tag rdr tag)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Public API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (def ^:dynamic *data-readers* "Map from reader tag symbols to data reader Vars. Reader tags without namespace qualifiers are reserved for Clojure. This light version of tools.reader has no implementation for default reader tags such as #inst and #uuid." {}) (def ^:dynamic *default-data-reader-fn* "When no data reader is found for a tag and *default-data-reader-fn* is non-nil, it will be called with two arguments, the tag and the value. If *default-data-reader-fn* is nil (the default value), an exception will be thrown for the unknown tag." nil) (def ^:dynamic *suppress-read* false) (def default-data-readers "Default map of data reader functions provided by Clojure. May be overridden by binding *data-readers*" {}) (defn- read*-internal [^not-native reader ^boolean eof-error? sentinel return-on opts pending-forms] (loop [] (log-source reader (if-not ^boolean (garray/isEmpty pending-forms) (let [form (aget pending-forms 0)] (garray/removeAt pending-forms 0) form) (let [ch (read-char reader)] (cond (whitespace? ch) (recur) (nil? ch) (if eof-error? (err/throw-eof-error reader nil) sentinel) (identical? ch return-on) READ_FINISHED (number-literal? reader ch) (read-number reader ch) :else (let [f (macros ch)] (if-not (nil? f) (let [res (f reader ch opts pending-forms)] (if (identical? res reader) (recur) res)) (read-symbol reader ch))))))))) (defn- read* ([reader eof-error? sentinel opts pending-forms] (read* reader eof-error? sentinel nil opts pending-forms)) ([^not-native reader eof-error? sentinel return-on opts pending-forms] (try (read*-internal reader eof-error? sentinel return-on opts pending-forms) (catch js/Error e (if (ex-info? e) (let [d (ex-data e)] (if (= :reader-exception (:type d)) (throw e) (throw (ex-info (.-message e) (merge {:type :reader-exception} d (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e)))) (throw (ex-info (.-message e) (merge {:type :reader-exception} (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e))))))) (defn read "Reads the first object from an IPushbackReader. Returns the object read. If EOF, throws if eof-error? is true. Otherwise returns sentinel. If no stream is provided, *in* will be used. Opts is a persistent map with valid keys: :read-cond - :allow to process reader conditionals, or :preserve to keep all branches :features - persistent set of feature keywords for reader conditionals :eof - on eof, return value unless :eofthrow, then throw. if not specified, will throw To read data structures only, use cljs.tools.reader.edn/read Note that the function signature of cljs.tools.reader/read and cljs.tools.reader.edn/read is not the same for eof-handling" {:arglists '([reader] [opts reader] [reader eof-error? eof-value])} ([reader] (read reader true nil)) ([{eof :eof :as opts :or {eof :eofthrow}} reader] (read* reader (= eof :eofthrow) eof nil opts (to-array []))) ([reader eof-error? sentinel] (read* reader eof-error? sentinel nil {} (to-array [])))) (defn read-string "Reads one object from the string s. Returns nil when s is nil or empty. To read data structures only, use cljs.tools.reader.edn/read-string Note that the function signature of cljs.tools.reader/read-string and cljs.tools.reader.edn/read-string is not the same for eof-handling" ([s] (read-string {} s)) ([opts s] (when (and s (not (identical? s ""))) (read opts (string-push-back-reader s))))) (defn read+string "Like read, and taking the same args. reader must be a SourceLoggingPushbackReader. Returns a vector containing the object read and the (whitespace-trimmed) string read." ([stream] (read+string stream true nil)) ([stream eof-error? eof-value] (let [buf (fn [stream] (str (:buffer @(.-frames stream)))) offset (count (buf stream)) o (log-source stream (read stream eof-error? eof-value)) s (.trim (subs (buf stream) offset))] [o s])) ([opts stream] (let [buf (fn [stream] (str (:buffer @(.-frames stream)))) offset (count (buf stream)) o (log-source stream (read opts stream)) s (.trim (subs (buf stream) offset))] [o s]))) tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/000077500000000000000000000000001375401310700245235ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/edn.cljs000066400000000000000000000357551375401310700261650ustar00rootroot00000000000000;; 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 ^{:doc "An EDN reader in clojure" :author "Bronsa"} cljs.tools.reader.edn (:refer-clojure :exclude [read read-string char default-data-readers]) (:require [cljs.tools.reader.impl.errors :as err] [cljs.tools.reader.reader-types :refer [read-char unread peek-char indexing-reader? get-line-number get-column-number get-file-name string-push-back-reader]] [cljs.tools.reader.impl.utils :refer [char ex-info? whitespace? numeric? desugar-meta namespace-keys second' char-code]] [cljs.tools.reader.impl.commons :refer [number-literal? read-past match-number parse-symbol read-comment throwing-reader]] [cljs.tools.reader :refer [default-data-readers]] [goog.string :as gstring]) (:import goog.string.StringBuffer)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (declare read macros dispatch-macros) (defn- ^boolean macro-terminating? [ch] (and (not (identical? \# ch)) (not (identical? \' ch)) (not (identical? \: ch)) (macros ch))) (defn- ^boolean not-constituent? [ch] (or (identical? \@ ch) (identical? \` ch) (identical? \~ ch))) (defn- read-token ([rdr kind initch] (read-token rdr kind initch true)) ([rdr kind initch validate-leading?] (cond (not initch) (err/throw-eof-at-start rdr kind) (and validate-leading? (not-constituent? initch)) (err/throw-bad-char rdr kind initch) :else (loop [sb (StringBuffer.) ch (do (unread rdr initch) initch)] (if (or (whitespace? ch) (macro-terminating? ch) (nil? ch)) (str sb) (if (not-constituent? ch) (err/throw-bad-char rdr kind ch) (recur (doto sb (.append (read-char rdr))) (peek-char rdr)))))))) (declare read-tagged) (defn- read-dispatch [rdr _ opts] (if-let [ch (read-char rdr)] (if-let [dm (dispatch-macros ch)] (dm rdr ch opts) (read-tagged (doto rdr (unread ch)) ch opts)) (err/throw-eof-at-dispatch rdr))) (defn- read-unmatched-delimiter [rdr ch opts] (err/throw-unmatch-delimiter rdr ch)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; readers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn- read-unicode-char ([token offset length base] (let [l (+ offset length)] (when-not (== (count token) l) (err/throw-invalid-unicode-literal nil token)) (loop [i offset uc 0] (if (== i l) (js/String.fromCharCode uc) (let [d (char-code (nth token i) base)] (if (== d -1) (err/throw-invalid-unicode-digit-in-token nil (nth token i) token) (recur (inc i) (+ d (* uc base))))))))) ([rdr initch base length exact?] (loop [i 1 uc (char-code initch base)] (if (== uc -1) (err/throw-invalid-unicode-digit rdr initch) (if-not (== i length) (let [ch (peek-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (if exact? (err/throw-invalid-unicode-len rdr i length) (js/String.fromCharCode uc)) (let [d (char-code ch base)] (read-char rdr) (if (== d -1) (err/throw-invalid-unicode-digit rdr ch) (recur (inc i) (+ d (* uc base))))))) (js/String.fromCharCode uc)))))) (def ^:private ^:const upper-limit (.charCodeAt \uD7ff 0)) (def ^:private ^:const lower-limit (.charCodeAt \uE000 0)) (defn- read-char* [rdr backslash opts] (let [ch (read-char rdr)] (if-not (nil? ch) (let [token (if (or (macro-terminating? ch) (not-constituent? ch) (whitespace? ch)) (str ch) (read-token rdr :character ch false)) token-len (count token)] (cond (== 1 token-len) (nth token 0) (identical? token "newline") \newline (identical? token "space") \space (identical? token "tab") \tab (identical? token "backspace") \backspace (identical? token "formfeed") \formfeed (identical? token "return") \return (gstring/startsWith token "u") (let [c (read-unicode-char token 1 4 16) ic (.charCodeAt c)] (if (and (> ic upper-limit) (< ic lower-limit)) (err/throw-invalid-character-literal rdr (.toString ic 16)) c)) (gstring/startsWith token "o") (let [len (dec token-len)] (if (> len 3) (err/throw-invalid-octal-len rdr token) (let [uc (read-unicode-char token 1 len 8)] (if (> (int uc) 0377) (err/throw-bad-octal-number rdr) uc)))) :else (err/throw-unsupported-character rdr token))) (err/throw-eof-in-character rdr)))) (defn ^:private starting-line-col-info [rdr] (when (indexing-reader? rdr) [(get-line-number rdr) (int (dec (int (get-column-number rdr))))])) (defn- read-delimited [kind delim rdr opts] (let [[start-line start-column] (starting-line-col-info rdr) delim (char delim)] (loop [a (transient [])] (let [ch (read-past whitespace? rdr)] (when-not ch (err/throw-eof-delimited rdr kind start-line start-column (count a))) (if (= delim (char ch)) (persistent! a) (if-let [macrofn (macros ch)] (let [mret (macrofn rdr ch opts)] (recur (if-not (identical? mret rdr) (conj! a mret) a))) (let [o (read (doto rdr (unread ch)) true nil opts)] (recur (if-not (identical? o rdr) (conj! a o) a))))))))) (defn- read-list [rdr _ opts] (let [the-list (read-delimited :list \) rdr opts)] (if (empty? the-list) '() (apply list the-list)))) (defn- read-vector [rdr _ opts] (read-delimited :vector \] rdr opts)) (defn- read-map [rdr _ opts] (let [[start-line start-column] (starting-line-col-info rdr) the-map (read-delimited :map \} rdr opts) map-count (count the-map) ks (take-nth 2 the-map) key-set (set ks)] (when (odd? map-count) (err/throw-odd-map rdr start-line start-column the-map)) (when-not (= (count key-set) (count ks)) (err/throw-dup-keys rdr :map ks)) (if (<= map-count (* 2 (.-HASHMAP-THRESHOLD cljs.core/PersistentArrayMap))) (.fromArray cljs.core/PersistentArrayMap (to-array the-map) true true) (.fromArray cljs.core/PersistentHashMap (to-array the-map) true)))) (defn- read-number [rdr initch opts] (loop [sb (doto (StringBuffer.) (.append initch)) ch (read-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (let [s (str sb)] (unread rdr ch) (or (match-number s) (err/throw-invalid-number rdr s))) (recur (doto sb (.append ch)) (read-char rdr))))) (defn- escape-char [sb rdr] (let [ch (read-char rdr)] (case ch \t "\t" \r "\r" \n "\n" \\ "\\" \" "\"" \b "\b" \f "\f" \u (let [ch (read-char rdr)] (if (== -1 (js/parseInt (int ch) 16)) (err/throw-invalid-unicode-escape rdr ch) (read-unicode-char rdr ch 16 4 true))) (if (numeric? ch) (let [ch (read-unicode-char rdr ch 8 3 false)] (if (> (int ch) 0377) (err/throw-bad-octal-number rdr) ch)) (err/throw-bad-escape-char rdr ch))))) (defn- read-string* [rdr _ opts] (loop [sb (StringBuffer.) ch (read-char rdr)] (case ch nil (err/throw-eof-reading rdr :string \" sb) \\ (recur (doto sb (.append (escape-char sb rdr))) (read-char rdr)) \" (str sb) (recur (doto sb (.append ch)) (read-char rdr))))) (defn- read-symbol [rdr initch] (when-let [token (read-token rdr :symbol initch)] (case token ;; special symbols "nil" nil "true" true "false" false "/" '/ (or (when-let [p (parse-symbol token)] (symbol (p 0) (p 1))) (err/throw-invalid rdr :symbol token))))) (defn- read-keyword [reader initch opts] (let [ch (read-char reader)] (if-not (whitespace? ch) (let [token (read-token reader :keyword ch) s (parse-symbol token)] (if (and s (== -1 (.indexOf token "::"))) (let [ns (s 0) name (s 1)] (if (identical? \: (nth token 0)) (err/throw-invalid reader :keyword token) ;; no ::keyword in edn (keyword ns name))) (err/throw-invalid reader :keyword token))) (err/throw-single-colon reader)))) (defn- wrapping-reader [sym] (fn [rdr _ opts] (list sym (read rdr true nil opts)))) (defn- read-meta [rdr _ opts] (let [m (desugar-meta (read rdr true nil opts))] (when-not (map? m) (err/throw-bad-metadata rdr m)) (let [o (read rdr true nil opts)] (if (implements? IMeta o) (with-meta o (merge (meta o) m)) (err/throw-bad-metadata-target rdr o))))) (defn- read-set [rdr _ opts] (let [coll (read-delimited :set \} rdr opts) the-set (set coll)] (when-not (= (count coll) (count the-set)) (err/throw-dup-keys rdr :set coll)) the-set)) (defn- read-discard [rdr _ opts] (doto rdr (read true nil true))) (defn- read-namespaced-map [rdr _ opts] (let [token (read-token rdr :namespaced-map (read-char rdr))] (if-let [ns (some-> token parse-symbol second')] (let [ch (read-past whitespace? rdr)] (if (identical? ch \{) (let [items (read-delimited :namespaced-map \} rdr opts)] (when (odd? (count items)) (err/throw-odd-map rdr nil nil items)) (let [keys (namespace-keys (str ns) (take-nth 2 items)) vals (take-nth 2 (rest items))] (when-not (= (count (set keys)) (count keys)) (err/throw-dup-keys rdr :namespaced-map keys)) (zipmap keys vals))) (err/throw-ns-map-no-map rdr token))) (err/throw-bad-ns rdr token)))) (defn- read-symbolic-value [rdr _ opts] (let [sym (read rdr true nil opts)] (case sym NaN js/Number.NaN -Inf js/Number.NEGATIVE_INFINITY Inf js/Number.POSITIVE_INFINITY (err/reader-error rdr (str "Invalid token: ##" sym))))) (defn- macros [ch] (case ch \" read-string* \: read-keyword \; read-comment \^ read-meta \( read-list \) read-unmatched-delimiter \[ read-vector \] read-unmatched-delimiter \{ read-map \} read-unmatched-delimiter \\ read-char* \# read-dispatch nil)) (defn- dispatch-macros [ch] (case ch \^ read-meta ;deprecated \{ read-set \< (throwing-reader "Unreadable form") \! read-comment \_ read-discard \: read-namespaced-map \# read-symbolic-value nil)) (defn- read-tagged [rdr initch opts] (let [tag (read rdr true nil opts) object (read rdr true nil opts)] (if-not (symbol? tag) (err/throw-bad-reader-tag rdr "Reader tag must be a symbol")) (if-let [f (or (get (:readers opts) tag) (default-data-readers tag))] (f object) (if-let [d (:default opts)] (d tag object) (err/throw-unknown-reader-tag rdr tag))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Public API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn read "Reads the first object from an IPushbackReader. Returns the object read. If EOF, throws if eof-error? is true otherwise returns eof. If no reader is provided, *in* will be used. Reads data in the edn format (subset of Clojure data): http://edn-format.org cljs.tools.reader.edn/read doesn't depend on dynamic Vars, all configuration is done by passing an opt map. opts is a map that can include the following keys: :eof - value to return on end-of-file. When not supplied, eof throws an exception. :readers - a map of tag symbols to data-reader functions to be considered before default-data-readers. When not supplied, only the default-data-readers will be used. :default - A function of two args, that will, if present and no reader is found for a tag, be called with the tag and the value." ([reader] (read {} reader)) ([{:keys [eof] :as opts} reader] (let [eof-error? (not (contains? opts :eof))] (read reader eof-error? eof opts))) ([reader eof-error? eof opts] (try (loop [] (let [ch (read-char reader)] (cond (whitespace? ch) (recur) (nil? ch) (if eof-error? (err/throw-eof-error reader nil) eof) (number-literal? reader ch) (read-number reader ch opts) :else (let [f (macros ch)] (if f (let [res (f reader ch opts)] (if (identical? res reader) (recur) res)) (read-symbol reader ch)))))) (catch js/Error e (if (ex-info? e) (let [d (ex-data e)] (if (= :reader-exception (:type d)) (throw e) (throw (ex-info (.-message e) (merge {:type :reader-exception} d (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e)))) (throw (ex-info (.-message e) (merge {:type :reader-exception} (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e))))))) (defn read-string "Reads one object from the string s. Returns nil when s is nil or empty. Reads data in the edn format (subset of Clojure data): http://edn-format.org opts is a map as per cljs.tools.reader.edn/read" ([s] (read-string {:eof nil} s)) ([opts s] (when (and s (not= s "")) (read opts (string-push-back-reader s))))) tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/impl/000077500000000000000000000000001375401310700254645ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/impl/commons.cljs000066400000000000000000000105231375401310700300150ustar00rootroot00000000000000;; 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 cljs.tools.reader.impl.commons (:refer-clojure :exclude [char]) (:require [cljs.tools.reader.impl.errors :refer [reader-error]] [cljs.tools.reader.reader-types :refer [peek-char read-char]] [cljs.tools.reader.impl.utils :refer [numeric? newline? char]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn ^boolean number-literal? "Checks whether the reader is at the start of a number literal" [^not-native reader initch] (or (numeric? initch) (and (or (identical? \+ initch) (identical? \- initch)) (numeric? (peek-char reader))))) (defn read-past "Read until first character that doesn't match pred, returning char." [pred ^not-native rdr] (loop [ch (read-char rdr)] (if ^boolean (pred ch) (recur (read-char rdr)) ch))) (defn skip-line "Advances the reader to the end of a line. Returns the reader" [^not-native reader] (loop [] (when-not (newline? (read-char reader)) (recur))) reader) (def int-pattern #"^([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)(N)?$") (def ratio-pattern #"([-+]?[0-9]+)/([0-9]+)") (def float-pattern #"([-+]?[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?") (defn- match-int [s] (let [m (vec (re-find int-pattern s))] (if-not (nil? (m 2)) 0 (let [^boolean negate? (identical? "-" (m 1)) a (cond (not (nil? (m 3))) [(m 3) 10] (not (nil? (m 4))) [(m 4) 16] (not (nil? (m 5))) [(m 5) 8] (not (nil? (m 7))) [(m 7) (js/parseInt (m 6))] :else [nil nil]) n (a 0)] (when-not (nil? n) (let [bn (js/parseInt n (a 1)) bn (if negate? (* -1 bn) bn)] (when-not (js/isNaN bn) bn))))))) (defn- match-ratio [s] (let [m (vec (re-find ratio-pattern s)) numerator (m 1) denominator (m 2) numerator (if (re-find #"^\+" numerator) (subs numerator 1) numerator)] (/ (-> numerator js/parseInt) ;;; No ratio type in cljs (-> denominator js/parseInt)))); So will convert to js/Number (defn- match-float [s] (let [m (vec (re-find float-pattern s))] (if-not (nil? (m 4)) ;; for BigDecimal "10.03M", as all parsed to js/Number (js/parseFloat (m 1)) (js/parseFloat s)))) (defn ^boolean matches? [pattern s] (let [[match] (re-find pattern s)] (identical? match s))) (defn match-number [s] (if (matches? int-pattern s) (match-int s) (if (matches? float-pattern s) (match-float s) (when (matches? ratio-pattern s) (match-ratio s))))) (defn parse-symbol "Parses a string into a vector of the namespace and symbol" [token] (when-not (or (identical? "" token) (true? (.test #":$" token)) (true? (.test #"^::" token))) (let [ns-idx (.indexOf token "/") ns (when (pos? ns-idx) (subs token 0 ns-idx))] (if-not (nil? ns) (let [ns-idx (inc ns-idx)] (when-not (== ns-idx (count token)) (let [sym (subs token ns-idx)] (when (and (not (numeric? (nth sym 0))) (not (identical? "" sym)) (false? (.test #":$" ns)) (or (identical? sym "/") (== -1 (.indexOf sym "/")))) [ns sym])))) (when (or (identical? token "/") (== -1 (.indexOf token "/"))) [nil token]))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; readers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn read-comment [rdr & _] (skip-line rdr)) (defn throwing-reader [msg] (fn [rdr & _] (reader-error rdr msg))) tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/impl/errors.cljs000066400000000000000000000154161375401310700276640ustar00rootroot00000000000000;; Copyright (c) Russ Olsen, 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 cljs.tools.reader.impl.errors (:require [cljs.tools.reader.reader-types :as types] [clojure.string :as s] [cljs.tools.reader.impl.inspect :as i])) (defn- ex-details [rdr ex-type] (let [details {:type :reader-exception :ex-kind ex-type}] (if (types/indexing-reader? rdr) (assoc details :file (types/get-file-name rdr) :line (types/get-line-number rdr) :col (types/get-column-number rdr)) details))) (defn- throw-ex "Throw an ex-info error." [rdr ex-type & msg] (let [details (ex-details rdr ex-type) file (:file details) line (:line details) col (:col details) msg1 (if file (str file " ")) msg2 (if line (str "[line " line ", col " col "]")) msg3 (if (or msg1 msg2) " ") full-msg (apply str msg1 msg2 msg3 msg)] (throw (ex-info full-msg details)))) (defn reader-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :reader-error (apply str msgs))) (defn illegal-arg-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :illegal-argument (apply str msgs))) (defn eof-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :eof (apply str msgs))) (defn throw-eof-delimited ([rdr kind column line] (throw-eof-delimited rdr kind line column nil)) ([rdr kind line column n] (eof-error rdr "Unexpected EOF while reading " (if n (str "item " n " of ")) (name kind) (if line (str ", starting at line " line " and column " column)) "."))) (defn throw-odd-map [rdr line col elements] (reader-error rdr "The map literal starting with " (i/inspect (first elements)) (if line (str " on line " line " column " col)) " contains " (count elements) " form(s). Map literals must contain an even number of forms.")) (defn throw-invalid-number [rdr token] (reader-error rdr "Invalid number: " token ".")) (defn throw-invalid-unicode-literal [rdr token] (throw (illegal-arg-error rdr "Invalid unicode literal: \\" token "."))) (defn throw-invalid-unicode-escape [rdr ch] (reader-error rdr "Invalid unicode escape: \\u" ch ".")) (defn throw-invalid [rdr kind token] (reader-error rdr "Invalid " (name kind) ": " token ".")) (defn throw-eof-at-start [rdr kind] (eof-error rdr "Unexpected EOF while reading start of " (name kind) ".")) (defn throw-bad-char [rdr kind ch] (reader-error rdr "Invalid character: " ch " found while reading " (name kind) ".")) (defn throw-eof-at-dispatch [rdr] (eof-error rdr "Unexpected EOF while reading dispatch character.")) (defn throw-unmatch-delimiter [rdr ch] (reader-error rdr "Unmatched delimiter " ch ".")) (defn throw-eof-reading [rdr kind & start] (let [init (case kind :regex "#\"" :string \")] (eof-error rdr "Unexpected EOF reading " (name kind) " starting " (apply str init start) "."))) (defn throw-invalid-unicode-char[rdr token] (reader-error rdr "Invalid unicode character \\" token ".")) (defn throw-invalid-unicode-digit-in-token[rdr ch token] (illegal-arg-error rdr "Invalid digit " ch " in unicode character \\" token ".")) (defn throw-invalid-unicode-digit[rdr ch] (illegal-arg-error rdr "Invalid digit " ch " in unicode character.")) (defn throw-invalid-unicode-len[rdr actual expected] (illegal-arg-error rdr "Invalid unicode literal. Unicode literals should be " expected "characters long. " "value suppled is " actual "characters long.")) (defn throw-invalid-character-literal[rdr token] (reader-error rdr "Invalid character literal \\u" token ".")) (defn throw-invalid-octal-len[rdr token] (reader-error rdr "Invalid octal escape sequence in a character literal:" token ". Octal escape sequences must be 3 or fewer digits.")) (defn throw-bad-octal-number [rdr] (reader-error rdr "Octal escape sequence must be in range [0, 377].")) (defn throw-unsupported-character[rdr token] (reader-error rdr "Unsupported character: " token ".")) (defn throw-eof-in-character [rdr] (eof-error rdr "Unexpected EOF while reading character.")) (defn throw-bad-escape-char [rdr ch] (reader-error rdr "Unsupported escape character: \\" ch ".")) (defn throw-single-colon [rdr] (reader-error rdr "A single colon is not a valid keyword.")) (defn throw-bad-metadata [rdr x] (reader-error rdr "Metadata cannot be " (i/inspect x) ". Metadata must be a Symbol, Keyword, String or Map.")) (defn throw-bad-metadata-target [rdr target] (reader-error rdr "Metadata can not be applied to " (i/inspect target) ". " "Metadata can only be applied to IMetas.")) (defn throw-feature-not-keyword [rdr feature] (reader-error rdr "Feature cannot be " (i/inspect feature) " Features must be keywords.")) (defn throw-ns-map-no-map [rdr ns-name] (reader-error rdr "Namespaced map with namespace " ns-name " does not specify a map.")) (defn throw-bad-ns [rdr ns-name] (reader-error rdr "Invalid value used as namespace in namespaced map: " ns-name ".")) (defn throw-bad-reader-tag [rdr tag] (reader-error rdr "Invalid reader tag: " (i/inspect tag) ". Reader tags must be symbols.")) (defn throw-unknown-reader-tag [rdr tag] (reader-error rdr "No reader function for tag " (i/inspect tag) ".")) (defn- duplicate-keys-error [msg coll] (letfn [(duplicates [seq] (for [[id freq] (frequencies seq) :when (> freq 1)] id))] (let [dups (duplicates coll)] (apply str msg (when (> (count dups) 1) "s") ": " (interpose ", " dups))))) (defn throw-dup-keys [rdr kind ks] (reader-error rdr (duplicate-keys-error (str (s/capitalize (name kind)) " literal contains duplicate key") ks))) (defn throw-eof-error [rdr line] (if line (eof-error rdr "EOF while reading, starting at line " line ".") (eof-error rdr "EOF while reading."))) tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/impl/inspect.cljs000066400000000000000000000052431375401310700300120ustar00rootroot00000000000000;; Copyright (c) Russ Olsen, 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 cljs.tools.reader.impl.inspect) (declare inspect*) (defn- inspect*-col [truncate col start end] (let [n (count col) l (if truncate 0 (min 10 n)) elements (map (partial inspect* true) (take l col)) content (apply str (interpose " " elements)) suffix (if (< l n) "...")] (str start content suffix end))) (defn- dispatch-inspect [_ x] (cond (nil? x) :nil (string? x) :string (keyword? x) :strable (number? x) :strable (symbol? x) :strable (vector? x) :vector (list? x) :list (map? x) :map (set? x) :set (= x true) :strable (= x false) :strable :default (type x))) (defmulti inspect* dispatch-inspect) (defmethod inspect* :string [truncate ^String x] (let [n (if truncate 5 20) suffix (if (> (.-length x) n) "...\"" "\"")] (str \" (.substring ^String x 0 (min n (.-length x))) suffix))) (defmethod inspect* :strable [truncate x] (str x)) (defmethod inspect* cljs.core/IndexedSeq [truncate x] "") (defmethod inspect* cljs.core/PersistentArrayMapSeq [truncate x] "") (defmethod inspect* cljs.core/NodeSeq [truncate x] "") (defmethod inspect* cljs.core/Cons [truncate x] "") (defmethod inspect* cljs.core/LazySeq [truncate x] "") (defmethod inspect* :nil [_ _] "nil") (defmethod inspect* :list [truncate col] (inspect*-col truncate col \( \))) (defmethod inspect* :map [truncate m] (let [len (count m) n-shown (if truncate 0 len) contents (apply concat (take n-shown m)) suffix (if (> len n-shown) "...}" \})] (inspect*-col truncate contents \{ suffix))) (defmethod inspect* :set [truncate col] (inspect*-col truncate col "#{" \})) (defmethod inspect* :vector [truncate col] (inspect*-col truncate col \[ \])) (defmethod inspect* :default [truncate x] (pr-str (type x))) (defn inspect "Return a string description of the value supplied. May be the a string version of the value itself (e.g. \"true\") or it may be a description (e.g. \"an instance of Foo\"). If truncate is true then return a very terse version of the inspection." ([x] (inspect* false x)) ([truncate x] (inspect* truncate x))) tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/impl/utils.cljs000066400000000000000000000051351375401310700275050ustar00rootroot00000000000000;; 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 cljs.tools.reader.impl.utils (:refer-clojure :exclude [char]) (:require [clojure.string :as string] [goog.string :as gstring])) (defn char [x] (when-not (nil? x) (cljs.core/char x))) (defn ^boolean ex-info? [ex] (instance? cljs.core.ExceptionInfo ex)) (defrecord ReaderConditional [splicing? form]) (defn ^boolean reader-conditional? "Return true if the value is the data representation of a reader conditional" [value] (instance? ReaderConditional value)) (defn reader-conditional "Construct a data representation of a reader conditional. If true, splicing? indicates read-cond-splicing." [form splicing?] (ReaderConditional. splicing? form)) (extend-protocol IPrintWithWriter ReaderConditional (-pr-writer [coll writer opts] (-write writer (str "#?" (when (:splicing? coll) "@"))) (pr-writer (:form coll) writer opts))) (def ws-rx #"[\s]") (defn ^boolean whitespace? "Checks whether a given character is whitespace" [ch] (when-not (nil? ch) (if (identical? ch \,) true (.test ws-rx ch)))) (defn ^boolean numeric? "Checks whether a given character is numeric" [ch] (when-not (nil? ch) (gstring/isNumeric ch))) (defn ^boolean newline? "Checks whether the character is a newline" [c] (or (identical? \newline c) (identical? "\n" c) (nil? c))) (defn desugar-meta "Resolves syntactical sugar in metadata" ;; could be combined with some other desugar? [f] (cond (keyword? f) {f true} (symbol? f) {:tag f} (string? f) {:tag f} :else f)) (def last-id (atom 0)) (defn next-id [] (swap! last-id inc)) (defn namespace-keys [ns keys] (for [key keys] (if (or (symbol? key) (keyword? key)) (let [[key-ns key-name] ((juxt namespace name) key) ->key (if (symbol? key) symbol keyword)] (cond (nil? key-ns) (->key ns key-name) (= "_" key-ns) (->key key-name) :else key)) key))) (defn second' [[a b]] (when-not a b)) (defn char-code [ch base] (let [code (js/parseInt ch base)] (if (js/isNaN code) -1 code))) tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/reader_types.clj000066400000000000000000000006321375401310700277040ustar00rootroot00000000000000(ns cljs.tools.reader.reader-types) (defmacro log-source "If reader is a SourceLoggingPushbackReader, execute body in a source logging context. Otherwise, execute body, returning the result." [reader & body] `(if (and (source-logging-reader? ~reader) (not (cljs.tools.reader.impl.utils/whitespace? (peek-char ~reader)))) (log-source* ~reader (^:once fn* [] ~@body)) (do ~@body)))tools.reader-tools.reader-1.3.4/src/main/cljs/cljs/tools/reader/reader_types.cljs000066400000000000000000000212341375401310700300700ustar00rootroot00000000000000;; 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 ^{:doc "Protocols and default Reader types implementation" :author "Bronsa"} cljs.tools.reader.reader-types (:refer-clojure :exclude [char read-line]) (:require [cljs.tools.reader.impl.utils :refer [char whitespace? newline?]] [goog.string]) (:import goog.string.StringBuffer)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; reader protocols ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defprotocol Reader (read-char [reader] "Returns the next char from the Reader, nil if the end of stream has been reached") (peek-char [reader] "Returns the next char from the Reader without removing it from the reader stream")) (defprotocol IPushbackReader (unread [reader ch] "Pushes back a single character on to the stream")) (defprotocol IndexingReader (get-line-number [reader] "Returns the line number of the next character to be read from the stream") (get-column-number [reader] "Returns the column number of the next character to be read from the stream") (get-file-name [reader] "Returns the file name the reader is reading from, or nil")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; reader deftypes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deftype StringReader [s s-len ^:mutable s-pos] Reader (read-char [reader] (when (> s-len s-pos) (let [r (.charAt s s-pos)] (set! s-pos (inc s-pos)) r))) (peek-char [reader] (when (> s-len s-pos) (.charAt s s-pos)))) (deftype NodeReadableReader [readable ^:mutable buf] Reader (read-char [reader] (if buf (let [c (aget buf 0)] (set! buf nil) (char c)) (let [c (str (.read readable 1))] (when c (char c))))) (peek-char [reader] (when-not buf (set! buf (str (.read readable 1)))) (when buf (char (aget buf 0))))) (deftype PushbackReader [^not-native rdr buf buf-len ^:mutable buf-pos] Reader (read-char [reader] (let [c (if (< buf-pos buf-len) (aget buf buf-pos) (read-char rdr))] (when (< buf-pos buf-len) (set! buf-pos (inc buf-pos))) (char c))) (peek-char [reader] (let [c (if (< buf-pos buf-len) (aget buf buf-pos) (peek-char rdr))] (char c))) IPushbackReader (unread [reader ch] (when ch (if (zero? buf-pos) (throw (js/Error. "Pushback buffer is full"))) (set! buf-pos (dec buf-pos)) (aset buf buf-pos ch)))) (defn- normalize-newline [^not-native rdr ch] (if (identical? \return ch) (let [c (peek-char rdr)] (when (or (identical? \formfeed c) (identical? \newline c)) (read-char rdr)) \newline) ch)) (deftype IndexingPushbackReader [^not-native rdr ^:mutable line ^:mutable column ^:mutable line-start? ^:mutable prev ^:mutable prev-column file-name] Reader (read-char [reader] (when-let [ch (read-char rdr)] (let [ch (normalize-newline rdr ch)] (set! prev line-start?) (set! line-start? (newline? ch)) (when line-start? (set! prev-column column) (set! column 0) (set! line (inc line))) (set! column (inc column)) ch))) (peek-char [reader] (peek-char rdr)) IPushbackReader (unread [reader ch] (if line-start? (do (set! line (dec line)) (set! column prev-column)) (set! column (dec column))) (set! line-start? prev) (unread rdr ch)) IndexingReader (get-line-number [reader] (int line)) (get-column-number [reader] (int column)) (get-file-name [reader] file-name)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Source Logging support ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn merge-meta "Returns an object of the same type and value as `obj`, with its metadata merged over `m`." [obj m] (let [orig-meta (meta obj)] (with-meta obj (merge m (dissoc orig-meta :source))))) (defn- peek-source-log "Returns a string containing the contents of the top most source logging frame." [frames] (subs (str (:buffer frames)) (first (:offset frames)))) (defn- log-source-char "Logs `char` to all currently active source logging frames." [frames char] (when-let [buffer (:buffer frames)] (.append buffer char))) (defn- drop-last-logged-char "Removes the last logged character from all currently active source logging frames. Called when pushing a character back." [frames] (when-let [buffer (:buffer frames)] (.set buffer (subs (str buffer) 0 (dec (.getLength buffer)))))) (deftype SourceLoggingPushbackReader [^not-native rdr ^:mutable line ^:mutable column ^:mutable line-start? ^:mutable prev ^:mutable prev-column file-name frames] Reader (read-char [reader] (when-let [ch (read-char rdr)] (let [ch (normalize-newline rdr ch)] (set! prev line-start?) (set! line-start? (newline? ch)) (when line-start? (set! prev-column column) (set! column 0) (set! line (inc line))) (set! column (inc column)) (log-source-char @frames ch) ch))) (peek-char [reader] (peek-char rdr)) IPushbackReader (unread [reader ch] (if line-start? (do (set! line (dec line)) (set! column prev-column)) (set! column (dec column))) (set! line-start? prev) (when ch (drop-last-logged-char @frames)) (unread rdr ch)) IndexingReader (get-line-number [reader] (int line)) (get-column-number [reader] (int column)) (get-file-name [reader] file-name)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Public API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; fast check for provided implementations (defn indexing-reader? "Returns true if the reader satisfies IndexingReader" [rdr] (implements? IndexingReader rdr)) (defn string-reader "Creates a StringReader from a given string" ([s] (StringReader. s (count s) 0))) (defn string-push-back-reader "Creates a PushbackReader from a given string" ([s] (string-push-back-reader s 1)) ([s buf-len] (PushbackReader. (string-reader s) (object-array buf-len) buf-len buf-len))) (defn node-readable-push-back-reader [readable] (PushbackReader. (NodeReadableReader. readable nil) (object-array 1) 1 1)) (defn indexing-push-back-reader "Creates an IndexingPushbackReader from a given string or PushbackReader" ([s-or-rdr] (indexing-push-back-reader s-or-rdr 1)) ([s-or-rdr buf-len] (indexing-push-back-reader s-or-rdr buf-len nil)) ([s-or-rdr buf-len file-name] (IndexingPushbackReader. (if (string? s-or-rdr) (string-push-back-reader s-or-rdr buf-len) s-or-rdr) 1 1 true nil 0 file-name))) (defn source-logging-push-back-reader "Creates a SourceLoggingPushbackReader from a given string or PushbackReader" ([s-or-rdr] (source-logging-push-back-reader s-or-rdr 1)) ([s-or-rdr buf-len] (source-logging-push-back-reader s-or-rdr buf-len nil)) ([s-or-rdr buf-len file-name] (SourceLoggingPushbackReader. (if (string? s-or-rdr) (string-push-back-reader s-or-rdr buf-len) s-or-rdr) 1 1 true nil 0 file-name (atom {:buffer (StringBuffer.) :offset '(0)})))) (defn read-line "Reads a line from the reader or from *in* if no reader is specified" ([^not-native rdr] (loop [c (read-char rdr) s (StringBuffer.)] (if (newline? c) (str s) (recur (read-char rdr) (.append s c)))))) (defn ^boolean source-logging-reader? [rdr] (instance? SourceLoggingPushbackReader rdr)) (defn ^boolean line-start? "Returns true if rdr is an IndexingReader and the current char starts a new line" [^not-native rdr] (when (indexing-reader? rdr) (== 1 (get-column-number rdr)))) (defn log-source* [reader f] (let [buffer (:buffer @(.-frames reader))] (try (swap! (.-frames reader) update-in [:offset] conj (.getLength buffer)) (let [ret (f)] (if (implements? IMeta ret) (merge-meta ret {:source (peek-source-log @ (.-frames reader))}) ret)) (finally (swap! (.-frames reader) update-in [:offset] rest))))) tools.reader-tools.reader-1.3.4/src/main/clojure/000077500000000000000000000000001375401310700216765ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/000077500000000000000000000000001375401310700233415ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/000077500000000000000000000000001375401310700245015ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader.clj000066400000000000000000001105411375401310700264370ustar00rootroot00000000000000;; 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 ^{:doc "A clojure reader in clojure" :author "Bronsa"} clojure.tools.reader (:refer-clojure :exclude [read read-line read-string char read+string default-data-readers *default-data-reader-fn* *read-eval* *data-readers* *suppress-read*]) (:require [clojure.tools.reader.reader-types :refer [read-char unread peek-char indexing-reader? source-logging-push-back-reader source-logging-reader? get-line-number get-column-number get-file-name string-push-back-reader log-source]] [clojure.tools.reader.impl.utils :refer :all] ;; [char ex-info? whitespace? numeric? desugar-meta] [clojure.tools.reader.impl.errors :as err] [clojure.tools.reader.impl.commons :refer :all] [clojure.tools.reader.default-data-readers :as data-readers]) (:import (clojure.lang PersistentHashSet IMeta RT Symbol Reflector Var IObj PersistentVector IRecord Namespace) clojure.tools.reader.reader_types.SourceLoggingPushbackReader java.lang.reflect.Constructor java.util.regex.Pattern (java.util List LinkedList))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (declare ^:private read* macros dispatch-macros ^:dynamic *read-eval* ^:dynamic *data-readers* ^:dynamic *default-data-reader-fn* ^:dynamic *suppress-read* default-data-readers) (defn ^:private ns-name* [x] (if (instance? Namespace x) (name (ns-name x)) (name x))) (defn- macro-terminating? [ch] (case ch (\" \; \@ \^ \` \~ \( \) \[ \] \{ \} \\) true false)) (defn- ^String read-token "Read in a single logical token from the reader" [rdr kind initch] (if-not initch (err/throw-eof-at-start rdr kind) (loop [sb (StringBuilder.) ch initch] (if (or (whitespace? ch) (macro-terminating? ch) (nil? ch)) (do (when ch (unread rdr ch)) (str sb)) (recur (.append sb ch) (read-char rdr)))))) (declare read-tagged) (defn- read-dispatch [rdr _ opts pending-forms] (if-let [ch (read-char rdr)] (if-let [dm (dispatch-macros ch)] (dm rdr ch opts pending-forms) (read-tagged (doto rdr (unread ch)) ch opts pending-forms)) ;; ctor reader is implemented as a taggedx literal (err/throw-eof-at-dispatch rdr))) (defn- read-unmatched-delimiter [rdr ch opts pending-forms] (err/throw-unmatch-delimiter rdr ch)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; readers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn read-regex [rdr ch opts pending-forms] (let [sb (StringBuilder.)] (loop [ch (read-char rdr)] (if (identical? \" ch) (Pattern/compile (str sb)) (if (nil? ch) (err/throw-eof-reading rdr :regex sb) (do (.append sb ch ) (when (identical? \\ ch) (let [ch (read-char rdr)] (if (nil? ch) (err/throw-eof-reading rdr :regex sb)) (.append sb ch))) (recur (read-char rdr)))))))) (defn- read-unicode-char ([^String token ^long offset ^long length ^long base] (let [l (+ offset length)] (when-not (== (count token) l) (err/throw-invalid-unicode-literal nil token)) (loop [i offset uc 0] (if (== i l) (char uc) (let [d (Character/digit (int (nth token i)) (int base))] (if (== d -1) (err/throw-invalid-unicode-digit-in-token nil (nth token i) token) (recur (inc i) (long (+ d (* uc base)))))))))) ([rdr initch base length exact?] (let [base (long base) length (long length)] (loop [i 1 uc (long (Character/digit (int initch) (int base)))] (if (== uc -1) (err/throw-invalid-unicode-digit rdr initch) (if-not (== i length) (let [ch (peek-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (if exact? (err/throw-invalid-unicode-len rdr i length) (char uc)) (let [d (Character/digit (int ch) (int base))] (read-char rdr) (if (== d -1) (err/throw-invalid-unicode-digit rdr ch) (recur (inc i) (long (+ d (* uc base)))))))) (char uc))))))) (def ^:private ^:const upper-limit (int \uD7ff)) (def ^:private ^:const lower-limit (int \uE000)) (defn- read-char* "Read in a character literal" [rdr backslash opts pending-forms] (let [ch (read-char rdr)] (if-not (nil? ch) (let [token (if (or (macro-terminating? ch) (whitespace? ch)) (str ch) (read-token rdr :character ch)) token-len (count token)] (cond (== 1 token-len) (Character/valueOf (nth token 0)) (= token "newline") \newline (= token "space") \space (= token "tab") \tab (= token "backspace") \backspace (= token "formfeed") \formfeed (= token "return") \return (.startsWith token "u") (let [c (read-unicode-char token 1 4 16) ic (int c)] (if (and (> ic upper-limit) (< ic lower-limit)) (err/throw-invalid-character-literal rdr (Integer/toString ic 16)) c)) (.startsWith token "o") (let [len (dec token-len)] (if (> len 3) (err/throw-invalid-octal-len rdr token) (let [uc (read-unicode-char token 1 len 8)] (if (> (int uc) 0377) (err/throw-bad-octal-number rdr) uc)))) :else (err/throw-unsupported-character rdr token))) (err/throw-eof-in-character rdr)))) (defn ^:private starting-line-col-info [rdr] (when (indexing-reader? rdr) [(get-line-number rdr) (int (dec (int (get-column-number rdr))))])) (defn ^:private ending-line-col-info [rdr] (when (indexing-reader? rdr) [(get-line-number rdr) (get-column-number rdr)])) (defonce ^:private READ_EOF (Object.)) (defonce ^:private READ_FINISHED (Object.)) (def ^:dynamic *read-delim* false) (defn- ^PersistentVector read-delimited "Reads and returns a collection ended with delim" [kind delim rdr opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) delim (char delim)] (binding [*read-delim* true] (loop [a (transient [])] (let [form (read* rdr false READ_EOF delim opts pending-forms)] (if (identical? form READ_FINISHED) (persistent! a) (if (identical? form READ_EOF) (err/throw-eof-delimited rdr kind start-line start-column (count a)) (recur (conj! a form))))))))) (defn- read-list "Read in a list, including its location if the reader is an indexing reader" [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) the-list (read-delimited :list \) rdr opts pending-forms) [end-line end-column] (ending-line-col-info rdr)] (with-meta (if (empty? the-list) '() (clojure.lang.PersistentList/create the-list)) (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-vector "Read in a vector, including its location if the reader is an indexing reader" [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) the-vector (read-delimited :vector \] rdr opts pending-forms) [end-line end-column] (ending-line-col-info rdr)] (with-meta the-vector (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-map "Read in a map, including its location if the reader is an indexing reader" [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) the-map (read-delimited :map \} rdr opts pending-forms) map-count (count the-map) [end-line end-column] (ending-line-col-info rdr)] (when (odd? map-count) (err/throw-odd-map rdr start-line start-column the-map)) (with-meta (if (zero? map-count) {} (RT/map (to-array the-map))) (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-number [rdr initch] (loop [sb (doto (StringBuilder.) (.append initch)) ch (read-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (let [s (str sb)] (unread rdr ch) (or (match-number s) (err/throw-invalid-number rdr s))) (recur (doto sb (.append ch)) (read-char rdr))))) (defn- escape-char [sb rdr] (let [ch (read-char rdr)] (case ch \t "\t" \r "\r" \n "\n" \\ "\\" \" "\"" \b "\b" \f "\f" \u (let [ch (read-char rdr)] (if (== -1 (Character/digit (int ch) 16)) (err/throw-invalid-unicode-escape rdr ch) (read-unicode-char rdr ch 16 4 true))) (if (numeric? ch) (let [ch (read-unicode-char rdr ch 8 3 false)] (if (> (int ch) 0377) (err/throw-bad-octal-number rdr) ch)) (err/throw-bad-escape-char rdr ch))))) (defn- read-string* [reader _ opts pending-forms] (loop [sb (StringBuilder.) ch (read-char reader)] (case ch nil (err/throw-eof-reading reader :string sb) \\ (recur (doto sb (.append (escape-char sb reader))) (read-char reader)) \" (str sb) (recur (doto sb (.append ch)) (read-char reader))))) (defn- read-symbol [rdr initch] (let [[line column] (starting-line-col-info rdr)] (when-let [token (read-token rdr :symbol initch)] (case token ;; special symbols "nil" nil "true" true "false" false "/" '/ (or (when-let [p (parse-symbol token)] (with-meta (symbol (p 0) (p 1)) (when line (merge (when-let [file (get-file-name rdr)] {:file file}) (let [[end-line end-column] (ending-line-col-info rdr)] {:line line :column column :end-line end-line :end-column end-column}))))) (err/throw-invalid rdr :symbol token)))))) (def ^:dynamic *alias-map* "Map from ns alias to ns, if non-nil, it will be used to resolve read-time ns aliases instead of (ns-aliases *ns*). Defaults to nil" nil) (defn- resolve-alias [sym] ((or *alias-map* (ns-aliases *ns*)) sym)) (defn- resolve-ns [sym] (or (resolve-alias sym) (find-ns sym))) (defn- read-keyword [reader initch opts pending-forms] (let [ch (read-char reader)] (if-not (whitespace? ch) (let [token (read-token reader :keyword ch) s (parse-symbol token)] (if s (let [^String ns (s 0) ^String name (s 1)] (if (identical? \: (nth token 0)) (if ns (let [ns (resolve-alias (symbol (subs ns 1)))] (if ns (keyword (str ns) name) (err/throw-invalid reader :keyword (str \: token)))) (keyword (str *ns*) (subs name 1))) (keyword ns name))) (err/throw-invalid reader :keyword (str \: token)))) (err/throw-single-colon reader)))) (defn- wrapping-reader "Returns a function which wraps a reader in a call to sym" [sym] (fn [rdr _ opts pending-forms] (list sym (read* rdr true nil opts pending-forms)))) (defn- read-meta "Read metadata and return the following object with the metadata applied" [rdr _ opts pending-forms] (log-source rdr (let [[line column] (starting-line-col-info rdr) m (desugar-meta (read* rdr true nil opts pending-forms))] (when-not (map? m) (err/throw-bad-metadata rdr m)) (let [o (read* rdr true nil opts pending-forms)] (if (instance? IMeta o) (let [m (if (and line (seq? o)) (assoc m :line line :column column) m)] (if (instance? IObj o) (with-meta o (merge (meta o) m)) (reset-meta! o m))) (err/throw-bad-metadata-target rdr o)))))) (defn- read-set [rdr _ opts pending-forms] (let [[start-line start-column] (starting-line-col-info rdr) ;; subtract 1 from start-column so it includes the # in the leading #{ start-column (if start-column (int (dec (int start-column)))) the-set (PersistentHashSet/createWithCheck (read-delimited :set \} rdr opts pending-forms)) [end-line end-column] (ending-line-col-info rdr)] (with-meta the-set (when start-line (merge (when-let [file (get-file-name rdr)] {:file file}) {:line start-line :column start-column :end-line end-line :end-column end-column}))))) (defn- read-discard "Read and discard the first object from rdr" [rdr _ opts pending-forms] (doto rdr (read* true nil opts pending-forms))) (defn- read-symbolic-value [rdr _ opts pending-forms] (let [sym (read* rdr true nil opts pending-forms)] (case sym Inf Double/POSITIVE_INFINITY -Inf Double/NEGATIVE_INFINITY NaN Double/NaN (err/reader-error rdr (str "Invalid token: ##" sym))))) (def ^:private RESERVED_FEATURES #{:else :none}) (defn- has-feature? [rdr feature opts] (if (keyword? feature) (or (= :default feature) (contains? (get opts :features) feature)) (err/throw-feature-not-keyword rdr feature))) ;; WIP, move to errors in the future (defn- check-eof-error [form rdr ^long first-line] (when (identical? form READ_EOF) (err/throw-eof-error rdr (and (< first-line 0) first-line)))) (defn- check-reserved-features [rdr form] (when (get RESERVED_FEATURES form) (err/reader-error rdr "Feature name " form " is reserved"))) (defn- check-invalid-read-cond [form rdr ^long first-line] (when (identical? form READ_FINISHED) (if (< first-line 0) (err/reader-error rdr "read-cond requires an even number of forms") (err/reader-error rdr "read-cond starting on line " first-line " requires an even number of forms")))) (defn- read-suppress "Read next form and suppress. Return nil or READ_FINISHED." [first-line rdr opts pending-forms] (binding [*suppress-read* true] (let [form (read* rdr false READ_EOF \) opts pending-forms)] (check-eof-error form rdr first-line) (when (identical? form READ_FINISHED) READ_FINISHED)))) (def ^:private NO_MATCH (Object.)) (defn- match-feature "Read next feature. If matched, read next form and return. Otherwise, read and skip next form, returning READ_FINISHED or nil." [first-line rdr opts pending-forms] (let [feature (read* rdr false READ_EOF \) opts pending-forms)] (check-eof-error feature rdr first-line) (if (= feature READ_FINISHED) READ_FINISHED (do (check-reserved-features rdr feature) (if (has-feature? rdr feature opts) ;; feature matched, read selected form (doto (read* rdr false READ_EOF \) opts pending-forms) (check-eof-error rdr first-line) (check-invalid-read-cond rdr first-line)) ;; feature not matched, ignore next form (or (read-suppress first-line rdr opts pending-forms) NO_MATCH)))))) (defn- read-cond-delimited [rdr splicing opts pending-forms] (let [first-line (if (indexing-reader? rdr) (get-line-number rdr) -1) result (loop [matched NO_MATCH finished nil] (cond ;; still looking for match, read feature+form (identical? matched NO_MATCH) (let [match (match-feature first-line rdr opts pending-forms)] (if (identical? match READ_FINISHED) READ_FINISHED (recur match nil))) ;; found match, just read and ignore the rest (not (identical? finished READ_FINISHED)) (recur matched (read-suppress first-line rdr opts pending-forms)) :else matched))] (if (identical? result READ_FINISHED) rdr (if splicing (if (instance? List result) (do (.addAll ^List pending-forms 0 ^List result) rdr) (err/reader-error rdr "Spliced form list in read-cond-splicing must implement java.util.List.")) result)))) (defn- read-cond [rdr _ opts pending-forms] (when (not (and opts (#{:allow :preserve} (:read-cond opts)))) (throw (RuntimeException. "Conditional read not allowed"))) (if-let [ch (read-char rdr)] (let [splicing (= ch \@) ch (if splicing (read-char rdr) ch)] (when splicing (when-not *read-delim* (err/reader-error rdr "cond-splice not in list"))) (if-let [ch (if (whitespace? ch) (read-past whitespace? rdr) ch)] (if (not= ch \() (throw (RuntimeException. "read-cond body must be a list")) (binding [*suppress-read* (or *suppress-read* (= :preserve (:read-cond opts)))] (if *suppress-read* (reader-conditional (read-list rdr ch opts pending-forms) splicing) (read-cond-delimited rdr splicing opts pending-forms)))) (err/throw-eof-in-character rdr))) (err/throw-eof-in-character rdr))) (def ^:private ^:dynamic arg-env) (defn- garg "Get a symbol for an anonymous ?argument?" [^long n] (symbol (str (if (== -1 n) "rest" (str "p" n)) "__" (RT/nextID) "#"))) (defn- read-fn [rdr _ opts pending-forms] (if (thread-bound? #'arg-env) (throw (IllegalStateException. "Nested #()s are not allowed"))) (binding [arg-env (sorted-map)] (let [form (read* (doto rdr (unread \()) true nil opts pending-forms) ;; this sets bindings rargs (rseq arg-env) args (if rargs (let [higharg (long (key ( first rargs)))] (let [args (loop [i 1 args (transient [])] (if (> i higharg) (persistent! args) (recur (inc i) (conj! args (or (get arg-env i) (garg i)))))) args (if (arg-env -1) (conj args '& (arg-env -1)) args)] args)) [])] (list 'fn* args form)))) (defn- register-arg "Registers an argument to the arg-env" [n] (if (thread-bound? #'arg-env) (if-let [ret (arg-env n)] ret (let [g (garg n)] (set! arg-env (assoc arg-env n g)) g)) (throw (IllegalStateException. "Arg literal not in #()")))) ;; should never hit this (declare read-symbol) (defn- read-arg [rdr pct opts pending-forms] (if-not (thread-bound? #'arg-env) (read-symbol rdr pct) (let [ch (peek-char rdr)] (cond (or (whitespace? ch) (macro-terminating? ch) (nil? ch)) (register-arg 1) (identical? ch \&) (do (read-char rdr) (register-arg -1)) :else (let [n (read* rdr true nil opts pending-forms)] (if-not (integer? n) (throw (IllegalStateException. "Arg literal must be %, %& or %integer")) (register-arg n))))))) (defn- read-eval "Evaluate a reader literal" [rdr _ opts pending-forms] (when-not *read-eval* (err/reader-error rdr "#= not allowed when *read-eval* is false")) (eval (read* rdr true nil opts pending-forms))) (def ^:private ^:dynamic gensym-env nil) (defn- read-unquote [rdr comma opts pending-forms] (if-let [ch (peek-char rdr)] (if (identical? \@ ch) ((wrapping-reader 'clojure.core/unquote-splicing) (doto rdr read-char) \@ opts pending-forms) ((wrapping-reader 'clojure.core/unquote) rdr \~ opts pending-forms)))) (declare syntax-quote*) (defn- unquote-splicing? [form] (and (seq? form) (= (first form) 'clojure.core/unquote-splicing))) (defn- unquote? [form] (and (seq? form) (= (first form) 'clojure.core/unquote))) (defn- expand-list "Expand a list by resolving its syntax quotes and unquotes" [s] (loop [s (seq s) r (transient [])] (if s (let [item (first s) ret (conj! r (cond (unquote? item) (list 'clojure.core/list (second item)) (unquote-splicing? item) (second item) :else (list 'clojure.core/list (syntax-quote* item))))] (recur (next s) ret)) (seq (persistent! r))))) (defn- flatten-map "Flatten a map into a seq of alternate keys and values" [form] (loop [s (seq form) key-vals (transient [])] (if s (let [e (first s)] (recur (next s) (-> key-vals (conj! (key e)) (conj! (val e))))) (seq (persistent! key-vals))))) (defn- register-gensym [sym] (if-not gensym-env (throw (IllegalStateException. "Gensym literal not in syntax-quote"))) (or (get gensym-env sym) (let [gs (symbol (str (subs (name sym) 0 (dec (count (name sym)))) "__" (RT/nextID) "__auto__"))] (set! gensym-env (assoc gensym-env sym gs)) gs))) (defn ^:dynamic resolve-symbol "Resolve a symbol s into its fully qualified namespace version" [s] (if (pos? (.indexOf (name s) ".")) (if (.endsWith (name s) ".") (let [csym (symbol (subs (name s) 0 (dec (count (name s)))))] (symbol (str (name (resolve-symbol csym)) "."))) s) (if-let [ns-str (namespace s)] (let [ns (resolve-ns (symbol ns-str))] (if (or (nil? ns) (= (ns-name* ns) ns-str)) ;; not an alias s (symbol (ns-name* ns) (name s)))) (if-let [o ((ns-map *ns*) s)] (if (class? o) (symbol (.getName ^Class o)) (if (var? o) (symbol (-> ^Var o .ns ns-name*) (-> ^Var o .sym name)))) (symbol (ns-name* *ns*) (name s)))))) (defn- add-meta [form ret] (if (and (instance? IObj form) (seq (dissoc (meta form) :line :column :end-line :end-column :file :source))) (list 'clojure.core/with-meta ret (syntax-quote* (meta form))) ret)) (defn- syntax-quote-coll [type coll] ;; We use sequence rather than seq here to fix http://dev.clojure.org/jira/browse/CLJ-1444 ;; But because of http://dev.clojure.org/jira/browse/CLJ-1586 we still need to call seq on the form (let [res (list 'clojure.core/sequence (list 'clojure.core/seq (cons 'clojure.core/concat (expand-list coll))))] (if type (list 'clojure.core/apply type res) res))) (defn map-func "Decide which map type to use, array-map if less than 16 elements" [coll] (if (>= (count coll) 16) 'clojure.core/hash-map 'clojure.core/array-map)) (defn- syntax-quote* [form] (->> (cond (special-symbol? form) (list 'quote form) (symbol? form) (list 'quote (if (namespace form) (let [maybe-class ((ns-map *ns*) (symbol (namespace form)))] (if (class? maybe-class) (symbol (.getName ^Class maybe-class) (name form)) (resolve-symbol form))) (let [sym (str form)] (cond (.endsWith sym "#") (register-gensym form) (.startsWith sym ".") form :else (resolve-symbol form))))) (unquote? form) (second form) (unquote-splicing? form) (throw (IllegalStateException. "unquote-splice not in list")) (coll? form) (cond (instance? IRecord form) form (map? form) (syntax-quote-coll (map-func form) (flatten-map form)) (vector? form) (list 'clojure.core/vec (syntax-quote-coll nil form)) (set? form) (syntax-quote-coll 'clojure.core/hash-set form) (or (seq? form) (list? form)) (let [seq (seq form)] (if seq (syntax-quote-coll nil seq) '(clojure.core/list))) :else (throw (UnsupportedOperationException. "Unknown Collection type"))) (or (keyword? form) (number? form) (char? form) (string? form) (nil? form) (instance? Boolean form) (instance? Pattern form)) form :else (list 'quote form)) (add-meta form))) (defn- read-syntax-quote [rdr backquote opts pending-forms] (binding [gensym-env {}] (-> (read* rdr true nil opts pending-forms) syntax-quote*))) (defn- read-namespaced-map [rdr _ opts pending-forms] (let [token (read-token rdr :namespaced-map (read-char rdr))] (if-let [ns (cond (= token ":") (ns-name *ns*) (= \: (first token)) (some-> token (subs 1) parse-symbol second' symbol resolve-ns ns-name) :else (some-> token parse-symbol second'))] (let [ch (read-past whitespace? rdr)] (if (identical? ch \{) (let [items (read-delimited :namespaced-map \} rdr opts pending-forms)] (when (odd? (count items)) (err/throw-odd-map rdr nil nil items)) (let [keys (take-nth 2 items) vals (take-nth 2 (rest items))] (RT/map (to-array (mapcat list (namespace-keys (str ns) keys) vals))))) (err/throw-ns-map-no-map rdr token))) (err/throw-bad-ns rdr token)))) (defn- macros [ch] (case ch \" read-string* \: read-keyword \; read-comment \' (wrapping-reader 'quote) \@ (wrapping-reader 'clojure.core/deref) \^ read-meta \` read-syntax-quote ;;(wrapping-reader 'syntax-quote) \~ read-unquote \( read-list \) read-unmatched-delimiter \[ read-vector \] read-unmatched-delimiter \{ read-map \} read-unmatched-delimiter \\ read-char* \% read-arg \# read-dispatch nil)) (defn- dispatch-macros [ch] (case ch \^ read-meta ;deprecated \' (wrapping-reader 'var) \( read-fn \= read-eval \{ read-set \< (throwing-reader "Unreadable form") \" read-regex \! read-comment \_ read-discard \? read-cond \: read-namespaced-map \# read-symbolic-value nil)) (defn- read-ctor [rdr class-name opts pending-forms] (when-not *read-eval* (err/reader-error rdr "Record construction syntax can only be used when *read-eval* == true")) (let [class (Class/forName (name class-name) false (RT/baseLoader)) ch (read-past whitespace? rdr)] ;; differs from clojure (if-let [[end-ch form] (case ch \[ [\] :short] \{ [\} :extended] nil)] (let [entries (to-array (read-delimited :record-ctor end-ch rdr opts pending-forms)) numargs (count entries) all-ctors (.getConstructors class) ctors-num (count all-ctors)] (case form :short (loop [i 0] (if (>= i ctors-num) (err/reader-error rdr "Unexpected number of constructor arguments to " (str class) ": got" numargs) (if (== (count (.getParameterTypes ^Constructor (aget all-ctors i))) numargs) (Reflector/invokeConstructor class entries) (recur (inc i))))) :extended (let [vals (RT/map entries)] (loop [s (keys vals)] (if s (if-not (keyword? (first s)) (err/reader-error rdr "Unreadable ctor form: key must be of type clojure.lang.Keyword") (recur (next s))))) (Reflector/invokeStaticMethod class "create" (object-array [vals]))))) (err/reader-error rdr "Invalid reader constructor form")))) (defn- read-tagged [rdr initch opts pending-forms] (let [tag (read* rdr true nil opts pending-forms)] (if-not (symbol? tag) (err/throw-bad-reader-tag rdr tag)) (if *suppress-read* (tagged-literal tag (read* rdr true nil opts pending-forms)) (if-let [f (or (*data-readers* tag) (default-data-readers tag))] (f (read* rdr true nil opts pending-forms)) (if (.contains (name tag) ".") (read-ctor rdr tag opts pending-forms) (if-let [f *default-data-reader-fn*] (f tag (read* rdr true nil opts pending-forms)) (err/throw-unknown-reader-tag rdr tag))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Public API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (def ^:dynamic *read-eval* "Defaults to true. ***WARNING*** This setting implies that the full power of the reader is in play, including syntax that can cause code to execute. It should never be used with untrusted sources. See also: clojure.tools.reader.edn/read. When set to logical false in the thread-local binding, the eval reader (#=) and *record/type literal syntax* are disabled in read/load. Example (will fail): (binding [*read-eval* false] (read-string \"#=(* 2 21)\")) When set to :unknown all reads will fail in contexts where *read-eval* has not been explicitly bound to either true or false. This setting can be a useful diagnostic tool to ensure that all of your reads occur in considered contexts." true) (def ^:dynamic *data-readers* "Map from reader tag symbols to data reader Vars. Reader tags without namespace qualifiers are reserved for Clojure. Default reader tags are defined in clojure.tools.reader/default-data-readers and may be overridden by binding this Var." {}) (def ^:dynamic *default-data-reader-fn* "When no data reader is found for a tag and *default-data-reader-fn* is non-nil, it will be called with two arguments, the tag and the value. If *default-data-reader-fn* is nil (the default value), an exception will be thrown for the unknown tag." nil) (def ^:dynamic *suppress-read* false) (def default-data-readers "Default map of data reader functions provided by Clojure. May be overridden by binding *data-readers*" {'inst #'data-readers/read-instant-date 'uuid #'data-readers/default-uuid-reader}) (defn ^:private read* ([reader eof-error? sentinel opts pending-forms] (read* reader eof-error? sentinel nil opts pending-forms)) ([reader eof-error? sentinel return-on opts pending-forms] (when (= :unknown *read-eval*) (err/reader-error "Reading disallowed - *read-eval* bound to :unknown")) (try (loop [] (let [ret (log-source reader (if (seq pending-forms) (.remove ^List pending-forms 0) (let [ch (read-char reader)] (cond (whitespace? ch) reader (nil? ch) (if eof-error? (err/throw-eof-error reader nil) sentinel) (= ch return-on) READ_FINISHED (number-literal? reader ch) (read-number reader ch) :else (if-let [f (macros ch)] (f reader ch opts pending-forms) (read-symbol reader ch))))))] (if (identical? ret reader) (recur) ret))) (catch Exception e (if (ex-info? e) (let [d (ex-data e)] (if (= :reader-exception (:type d)) (throw e) (throw (ex-info (.getMessage e) (merge {:type :reader-exception} d (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e)))) (throw (ex-info (.getMessage e) (merge {:type :reader-exception} (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e))))))) (defn read "Reads the first object from an IPushbackReader or a java.io.PushbackReader. Returns the object read. If EOF, throws if eof-error? is true. Otherwise returns sentinel. If no stream is providen, *in* will be used. Opts is a persistent map with valid keys: :read-cond - :allow to process reader conditionals, or :preserve to keep all branches :features - persistent set of feature keywords for reader conditionals :eof - on eof, return value unless :eofthrow, then throw. if not specified, will throw ***WARNING*** Note that read can execute code (controlled by *read-eval*), and as such should be used only with trusted sources. To read data structures only, use clojure.tools.reader.edn/read Note that the function signature of clojure.tools.reader/read and clojure.tools.reader.edn/read is not the same for eof-handling" {:arglists '([] [reader] [opts reader] [reader eof-error? eof-value])} ([] (read *in* true nil)) ([reader] (read reader true nil)) ([{eof :eof :as opts :or {eof :eofthrow}} reader] (when (source-logging-reader? reader) (let [^StringBuilder buf (:buffer @(.source-log-frames ^SourceLoggingPushbackReader reader))] (.setLength buf 0))) (read* reader (= eof :eofthrow) eof nil opts (LinkedList.))) ([reader eof-error? sentinel] (when (source-logging-reader? reader) (let [^StringBuilder buf (:buffer @(.source-log-frames ^SourceLoggingPushbackReader reader))] (.setLength buf 0))) (read* reader eof-error? sentinel nil {} (LinkedList.)))) (defn read-string "Reads one object from the string s. Returns nil when s is nil or empty. ***WARNING*** Note that read-string can execute code (controlled by *read-eval*), and as such should be used only with trusted sources. To read data structures only, use clojure.tools.reader.edn/read-string Note that the function signature of clojure.tools.reader/read-string and clojure.tools.reader.edn/read-string is not the same for eof-handling" ([s] (read-string {} s)) ([opts s] (when (and s (not (identical? s ""))) (read opts (string-push-back-reader s))))) (defmacro syntax-quote "Macro equivalent to the syntax-quote reader macro (`)." [form] (binding [gensym-env {}] (syntax-quote* form))) (defn read+string "Like read, and taking the same args. reader must be a SourceLoggingPushbackReader. Returns a vector containing the object read and the (whitespace-trimmed) string read." ([] (read+string (source-logging-push-back-reader *in*))) ([stream] (read+string stream true nil)) ([^SourceLoggingPushbackReader stream eof-error? eof-value] (let [o (log-source stream (read stream eof-error? eof-value)) s (.trim (str (:buffer @(.source-log-frames stream))))] [o s])) ([opts ^SourceLoggingPushbackReader stream] (let [o (log-source stream (read opts stream)) s (.trim (str (:buffer @(.source-log-frames stream))))] [o s]))) tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/000077500000000000000000000000001375401310700257435ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/default_data_readers.clj000066400000000000000000000265201375401310700325640ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; 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. ;;; copied from clojure.instant and clojure.uuid ;;; (ns ^:skip-wiki clojure.tools.reader.default-data-readers (:import [java.util Calendar Date GregorianCalendar TimeZone] [java.sql Timestamp])) ;;; clojure.instant ;;; ;;; ------------------------------------------------------------------------ ;;; convenience macros (defmacro ^:private fail [msg] `(throw (RuntimeException. ~msg))) (defmacro ^:private verify ([test msg] `(when-not ~test (fail ~msg))) ([test] `(verify ~test ~(str "failed: " (pr-str test))))) (defn- divisible? [num div] (zero? (mod num div))) (defn- indivisible? [num div] (not (divisible? num div))) ;;; ------------------------------------------------------------------------ ;;; parser implementation (defn- parse-int [^String s] (Long/parseLong s)) (defn- zero-fill-right [^String s width] (cond (= width (count s)) s (< width (count s)) (.substring s 0 width) :else (loop [b (StringBuilder. s)] (if (< (.length b) width) (recur (.append b \0)) (.toString b))))) (def parse-timestamp "Parse a string containing an RFC3339-like like timestamp. The function new-instant is called with the following arguments. min max default --- ------------ ------- years 0 9999 N/A (s must provide years) months 1 12 1 days 1 31 1 (actual max days depends hours 0 23 0 on month and year) minutes 0 59 0 seconds 0 60 0 (though 60 is only valid nanoseconds 0 999999999 0 when minutes is 59) offset-sign -1 1 0 offset-hours 0 23 0 offset-minutes 0 59 0 These are all integers and will be non-nil. (The listed defaults will be passed if the corresponding field is not present in s.) Grammar (of s): date-fullyear = 4DIGIT date-month = 2DIGIT ; 01-12 date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on ; month/year time-hour = 2DIGIT ; 00-23 time-minute = 2DIGIT ; 00-59 time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second ; rules time-secfrac = '.' 1*DIGIT time-numoffset = ('+' / '-') time-hour ':' time-minute time-offset = 'Z' / time-numoffset time-part = time-hour [ ':' time-minute [ ':' time-second [time-secfrac] [time-offset] ] ] timestamp = date-year [ '-' date-month [ '-' date-mday [ 'T' time-part ] ] ] Unlike RFC3339: - we only parse the timestamp format - timestamp can elide trailing components - time-offset is optional (defaults to +00:00) Though time-offset is syntactically optional, a missing time-offset will be treated as if the time-offset zero (+00:00) had been specified. " (let [timestamp #"(\d\d\d\d)(?:-(\d\d)(?:-(\d\d)(?:[T](\d\d)(?::(\d\d)(?::(\d\d)(?:[.](\d+))?)?)?)?)?)?(?:[Z]|([-+])(\d\d):(\d\d))?"] (fn [new-instant ^CharSequence cs] (if-let [[_ years months days hours minutes seconds fraction offset-sign offset-hours offset-minutes] (re-matches timestamp cs)] (new-instant (parse-int years) (if-not months 1 (parse-int months)) (if-not days 1 (parse-int days)) (if-not hours 0 (parse-int hours)) (if-not minutes 0 (parse-int minutes)) (if-not seconds 0 (parse-int seconds)) (if-not fraction 0 (parse-int (zero-fill-right fraction 9))) (cond (= "-" offset-sign) -1 (= "+" offset-sign) 1 :else 0) (if-not offset-hours 0 (parse-int offset-hours)) (if-not offset-minutes 0 (parse-int offset-minutes))) (fail (str "Unrecognized date/time syntax: " cs)))))) ;;; ------------------------------------------------------------------------ ;;; Verification of Extra-Grammatical Restrictions from RFC3339 (defn- leap-year? [year] (and (divisible? year 4) (or (indivisible? year 100) (divisible? year 400)))) (def ^:private days-in-month (let [dim-norm [nil 31 28 31 30 31 30 31 31 30 31 30 31] dim-leap [nil 31 29 31 30 31 30 31 31 30 31 30 31]] (fn [month leap-year?] ((if leap-year? dim-leap dim-norm) month)))) (defn validated "Return a function which constructs and instant by calling constructor after first validating that those arguments are in range and otherwise plausible. The resulting function will throw an exception if called with invalid arguments." [new-instance] (fn [years months days hours minutes seconds nanoseconds offset-sign offset-hours offset-minutes] (verify (<= 1 months 12)) (verify (<= 1 days (days-in-month months (leap-year? years)))) (verify (<= 0 hours 23)) (verify (<= 0 minutes 59)) (verify (<= 0 seconds (if (= minutes 59) 60 59))) (verify (<= 0 nanoseconds 999999999)) (verify (<= -1 offset-sign 1)) (verify (<= 0 offset-hours 23)) (verify (<= 0 offset-minutes 59)) (new-instance years months days hours minutes seconds nanoseconds offset-sign offset-hours offset-minutes))) ;;; ------------------------------------------------------------------------ ;;; print integration (def ^:private ^ThreadLocal thread-local-utc-date-format ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access. ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335 (proxy [ThreadLocal] [] (initialValue [] (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00") ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))) (defn- print-date "Print a java.util.Date as RFC3339 timestamp, always in UTC." [^java.util.Date d, ^java.io.Writer w] (let [utc-format (.get thread-local-utc-date-format)] (.write w "#inst \"") (.write w ^String (.format ^java.text.SimpleDateFormat utc-format d)) (.write w "\""))) (defmethod print-method java.util.Date [^java.util.Date d, ^java.io.Writer w] (print-date d w)) (defmethod print-dup java.util.Date [^java.util.Date d, ^java.io.Writer w] (print-date d w)) (defn- print-calendar "Print a java.util.Calendar as RFC3339 timestamp, preserving timezone." [^java.util.Calendar c, ^java.io.Writer w] (let [calstr (format "%1$tFT%1$tT.%1$tL%1$tz" c) offset-minutes (- (.length calstr) 2)] ;; calstr is almost right, but is missing the colon in the offset (.write w "#inst \"") (.write w calstr 0 offset-minutes) (.write w ":") (.write w calstr offset-minutes 2) (.write w "\""))) (defmethod print-method java.util.Calendar [^java.util.Calendar c, ^java.io.Writer w] (print-calendar c w)) (defmethod print-dup java.util.Calendar [^java.util.Calendar c, ^java.io.Writer w] (print-calendar c w)) (def ^:private ^ThreadLocal thread-local-utc-timestamp-format ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access. ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335 (proxy [ThreadLocal] [] (initialValue [] (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss") (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))) (defn- print-timestamp "Print a java.sql.Timestamp as RFC3339 timestamp, always in UTC." [^java.sql.Timestamp ts, ^java.io.Writer w] (let [utc-format (.get thread-local-utc-timestamp-format)] (.write w "#inst \"") (.write w ^String (.format ^java.text.SimpleDateFormat utc-format ts)) ;; add on nanos and offset ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) (.write w (format ".%09d-00:00" (.getNanos ts))) (.write w "\""))) (defmethod print-method java.sql.Timestamp [^java.sql.Timestamp ts, ^java.io.Writer w] (print-timestamp ts w)) (defmethod print-dup java.sql.Timestamp [^java.sql.Timestamp ts, ^java.io.Writer w] (print-timestamp ts w)) ;;; ------------------------------------------------------------------------ ;;; reader integration (defn- construct-calendar "Construct a java.util.Calendar, preserving the timezone offset, but truncating the subsecond fraction to milliseconds." ^GregorianCalendar [years months days hours minutes seconds nanoseconds offset-sign offset-hours offset-minutes] (doto (GregorianCalendar. years (dec months) days hours minutes seconds) (.set Calendar/MILLISECOND (quot nanoseconds 1000000)) (.setTimeZone (TimeZone/getTimeZone (format "GMT%s%02d:%02d" (if (neg? offset-sign) "-" "+") offset-hours offset-minutes))))) (defn- construct-date "Construct a java.util.Date, which expresses the original instant as milliseconds since the epoch, UTC." [years months days hours minutes seconds nanoseconds offset-sign offset-hours offset-minutes] (.getTime (construct-calendar years months days hours minutes seconds nanoseconds offset-sign offset-hours offset-minutes))) (defn- construct-timestamp "Construct a java.sql.Timestamp, which has nanosecond precision." [years months days hours minutes seconds nanoseconds offset-sign offset-hours offset-minutes] (doto (Timestamp. (.getTimeInMillis (construct-calendar years months days hours minutes seconds 0 offset-sign offset-hours offset-minutes))) ;; nanos must be set separately, pass 0 above for the base calendar (.setNanos nanoseconds))) (def read-instant-date "To read an instant as a java.util.Date, bind *data-readers* to a map with this var as the value for the 'inst key. The timezone offset will be used to convert into UTC." (partial parse-timestamp (validated construct-date))) (def read-instant-calendar "To read an instant as a java.util.Calendar, bind *data-readers* to a map with this var as the value for the 'inst key. Calendar preserves the timezone offset." (partial parse-timestamp (validated construct-calendar))) (def read-instant-timestamp "To read an instant as a java.sql.Timestamp, bind *data-readers* to a map with this var as the value for the 'inst key. Timestamp preserves fractional seconds with nanosecond precision. The timezone offset will be used to convert into UTC." (partial parse-timestamp (validated construct-timestamp))) ;;; clojure.uuid ;;; (defn default-uuid-reader [form] {:pre [(string? form)]} (java.util.UUID/fromString form)) (defmethod print-method java.util.UUID [uuid ^java.io.Writer w] (.write w (str "#uuid \"" (str uuid) "\""))) (defmethod print-dup java.util.UUID [o w] (print-method o w)) tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/edn.clj000066400000000000000000000347411375401310700272140ustar00rootroot00000000000000;; 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 ^{:doc "An EDN reader in clojure" :author "Bronsa"} clojure.tools.reader.edn (:refer-clojure :exclude [read read-string char default-data-readers]) (:require [clojure.tools.reader.reader-types :refer [read-char unread peek-char indexing-reader? get-line-number get-column-number get-file-name string-push-back-reader]] [clojure.tools.reader.impl.utils :refer [char ex-info? whitespace? numeric? desugar-meta namespace-keys second']] [clojure.tools.reader.impl.commons :refer :all] [clojure.tools.reader.impl.errors :as err] [clojure.tools.reader :refer [default-data-readers]]) (:import (clojure.lang PersistentHashSet IMeta RT PersistentVector))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (declare read macros dispatch-macros) (defn- macro-terminating? [ch] (and (not (identical? \# ch)) (not (identical? \' ch)) (not (identical? \: ch)) (macros ch))) (defn- not-constituent? [ch] (or (identical? \@ ch) (identical? \` ch) (identical? \~ ch))) (defn- ^String read-token ([rdr kind initch] (read-token rdr kind initch true)) ([rdr kind initch validate-leading?] (cond (not initch) (err/throw-eof-at-start rdr kind) (and validate-leading? (not-constituent? initch)) (err/throw-bad-char rdr kind initch) :else (loop [sb (StringBuilder.) ch initch] (if (or (whitespace? ch) (macro-terminating? ch) (nil? ch)) (do (unread rdr ch) (str sb)) (if (not-constituent? ch) (err/throw-bad-char rdr kind ch) (recur (doto sb (.append ch)) (read-char rdr)))))))) (declare read-tagged) (defn- read-dispatch [rdr _ opts] (if-let [ch (read-char rdr)] (if-let [dm (dispatch-macros ch)] (dm rdr ch opts) (read-tagged (doto rdr (unread ch)) ch opts)) (err/throw-eof-at-dispatch rdr))) (defn- read-unmatched-delimiter [rdr ch opts] (err/throw-unmatch-delimiter rdr ch)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; readers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn- read-unicode-char ([^String token ^long offset ^long length ^long base] (let [l (+ offset length)] (when-not (== (count token) l) (err/throw-invalid-unicode-literal nil token)) (loop [i offset uc 0] (if (== i l) (char uc) (let [d (Character/digit (int (nth token i)) (int base))] (if (== d -1) (err/throw-invalid-unicode-digit-in-token nil (nth token i) token) (recur (inc i) (long (+ d (* uc base)))))))))) ([rdr initch base length exact?] (let [length (long length) base (long base)] (loop [i 1 uc (Character/digit (int initch) (int base))] (if (== uc -1) (err/throw-invalid-unicode-digit rdr initch) (if-not (== i length) (let [ch (peek-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (if exact? (err/throw-invalid-unicode-len rdr i length) (char uc)) (let [d (Character/digit (int ch) (int base))] (read-char rdr) (if (== d -1) (err/throw-invalid-unicode-digit rdr ch) (recur (inc i) (long (+ d (* uc base)))))))) (char uc))))))) (def ^:private ^:const upper-limit (int \uD7ff)) (def ^:private ^:const lower-limit (int \uE000)) (defn- read-char* [rdr backslash opts] (let [ch (read-char rdr)] (if-not (nil? ch) (let [token (if (or (macro-terminating? ch) (not-constituent? ch) (whitespace? ch)) (str ch) (read-token rdr :character ch false)) token-len (count token)] (cond (== 1 token-len) (Character/valueOf (nth token 0)) (= token "newline") \newline (= token "space") \space (= token "tab") \tab (= token "backspace") \backspace (= token "formfeed") \formfeed (= token "return") \return (.startsWith token "u") (let [c (read-unicode-char token 1 4 16) ic (int c)] (if (and (> ic upper-limit) (< ic lower-limit)) (err/throw-invalid-character-literal rdr (Integer/toString ic 16)) c)) (.startsWith token "o") (let [len (dec token-len)] (if (> len 3) (err/throw-invalid-octal-len rdr token) (let [uc (read-unicode-char token 1 len 8)] (if (> (int uc) 0377) (err/throw-bad-octal-number rdr) uc)))) :else (err/throw-unsupported-character rdr token))) (err/throw-eof-in-character rdr)))) (defn ^:private starting-line-col-info [rdr] (when (indexing-reader? rdr) [(get-line-number rdr) (int (dec (int (get-column-number rdr))))])) (defn- ^PersistentVector read-delimited [kind delim rdr opts] (let [[start-line start-column] (starting-line-col-info rdr) delim (char delim)] (loop [a (transient [])] (let [ch (read-past whitespace? rdr)] (when-not ch (err/throw-eof-delimited rdr kind start-line start-column (count a))) (if (identical? delim (char ch)) (persistent! a) (if-let [macrofn (macros ch)] (let [mret (macrofn rdr ch opts)] (recur (if-not (identical? mret rdr) (conj! a mret) a))) (let [o (read (doto rdr (unread ch)) true nil opts)] (recur (if-not (identical? o rdr) (conj! a o) a))))))))) (defn- read-list [rdr _ opts] (let [the-list (read-delimited :list \) rdr opts)] (if (empty? the-list) '() (clojure.lang.PersistentList/create the-list)))) (defn- read-vector [rdr _ opts] (read-delimited :vector \] rdr opts)) (defn- read-map [rdr _ opts] (let [[start-line start-column] (starting-line-col-info rdr) coll (read-delimited :map \} rdr opts) l (to-array coll)] (when (== 1 (bit-and (alength l) 1)) (err/throw-odd-map rdr start-line start-column coll)) (RT/map l))) (defn- read-number [rdr initch opts] (loop [sb (doto (StringBuilder.) (.append initch)) ch (read-char rdr)] (if (or (whitespace? ch) (macros ch) (nil? ch)) (let [s (str sb)] (unread rdr ch) (or (match-number s) (err/throw-invalid-number rdr s))) (recur (doto sb (.append ch)) (read-char rdr))))) (defn- escape-char [sb rdr] (let [ch (read-char rdr)] (case ch \t "\t" \r "\r" \n "\n" \\ "\\" \" "\"" \b "\b" \f "\f" \u (let [ch (read-char rdr)] (if (== -1 (Character/digit (int ch) 16)) (err/throw-invalid-unicode-escape rdr ch) (read-unicode-char rdr ch 16 4 true))) (if (numeric? ch) (let [ch (read-unicode-char rdr ch 8 3 false)] (if (> (int ch) 0377) (err/throw-bad-octal-number rdr) ch)) (err/throw-bad-escape-char rdr ch))))) (defn- read-string* [rdr _ opts] (loop [sb (StringBuilder.) ch (read-char rdr)] (case ch nil (err/throw-eof-reading rdr :string \" sb) \\ (recur (doto sb (.append (escape-char sb rdr))) (read-char rdr)) \" (str sb) (recur (doto sb (.append ch)) (read-char rdr))))) (defn- read-symbol [rdr initch] (when-let [token (read-token rdr :symbol initch)] (case token ;; special symbols "nil" nil "true" true "false" false "/" '/ (or (when-let [p (parse-symbol token)] (symbol (p 0) (p 1))) (err/throw-invalid rdr :symbol token))))) (defn- read-keyword [reader initch opts] (let [ch (read-char reader)] (if-not (whitespace? ch) (let [token (read-token reader :keyword ch) s (parse-symbol token)] (if (and s (== -1 (.indexOf token "::"))) (let [^String ns (s 0) ^String name (s 1)] (if (identical? \: (nth token 0)) (err/throw-invalid reader :keyword token) ; No ::kw in edn. (keyword ns name))) (err/throw-invalid reader :keyword token))) (err/throw-single-colon reader)))) (defn- wrapping-reader [sym] (fn [rdr _ opts] (list sym (read rdr true nil opts)))) (defn- read-meta [rdr _ opts] (let [m (desugar-meta (read rdr true nil opts))] (when-not (map? m) (err/throw-bad-metadata rdr m)) (let [o (read rdr true nil opts)] (if (instance? IMeta o) (with-meta o (merge (meta o) m)) (err/throw-bad-metadata-target rdr o))))) (defn- read-set [rdr _ opts] (PersistentHashSet/createWithCheck (read-delimited :set \} rdr opts))) (defn- read-discard [rdr _ opts] (doto rdr (read true nil true))) (defn- read-namespaced-map [rdr _ opts] (let [token (read-token rdr :namespaced-map (read-char rdr))] (if-let [ns (some-> token parse-symbol second)] (let [ch (read-past whitespace? rdr)] (if (identical? ch \{) (let [items (read-delimited :namespaced-map \} rdr opts)] (when (odd? (count items)) (err/throw-odd-map rdr nil nil items)) (let [keys (take-nth 2 items) vals (take-nth 2 (rest items))] (RT/map (to-array (mapcat list (namespace-keys (str ns) keys) vals))))) (err/throw-ns-map-no-map rdr token))) (err/throw-bad-ns rdr token)))) (defn- read-symbolic-value [rdr _ opts] (let [sym (read rdr true nil opts)] (case sym Inf Double/POSITIVE_INFINITY -Inf Double/NEGATIVE_INFINITY NaN Double/NaN (err/reader-error rdr (str "Invalid token: ##" sym))))) (defn- macros [ch] (case ch \" read-string* \: read-keyword \; read-comment \^ read-meta \( read-list \) read-unmatched-delimiter \[ read-vector \] read-unmatched-delimiter \{ read-map \} read-unmatched-delimiter \\ read-char* \# read-dispatch nil)) (defn- dispatch-macros [ch] (case ch \^ read-meta ;deprecated \{ read-set \< (throwing-reader "Unreadable form") \! read-comment \_ read-discard \: read-namespaced-map \# read-symbolic-value nil)) (defn- read-tagged [rdr initch opts] (let [tag (read rdr true nil opts) object (read rdr true nil opts)] (if-not (symbol? tag) (err/throw-bad-reader-tag rdr "Reader tag must be a symbol")) (if-let [f (or (get (:readers opts) tag) (default-data-readers tag))] (f object) (if-let [d (:default opts)] (d tag object) (err/throw-unknown-reader-tag rdr tag))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Public API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn read "Reads the first object from an IPushbackReader or a java.io.PushbackReader. Returns the object read. If EOF, throws if eof-error? is true otherwise returns eof. If no reader is provided, *in* will be used. Reads data in the edn format (subset of Clojure data): http://edn-format.org clojure.tools.reader.edn/read doesn't depend on dynamic Vars, all configuration is done by passing an opt map. opts is a map that can include the following keys: :eof - value to return on end-of-file. When not supplied, eof throws an exception. :readers - a map of tag symbols to data-reader functions to be considered before default-data-readers. When not supplied, only the default-data-readers will be used. :default - A function of two args, that will, if present and no reader is found for a tag, be called with the tag and the value." ([] (read *in*)) ([reader] (read {} reader)) ([{:keys [eof] :as opts} reader] (let [eof-error? (not (contains? opts :eof))] (read reader eof-error? eof opts))) ([reader eof-error? eof opts] (try (loop [] (let [ch (read-char reader)] (cond (whitespace? ch) (recur) (nil? ch) (if eof-error? (err/throw-eof-error reader nil) eof) (number-literal? reader ch) (read-number reader ch opts) :else (let [f (macros ch)] (if f (let [res (f reader ch opts)] (if (identical? res reader) (recur) res)) (read-symbol reader ch)))))) (catch Exception e (if (ex-info? e) (let [d (ex-data e)] (if (= :reader-exception (:type d)) (throw e) (throw (ex-info (.getMessage e) (merge {:type :reader-exception} d (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e)))) (throw (ex-info (.getMessage e) (merge {:type :reader-exception} (if (indexing-reader? reader) {:line (get-line-number reader) :column (get-column-number reader) :file (get-file-name reader)})) e))))))) (defn read-string "Reads one object from the string s. Returns nil when s is nil or empty. Reads data in the edn format (subset of Clojure data): http://edn-format.org opts is a map as per clojure.tools.reader.edn/read" ([s] (read-string {:eof nil} s)) ([opts s] (when (and s (not (identical? s ""))) (read opts (string-push-back-reader s))))) tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/impl/000077500000000000000000000000001375401310700267045ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/impl/commons.clj000066400000000000000000000111241375401310700310500ustar00rootroot00000000000000;; 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.reader.impl.commons (:refer-clojure :exclude [char]) (:require [clojure.tools.reader.reader-types :refer [peek-char read-char]] [clojure.tools.reader.impl.errors :refer [reader-error]] [clojure.tools.reader.impl.utils :refer [numeric? newline? char]]) (:import (clojure.lang BigInt Numbers) (java.util.regex Pattern Matcher) java.lang.reflect.Constructor)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn number-literal? "Checks whether the reader is at the start of a number literal" [reader initch] (or (numeric? initch) (and (or (identical? \+ initch) (identical? \- initch)) (numeric? (peek-char reader))))) (defn read-past "Read until first character that doesn't match pred, returning char." [pred rdr] (loop [ch (read-char rdr)] (if (pred ch) (recur (read-char rdr)) ch))) (defn skip-line "Advances the reader to the end of a line. Returns the reader" [reader] (loop [] (when-not (newline? (read-char reader)) (recur))) reader) (def ^Pattern int-pattern #"([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)(N)?") (def ^Pattern ratio-pattern #"([-+]?[0-9]+)/([0-9]+)") (def ^Pattern float-pattern #"([-+]?[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?") (defn- match-int [^Matcher m] (if (.group m 2) (if (.group m 8) 0N 0) (let [negate? (= "-" (.group m 1)) a (cond (.group m 3) [(.group m 3) 10] (.group m 4) [(.group m 4) 16] (.group m 5) [(.group m 5) 8] (.group m 7) [(.group m 7) (Integer/parseInt (.group m 6))] :else [nil nil]) ^String n (a 0)] (when n (let [bn (BigInteger. n (int (a 1))) bn (if negate? (.negate bn) bn)] (if (.group m 8) (BigInt/fromBigInteger bn) (if (< (.bitLength bn) 64) (.longValue bn) (BigInt/fromBigInteger bn)))))))) (defn- match-ratio [^Matcher m] (let [^String numerator (.group m 1) ^String denominator (.group m 2) numerator (if (.startsWith numerator "+") (subs numerator 1) numerator)] (/ (-> numerator BigInteger. BigInt/fromBigInteger Numbers/reduceBigInt) (-> denominator BigInteger. BigInt/fromBigInteger Numbers/reduceBigInt)))) (defn- match-float [^String s ^Matcher m] (if (.group m 4) (BigDecimal. ^String (.group m 1)) (Double/parseDouble s))) (defn match-number [^String s] (let [int-matcher (.matcher int-pattern s)] (if (.matches int-matcher) (match-int int-matcher) (let [float-matcher (.matcher float-pattern s)] (if (.matches float-matcher) (match-float s float-matcher) (let [ratio-matcher (.matcher ratio-pattern s)] (when (.matches ratio-matcher) (match-ratio ratio-matcher)))))))) (defn parse-symbol "Parses a string into a vector of the namespace and symbol" [^String token] (when-not (or (= "" token) (.endsWith token ":") (.startsWith token "::")) (let [ns-idx (.indexOf token "/")] (if-let [^String ns (and (pos? ns-idx) (subs token 0 ns-idx))] (let [ns-idx (inc ns-idx)] (when-not (== ns-idx (count token)) (let [sym (subs token ns-idx)] (when (and (not (numeric? (nth sym 0))) (not (= "" sym)) (not (.endsWith ns ":")) (or (= sym "/") (== -1 (.indexOf sym "/")))) [ns sym])))) (when (or (= token "/") (== -1 (.indexOf token "/"))) [nil token]))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; readers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn read-comment [rdr & _] (skip-line rdr)) (defn throwing-reader [msg] (fn [rdr & _] (reader-error rdr msg))) tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/impl/errors.clj000066400000000000000000000150011375401310700307070ustar00rootroot00000000000000;; Copyright (c) Russ Olsen, 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.reader.impl.errors (:require [clojure.tools.reader.reader-types :as types] [clojure.tools.reader.impl.inspect :as i])) (defn- location-details [rdr ex-type] (let [details {:type :reader-exception :ex-kind ex-type}] (if (types/indexing-reader? rdr) (assoc details :file (types/get-file-name rdr) :line (types/get-line-number rdr) :col (types/get-column-number rdr)) details))) (defn ^:private throw-ex [rdr ex-type & msg] (let [details (location-details rdr ex-type) file (:file details) line (:line details) col (:col details) msg1 (if file (str file " ")) msg2 (if line (str "[line " line ", col " col "]")) msg3 (if (or msg1 msg2) " ") full-msg (apply str msg1 msg2 msg3 msg)] (throw (ex-info full-msg details)))) (defn reader-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :reader-error (apply str msgs))) (defn eof-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :eof (apply str msgs))) (defn illegal-arg-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :illegal-argument (apply str msgs))) (defn throw-eof-delimited ([rdr kind line column] (throw-eof-delimited rdr kind line column nil)) ([rdr kind line column n] (eof-error rdr "Unexpected EOF while reading " (if n (str "item " n " of ")) (name kind) (if line (str ", starting at line " line " and column " column)) "."))) (defn throw-odd-map [rdr line col elements] (reader-error rdr "The map literal starting with " (i/inspect (first elements)) (if line (str " on line " line " column " col)) " contains " (count elements) " form(s). Map literals must contain an even number of forms.")) (defn throw-invalid-number [rdr token] (reader-error rdr "Invalid number: " token ".")) (defn throw-invalid-unicode-literal [rdr token] (throw (illegal-arg-error rdr (str "Invalid unicode literal: \\" token ".")))) (defn throw-invalid-unicode-escape [rdr ch] (reader-error rdr "Invalid unicode escape: \\u" ch ".")) (defn throw-invalid [rdr kind token] (reader-error rdr "Invalid " (name kind) ": " token ".")) (defn throw-eof-at-start [rdr kind] (eof-error rdr "Unexpected EOF while reading start of " (name kind) ".")) (defn throw-bad-char [rdr kind ch] (reader-error rdr "Invalid character: " ch " found while reading " (name kind) ".")) (defn throw-eof-at-dispatch [rdr] (eof-error rdr "Unexpected EOF while reading dispatch character.")) (defn throw-unmatch-delimiter [rdr ch] (reader-error rdr "Unmatched delimiter " ch ".")) (defn throw-eof-reading [rdr kind & start] (let [init (case kind :regex "#\"" :string \")] (eof-error rdr "Unexpected EOF reading " (name kind) " starting " (apply str init start) "."))) (defn throw-invalid-unicode-char[rdr token] (throw (illegal-arg-error rdr (str "Invalid unicode character \\" token ".")))) (defn throw-invalid-unicode-digit-in-token [rdr ch token] (throw (illegal-arg-error rdr (str "Invalid digit " ch " in unicode character \\" token ".")))) (defn throw-invalid-unicode-digit[rdr ch] (throw (illegal-arg-error rdr (str "Invalid digit " ch " in unicode character.")))) (defn throw-invalid-unicode-len[rdr actual expected] (throw (illegal-arg-error rdr (str "Invalid unicode literal. Unicode literals should be " expected "characters long. " "value suppled is " actual "characters long.")))) (defn throw-invalid-character-literal[rdr token] (reader-error rdr "Invalid character literal \\u" token ".")) (defn throw-invalid-octal-len[rdr token] (reader-error rdr "Invalid octal escape sequence in a character literal:" token ". Octal escape sequences must be 3 or fewer digits.")) (defn throw-bad-octal-number [rdr] (reader-error rdr "Octal escape sequence must be in range [0, 377].")) (defn throw-unsupported-character[rdr token] (reader-error rdr "Unsupported character: " token ".")) (defn throw-eof-in-character[rdr] (eof-error rdr "Unexpected EOF while reading character.")) (defn throw-bad-escape-char [rdr ch] (reader-error rdr "Unsupported escape character: \\" ch ".")) (defn throw-single-colon [rdr] (reader-error rdr "A single colon is not a valid keyword.")) (defn throw-bad-metadata [rdr x] (reader-error rdr "Metadata cannot be " (i/inspect x) ". Metadata must be a Symbol, Keyword, String or Map.")) (defn throw-bad-metadata-target [rdr target] (reader-error rdr "Metadata can not be applied to " (i/inspect target) ". " "Metadata can only be applied to IMetas.")) (defn throw-feature-not-keyword [rdr feature] (reader-error rdr "Feature cannot be " (i/inspect feature) " Features must be keywords.")) (defn throw-ns-map-no-map [rdr ns-name] (reader-error rdr "Namespaced map with namespace " ns-name " does not specify a map.")) (defn throw-bad-ns [rdr ns-name] (reader-error rdr "Invalid value used as namespace in namespaced map: " ns-name ".")) (defn throw-bad-reader-tag [rdr tag] (reader-error rdr "Invalid reader tag: " (i/inspect tag) ". Reader tags must be symbols.")) (defn throw-unknown-reader-tag [rdr tag] (reader-error rdr "No reader function for tag " (i/inspect tag) ".")) (defn throw-eof-error [rdr line] (if line (eof-error rdr "EOF while reading, starting at line " line ".") (eof-error rdr "EOF while reading."))) tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/impl/inspect.clj000066400000000000000000000054301375401310700310450ustar00rootroot00000000000000;; Copyright (c) Russ Olsen, 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.reader.impl.inspect) (declare inspect*) (defn- inspect*-col [truncate col start end] (let [n (count col) l (if truncate 0 (min 10 n)) elements (map (partial inspect* true) (take l col)) content (apply str (interpose " " elements)) suffix (if (< l n) "...")] (str start content suffix end))) (defn- dispatch-inspect [_ x] (cond (nil? x) :nil (string? x) :string (keyword? x) :strable (number? x) :strable (symbol? x) :strable (vector? x) :vector (list? x) :list (map? x) :map (set? x) :set (= x true) :strable (= x false) :strable :default (class x))) (defmulti inspect* dispatch-inspect) (defmethod inspect* :string [truncate ^String x] (let [n (if truncate 5 20) suffix (if (> (.length x) n) "...\"" "\"")] (str \" (.substring ^String x 0 (min n (.length x))) suffix))) (defmethod inspect* :strable [truncate x] (str x)) (defmethod inspect* clojure.lang.PersistentVector$ChunkedSeq [truncate x] "") (defmethod inspect* clojure.lang.PersistentArrayMap$Seq [truncate x] "") (defmethod inspect* clojure.lang.PersistentHashMap$NodeSeq [truncate x] "") (defmethod inspect* clojure.lang.Cons [truncate x] "") (defmethod inspect* clojure.lang.LazySeq [truncate x] "") (defmethod inspect* :nil [_ _] "nil") (defmethod inspect* :list [truncate col] (inspect*-col truncate col \( \))) (defmethod inspect* :map [truncate m] (let [len (count m) n-shown (if truncate 0 len) contents (apply concat (take n-shown m)) suffix (if (> len n-shown) "...}" \})] (inspect*-col truncate contents \{ suffix))) (defmethod inspect* :set [truncate col] (inspect*-col truncate col "#{" \})) (defmethod inspect* :vector [truncate col] (inspect*-col truncate col \[ \])) (defmethod inspect* :default [truncate x] (let [classname (if (nil? x) "nil" (.getName (class x)))] (str "<" classname ">"))) (defn inspect "Return a string description of the value supplied. May be the a string version of the value itself (e.g. \"true\") or it may be a description (e.g. \"an instance of Foo\"). If truncate is true then return a very terse version of the inspection." ([x] (inspect* false x)) ([truncate x] (inspect* truncate x))) tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/impl/utils.clj000066400000000000000000000072561375401310700305500ustar00rootroot00000000000000;; 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 ^:skip-wiki clojure.tools.reader.impl.utils (:refer-clojure :exclude [char reader-conditional tagged-literal])) (defn char [x] (when x (clojure.core/char x))) (def <=clojure-1-7-alpha5 (let [{:keys [minor qualifier]} *clojure-version*] (or (< minor 7) (and (= minor 7) (= "alpha" (when qualifier (subs qualifier 0 (dec (count qualifier))))) (<= (read-string (subs qualifier (dec (count qualifier)))) 5))))) (defmacro compile-when [cond & then] (when (eval cond) `(do ~@then))) (defn ex-info? [ex] (instance? clojure.lang.ExceptionInfo ex)) (compile-when <=clojure-1-7-alpha5 (defrecord TaggedLiteral [tag form]) (defn tagged-literal? "Return true if the value is the data representation of a tagged literal" [value] (instance? clojure.tools.reader.impl.utils.TaggedLiteral value)) (defn tagged-literal "Construct a data representation of a tagged literal from a tag symbol and a form." [tag form] (clojure.tools.reader.impl.utils.TaggedLiteral. tag form)) (ns-unmap *ns* '->TaggedLiteral) (ns-unmap *ns* 'map->TaggedLiteral) (defmethod print-method clojure.tools.reader.impl.utils.TaggedLiteral [o ^java.io.Writer w] (.write w "#") (print-method (:tag o) w) (.write w " ") (print-method (:form o) w)) (defrecord ReaderConditional [splicing? form]) (ns-unmap *ns* '->ReaderConditional) (ns-unmap *ns* 'map->ReaderConditional) (defn reader-conditional? "Return true if the value is the data representation of a reader conditional" [value] (instance? clojure.tools.reader.impl.utils.ReaderConditional value)) (defn reader-conditional "Construct a data representation of a reader conditional. If true, splicing? indicates read-cond-splicing." [form splicing?] (clojure.tools.reader.impl.utils.ReaderConditional. splicing? form)) (defmethod print-method clojure.tools.reader.impl.utils.ReaderConditional [o ^java.io.Writer w] (.write w "#?") (when (:splicing? o) (.write w "@")) (print-method (:form o) w))) (defn whitespace? "Checks whether a given character is whitespace" [ch] (when ch (or (Character/isWhitespace ^Character ch) (identical? \, ch)))) (defn numeric? "Checks whether a given character is numeric" [^Character ch] (when ch (Character/isDigit ch))) (defn newline? "Checks whether the character is a newline" [c] (or (identical? \newline c) (nil? c))) (defn desugar-meta "Resolves syntactical sugar in metadata" ;; could be combined with some other desugar? [f] (cond (keyword? f) {f true} (symbol? f) {:tag f} (string? f) {:tag f} :else f)) (defn make-var "Returns an anonymous unbound Var" [] (with-local-vars [x nil] x)) (defn namespace-keys [ns keys] (for [key keys] (if (or (symbol? key) (keyword? key)) (let [[key-ns key-name] ((juxt namespace name) key) ->key (if (symbol? key) symbol keyword)] (cond (nil? key-ns) (->key ns key-name) (= "_" key-ns) (->key key-name) :else key)) key))) (defn second' [[a b]] (when-not a b)) tools.reader-tools.reader-1.3.4/src/main/clojure/clojure/tools/reader/reader_types.clj000066400000000000000000000334711375401310700311330ustar00rootroot00000000000000;; 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 ^{:doc "Protocols and default Reader types implementation" :author "Bronsa"} clojure.tools.reader.reader-types (:refer-clojure :exclude [char read-line]) (:require [clojure.tools.reader.impl.utils :refer [char whitespace? newline? make-var]]) (:import clojure.lang.LineNumberingPushbackReader (java.io InputStream BufferedReader Closeable))) (defmacro ^:private update! [what f] (list 'set! what (list f what))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; reader protocols ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defprotocol Reader (read-char [reader] "Returns the next char from the Reader, nil if the end of stream has been reached") (peek-char [reader] "Returns the next char from the Reader without removing it from the reader stream")) (defprotocol IPushbackReader (unread [reader ch] "Pushes back a single character on to the stream")) (defprotocol IndexingReader (get-line-number [reader] "Returns the line number of the next character to be read from the stream") (get-column-number [reader] "Returns the column number of the next character to be read from the stream") (get-file-name [reader] "Returns the file name the reader is reading from, or nil")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; reader deftypes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deftype StringReader [^String s ^long s-len ^:unsynchronized-mutable ^long s-pos] Reader (read-char [reader] (when (> s-len s-pos) (let [r (nth s s-pos)] (update! s-pos inc) r))) (peek-char [reader] (when (> s-len s-pos) (nth s s-pos)))) (deftype InputStreamReader [^InputStream is ^:unsynchronized-mutable ^"[B" buf] Reader (read-char [reader] (if buf (let [c (aget buf 0)] (set! buf nil) (char c)) (let [c (.read is)] (when (>= c 0) (char c))))) (peek-char [reader] (when-not buf (set! buf (byte-array 1)) (when (== -1 (.read is buf)) (set! buf nil))) (when buf (char (aget buf 0)))) Closeable (close [this] (.close is))) (deftype PushbackReader [rdr ^"[Ljava.lang.Object;" buf ^long buf-len ^:unsynchronized-mutable ^long buf-pos] Reader (read-char [reader] (char (if (< buf-pos buf-len) (let [r (aget buf buf-pos)] (update! buf-pos inc) r) (read-char rdr)))) (peek-char [reader] (char (if (< buf-pos buf-len) (aget buf buf-pos) (peek-char rdr)))) IPushbackReader (unread [reader ch] (when ch (if (zero? buf-pos) (throw (RuntimeException. "Pushback buffer is full"))) (update! buf-pos dec) (aset buf buf-pos ch))) Closeable (close [this] (when (instance? Closeable rdr) (.close ^Closeable rdr)))) (deftype IndexingPushbackReader [rdr ^:unsynchronized-mutable ^long line ^:unsynchronized-mutable ^long column ^:unsynchronized-mutable line-start? ^:unsynchronized-mutable prev ^:unsynchronized-mutable ^long prev-column file-name ^:unsynchronized-mutable normalize?] Reader (read-char [reader] (when-let [ch (read-char rdr)] (let [ch (if normalize? (do (set! normalize? false) (if (or (identical? \newline ch) (identical? \formfeed ch)) (read-char rdr) ch)) ch) ch (if (identical? \return ch) (do (set! normalize? true) \newline) ch)] (set! prev line-start?) (set! line-start? (newline? ch)) (when line-start? (set! prev-column column) (set! column 0) (update! line inc)) (update! column inc) ch))) (peek-char [reader] (peek-char rdr)) IPushbackReader (unread [reader ch] (if line-start? (do (update! line dec) (set! column prev-column)) (update! column dec)) (set! line-start? prev) ;; This may look a bit convoluted, but it helps in the following ;; scenario: ;; + The underlying reader is about to return \return from the ;; next read-char, and then \newline after that. ;; + read-char gets \return, sets normalize? to true, returns ;; \newline instead. ;; + Caller calls unread on the \newline it just got. If we ;; unread the \newline to the underlying reader, now it is ready ;; to return two \newline chars in a row, which will throw off ;; the tracked line numbers. (let [ch (if normalize? (do (set! normalize? false) (if (identical? \newline ch) \return ch)) ch)] (unread rdr ch))) IndexingReader (get-line-number [reader] (int line)) (get-column-number [reader] (int column)) (get-file-name [reader] file-name) Closeable (close [this] (when (instance? Closeable rdr) (.close ^Closeable rdr)))) ;; Java interop (extend-type java.io.PushbackReader Reader (read-char [rdr] (let [c (.read ^java.io.PushbackReader rdr)] (when (>= c 0) (char c)))) (peek-char [rdr] (when-let [c (read-char rdr)] (unread rdr c) c)) IPushbackReader (unread [rdr c] (when c (.unread ^java.io.PushbackReader rdr (int c))))) (extend LineNumberingPushbackReader IndexingReader {:get-line-number (fn [rdr] (.getLineNumber ^LineNumberingPushbackReader rdr)) :get-column-number (fn [rdr] (.getColumnNumber ^LineNumberingPushbackReader rdr)) :get-file-name (constantly nil)}) (defprotocol ReaderCoercer (to-rdr [rdr])) (declare string-reader push-back-reader) (extend-protocol ReaderCoercer Object (to-rdr [rdr] (if (satisfies? Reader rdr) rdr (throw (IllegalArgumentException. (str "Argument of type: " (class rdr) " cannot be converted to Reader"))))) clojure.tools.reader.reader_types.Reader (to-rdr [rdr] rdr) String (to-rdr [str] (string-reader str)) java.io.Reader (to-rdr [rdr] (java.io.PushbackReader. rdr))) (defprotocol PushbackReaderCoercer (to-pbr [rdr buf-len])) (extend-protocol PushbackReaderCoercer Object (to-pbr [rdr buf-len] (if (satisfies? Reader rdr) (push-back-reader rdr buf-len) (throw (IllegalArgumentException. (str "Argument of type: " (class rdr) " cannot be converted to IPushbackReader"))))) clojure.tools.reader.reader_types.Reader (to-pbr [rdr buf-len] (push-back-reader rdr buf-len)) clojure.tools.reader.reader_types.PushbackReader (to-pbr [rdr buf-len] (push-back-reader rdr buf-len)) String (to-pbr [str buf-len] (push-back-reader str buf-len)) java.io.Reader (to-pbr [rdr buf-len] (java.io.PushbackReader. rdr buf-len))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Source Logging support ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn merge-meta "Returns an object of the same type and value as `obj`, with its metadata merged over `m`." [obj m] (let [orig-meta (meta obj)] (with-meta obj (merge m (dissoc orig-meta :source))))) (defn- peek-source-log "Returns a string containing the contents of the top most source logging frame." [source-log-frames] (let [current-frame @source-log-frames] (.substring ^StringBuilder (:buffer current-frame) (:offset current-frame)))) (defn- log-source-char "Logs `char` to all currently active source logging frames." [source-log-frames char] (when-let [^StringBuilder buffer (:buffer @source-log-frames)] (.append buffer char))) (defn- drop-last-logged-char "Removes the last logged character from all currently active source logging frames. Called when pushing a character back." [source-log-frames] (when-let [^StringBuilder buffer (:buffer @source-log-frames)] (.deleteCharAt buffer (dec (.length buffer))))) (deftype SourceLoggingPushbackReader [rdr ^:unsynchronized-mutable ^long line ^:unsynchronized-mutable ^long column ^:unsynchronized-mutable line-start? ^:unsynchronized-mutable prev ^:unsynchronized-mutable ^long prev-column file-name source-log-frames ^:unsynchronized-mutable normalize?] Reader (read-char [reader] (when-let [ch (read-char rdr)] (let [ch (if normalize? (do (set! normalize? false) (if (or (identical? \newline ch) (identical? \formfeed ch)) (read-char rdr) ch)) ch) ch (if (identical? \return ch) (do (set! normalize? true) \newline) ch)] (set! prev line-start?) (set! line-start? (newline? ch)) (when line-start? (set! prev-column column) (set! column 0) (update! line inc)) (update! column inc) (log-source-char source-log-frames ch) ch))) (peek-char [reader] (peek-char rdr)) IPushbackReader (unread [reader ch] (if line-start? (do (update! line dec) (set! column prev-column)) (update! column dec)) (set! line-start? prev) (when ch (drop-last-logged-char source-log-frames)) (unread rdr ch)) IndexingReader (get-line-number [reader] (int line)) (get-column-number [reader] (int column)) (get-file-name [reader] file-name) Closeable (close [this] (when (instance? Closeable rdr) (.close ^Closeable rdr)))) (defn log-source* [reader f] (let [frame (.source-log-frames ^SourceLoggingPushbackReader reader) ^StringBuilder buffer (:buffer @frame) new-frame (assoc-in @frame [:offset] (.length buffer))] (with-bindings {frame new-frame} (let [ret (f)] (if (instance? clojure.lang.IObj ret) (merge-meta ret {:source (peek-source-log frame)}) ret))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Public API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; fast check for provided implementations (defn indexing-reader? "Returns true if the reader satisfies IndexingReader" [rdr] (or (instance? clojure.tools.reader.reader_types.IndexingReader rdr) (instance? LineNumberingPushbackReader rdr) (and (not (instance? clojure.tools.reader.reader_types.PushbackReader rdr)) (not (instance? clojure.tools.reader.reader_types.StringReader rdr)) (not (instance? clojure.tools.reader.reader_types.InputStreamReader rdr)) (get (:impls IndexingReader) (class rdr))))) (defn string-reader "Creates a StringReader from a given string" ([^String s] (StringReader. s (count s) 0))) (defn ^Closeable push-back-reader "Creates a PushbackReader from a given reader or string" ([rdr] (push-back-reader rdr 1)) ([rdr buf-len] (PushbackReader. (to-rdr rdr) (object-array buf-len) buf-len buf-len))) (defn ^Closeable string-push-back-reader "Creates a PushbackReader from a given string" ([s] (string-push-back-reader s 1)) ([^String s buf-len] (push-back-reader (string-reader s) buf-len))) (defn ^Closeable input-stream-reader "Creates an InputStreamReader from an InputStream" [is] (InputStreamReader. is nil)) (defn ^Closeable input-stream-push-back-reader "Creates a PushbackReader from a given InputStream" ([is] (input-stream-push-back-reader is 1)) ([^InputStream is buf-len] (push-back-reader (input-stream-reader is) buf-len))) (defn ^Closeable indexing-push-back-reader "Creates an IndexingPushbackReader from a given string or PushbackReader" ([s-or-rdr] (indexing-push-back-reader s-or-rdr 1)) ([s-or-rdr buf-len] (indexing-push-back-reader s-or-rdr buf-len nil)) ([s-or-rdr buf-len file-name] (IndexingPushbackReader. (to-pbr s-or-rdr buf-len) 1 1 true nil 0 file-name false))) (defn ^Closeable source-logging-push-back-reader "Creates a SourceLoggingPushbackReader from a given string or PushbackReader" ([s-or-rdr] (source-logging-push-back-reader s-or-rdr 1)) ([s-or-rdr buf-len] (source-logging-push-back-reader s-or-rdr buf-len nil)) ([s-or-rdr buf-len file-name] (SourceLoggingPushbackReader. (to-pbr s-or-rdr buf-len) 1 1 true nil 0 file-name (doto (make-var) (alter-var-root (constantly {:buffer (StringBuilder.) :offset 0}))) false))) (defn read-line "Reads a line from the reader or from *in* if no reader is specified" ([] (read-line *in*)) ([rdr] (if (or (instance? LineNumberingPushbackReader rdr) (instance? BufferedReader rdr)) (binding [*in* rdr] (clojure.core/read-line)) (loop [c (read-char rdr) s (StringBuilder.)] (if (newline? c) (str s) (recur (read-char rdr) (.append s c))))))) (defn source-logging-reader? [rdr] (instance? SourceLoggingPushbackReader rdr)) (defmacro log-source "If reader is a SourceLoggingPushbackReader, execute body in a source logging context. Otherwise, execute body, returning the result." [reader & body] `(if (and (source-logging-reader? ~reader) (not (whitespace? (peek-char ~reader)))) (log-source* ~reader (^:once fn* [] ~@body)) (do ~@body))) (defn line-start? "Returns true if rdr is an IndexingReader and the current char starts a new line" [rdr] (when (indexing-reader? rdr) (== 1 (int (get-column-number rdr))))) tools.reader-tools.reader-1.3.4/src/test/000077500000000000000000000000001375401310700202665ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/test/cljs/000077500000000000000000000000001375401310700212215ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/test/cljs/cljs/000077500000000000000000000000001375401310700221545ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/test/cljs/cljs/tools/000077500000000000000000000000001375401310700233145ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/test/cljs/cljs/tools/metadata_test.cljs000066400000000000000000000213771375401310700270220ustar00rootroot00000000000000(ns cljs.tools.metadata-test (:refer-clojure :exclude [read *default-data-reader-fn* read-string]) (:require [cljs.tools.reader :refer [read *data-readers* *default-data-reader-fn* read-string]] [cljs.test :as t :refer-macros [deftest is run-tests]] [cljs.tools.reader.reader-types :as reader-types] [clojure.string :as str] [clojure.walk :as walk])) (defn inst [s] (js/Date. s)) (set! *data-readers* {'inst inst 'uuid uuid}) (defn compare-forms-with-meta [expected-form actual-form] (let [comparisons (map vector (tree-seq coll? identity expected-form) (tree-seq coll? identity actual-form))] (doseq [[expected actual] comparisons] (is (= [expected (meta expected)] [actual (meta actual)]))))) (def test-contents "Contents of a file stream for testing." "(ns clojure.tools.reader.haiku)\n\n(defn haiku \"It will read the form but will the form metadata be or never become?\" [first-five middle-seven last-five] (- (apply + ^{:last last-five} [1 2 3]) first-five middle-seven))") (defn test-reader "Return a fresh byte array input stream reading off test-bytes" [] (reader-types/string-reader test-contents)) (def expected-haiku-ns (with-meta (list (with-meta 'ns {:line 1 :column 2 :end-line 1 :end-column 4 :file "haiku.clj"}) (with-meta 'clojure.tools.reader.haiku {:line 1 :column 5 :end-line 1 :end-column 31 :file "haiku.clj"})) {:line 1 :column 1 :end-line 1 :end-column 32 :file "haiku.clj"})) (def expected-haiku-defn (with-meta (list (with-meta 'defn {:line 3 :column 2 :end-line 3 :end-column 6 :file "haiku.clj"}) (with-meta 'haiku {:line 3 :column 7 :end-line 3 :end-column 12 :file "haiku.clj"}) "It will read the form\n but will the form metadata be\n or never become?" (with-meta [(with-meta 'first-five {:line 7 :column 6 :end-line 7 :end-column 16 :file "haiku.clj"}) (with-meta 'middle-seven {:line 7 :column 17 :end-line 7 :end-column 29 :file "haiku.clj"}) (with-meta 'last-five {:line 7 :column 30 :end-line 7 :end-column 39 :file "haiku.clj"})] {:line 7 :column 5 :end-line 7 :end-column 40 :file "haiku.clj"}) (with-meta (list (with-meta '- {:line 8 :column 6 :end-line 8, :end-column 7 :file "haiku.clj"}) (with-meta (list (with-meta 'apply {:line 8 :column 9 :end-line 8 :end-column 14 :file "haiku.clj"}) (with-meta '+ {:line 8 :column 15 :end-line 8 :end-column 16 :file "haiku.clj"}) (with-meta [1 2 3] {:last 'last-five :line 9 :column 34 :end-line 9 :end-column 41 :file "haiku.clj"})) {:line 8 :column 8 :end-line 9 :end-column 42 :file "haiku.clj"}) (with-meta 'first-five {:line 10 :column 8 :end-line 10 :end-column 18 :file "haiku.clj"}) (with-meta 'middle-seven {:line 10 :column 19 :end-line 10 :end-column 31 :file "haiku.clj"})) {:line 8 :column 5 :end-line 10 :end-column 32 :file "haiku.clj"})) {:line 3 :column 1 :end-line 10 :end-column 33 :file "haiku.clj"})) (deftest read-metadata (let [reader (-> test-contents (reader-types/string-push-back-reader) (reader-types/indexing-push-back-reader 1 "haiku.clj")) first-form (read reader) second-form (read reader)] (is (= {:line 1 :column 1 :end-line 1 :end-column 32 :file "haiku.clj"} (meta first-form))) (compare-forms-with-meta expected-haiku-ns first-form) (compare-forms-with-meta expected-haiku-defn second-form))) (def expected-haiku-ns-with-source (with-meta (list (with-meta 'ns {:line 1 :column 2 :end-line 1 :end-column 4 :source "ns" :file "haiku.clj"}) (with-meta ' clojure.tools.reader.haiku {:line 1 :column 5 :end-line 1 :end-column 31 :source "clojure.tools.reader.haiku" :file "haiku.clj"})) {:line 1 :column 1 :end-line 1 :end-column 32 :source "(ns clojure.tools.reader.haiku)" :file "haiku.clj"})) (def expected-haiku-defn-with-source (with-meta (list (with-meta 'defn {:line 3 :column 2 :end-line 3 :end-column 6 :source "defn" :file "haiku.clj"}) (with-meta 'haiku {:line 3 :column 7 :end-line 3 :end-column 12 :source "haiku" :file "haiku.clj"}) "It will read the form\n but will the form metadata be\n or never become?" (with-meta [(with-meta 'first-five {:line 7 :column 6 :end-line 7 :end-column 16 :source "first-five" :file "haiku.clj"}) (with-meta 'middle-seven {:line 7 :column 17 :end-line 7 :end-column 29 :source "middle-seven" :file "haiku.clj"}) (with-meta 'last-five {:line 7 :column 30 :end-line 7 :end-column 39 :source "last-five" :file "haiku.clj"})] {:line 7 :column 5 :end-line 7 :end-column 40 :source "[first-five middle-seven last-five]" :file "haiku.clj"}) (with-meta (list (with-meta '- {:line 8 :column 6 :end-line 8, :end-column 7 :source "-" :file "haiku.clj"}) (with-meta (list (with-meta 'apply {:line 8 :column 9 :end-line 8 :end-column 14 :source "apply" :file "haiku.clj"}) (with-meta '+ {:line 8 :column 15 :end-line 8 :end-column 16 :source "+" :file "haiku.clj"}) (with-meta [1 2 3] {:last 'last-five :line 9 :column 34 :end-line 9 :end-column 41 :source "^{:last last-five} [1 2 3]" :file "haiku.clj"})) {:line 8 :column 8 :end-line 9 :end-column 42 :source "(apply + ^{:last last-five} [1 2 3])" :file "haiku.clj"}) (with-meta 'first-five {:line 10 :column 8 :end-line 10 :end-column 18 :source "first-five" :file "haiku.clj"}) (with-meta 'middle-seven {:line 10 :column 19 :end-line 10 :end-column 31 :source "middle-seven" :file "haiku.clj"})) {:line 8 :column 5 :end-line 10 :end-column 32 :source "(- (apply + ^{:last last-five} [1 2 3]) first-five middle-seven)" :file "haiku.clj"})) {:line 3 :column 1 :end-line 10 :end-column 33 :source "(defn haiku \"It will read the form but will the form metadata be or never become?\" [first-five middle-seven last-five] (- (apply + ^{:last last-five} [1 2 3]) first-five middle-seven))" :file "haiku.clj"})) (deftest read-metadata-with-source (let [reader (-> test-contents (reader-types/string-push-back-reader) (reader-types/source-logging-push-back-reader 1 "haiku.clj")) first-form (read reader) second-form (read reader)] (is (= {:line 1 :column 1 :end-line 1 :end-column 32 :source "(ns clojure.tools.reader.haiku)" :file "haiku.clj"} (meta first-form))) (compare-forms-with-meta expected-haiku-ns-with-source first-form) (compare-forms-with-meta expected-haiku-defn-with-source second-form))) (def test2-contents (str/join "\n" ["[ +42 -42 0N +042 +0x42e -0x42e -36rCRAZY -42.2e-3M 0.314e+1" " true false :kw :ns/kw 'foo/bar nil" " \\f \\u0194 \\newline \\o377 \\ud7ff " " () [7] #{9 8} '^{:meta []} bar " " #inst \"2010-11-12T13:14:15.666\"" " ]"])) (def expected-vector (with-meta (vector 42 -42 0N 34 1070 -1070 -21429358 -0.0422M 3.14 true false :kw :ns/kw (list 'quote (with-meta 'foo/bar {:line 2, :column 26, :end-line 2, :end-column 33, :file "vector.clj"})) nil \f \Ɣ \newline \ÿ \퟿ (with-meta '() {:line 4, :column 2, :end-line 4, :end-column 4, :file "vector.clj"}) (with-meta [7] {:line 4, :column 5, :end-line 4, :end-column 8, :file "vector.clj"}) (with-meta #{9 8} {:line 4, :column 9, :end-line 4, :end-column 15, :file "vector.clj"}) ^{:source "'^{:meta []} bar"} (list 'quote (with-meta 'bar {:meta ^{:line 4, :column 25, :end-line 4, :end-column 27, :file "vector.clj"} [], :line 4, :column 29, :end-line 4, :end-column 32, :file "vector.clj"})) (read-string "#inst \"2010-11-12T13:14:15.666-00:00\"")) {:line 1 :column 1 :end-line 6 :end-column 3 :file "vector.clj"})) (deftest read-metadata2 (let [reader (-> test2-contents (reader-types/string-push-back-reader) (reader-types/indexing-push-back-reader 1 "vector.clj")) first-form (read reader)] (compare-forms-with-meta expected-vector first-form))) tools.reader-tools.reader-1.3.4/src/test/cljs/cljs/tools/reader_edn_test.cljs000066400000000000000000000131031375401310700273160ustar00rootroot00000000000000(ns cljs.tools.reader-edn-test (:require [cljs.test :as t :refer-macros [deftest is run-tests]] [cljs.tools.reader.edn :refer [read-string]])) ;;============================================================================== ;; common_tests.clj ;;============================================================================== (deftest read-integer (is (== 42 (read-string "42"))) (is (== +42 (read-string "+42"))) (is (== -42 (read-string "-42"))) (is (== 0 (read-string "0"))) (is (== 042 (read-string "042"))) (is (== +042 (read-string "+042"))) (is (== -042 (read-string "-042"))) ;;hex (is (== 0x42e (read-string "0x42e"))) (is (== +0x42e (read-string "+0x42e"))) (is (== -0x42e (read-string "-0x42e"))) ;;oct (is (== 511 (js/parseInt "777" 8) (read-string "0777"))) (is (== -511 (js/parseInt "-777" 8) (read-string "-0777"))) (is (== 1340 (js/parseInt "02474" 8) (read-string "02474"))) (is (== -1340 (js/parseInt "-02474" 8) (read-string "-02474")))) (deftest read-floating (is (== 42.23 (read-string "42.23"))) (is (== +42.23 (read-string "+42.23"))) (is (== -42.23 (read-string "-42.23"))) (is (== 42.2e3 (read-string "42.2e3"))) (is (== +42.2e+3 (read-string "+42.2e+3"))) (is (== -42.2e-3 (read-string "-42.2e-3")))) (deftest read-ratio (is (== 4/2 (read-string "4/2"))) (is (== 4/2 (read-string "+4/2"))) (is (== -4/2 (read-string "-4/2")))) (deftest read-symbol (is (= 'foo (read-string "foo"))) (is (= 'foo/bar (read-string "foo/bar"))) (is (= '*+!-_? (read-string "*+!-_?"))) (is (= 'abc:def:ghi (read-string "abc:def:ghi"))) (is (= 'abc.def/ghi (read-string "abc.def/ghi"))) (is (= 'abc/def.ghi (read-string "abc/def.ghi"))) (is (= 'abc:def/ghi:jkl.mno (read-string "abc:def/ghi:jkl.mno"))) (is (instance? cljs.core/Symbol (read-string "alphabet"))) (is (= "foo//" (str (read-string "foo//")))) (is (js/isNaN (read-string "##NaN"))) (is (= js/Number.POSITIVE_INFINITY (read-string "##Inf"))) (is (= js/Number.NEGATIVE_INFINITY (read-string "##-Inf")))) (deftest read-specials (is (= 'nil nil)) (is (= 'false false)) (is (= 'true true))) (deftest read-char (is (= \f (read-string "\\f"))) (is (= \u0194 (read-string "\\u0194"))) (is (= \o123 (read-string "\\o123"))) (is (= \newline (read-string "\\newline"))) (is (= (char 0) (read-string "\\o0"))) (is (= (char 0) (read-string "\\o000"))) (is (= (char 0377) (read-string "\\o377"))) (is (= \A (read-string "\\u0041"))) (is (= \@ (read-string "\\@"))) (is (= (char 0xd7ff) (read-string "\\ud7ff"))) (is (= (char 0xe000) (read-string "\\ue000"))) (is (= (char 0xffff) (read-string "\\uffff"))) (is (thrown-with-msg? js/Error #"Invalid character literal \\ud800" (read-string "\\ud800")))) (deftest read-string* (is (= "foo bar" (read-string "\"foo bar\""))) (is (= "foo\\bar" (read-string "\"foo\\\\bar\""))) (is (= "foo\000bar" (read-string "\"foo\\000bar\""))) (is (= "foo\u0194bar" (read-string "\"foo\\u0194bar\""))) (is (= "foo\123bar" (read-string "\"foo\\123bar\""))) (is (= "\060" (read-string "\"\\060\""))) (is (= "\340" (read-string "\"\\340\""))) (is (= "\377" (read-string "\"\\377\"")))) (deftest read-list (is (= '() (read-string "()"))) (is (= '(foo bar) (read-string "(foo bar)"))) (is (= '(foo (bar) baz) (read-string "(foo (bar) baz)")))) (deftest read-vector (is (= '[] (read-string "[]"))) (is (= '[foo bar] (read-string "[foo bar]"))) (is (= '[foo [bar] baz] (read-string "[foo [bar] baz]")))) (deftest read-map (is (= '{} (read-string "{}"))) (is (= '{foo bar} (read-string "{foo bar}"))) (is (= '{foo {bar baz}} (read-string "{foo {bar baz}}")))) (deftest read-set (is (= '#{} (read-string "#{}"))) (is (= '#{foo bar} (read-string "#{foo bar}"))) (is (= '#{foo #{bar} baz} (read-string "#{foo #{bar} baz}")))) (deftest read-metadata (is (= {:foo true} (meta (read-string "^:foo 'bar")))) (is (= {:foo 'bar} (meta (read-string "^{:foo bar} 'baz")))) (is (= {:tag "foo"} (meta (read-string "^\"foo\" 'bar")))) (is (= {:tag 'String} (meta (read-string "^String 'x"))))) (defn inst [s] (js/Date. s)) (def data-readers {'inst inst 'uuid uuid}) (deftest read-keyword (is (= :foo-bar (read-string ":foo-bar"))) (is (= :foo/bar (read-string ":foo/bar"))) (is (= :*+!-_? (read-string ":*+!-_?"))) (is (= :abc:def:ghi (read-string ":abc:def:ghi"))) (is (= :abc.def/ghi (read-string ":abc.def/ghi"))) (is (= :abc/def.ghi (read-string ":abc/def.ghi"))) (is (= :abc:def/ghi:jkl.mno (read-string ":abc:def/ghi:jkl.mno"))) (is (instance? cljs.core.Keyword (read-string ":alphabet"))) ) (deftest read-tagged (is (= #inst "2010-11-12T13:14:15.666" (read-string {:readers data-readers} "#inst \"2010-11-12T13:14:15.666\""))) (is (= #inst "2010-11-12T13:14:15.666" (read-string {:readers data-readers} "#inst\"2010-11-12T13:14:15.666\""))) (is (= #uuid "550e8400-e29b-41d4-a716-446655440000" (read-string {:readers data-readers} "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))) (is (= #uuid "550e8400-e29b-41d4-a716-446655440000" (read-string {:readers data-readers} "#uuid\"550e8400-e29b-41d4-a716-446655440000\""))) (let [my-unknown (fn [tag val] {:unknown-tag tag :value val})] (is (= {:unknown-tag 'foo :value 'bar} (read-string {:default my-unknown} "#foo bar"))))) (deftest read-namespaced-map (is (= {:foo/bar 1 :baz 2} (read-string "#:foo{:bar 1 :_/baz 2}"))) (is (= '{foo/bar 1 :baz 2} (read-string "#:foo{bar 1 :_/baz 2}")))) tools.reader-tools.reader-1.3.4/src/test/cljs/cljs/tools/reader_test.cljs000066400000000000000000000322671375401310700265040ustar00rootroot00000000000000(ns cljs.tools.reader-test (:refer-clojure :exclude [read-string]) (:require [cljs.test :as t :refer-macros [are deftest is run-tests testing]] [cljs.tools.reader :as reader :refer [*data-readers* *default-data-reader-fn* read-string *alias-map* resolve-symbol]] [cljs.tools.reader.impl.utils :refer [reader-conditional reader-conditional?]] [cljs.tools.reader.reader-types :as rt] [goog.string])) ;;============================================================================== ;; common_tests.clj ;;============================================================================== (deftest read-integer (is (== 42 (read-string "42"))) (is (== +42 (read-string "+42"))) (is (== -42 (read-string "-42"))) (is (== 0 (read-string "0"))) (is (== 042 (read-string "042"))) (is (== +042 (read-string "+042"))) (is (== -042 (read-string "-042"))) ;;hex (is (== 0x42e (read-string "0x42e"))) (is (== +0x42e (read-string "+0x42e"))) (is (== -0x42e (read-string "-0x42e"))) ;;oct (is (== 511 (js/parseInt "777" 8) (read-string "0777"))) (is (== -511 (js/parseInt "-777" 8) (read-string "-0777"))) (is (== 1340 (js/parseInt "02474" 8) (read-string "02474"))) (is (== -1340 (js/parseInt "-02474" 8) (read-string "-02474"))) (is (thrown-with-msg? js/Error #"Invalid number: 09." (read-string "09")))) (deftest read-floating (is (== 42.23 (read-string "42.23"))) (is (== +42.23 (read-string "+42.23"))) (is (== -42.23 (read-string "-42.23"))) (is (== 42.2e3 (read-string "42.2e3"))) (is (== +42.2e+3 (read-string "+42.2e+3"))) (is (== -42.2e-3 (read-string "-42.2e-3")))) (deftest read-ratio (is (== 4/2 (read-string "4/2"))) (is (== 4/2 (read-string "+4/2"))) (is (== -4/2 (read-string "-4/2")))) (deftest read-symbol (is (= 'foo (read-string "foo"))) (is (= 'foo/bar (read-string "foo/bar"))) (is (= '*+!-_? (read-string "*+!-_?"))) (is (= 'abc:def:ghi (read-string "abc:def:ghi"))) (is (= 'abc.def/ghi (read-string "abc.def/ghi"))) (is (= 'abc/def.ghi (read-string "abc/def.ghi"))) (is (= 'abc:def/ghi:jkl.mno (read-string "abc:def/ghi:jkl.mno"))) (is (instance? cljs.core/Symbol (read-string "alphabet"))) (is (= "foo//" (str (read-string "foo//")))) (is (js/isNaN (read-string "##NaN"))) (is (= js/Number.POSITIVE_INFINITY (read-string "##Inf"))) (is (= js/Number.NEGATIVE_INFINITY (read-string "##-Inf")))) (deftest read-specials (is (= 'nil nil)) (is (= 'false false)) (is (= 'true true))) (deftest read-char (is (= \f (read-string "\\f"))) (is (= \u0194 (read-string "\\u0194"))) (is (= \o123 (read-string "\\o123"))) (is (= \newline (read-string "\\newline"))) (is (= (char 0) (read-string "\\o0"))) (is (= (char 0) (read-string "\\o000"))) (is (= (char 0377) (read-string "\\o377"))) (is (= \A (read-string "\\u0041"))) (is (= \@ (read-string "\\@"))) (is (= (char 0xd7ff) (read-string "\\ud7ff"))) (is (= (char 0xe000) (read-string "\\ue000"))) (is (= (char 0xffff) (read-string "\\uffff"))) (is (thrown-with-msg? js/Error #"Invalid character literal \\ud800" (read-string "\\ud800")))) (deftest read-string* (is (= "foo bar" (read-string "\"foo bar\""))) (is (= "foo\\bar" (read-string "\"foo\\\\bar\""))) (is (= "foo\000bar" (read-string "\"foo\\000bar\""))) (is (= "foo\u0194bar" (read-string "\"foo\\u0194bar\""))) (is (= "foo\123bar" (read-string "\"foo\\123bar\""))) (is (= "\060" (read-string "\"\\060\""))) (is (= "\340" (read-string "\"\\340\""))) (is (= "\377" (read-string "\"\\377\"")))) (deftest read-list (is (= '() (read-string "()"))) (is (= '(foo bar) (read-string "(foo bar)"))) (is (= '(foo (bar) baz) (read-string "(foo (bar) baz)")))) (deftest read-vector (is (= '[] (read-string "[]"))) (is (= '[foo bar] (read-string "[foo bar]"))) (is (= '[foo [bar] baz] (read-string "[foo [bar] baz]")))) (deftest read-map (is (= '{} (read-string "{}"))) (is (= '{foo bar} (read-string "{foo bar}"))) (is (= '{foo {bar baz}} (read-string "{foo {bar baz}}"))) (is (thrown-with-msg? js/Error #"Map literals must contain an even number of forms." (read-string "{foo bar bar}"))) (is (thrown-with-msg? js/Error #"Map literal contains duplicate key: foo" (read-string "{foo bar foo bar}")))) (deftest read-set (is (= '#{} (read-string "#{}"))) (is (= '#{foo bar} (read-string "#{foo bar}"))) (is (= '#{foo #{bar} baz} (read-string "#{foo #{bar} baz}"))) (is (thrown-with-msg? js/Error #"Set literal contains duplicate key: foo" (read-string "#{foo foo}"))) (is (thrown-with-msg? js/Error #"Set literal contains duplicate keys: foo, bar" (read-string "#{foo foo bar bar}")))) (deftest read-metadata (is (= {:foo true} (meta (read-string "^:foo 'bar")))) (is (= {:foo 'bar} (meta (read-string "^{:foo bar} 'baz")))) (is (= {:tag "foo"} (meta (read-string "^\"foo\" 'bar")))) (is (= {:tag 'String} (meta (read-string "^String 'x"))))) (deftest read-keyword (is (= :foo-bar (read-string ":foo-bar"))) (is (= :foo/bar (read-string ":foo/bar"))) (is (= :*+!-_? (read-string ":*+!-_?"))) (is (= :abc:def:ghi (read-string ":abc:def:ghi"))) (is (= :abc.def/ghi (read-string ":abc.def/ghi"))) (is (= :abc/def.ghi (read-string ":abc/def.ghi"))) (is (= :abc:def/ghi:jkl.mno (read-string ":abc:def/ghi:jkl.mno"))) (is (instance? cljs.core.Keyword (read-string ":alphabet"))) (is (= :bar/bar (binding [*alias-map* '{foo bar}] (read-string "::foo/bar"))))) (deftest read-regex (is (= (str #"(?i)abc") (str (read-string "#\"(?i)abc\"")))) (is (= (str #"\[\]?(\")\\") (str (read-string "#\"\\[\\]?(\\\")\\\\\""))))) (deftest read-quote (is (= ''foo (read-string "'foo")))) (deftest read-syntax-quote (is (= (binding [resolve-symbol (constantly 'cljs.user/x)] (read-string "`x")) ''cljs.user/x)) #_(let [q (read-string "quote")] (is (= 'bar/bar (binding [*alias-map* '{foo bar}] (second (read-string "`foo/bar"))))) (is (= q (first (read-string "`foo")))) (is (= 'foo (second (read-string "`foo")))) (is (= q (first (read-string "`+")))) (is (= '+ (second (read-string "`+")))) (is (= q (first (read-string "`foo/bar")))) (is (= 'foo/bar (second (read-string "`foo/bar")))) (is (= 1 (read-string "`1"))))) (deftest read-deref (is (= '@foo (read-string "@foo")))) (deftest read-var (is (= '(var foo) (read-string "#'foo")))) (deftest read-fn (is (= '(fn* [] (foo bar baz)) (read-string "#(foo bar baz)")))) (defn inst [s] (js/Date. s)) (deftest read-tagged (binding [*data-readers* {'inst inst 'uuid uuid}] (is (= #inst "2010-11-12T13:14:15.666" (read-string "#inst \"2010-11-12T13:14:15.666\""))) (is (= #inst "2010-11-12T13:14:15.666" (read-string "#inst\"2010-11-12T13:14:15.666\""))) (is (= (uuid "550e8400-e29b-41d4-a716-446655440000") (read-string "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))) (is (= (uuid "550e8400-e29b-41d4-a716-446655440000") (read-string "#uuid\"550e8400-e29b-41d4-a716-446655440000\""))) (when *default-data-reader-fn* (let [my-unknown (fn [tag val] {:unknown-tag tag :value val})] (is (= {:unknown-tag 'foo :value 'bar} (binding [*default-data-reader-fn* my-unknown] (read-string "#foo bar")))))))) (defrecord ^:export foo []) (defrecord ^:export bar [baz buz]) #_(deftest read-record (is (= (foo.) (read-string "#cljs.tools.reader_test.foo[]"))) (is (= (foo.) (read-string "#cljs.tools.reader_test.foo []"))) ;; not valid in clojure (is (= (foo.) (read-string "#cljs.tools.reader_test.foo{}"))) (is (= (assoc (foo.) :foo 'bar) (read-string "#cljs.tools.reader_test.foo{:foo bar}"))) (is (= (map->bar {:baz 1}) (read-string "#cljs.tools.reader_test.bar{:baz 1}"))) (is (= (bar. 1 nil) (read-string "#cljs.tools.reader_test.bar[1 nil]"))) (is (= (bar. 1 2) (read-string "#cljs.tools.reader_test.bar[1 2]")))) (deftest source-logging-meta-test (-> (loop [r (cljs.tools.reader.reader-types/source-logging-push-back-reader "(def test 8)\n(def test2 9)\n") forms []] (if-let [form (reader/read r false nil)] (recur r (conj forms [(meta form) form])) forms)) (= [[{:line 1 :column 1 :end-line 1 :end-column 13} '(def test 8)] [{:line 2 :column 0 :end-line 2 :end-column 1}] [{:line 2, :column 1, :end-line 2, :end-column 14} '(def test2 9)] [{:line 3, :column 0, :end-line 3, :end-column 1}]]))) (defrecord JSValue [v]) (extend-protocol IPrintWithWriter JSValue (-pr-writer [coll writer opts] (-write writer "#js") (print-map coll pr-writer writer opts))) (deftest reader-conditionals (let [opts {:read-cond :allow :features #{:clj}}] (are [out s opts] (= out (read-string opts s)) ;; basic read-cond '[foo-form] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:foo}} '[bar-form] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:bar}} '[foo-form] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:foo :bar}} '[] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:baz}} 'nil "#?(:default nil)" opts ;; environmental features "clojure" "#?(:clj \"clojure\" :cljs \"clojurescript\" :default \"default\")" opts ;; default features "default" "#?(:cljr \"clr\" :cljs \"cljs\" :default \"default\")" opts ;; splicing [] "[#?@(:clj [])]" opts [:a] "[#?@(:clj [:a])]" opts [:a :b] "[#?@(:clj [:a :b])]" opts [:a :b :c] "[#?@(:clj [:a :b :c])]" opts ;; nested splicing [:a :b :c :d :e] "[#?@(:clj [:a #?@(:clj [:b #?@(:clj [:c]) :d]):e])]" opts '(+ 1 (+ 2 3)) "(+ #?@(:clj [1 (+ #?@(:clj [2 3]))]))" opts '(+ (+ 2 3) 1) "(+ #?@(:clj [(+ #?@(:clj [2 3])) 1]))" opts [:a [:b [:c] :d] :e] "[#?@(:clj [:a [#?@(:clj [:b #?@(:clj [[:c]]) :d])] :e])]" opts ;; bypass unknown tagged literals [1 2 3] "#?(:cljs #js [1 2 3] :clj [1 2 3])" opts :clojure "#?(:foo #some.nonexistent.Record {:x 1} :clj :clojure)" opts) (are [re s opts] (is (thrown-with-msg? js/Error re (read-string opts s))) #"Feature should be a keyword" "#?((+ 1 2) :a)" opts #"even number of forms" "#?(:cljs :a :clj)" opts #"cond-splice not in list" "#?@(:clj :a)" opts #"cond-splice not in list" "#?@(:foo :a :else :b)" opts #"must be a list" "#?[:foo :a :else :b]" opts #"Conditional read not allowed" "#?[:clj :a :default nil]" {:read-cond :BOGUS} #"Conditional read not allowed" "#?[:clj :a :default nil]" {})) (binding [*data-readers* {'js (fn [v] (JSValue. v) )}] (is (= (JSValue. [1 2 3]) (read-string {:features #{:cljs} :read-cond :allow} "#?(:cljs #js [1 2 3] :foo #foo [1])"))))) (deftest preserve-read-cond (is (= 1 (binding [*data-readers* {'foo (constantly 1)}] (read-string {:read-cond :preserve} "#foo []")))) (let [x (read-string {:read-cond :preserve} "#?(:clj foo :cljs bar)")] (is (reader-conditional? x)) (is (= x (reader-conditional '(:clj foo :cljs bar) false))) (is (not (:splicing? x))) (is (= :foo (get x :no-such-key :foo))) (is (= (:form x) '(:clj foo :cljs bar)))) (let [x (first (read-string {:read-cond :preserve} "(#?@(:clj [foo]))" ))] (is (reader-conditional? x)) (is (= x (reader-conditional '(:clj [foo]) true))) (is (:splicing? x)) (is (= :foo (get x :no-such-key :foo))) (is (= (:form x) '(:clj [foo])))) (is (thrown-with-msg? js/Error #"No reader function for tag" (read-string {:read-cond :preserve} "#js {:x 1 :y 2}" ))) (let [x (read-string {:read-cond :preserve} "#?(:cljs #js {:x 1 :y 2})") [platform tl] (:form x)] (is (reader-conditional? x)) (is (tagged-literal? tl)) (is (= tl (tagged-literal 'js {:x 1 :y 2}))) (is (= 'js (:tag tl))) (is (= {:x 1 :y 2} (:form tl))) (is (= :foo (get tl :no-such-key :foo)))) (testing "print form roundtrips" (doseq [s ["#?(:clj foo :cljs bar)" "#?(:cljs #js {:y 2, :x 1})" "#?(:clj #cljs.test_clojure.reader.TestRecord [42 85])"]] (is (= s (pr-str (read-string {:read-cond :preserve} s))))))) (deftest read-namespaced-map (binding [*ns* (create-ns 'cljs.tools.reader-test)] (is (= {:foo/bar 1 :baz 2} (read-string "#:foo{:bar 1 :_/baz 2}"))) (is (= '{foo/bar 1 :baz 2} (read-string "#:foo{bar 1 :_/baz 2}"))) (is (= {::foo 1} (read-string "#::{:foo 1}"))) (is (= {::foo 1 :bar 2} (read-string "#::{:foo 1 :_/bar 2}"))) (is (= {:a/foo 1 :bar 2} (read-string "#:a{:foo 1 :_/bar 2}"))))) (deftest read-map-types (let [a (reader/read-string "{:a 1 :b 2 :c 3}") b (reader/read-string "{:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}")] (is (= a {:a 1 :b 2 :c 3})) (is (instance? PersistentArrayMap a)) (is (= b {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9})) (is (instance? PersistentHashMap b)))) tools.reader-tools.reader-1.3.4/src/test/cljs/cljs/tools/test_runner.cljs000066400000000000000000000003531375401310700265420ustar00rootroot00000000000000(ns cljs.tools.test-runner (:require cljs.tools.metadata-test cljs.tools.reader-test cljs.tools.reader-edn-test [cljs.test :refer-macros [run-all-tests]])) (enable-console-print!) (run-all-tests) tools.reader-tools.reader-1.3.4/src/test/clojure/000077500000000000000000000000001375401310700217315ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/test/clojure/clojure/000077500000000000000000000000001375401310700233745ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/test/clojure/clojure/tools/000077500000000000000000000000001375401310700245345ustar00rootroot00000000000000tools.reader-tools.reader-1.3.4/src/test/clojure/clojure/tools/common_tests.clj000066400000000000000000000223731375401310700277470ustar00rootroot00000000000000 (deftest read-integer (is (== 42 (read-string "42"))) (is (== +42 (read-string "+42"))) (is (== -42 (read-string "-42"))) (is (== 42 (read-string "42N"))) (is (== +42 (read-string "+42N"))) (is (== -42 (read-string "-42N"))) (is (== 0 (read-string "0"))) (is (== 0N (read-string "0N"))) (is (== 042 (read-string "042"))) (is (== +042 (read-string "+042"))) (is (== -042 (read-string "-042"))) (is (== 0x42e (read-string "0x42e"))) (is (== +0x42e (read-string "+0x42e"))) (is (== -0x42e (read-string "-0x42e"))) (is (instance? Long (read-string "2147483647"))) (is (instance? Long (read-string "+1"))) (is (instance? Long (read-string "1"))) (is (instance? Long (read-string "+0"))) (is (instance? Long (read-string "0"))) (is (instance? Long (read-string "-0"))) (is (instance? Long (read-string "-1"))) (is (instance? Long (read-string "-2147483648"))) (is (instance? Long (read-string "2147483648"))) (is (instance? Long (read-string "-2147483649"))) (is (instance? Long (read-string "9223372036854775807"))) (is (instance? Long (read-string "-9223372036854775808"))) (is (instance? BigInt (read-string "9223372036854775808"))) (is (instance? BigInt (read-string "-9223372036854775809"))) (is (instance? BigInt (read-string "10000000000000000000000000000000000000000000000000"))) (is (instance? BigInt (read-string "-10000000000000000000000000000000000000000000000000")))) (deftest read-floating (is (== 42.23 (read-string "42.23"))) (is (== +42.23 (read-string "+42.23"))) (is (== -42.23 (read-string "-42.23"))) (is (== 42.23M (read-string "42.23M"))) (is (== +42.23M (read-string "+42.23M"))) (is (== -42.23M (read-string "-42.23M"))) (is (== 42.2e3 (read-string "42.2e3"))) (is (== +42.2e+3 (read-string "+42.2e+3"))) (is (== -42.2e-3 (read-string "-42.2e-3"))) (is (== 42.2e3M (read-string "42.2e3M"))) (is (== +42.2e+3M (read-string "+42.2e+3M"))) (is (== -42.2e-3M (read-string "-42.2e-3M"))) (is (instance? Double (read-string "+1.0e+1"))) (is (instance? Double (read-string "+1.e+1"))) (is (instance? Double (read-string "+1e+1"))) (is (instance? Double (read-string "+1.0e+1"))) (is (instance? Double (read-string "+1.e+1"))) (is (instance? Double (read-string "+1e+1"))) (is (instance? Double (read-string "+1.0e1"))) (is (instance? Double (read-string "+1.e1"))) (is (instance? Double (read-string "+1e1"))) (is (instance? Double (read-string "+1.0e-1"))) (is (instance? Double (read-string "+1.e-1"))) (is (instance? Double (read-string "+1e-1"))) (is (instance? Double (read-string "1.0e+1"))) (is (instance? Double (read-string "1.e+1"))) (is (instance? Double (read-string "1e+1"))) (is (instance? Double (read-string "1.0e-1"))) (is (instance? Double (read-string "1.e-1"))) (is (instance? Double (read-string "1e-1"))) (is (instance? Double (read-string "-1.0e+1"))) (is (instance? Double (read-string "-1.e+1"))) (is (instance? Double (read-string "-1e+1"))) (is (instance? Double (read-string "-1.0e1"))) (is (instance? Double (read-string "-1.e1"))) (is (instance? Double (read-string "-1e1"))) (is (instance? Double (read-string "-1.0e-1"))) (is (instance? Double (read-string "-1.e-1"))) (is (instance? Double (read-string "-1e-1"))) (is (instance? Double (read-string "+1.0"))) (is (instance? Double (read-string "+1."))) (is (instance? Double (read-string "1.0"))) (is (instance? Double (read-string "1."))) (is (instance? Double (read-string "+0.0"))) (is (instance? Double (read-string "+0."))) (is (instance? Double (read-string "0.0"))) (is (instance? Double (read-string "0."))) (is (instance? Double (read-string "-0.0"))) (is (instance? Double (read-string "-0."))) (is (instance? Double (read-string "-1.0"))) (is (instance? Double (read-string "-1."))) (is (instance? BigDecimal (read-string "9223372036854775808M"))) (is (instance? BigDecimal (read-string "-9223372036854775809M"))) (is (instance? BigDecimal (read-string "2147483647M"))) (is (instance? BigDecimal (read-string "+1M"))) (is (instance? BigDecimal (read-string "1M"))) (is (instance? BigDecimal (read-string "+0M"))) (is (instance? BigDecimal (read-string "0M"))) (is (instance? BigDecimal (read-string "-0M"))) (is (instance? BigDecimal (read-string "-1M"))) (is (instance? BigDecimal (read-string "-2147483648M"))) (is (instance? BigDecimal (read-string "+1.0e+1M"))) (is (instance? BigDecimal (read-string "+1.e+1M"))) (is (instance? BigDecimal (read-string "+1e+1M"))) (is (instance? BigDecimal (read-string "+1.0e1M"))) (is (instance? BigDecimal (read-string "+1.e1M"))) (is (instance? BigDecimal (read-string "+1e1M"))) (is (instance? BigDecimal (read-string "+1.0e-1M"))) (is (instance? BigDecimal (read-string "+1.e-1M"))) (is (instance? BigDecimal (read-string "+1e-1M"))) (is (instance? BigDecimal (read-string "1.0e+1M"))) (is (instance? BigDecimal (read-string "1.e+1M"))) (is (instance? BigDecimal (read-string "1e+1M"))) (is (instance? BigDecimal (read-string "1.0e1M"))) (is (instance? BigDecimal (read-string "1.e1M"))) (is (instance? BigDecimal (read-string "1e1M"))) (is (instance? BigDecimal (read-string "1.0e-1M"))) (is (instance? BigDecimal (read-string "1.e-1M"))) (is (instance? BigDecimal (read-string "1e-1M"))) (is (instance? BigDecimal (read-string "-1.0e+1M"))) (is (instance? BigDecimal (read-string "-1.e+1M"))) (is (instance? BigDecimal (read-string "-1e+1M"))) (is (instance? BigDecimal (read-string "-1.0e1M"))) (is (instance? BigDecimal (read-string "-1.e1M"))) (is (instance? BigDecimal (read-string "-1e1M"))) (is (instance? BigDecimal (read-string "-1.0e-1M"))) (is (instance? BigDecimal (read-string "-1.e-1M"))) (is (instance? BigDecimal (read-string "-1e-1M"))) (is (instance? BigDecimal (read-string "+1.0M"))) (is (instance? BigDecimal (read-string "+1.M"))) (is (instance? BigDecimal (read-string "1.0M"))) (is (instance? BigDecimal (read-string "1.M"))) (is (instance? BigDecimal (read-string "+0.0M"))) (is (instance? BigDecimal (read-string "+0.M"))) (is (instance? BigDecimal (read-string "0.0M"))) (is (instance? BigDecimal (read-string "0.M"))) (is (instance? BigDecimal (read-string "-0.0M"))) (is (instance? BigDecimal (read-string "-0.M"))) (is (instance? BigDecimal (read-string "-1.0M"))) (is (instance? BigDecimal (read-string "-1.M")))) (deftest read-ratio (is (== 4/2 (read-string "4/2"))) (is (== 4/2 (read-string "+4/2"))) (is (== -4/2 (read-string "-4/2")))) (deftest read-symbol (is (= 'foo (read-string "foo"))) (is (= 'foo/bar (read-string "foo/bar"))) (is (= '*+!-_? (read-string "*+!-_?"))) (is (= 'abc:def:ghi (read-string "abc:def:ghi"))) (is (= 'abc.def/ghi (read-string "abc.def/ghi"))) (is (= 'abc/def.ghi (read-string "abc/def.ghi"))) (is (= 'abc:def/ghi:jkl.mno (read-string "abc:def/ghi:jkl.mno"))) (is (instance? clojure.lang.Symbol (read-string "alphabet"))) (is (= "foo//" (str (read-string "foo//")))) ;; the clojure reader can't read this (is (= (str 'NaN) (str (read-string "##NaN")))) (is (= Double/POSITIVE_INFINITY (read-string "##Inf"))) (is (= Double/NEGATIVE_INFINITY (read-string "##-Inf")))) (deftest read-specials (is (= 'nil nil)) (is (= 'false false)) (is (= 'true true))) (deftest read-char (is (= \f (read-string "\\f"))) (is (= \u0194 (read-string "\\u0194"))) (is (= \o123 (read-string "\\o123"))) (is (= \newline (read-string "\\newline"))) (is (= (char 0) (read-string "\\o0"))) (is (= (char 0) (read-string "\\o000"))) (is (= (char 0377) (read-string "\\o377"))) (is (= \A (read-string "\\u0041"))) (is (= \@ (read-string "\\@"))) (is (= (char 0xd7ff) (read-string "\\ud7ff"))) (is (= (char 0xe000) (read-string "\\ue000"))) (is (= (char 0xffff) (read-string "\\uffff")))) (deftest read-string* (is (= "foo bar" (read-string "\"foo bar\""))) (is (= "foo\\bar" (read-string "\"foo\\\\bar\""))) (is (= "foo\000bar" (read-string "\"foo\\000bar\""))) (is (= "foo\u0194bar" (read-string "\"foo\\u0194bar\""))) (is (= "foo\123bar" (read-string "\"foo\\123bar\""))) (is (= "\060" (read-string "\"\\060\""))) (is (= "\340" (read-string "\"\\340\""))) (is (= "\377" (read-string "\"\\377\"")))) (deftest read-list (is (= '() (read-string "()"))) (is (= '(foo bar) (read-string "(foo bar)"))) (is (= '(foo (bar) baz) (read-string "(foo (bar) baz)")))) (deftest read-vector (is (= '[] (read-string "[]"))) (is (= '[foo bar] (read-string "[foo bar]"))) (is (= '[foo [bar] baz] (read-string "[foo [bar] baz]")))) (deftest read-map (is (= '{} (read-string "{}"))) (is (= '{foo bar} (read-string "{foo bar}"))) (is (= '{foo {bar baz}} (read-string "{foo {bar baz}}")))) (deftest read-set (is (= '#{} (read-string "#{}"))) (is (= '#{foo bar} (read-string "#{foo bar}"))) (is (= '#{foo #{bar} baz} (read-string "#{foo #{bar} baz}")))) (deftest read-metadata (is (= {:foo true} (meta (read-string "^:foo 'bar")))) (is (= {:foo 'bar} (meta (read-string "^{:foo bar} 'baz")))) (is (= {:tag "foo"} (meta (read-string "^\"foo\" 'bar")))) (is (= {:tag 'String} (meta (read-string "^String 'x"))))) (deftest read-namespaced-map (is (= {:foo/bar 1 :baz 2} (read-string "#:foo{:bar 1 :_/baz 2}"))) (is (= '{foo/bar 1 :baz 2} (read-string "#:foo{bar 1 :_/baz 2}")))) tools.reader-tools.reader-1.3.4/src/test/clojure/clojure/tools/metadata_test.clj000066400000000000000000000243451375401310700300550ustar00rootroot00000000000000(ns clojure.tools.metadata-test (:refer-clojure :exclude [read *default-data-reader-fn* read-string]) (:use [clojure.tools.reader :only [read *default-data-reader-fn* read-string]] [clojure.test :only [deftest is]]) (:require [clojure.tools.reader.reader-types :as reader-types] [clojure.string :as str] [clojure.walk :as walk]) (:import java.nio.charset.Charset (java.io StringReader BufferedReader) clojure.lang.LineNumberingPushbackReader)) (defn compare-forms-with-meta [expected-form actual-form] (let [comparisons (map vector (tree-seq coll? identity expected-form) (tree-seq coll? identity actual-form))] (doseq [[expected actual] comparisons] (is (= [expected (meta expected)] [actual (meta actual)]))))) (def test-contents "Contents of a file stream for testing." "(ns clojure.tools.reader.haiku)\n\n(defn haiku \"It will read the form but will the form metadata be or never become?\" [first-five middle-seven last-five] (- (apply + ^{:last last-five} [1 2 3]) first-five middle-seven))") (defn test-reader "Return a fresh byte array input stream reading off test-bytes" [test-contents] (StringReader. test-contents)) (defn replace-newlines [s replacement] (str/replace s "\n" replacement)) (def expected-haiku-ns (with-meta '(^{:line 1 :column 2 :end-line 1 :end-column 4 :file "haiku.clj"} ns ^{:line 1 :column 5 :end-line 1 :end-column 31 :file "haiku.clj"} clojure.tools.reader.haiku) {:line 1 :column 1 :end-line 1 :end-column 32 :file "haiku.clj"})) (def expected-haiku-defn (with-meta (list '^{:line 3 :column 2 :end-line 3 :end-column 6 :file "haiku.clj"} defn '^{:line 3 :column 7 :end-line 3 :end-column 12 :file "haiku.clj"} haiku "It will read the form\n but will the form metadata be\n or never become?" (with-meta ['^{:line 7 :column 6 :end-line 7 :end-column 16 :file "haiku.clj"} first-five '^{:line 7 :column 17 :end-line 7 :end-column 29 :file "haiku.clj"} middle-seven '^{:line 7 :column 30 :end-line 7 :end-column 39 :file "haiku.clj"} last-five] {:line 7 :column 5 :end-line 7 :end-column 40 :file "haiku.clj"}) (with-meta (list '^{:line 8 :column 6 :end-line 8, :end-column 7 :file "haiku.clj"} - (with-meta (list '^{:line 8 :column 9 :end-line 8 :end-column 14 :file "haiku.clj"} apply '^{:line 8 :column 15 :end-line 8 :end-column 16 :file "haiku.clj"} + ^{:last 'last-five :line 9 :column 34 :end-line 9 :end-column 41 :file "haiku.clj"} [1 2 3]) {:line 8 :column 8 :end-line 9 :end-column 42 :file "haiku.clj"}) '^{:line 10 :column 8 :end-line 10 :end-column 18 :file "haiku.clj"} first-five '^{:line 10 :column 19 :end-line 10 :end-column 31 :file "haiku.clj"} middle-seven) {:line 8 :column 5 :end-line 10 :end-column 32 :file "haiku.clj"})) {:line 3 :column 1 :end-line 10 :end-column 33 :file "haiku.clj"})) (defn multiple-reader-variants-from-string [s filename] [(-> (test-reader s) (LineNumberingPushbackReader.) (reader-types/indexing-push-back-reader 1 filename)) (-> (test-reader s) (BufferedReader.) (reader-types/indexing-push-back-reader 1 filename))]) (defn read-metadata-helper [reader] (let [first-form (read reader) second-form (read reader) third-form (read reader false :eof)] (is (= {:line 1 :column 1 :end-line 1 :end-column 32 :file "haiku.clj"} (meta first-form))) (compare-forms-with-meta expected-haiku-ns first-form) (compare-forms-with-meta expected-haiku-defn second-form) (is (= :eof third-form)))) (deftest read-metadata (doseq [s [test-contents (replace-newlines test-contents "\r") (replace-newlines test-contents "\r\n")] rdr (multiple-reader-variants-from-string s "haiku.clj")] (read-metadata-helper rdr))) (def expected-haiku-ns-with-source (with-meta '(^{:line 1 :column 2 :end-line 1 :end-column 4 :source "ns" :file "haiku.clj"} ns ^{:line 1 :column 5 :end-line 1 :end-column 31 :source "clojure.tools.reader.haiku" :file "haiku.clj"} clojure.tools.reader.haiku) {:line 1 :column 1 :end-line 1 :end-column 32 :source "(ns clojure.tools.reader.haiku)" :file "haiku.clj"})) (def expected-haiku-defn-with-source (with-meta (list '^{:line 3 :column 2 :end-line 3 :end-column 6 :source "defn" :file "haiku.clj"} defn '^{:line 3 :column 7 :end-line 3 :end-column 12 :source "haiku" :file "haiku.clj"} haiku "It will read the form\n but will the form metadata be\n or never become?" (with-meta ['^{:line 7 :column 6 :end-line 7 :end-column 16 :source "first-five" :file "haiku.clj"} first-five '^{:line 7 :column 17 :end-line 7 :end-column 29 :source "middle-seven" :file "haiku.clj"} middle-seven '^{:line 7 :column 30 :end-line 7 :end-column 39 :source "last-five" :file "haiku.clj"} last-five] {:line 7 :column 5 :end-line 7 :end-column 40 :source "[first-five middle-seven last-five]" :file "haiku.clj"}) (with-meta (list '^{:line 8 :column 6 :end-line 8, :end-column 7 :source "-" :file "haiku.clj"} - (with-meta (list '^{:line 8 :column 9 :end-line 8 :end-column 14 :source "apply" :file "haiku.clj"} apply '^{:line 8 :column 15 :end-line 8 :end-column 16 :source "+" :file "haiku.clj"} + ^{:last 'last-five :line 9 :column 34 :end-line 9 :end-column 41 :source "^{:last last-five} [1 2 3]" :file "haiku.clj"} [1 2 3]) {:line 8 :column 8 :end-line 9 :end-column 42 :source "(apply + ^{:last last-five} [1 2 3])" :file "haiku.clj"}) '^{:line 10 :column 8 :end-line 10 :end-column 18 :source "first-five" :file "haiku.clj"} first-five '^{:line 10 :column 19 :end-line 10 :end-column 31 :source "middle-seven" :file "haiku.clj"} middle-seven) {:line 8 :column 5 :end-line 10 :end-column 32 :source "(- (apply + ^{:last last-five} [1 2 3]) first-five middle-seven)" :file "haiku.clj"})) {:line 3 :column 1 :end-line 10 :end-column 33 :source "(defn haiku \"It will read the form but will the form metadata be or never become?\" [first-five middle-seven last-five] (- (apply + ^{:last last-five} [1 2 3]) first-five middle-seven))" :file "haiku.clj"})) (defn read-metadata-with-source-helper [rdr] (let [reader (-> rdr (LineNumberingPushbackReader.) (reader-types/source-logging-push-back-reader 1 "haiku.clj")) first-form (read reader) second-form (read reader)] (is (= {:line 1 :column 1 :end-line 1 :end-column 32 :source "(ns clojure.tools.reader.haiku)" :file "haiku.clj"} (meta first-form))) (compare-forms-with-meta expected-haiku-ns-with-source first-form) (compare-forms-with-meta expected-haiku-defn-with-source second-form))) (deftest read-metadata-with-source (doseq [s [test-contents (replace-newlines test-contents "\r") (replace-newlines test-contents "\r\n")]] (read-metadata-with-source-helper (test-reader s)))) (def test2-contents (str/join "\n" ["[ +42 -42 0N +042 +0x42e -0x42e -36rCRAZY -42.2e-3M 0.314e+1" " true false :kw :ns/kw 'foo/bar nil" " \\f \\u0194 \\newline \\o377 \\ud7ff " " () [7] #{8 9} '^{:meta []} bar " ;;" () [7] #{8 9} " " #inst \"2010-11-12T13:14:15.666\"" " ]"])) (def expected-vector (with-meta (vector 42 -42 0N 34 1070 -1070 -21429358 -0.0422M 3.14 true false :kw :ns/kw (list 'quote (with-meta 'foo/bar {:line 2, :column 26, :end-line 2, :end-column 33, :file "vector.clj"})) nil \f \Ɣ \newline \ÿ \퟿ (with-meta '() {:line 4, :column 2, :end-line 4, :end-column 4, :file "vector.clj"}) '^{:line 4, :column 5, :end-line 4, :end-column 8, :file "vector.clj"} [7] '^{:line 4, :column 9, :end-line 4, :end-column 15, :file "vector.clj"} #{9 8} ^{:source "'^{:meta []} bar"} (list 'quote (with-meta 'bar {:meta ^{:line 4, :column 25, :end-line 4, :end-column 27, :file "vector.clj"} [], :line 4, :column 29, :end-line 4, :end-column 32, :file "vector.clj"})) (read-string "#inst \"2010-11-12T13:14:15.666-00:00\"")) {:line 1 :column 1 :end-line 6 :end-column 3 :file "vector.clj"})) (deftest read-metadata2 (let [reader (-> (StringReader. test2-contents) (LineNumberingPushbackReader.) (reader-types/indexing-push-back-reader 1 "vector.clj")) first-form (read reader)] (compare-forms-with-meta expected-vector first-form))) (defn test-string [n linesep] (apply str (concat ["a "] (repeat n linesep) [" b"]))) (deftest many-consecutive-lineseps ;; With older versions of tools.reader, consecutive-lineseps of ;; 10,000, linesep "\r", and one of the variants of reader, would ;; cause a StackOverflowError exception. (doseq [consecutive-lineseps [1 10 10000] linesep ["\n" "\r" "\r\n"] reader (multiple-reader-variants-from-string (test-string consecutive-lineseps linesep) "foo.clj")] (let [first-form (read reader) second-form (read reader) third-form (read reader false :eof)] (is (= {:line 1 :column 1 :end-line 1 :end-column 2 :file "foo.clj"} (meta first-form))) (is (= {:line (inc consecutive-lineseps) :column 2 :end-line (inc consecutive-lineseps) :end-column 3 :file "foo.clj"} (meta second-form))) (is (= :eof third-form))))) tools.reader-tools.reader-1.3.4/src/test/clojure/clojure/tools/reader_edn_test.clj000066400000000000000000000034221375401310700303560ustar00rootroot00000000000000(ns clojure.tools.reader-edn-test (:refer-clojure :exclude [read-string]) (:use [clojure.tools.reader.edn :as edn :only [read-string]] [clojure.test :only [deftest is testing]]) (:import clojure.lang.BigInt)) (load "common_tests") (deftest read-keyword (is (= :foo-bar (read-string ":foo-bar"))) (is (= :foo/bar (read-string ":foo/bar"))) (is (= :*+!-_? (read-string ":*+!-_?"))) (is (= :abc:def:ghi (read-string ":abc:def:ghi"))) (is (= :abc.def/ghi (read-string ":abc.def/ghi"))) (is (= :abc/def.ghi (read-string ":abc/def.ghi"))) (is (= :abc:def/ghi:jkl.mno (read-string ":abc:def/ghi:jkl.mno"))) (is (instance? clojure.lang.Keyword (read-string ":alphabet"))) ) (deftest read-tagged ;; (is (= #inst "2010-11-12T13:14:15.666" ;; (read-string "#inst \"2010-11-12T13:14:15.666\""))) ;; (is (= #inst "2010-11-12T13:14:15.666" ;; (read-string "#inst\"2010-11-12T13:14:15.666\""))) ;; (is (= #uuid "550e8400-e29b-41d4-a716-446655440000" ;; (read-string "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))) ;; (is (= #uuid "550e8400-e29b-41d4-a716-446655440000" ;; (read-string "#uuid\"550e8400-e29b-41d4-a716-446655440000\""))) (is (= (java.util.UUID/fromString "550e8400-e29b-41d4-a716-446655440000") (read-string "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))) (is (= (java.util.UUID/fromString "550e8400-e29b-41d4-a716-446655440000") (read-string "#uuid\"550e8400-e29b-41d4-a716-446655440000\""))) (let [my-unknown (fn [tag val] {:unknown-tag tag :value val})] (is (= {:unknown-tag 'foo :value 'bar} (read-string {:default my-unknown} "#foo bar"))))) (deftest pushback-reader-test (testing "TRDR-63" (is (= '(+) (edn/read (java.io.PushbackReader. (java.io.StringReader. "(+)"))))))) tools.reader-tools.reader-1.3.4/src/test/clojure/clojure/tools/reader_test.clj000066400000000000000000000212621375401310700275320ustar00rootroot00000000000000(ns clojure.tools.reader-test (:refer-clojure :exclude [read read-string *default-data-reader-fn* *data-readers*]) (:use [clojure.tools.reader :only [read read-string *default-data-reader-fn* *data-readers*]] [clojure.tools.reader.reader-types :only [string-push-back-reader indexing-push-back-reader]] [clojure.test :only [deftest is are testing]] [clojure.tools.reader.impl.utils :exclude [char]]) (:require [clojure.tools.reader.edn :as tre]) (:import clojure.lang.BigInt (java.io StringReader BufferedReader) clojure.lang.LineNumberingPushbackReader)) (load "common_tests") (deftest read-keyword (is (= :foo-bar (read-string ":foo-bar"))) (is (= :foo/bar (read-string ":foo/bar"))) (is (= :user/foo-bar (binding [*ns* (the-ns 'user)] (read-string "::foo-bar")))) (is (= :clojure.core/foo-bar (do (alias 'core 'clojure.core) (read-string "::core/foo-bar")))) (is (= :*+!-_? (read-string ":*+!-_?"))) (is (= :abc:def:ghi (read-string ":abc:def:ghi"))) (is (= :abc.def/ghi (read-string ":abc.def/ghi"))) (is (= :abc/def.ghi (read-string ":abc/def.ghi"))) (is (= :abc:def/ghi:jkl.mno (read-string ":abc:def/ghi:jkl.mno"))) (is (instance? clojure.lang.Keyword (read-string ":alphabet"))) ) (deftest read-regex (is (= (str #"\[\]?(\")\\") (str (read-string "#\"\\[\\]?(\\\")\\\\\""))))) (deftest read-quote (is (= ''foo (read-string "'foo")))) (deftest read-syntax-quote (is (= '`user/foo (binding [*ns* (the-ns 'user)] (read-string "`foo")))) (is (= () (eval (read-string "`(~@[])")))) (is (= '`+ (read-string "`+"))) (is (= '`foo/bar (read-string "`foo/bar"))) (is (= '`1 (read-string "`1"))) (is (= `(1 (~2 ~@'(3))) (eval (read-string "`(1 (~2 ~@'(3)))"))))) (deftest read-deref (is (= '@foo (read-string "@foo")))) (deftest read-var (is (= '(var foo) (read-string "#'foo")))) (deftest read-fn (is (= '(fn* [] (foo bar baz)) (read-string "#(foo bar baz)")))) (deftest read-arg (is (= 14 ((eval (read-string "#(apply + % %1 %3 %&)")) 1 2 3 4 5))) (is (= 4 ((eval (read-string "#(last %&)")) 1 2 3 4)))) (deftest read-eval (is (= 3 (read-string "#=(+ 1 2)")))) (deftest read-tagged ;; (is (= #inst "2010-11-12T13:14:15.666" ;; (read-string "#inst \"2010-11-12T13:14:15.666\""))) ;; (is (= #inst "2010-11-12T13:14:15.666" ;; (read-string "#inst\"2010-11-12T13:14:15.666\""))) ;; (is (= #uuid "550e8400-e29b-41d4-a716-446655440000" ;; (read-string "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))) ;; (is (= #uuid "550e8400-e29b-41d4-a716-446655440000" ;; (read-string "#uuid\"550e8400-e29b-41d4-a716-446655440000\""))) (is (= (java.util.UUID/fromString "550e8400-e29b-41d4-a716-446655440000") (read-string "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))) (is (= (java.util.UUID/fromString "550e8400-e29b-41d4-a716-446655440000") (read-string "#uuid\"550e8400-e29b-41d4-a716-446655440000\""))) (when *default-data-reader-fn* (let [my-unknown (fn [tag val] {:unknown-tag tag :value val})] (is (= {:unknown-tag 'foo :value 'bar} (binding [*default-data-reader-fn* my-unknown] (read-string "#foo bar"))))))) (defrecord foo []) (defrecord bar [baz buz]) (deftest read-record (is (= (foo.) (read-string "#clojure.tools.reader_test.foo[]"))) (is (= (foo.) (read-string "#clojure.tools.reader_test.foo []"))) ;; not valid in clojure (is (= (foo.) (read-string "#clojure.tools.reader_test.foo{}"))) (is (= (assoc (foo.) :foo 'bar) (read-string "#clojure.tools.reader_test.foo{:foo bar}"))) (is (= (map->bar {}) (read-string "#clojure.tools.reader_test.bar{}"))) (is (= (bar. 1 nil) (read-string "#clojure.tools.reader_test.bar{:baz 1}"))) (is (= (bar. 1 nil) (read-string "#clojure.tools.reader_test.bar[1 nil]"))) (is (= (bar. 1 2) (read-string "#clojure.tools.reader_test.bar[1 2]")))) (deftest read-ctor (is (= "foo" (read-string "#java.lang.String[\"foo\"]")))) (defrecord JSValue [v]) (deftest reader-conditionals (let [opts {:read-cond :allow :features #{:clj}}] (are [out s opts] (= out (read-string opts s)) ;; basic read-cond '[foo-form] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:foo}} '[bar-form] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:bar}} '[foo-form] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:foo :bar}} '[] "[#?(:foo foo-form :bar bar-form)]" {:read-cond :allow :features #{:baz}} 'nil "#?(:default nil)" opts ;; environmental features "clojure" "#?(:clj \"clojure\" :cljs \"clojurescript\" :default \"default\")" opts ;; default features "default" "#?(:cljr \"clr\" :cljs \"cljs\" :default \"default\")" opts ;; splicing [] "[#?@(:clj [])]" opts [:a] "[#?@(:clj [:a])]" opts [:a :b] "[#?@(:clj [:a :b])]" opts [:a :b :c] "[#?@(:clj [:a :b :c])]" opts ;; nested splicing [:a :b :c :d :e] "[#?@(:clj [:a #?@(:clj [:b #?@(:clj [:c]) :d]):e])]" opts '(+ 1 (+ 2 3)) "(+ #?@(:clj [1 (+ #?@(:clj [2 3]))]))" opts '(+ (+ 2 3) 1) "(+ #?@(:clj [(+ #?@(:clj [2 3])) 1]))" opts [:a [:b [:c] :d] :e] "[#?@(:clj [:a [#?@(:clj [:b #?@(:clj [[:c]]) :d])] :e])]" opts ;; bypass unknown tagged literals [1 2 3] "#?(:cljs #js [1 2 3] :clj [1 2 3])" opts :clojure "#?(:foo #some.nonexistent.Record {:x 1} :clj :clojure)" opts) (are [re s opts] (is (thrown-with-msg? RuntimeException re (read-string opts s))) #"Features must be keywords" "#?((+ 1 2) :a)" opts #"even number of forms" "#?(:cljs :a :clj)" opts #"read-cond-splicing must implement" "(#?@(:clj :a))" opts #"is reserved" "(#?@(:foo :a :else :b))" opts #"must be a list" "#?[:foo :a :else :b]" opts #"Conditional read not allowed" "#?[:clj :a :default nil]" {:read-cond :BOGUS} #"Conditional read not allowed" "#?[:clj :a :default nil]" {})) (binding [*data-readers* {'js (fn [v] (JSValue. v) )}] (is (= (JSValue. [1 2 3]) (read-string {:features #{:cljs} :read-cond :allow} "#?(:cljs #js [1 2 3] :foo #foo [1])"))))) (deftest preserve-read-cond (is (= 1 (binding [*data-readers* {'foo (constantly 1)}] (read-string {:read-cond :preserve} "#foo []")))) (let [x (read-string {:read-cond :preserve} "#?(:clj foo :cljs bar)")] (is (reader-conditional? x)) (is (= x (reader-conditional '(:clj foo :cljs bar) false))) (is (not (:splicing? x))) (is (= :foo (get x :no-such-key :foo))) (is (= (:form x) '(:clj foo :cljs bar)))) (let [x (first (read-string {:read-cond :preserve} "(#?@(:clj [foo]))"))] (is (reader-conditional? x)) (is (= x (reader-conditional '(:clj [foo]) true))) (is (:splicing? x)) (is (= :foo (get x :no-such-key :foo))) (is (= (:form x) '(:clj [foo])))) (is (thrown-with-msg? RuntimeException #"No reader function for tag" (read-string {:read-cond :preserve} "#js {:x 1 :y 2}" ))) (let [x (read-string {:read-cond :preserve} "#?(:cljs #js {:x 1 :y 2})") [platform tl] (:form x)] (is (reader-conditional? x)) (is (tagged-literal? tl)) (is (= tl (tagged-literal 'js {:x 1 :y 2}))) (is (= 'js (:tag tl))) (is (= {:x 1 :y 2} (:form tl))) (is (= :foo (get tl :no-such-key :foo)))) (testing "print form roundtrips" (doseq [s ["#?(:clj foo :cljs bar)" "#?(:cljs #js {:x 1, :y 2})" "#?(:clj #clojure.test_clojure.reader.TestRecord [42 85])"]] (is (= s (pr-str (read-string {:read-cond :preserve} s))))))) (alias 'c.c 'clojure.core) (deftest read-namespaced-map (binding [*ns* (the-ns 'clojure.tools.reader-test)] (is (= {::foo 1} (read-string "#::{:foo 1}"))) (is (= {::foo 1 :bar 2} (read-string "#::{:foo 1 :_/bar 2}"))) (is (= {:a/foo 1 :bar 2} (read-string "#:a{:foo 1 :_/bar 2}"))) (is (= {:clojure.core/foo 2} (read-string "#::c.c{:foo 2}"))))) (defn multiple-reader-variants-from-string [s filename] [(-> (StringReader. s) (LineNumberingPushbackReader.) (indexing-push-back-reader 1 filename)) (-> (StringReader. s) (BufferedReader.) (indexing-push-back-reader 1 filename))]) (defn first-reads-from-multiple-readers [s] (for [rdr (multiple-reader-variants-from-string s "file.edn")] (tre/read rdr))) (deftest trdr-54 (let [read-vals (mapcat first-reads-from-multiple-readers ["[a\rb]" "[a\r b]" "[a \rb]"])] (doseq [pairs (partition 2 1 read-vals)] (is (= (first pairs) (second pairs))))))