clementine 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +4 -2
  3. data/LICENSE.txt +22 -0
  4. data/README.md +11 -6
  5. data/Rakefile +22 -0
  6. data/clementine.gemspec +2 -1
  7. data/ext/clojure-clojurescript-bef56a7/.gitignore +13 -0
  8. data/ext/clojure-clojurescript-bef56a7/Clojurescript.iml +12 -0
  9. data/ext/clojure-clojurescript-bef56a7/README.md +29 -0
  10. data/ext/clojure-clojurescript-bef56a7/benchmark/cljs/benchmark_runner.cljs +155 -0
  11. data/ext/clojure-clojurescript-bef56a7/bin/cljsc +21 -0
  12. data/ext/clojure-clojurescript-bef56a7/bin/cljsc.bat +18 -0
  13. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/bin/cljsc.clj +0 -0
  14. data/ext/clojure-clojurescript-bef56a7/devnotes/README.org +35 -0
  15. data/ext/clojure-clojurescript-bef56a7/devnotes/bcrepl.org +13 -0
  16. data/ext/clojure-clojurescript-bef56a7/devnotes/cljs.org +500 -0
  17. data/ext/clojure-clojurescript-bef56a7/devnotes/corelib.org +583 -0
  18. data/ext/clojure-clojurescript-bef56a7/devnotes/day1.org +203 -0
  19. data/ext/clojure-clojurescript-bef56a7/devnotes/day2.org +44 -0
  20. data/ext/clojure-clojurescript-bef56a7/devnotes/talk.org +126 -0
  21. data/ext/clojure-clojurescript-bef56a7/devnotes/testing +13 -0
  22. data/ext/clojure-clojurescript-bef56a7/devnotes/todo.org +121 -0
  23. data/ext/clojure-clojurescript-bef56a7/epl-v10.html +261 -0
  24. data/ext/clojure-clojurescript-bef56a7/pom.template.xml +88 -0
  25. data/ext/clojure-clojurescript-bef56a7/samples/dom/.gitignore +2 -0
  26. data/ext/clojure-clojurescript-bef56a7/samples/dom/src/dom/test.cljs +48 -0
  27. data/ext/clojure-clojurescript-bef56a7/samples/dom/test.html +30 -0
  28. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/.gitignore +2 -0
  29. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/README.md +53 -0
  30. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externed-lib.js +7 -0
  31. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externs.js +3 -0
  32. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-extern.html +14 -0
  33. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js-dev.html +18 -0
  34. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js.html +17 -0
  35. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/my-external-lib.js +3 -0
  36. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/core.cljs +9 -0
  37. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/extern-example.cljs +5 -0
  38. data/ext/clojure-clojurescript-bef56a7/samples/hello/.gitignore +2 -0
  39. data/ext/clojure-clojurescript-bef56a7/samples/hello/README.md +34 -0
  40. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello-dev.html +18 -0
  41. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello.html +13 -0
  42. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/core.cljs +8 -0
  43. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/foo/bar.cljs +4 -0
  44. data/ext/clojure-clojurescript-bef56a7/samples/nodehello.cljs +18 -0
  45. data/ext/clojure-clojurescript-bef56a7/samples/nodels.cljs +17 -0
  46. data/ext/clojure-clojurescript-bef56a7/samples/repl/.gitignore +2 -0
  47. data/ext/clojure-clojurescript-bef56a7/samples/repl/README.md +101 -0
  48. data/ext/clojure-clojurescript-bef56a7/samples/repl/index.html +27 -0
  49. data/ext/clojure-clojurescript-bef56a7/samples/repl/src/repl/test.cljs +73 -0
  50. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/.gitignore +2 -0
  51. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/README.md +42 -0
  52. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index-advanced.html +80 -0
  53. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index.html +88 -0
  54. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/reset.css +48 -0
  55. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/anneal.cljs +66 -0
  56. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/core.cljs +307 -0
  57. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/dom-helpers.cljs +95 -0
  58. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/layout.cljs +100 -0
  59. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/leaderboard.cljs +40 -0
  60. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/radial.cljs +91 -0
  61. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/showgraph.cljs +121 -0
  62. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/timeline.cljs +39 -0
  63. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/style.css +301 -0
  64. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/test_data.txt +1 -0
  65. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/tweet_maps.txt +1 -0
  66. data/ext/clojure-clojurescript-bef56a7/script/benchmark +30 -0
  67. data/ext/clojure-clojurescript-bef56a7/script/bootstrap +70 -0
  68. data/ext/clojure-clojurescript-bef56a7/script/browser-repl +16 -0
  69. data/ext/clojure-clojurescript-bef56a7/script/build +59 -0
  70. data/ext/clojure-clojurescript-bef56a7/script/clean +5 -0
  71. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library-third-party.pom.template +59 -0
  72. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library.pom.template +54 -0
  73. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/make-closure-library-jars.sh +87 -0
  74. data/ext/clojure-clojurescript-bef56a7/script/compile +41 -0
  75. data/ext/clojure-clojurescript-bef56a7/script/repl +13 -0
  76. data/ext/clojure-clojurescript-bef56a7/script/repl.bat +13 -0
  77. data/ext/clojure-clojurescript-bef56a7/script/repljs +15 -0
  78. data/ext/clojure-clojurescript-bef56a7/script/repljs.bat +14 -0
  79. data/ext/clojure-clojurescript-bef56a7/script/test +38 -0
  80. data/ext/clojure-clojurescript-bef56a7/script/test-compile +30 -0
  81. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/analyzer.clj +975 -0
  82. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/closure.clj +173 -73
  83. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/compiler.clj +1081 -0
  84. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/core.clj +1158 -0
  85. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl.clj +51 -25
  86. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/browser.clj +258 -0
  87. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/reflect.clj +75 -0
  88. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl/rhino.clj +6 -5
  89. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/server.clj +173 -0
  90. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/tagged_literals.clj +30 -0
  91. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/core.cljs +7197 -0
  92. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs.cljs +1 -1
  93. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs_externs.js +0 -0
  94. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejscli.cljs +1 -1
  95. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/reader.cljs +551 -0
  96. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/dom.cljs +59 -13
  97. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/event.cljs +0 -0
  98. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/net.cljs +8 -7
  99. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/repl.cljs +2 -2
  100. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/core/reducers.cljs +298 -0
  101. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/data.cljs +162 -0
  102. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/reflect.cljs +48 -0
  103. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/set.cljs +0 -0
  104. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/string.cljs +4 -10
  105. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/walk.cljs +0 -0
  106. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/zip.cljs +0 -0
  107. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test.cljs +7 -0
  108. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test_other_ns.cljs +3 -0
  109. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/core_test.cljs +1678 -0
  110. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test.cljs +11 -0
  111. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test/foo.cljs +5 -0
  112. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/letfn_test.cljs +19 -0
  113. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test.cljs +6 -0
  114. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test/macros.clj +5 -0
  115. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test.cljs +14 -0
  116. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/bar.cljs +3 -0
  117. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/foo.cljs +7 -0
  118. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/reader_test.cljs +124 -0
  119. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/data_test.cljs +22 -0
  120. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/string_test.cljs +97 -0
  121. data/ext/clojure-clojurescript-bef56a7/test/cljs/foo/ns_shadow_test.cljs +9 -0
  122. data/ext/clojure-clojurescript-bef56a7/test/cljs/test_runner.cljs +26 -0
  123. data/lib/clementine.rb +3 -24
  124. data/lib/clementine/clojurescript_engine.rb +9 -48
  125. data/lib/clementine/clojurescript_engine/base.rb +15 -0
  126. data/lib/clementine/clojurescript_engine/jruby.rb +46 -0
  127. data/lib/clementine/{clojurescript_engine_mri.rb → clojurescript_engine/mri.rb} +17 -10
  128. data/lib/clementine/version.rb +1 -1
  129. data/test/clojurescript_engine_test.rb +36 -14
  130. metadata +177 -83
  131. data/vendor/assets/lib/clojure.jar +0 -0
  132. data/vendor/assets/lib/compiler.jar +0 -0
  133. data/vendor/assets/lib/goog.jar +0 -0
  134. data/vendor/assets/lib/js.jar +0 -0
  135. data/vendor/assets/src/clj/cljs/compiler.clj +0 -1341
  136. data/vendor/assets/src/clj/cljs/core.clj +0 -702
  137. data/vendor/assets/src/clj/cljs/repl/browser.clj +0 -341
  138. data/vendor/assets/src/cljs/cljs/core.cljs +0 -3330
  139. data/vendor/assets/src/cljs/cljs/reader.cljs +0 -360
@@ -8,4 +8,4 @@
8
8
  (def process (js* "process"))
9
9
 
10
10
  ; Have ClojureScript print using Node's sys.print function
11
- (set! cljs.core/string-print (.print (require "sys")))
11
+ (set! cljs.core/string-print (.-print (require "util")))
@@ -5,5 +5,5 @@
5
5
  (:require [cljs.nodejs :as nodejs]))
6
6
 
7
7
  ; Call the user's main function
8
- (apply cljs.core/*main-cli-fn* (drop 2 (.argv nodejs/process)))
8
+ (apply cljs.core/*main-cli-fn* (drop 2 (.-argv nodejs/process)))
9
9
 
@@ -0,0 +1,551 @@
1
+ ; Copyright (c) Rich Hickey. All rights reserved.
2
+ ; The use and distribution terms for this software are covered by the
3
+ ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4
+ ; which can be found in the file epl-v10.html at the root of this distribution.
5
+ ; By using this software in any fashion, you are agreeing to be bound by
6
+ ; the terms of this license.
7
+ ; You must not remove this notice, or any other, from this software.
8
+
9
+ (ns cljs.reader
10
+ (:require [goog.string :as gstring]))
11
+
12
+ (defprotocol PushbackReader
13
+ (read-char [reader] "Returns the next char from the Reader,
14
+ nil if the end of stream has been reached")
15
+ (unread [reader ch] "Push back a single character on to the stream"))
16
+
17
+ ; Using two atoms is less idomatic, but saves the repeat overhead of map creation
18
+ (deftype StringPushbackReader [s index-atom buffer-atom]
19
+ PushbackReader
20
+ (read-char [reader]
21
+ (if (empty? @buffer-atom)
22
+ (let [idx @index-atom]
23
+ (swap! index-atom inc)
24
+ (aget s idx))
25
+ (let [buf @buffer-atom]
26
+ (swap! buffer-atom rest)
27
+ (first buf))))
28
+ (unread [reader ch] (swap! buffer-atom #(cons ch %))))
29
+
30
+ (defn push-back-reader [s]
31
+ "Creates a StringPushbackReader from a given string"
32
+ (StringPushbackReader. s (atom 0) (atom nil)))
33
+
34
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35
+ ;; predicates
36
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
37
+
38
+ (defn- ^boolean whitespace?
39
+ "Checks whether a given character is whitespace"
40
+ [ch]
41
+ (or (gstring/isBreakingWhitespace ch) (identical? \, ch)))
42
+
43
+ (defn- ^boolean numeric?
44
+ "Checks whether a given character is numeric"
45
+ [ch]
46
+ (gstring/isNumeric ch))
47
+
48
+ (defn- ^boolean comment-prefix?
49
+ "Checks whether the character begins a comment."
50
+ [ch]
51
+ (identical? \; ch))
52
+
53
+ (defn- ^boolean number-literal?
54
+ "Checks whether the reader is at the start of a number literal"
55
+ [reader initch]
56
+ (or (numeric? initch)
57
+ (and (or (identical? \+ initch) (identical? \- initch))
58
+ (numeric? (let [next-ch (read-char reader)]
59
+ (unread reader next-ch)
60
+ next-ch)))))
61
+
62
+ (declare read macros dispatch-macros)
63
+
64
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
65
+ ;; read helpers
66
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
67
+
68
+
69
+ ; later will do e.g. line numbers...
70
+ (defn reader-error
71
+ [rdr & msg]
72
+ (throw (js/Error. (apply str msg))))
73
+
74
+ (defn ^boolean macro-terminating? [ch]
75
+ (and (not (identical? ch "#"))
76
+ (not (identical? ch \'))
77
+ (not (identical? ch ":"))
78
+ (macros ch)))
79
+
80
+ (defn read-token
81
+ [rdr initch]
82
+ (loop [sb (gstring/StringBuffer. initch)
83
+ ch (read-char rdr)]
84
+ (if (or (nil? ch)
85
+ (whitespace? ch)
86
+ (macro-terminating? ch))
87
+ (do (unread rdr ch) (. sb (toString)))
88
+ (recur (do (.append sb ch) sb) (read-char rdr)))))
89
+
90
+ (defn skip-line
91
+ "Advances the reader to the end of a line. Returns the reader"
92
+ [reader _]
93
+ (loop []
94
+ (let [ch (read-char reader)]
95
+ (if (or (identical? ch \n) (identical? ch \r) (nil? ch))
96
+ reader
97
+ (recur)))))
98
+
99
+ (def int-pattern (re-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)?"))
100
+ (def ratio-pattern (re-pattern "([-+]?[0-9]+)/([0-9]+)"))
101
+ (def float-pattern (re-pattern "([-+]?[0-9]+(\\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?"))
102
+ (def symbol-pattern (re-pattern "[:]?([^0-9/].*/)?([^0-9/][^/]*)"))
103
+
104
+ (defn- re-find*
105
+ [re s]
106
+ (let [matches (.exec re s)]
107
+ (when-not (nil? matches)
108
+ (if (== (alength matches) 1)
109
+ (aget matches 0)
110
+ matches))))
111
+
112
+ (defn- match-int
113
+ [s]
114
+ (let [groups (re-find* int-pattern s)
115
+ group3 (aget groups 2)]
116
+ (if-not (or (nil? group3)
117
+ (< (alength group3) 1))
118
+ 0
119
+ (let [negate (if (identical? "-" (aget groups 1)) -1 1)
120
+ a (cond
121
+ (aget groups 3) (array (aget groups 3) 10)
122
+ (aget groups 4) (array (aget groups 4) 16)
123
+ (aget groups 5) (array (aget groups 5) 8)
124
+ (aget groups 7) (array (aget groups 7) (js/parseInt (aget groups 7)))
125
+ :default (array nil nil))
126
+ n (aget a 0)
127
+ radix (aget a 1)]
128
+ (if (nil? n)
129
+ nil
130
+ (* negate (js/parseInt n radix)))))))
131
+
132
+
133
+ (defn- match-ratio
134
+ [s]
135
+ (let [groups (re-find* ratio-pattern s)
136
+ numinator (aget groups 1)
137
+ denominator (aget groups 2)]
138
+ (/ (js/parseInt numinator) (js/parseInt denominator))))
139
+
140
+ (defn- match-float
141
+ [s]
142
+ (js/parseFloat s))
143
+
144
+ (defn- re-matches*
145
+ [re s]
146
+ (let [matches (.exec re s)]
147
+ (when (and (not (nil? matches))
148
+ (identical? (aget matches 0) s))
149
+ (if (== (alength matches) 1)
150
+ (aget matches 0)
151
+ matches))))
152
+
153
+ (defn- match-number
154
+ [s]
155
+ (cond
156
+ (re-matches* int-pattern s) (match-int s)
157
+ (re-matches* ratio-pattern s) (match-ratio s)
158
+ (re-matches* float-pattern s) (match-float s)))
159
+
160
+ (defn escape-char-map [c]
161
+ (cond
162
+ (identical? c \t) "\t"
163
+ (identical? c \r) "\r"
164
+ (identical? c \n) "\n"
165
+ (identical? c \\) \\
166
+ (identical? c \") \"
167
+ (identical? c \b) "\b"
168
+ (identical? c \f) "\f"
169
+ :else nil))
170
+
171
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172
+ ;; unicode
173
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
174
+
175
+ (defn read-2-chars [reader]
176
+ (.toString
177
+ (gstring/StringBuffer.
178
+ (read-char reader)
179
+ (read-char reader))))
180
+
181
+ (defn read-4-chars [reader]
182
+ (.toString
183
+ (gstring/StringBuffer.
184
+ (read-char reader)
185
+ (read-char reader)
186
+ (read-char reader)
187
+ (read-char reader))))
188
+
189
+ (def unicode-2-pattern (re-pattern "[0-9A-Fa-f]{2}"))
190
+ (def unicode-4-pattern (re-pattern "[0-9A-Fa-f]{4}"))
191
+
192
+ (defn validate-unicode-escape [unicode-pattern reader escape-char unicode-str]
193
+ (if (re-matches unicode-pattern unicode-str)
194
+ unicode-str
195
+ (reader-error reader "Unexpected unicode escape \\" escape-char unicode-str)))
196
+
197
+ (defn make-unicode-char [code-str]
198
+ (let [code (js/parseInt code-str 16)]
199
+ (.fromCharCode js/String code)))
200
+
201
+ (defn escape-char
202
+ [buffer reader]
203
+ (let [ch (read-char reader)
204
+ mapresult (escape-char-map ch)]
205
+ (if mapresult
206
+ mapresult
207
+ (cond
208
+ (identical? ch \x)
209
+ (->> (read-2-chars reader)
210
+ (validate-unicode-escape unicode-2-pattern reader ch)
211
+ (make-unicode-char))
212
+
213
+ (identical? ch \u)
214
+ (->> (read-4-chars reader)
215
+ (validate-unicode-escape unicode-4-pattern reader ch)
216
+ (make-unicode-char))
217
+
218
+ (numeric? ch)
219
+ (.fromCharCode js/String ch)
220
+
221
+ :else
222
+ (reader-error reader "Unexpected unicode escape \\" ch )))))
223
+
224
+ (defn read-past
225
+ "Read until first character that doesn't match pred, returning
226
+ char."
227
+ [pred rdr]
228
+ (loop [ch (read-char rdr)]
229
+ (if (pred ch)
230
+ (recur (read-char rdr))
231
+ ch)))
232
+
233
+ (defn read-delimited-list
234
+ [delim rdr recursive?]
235
+ (loop [a (transient [])]
236
+ (let [ch (read-past whitespace? rdr)]
237
+ (when-not ch (reader-error rdr "EOF while reading"))
238
+ (if (identical? delim ch)
239
+ (persistent! a)
240
+ (if-let [macrofn (macros ch)]
241
+ (let [mret (macrofn rdr ch)]
242
+ (recur (if (identical? mret rdr) a (conj! a mret))))
243
+ (do
244
+ (unread rdr ch)
245
+ (let [o (read rdr true nil recursive?)]
246
+ (recur (if (identical? o rdr) a (conj! a o))))))))))
247
+
248
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
249
+ ;; data structure readers
250
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
251
+
252
+ (defn not-implemented
253
+ [rdr ch]
254
+ (reader-error rdr "Reader for " ch " not implemented yet"))
255
+
256
+ (declare maybe-read-tagged-type)
257
+
258
+ (defn read-dispatch
259
+ [rdr _]
260
+ (let [ch (read-char rdr)
261
+ dm (dispatch-macros ch)]
262
+ (if dm
263
+ (dm rdr _)
264
+ (if-let [obj (maybe-read-tagged-type rdr ch)]
265
+ obj
266
+ (reader-error rdr "No dispatch macro for " ch)))))
267
+
268
+ (defn read-unmatched-delimiter
269
+ [rdr ch]
270
+ (reader-error rdr "Unmached delimiter " ch))
271
+
272
+ (defn read-list
273
+ [rdr _]
274
+ (apply list (read-delimited-list ")" rdr true)))
275
+
276
+ (def read-comment skip-line)
277
+
278
+ (defn read-vector
279
+ [rdr _]
280
+ (read-delimited-list "]" rdr true))
281
+
282
+ (defn read-map
283
+ [rdr _]
284
+ (let [l (read-delimited-list "}" rdr true)]
285
+ (when (odd? (count l))
286
+ (reader-error rdr "Map literal must contain an even number of forms"))
287
+ (apply hash-map l)))
288
+
289
+ (defn read-number
290
+ [reader initch]
291
+ (loop [buffer (gstring/StringBuffer. initch)
292
+ ch (read-char reader)]
293
+ (if (or (nil? ch) (whitespace? ch) (macros ch))
294
+ (do
295
+ (unread reader ch)
296
+ (let [s (. buffer (toString))]
297
+ (or (match-number s)
298
+ (reader-error reader "Invalid number format [" s "]"))))
299
+ (recur (do (.append buffer ch) buffer) (read-char reader)))))
300
+
301
+ (defn read-string*
302
+ [reader _]
303
+ (loop [buffer (gstring/StringBuffer.)
304
+ ch (read-char reader)]
305
+ (cond
306
+ (nil? ch) (reader-error reader "EOF while reading")
307
+ (identical? "\\" ch) (recur (do (.append buffer (escape-char buffer reader)) buffer)
308
+ (read-char reader))
309
+ (identical? \" ch) (. buffer (toString))
310
+ :default (recur (do (.append buffer ch) buffer) (read-char reader)))))
311
+
312
+ (defn special-symbols [t not-found]
313
+ (cond
314
+ (identical? t "nil") nil
315
+ (identical? t "true") true
316
+ (identical? t "false") false
317
+ :else not-found))
318
+
319
+ (defn read-symbol
320
+ [reader initch]
321
+ (let [token (read-token reader initch)]
322
+ (if (gstring/contains token "/")
323
+ (symbol (subs token 0 (.indexOf token "/"))
324
+ (subs token (inc (.indexOf token "/")) (.-length token)))
325
+ (special-symbols token (symbol token)))))
326
+
327
+ (defn read-keyword
328
+ [reader initch]
329
+ (let [token (read-token reader (read-char reader))
330
+ a (re-matches* symbol-pattern token)
331
+ token (aget a 0)
332
+ ns (aget a 1)
333
+ name (aget a 2)]
334
+ (if (or (and (not (undefined? ns))
335
+ (identical? (. ns (substring (- (.-length ns) 2) (.-length ns))) ":/"))
336
+ (identical? (aget name (dec (.-length name))) ":")
337
+ (not (== (.indexOf token "::" 1) -1)))
338
+ (reader-error reader "Invalid token: " token)
339
+ (if (and (not (nil? ns)) (> (.-length ns) 0))
340
+ (keyword (.substring ns 0 (.indexOf ns "/")) name)
341
+ (keyword token)))))
342
+
343
+ (defn desugar-meta
344
+ [f]
345
+ (cond
346
+ (symbol? f) {:tag f}
347
+ (string? f) {:tag f}
348
+ (keyword? f) {f true}
349
+ :else f))
350
+
351
+ (defn wrapping-reader
352
+ [sym]
353
+ (fn [rdr _]
354
+ (list sym (read rdr true nil true))))
355
+
356
+ (defn throwing-reader
357
+ [msg]
358
+ (fn [rdr _]
359
+ (reader-error rdr msg)))
360
+
361
+ (defn read-meta
362
+ [rdr _]
363
+ (let [m (desugar-meta (read rdr true nil true))]
364
+ (when-not (map? m)
365
+ (reader-error rdr "Metadata must be Symbol,Keyword,String or Map"))
366
+ (let [o (read rdr true nil true)]
367
+ (if (satisfies? IWithMeta o)
368
+ (with-meta o (merge (meta o) m))
369
+ (reader-error rdr "Metadata can only be applied to IWithMetas")))))
370
+
371
+ (defn read-set
372
+ [rdr _]
373
+ (set (read-delimited-list "}" rdr true)))
374
+
375
+ (defn read-regex
376
+ [rdr ch]
377
+ (-> (read-string* rdr ch) re-pattern))
378
+
379
+ (defn read-discard
380
+ [rdr _]
381
+ (read rdr true nil true)
382
+ rdr)
383
+
384
+ (defn macros [c]
385
+ (cond
386
+ (identical? c \") read-string*
387
+ (identical? c \:) read-keyword
388
+ (identical? c \;) not-implemented ;; never hit this
389
+ (identical? c \') (wrapping-reader 'quote)
390
+ (identical? c \@) (wrapping-reader 'deref)
391
+ (identical? c \^) read-meta
392
+ (identical? c \`) not-implemented
393
+ (identical? c \~) not-implemented
394
+ (identical? c \() read-list
395
+ (identical? c \)) read-unmatched-delimiter
396
+ (identical? c \[) read-vector
397
+ (identical? c \]) read-unmatched-delimiter
398
+ (identical? c \{) read-map
399
+ (identical? c \}) read-unmatched-delimiter
400
+ (identical? c \\) read-char
401
+ (identical? c \%) not-implemented
402
+ (identical? c \#) read-dispatch
403
+ :else nil))
404
+
405
+ ;; omitted by design: var reader, eval reader
406
+ (defn dispatch-macros [s]
407
+ (cond
408
+ (identical? s "{") read-set
409
+ (identical? s "<") (throwing-reader "Unreadable form")
410
+ (identical? s "\"") read-regex
411
+ (identical? s"!") read-comment
412
+ (identical? s "_") read-discard
413
+ :else nil))
414
+
415
+ (defn read
416
+ "Reads the first object from a PushbackReader. Returns the object read.
417
+ If EOF, throws if eof-is-error is true. Otherwise returns sentinel."
418
+ [reader eof-is-error sentinel is-recursive]
419
+ (let [ch (read-char reader)]
420
+ (cond
421
+ (nil? ch) (if eof-is-error (reader-error reader "EOF while reading") sentinel)
422
+ (whitespace? ch) (recur reader eof-is-error sentinel is-recursive)
423
+ (comment-prefix? ch) (recur (read-comment reader ch) eof-is-error sentinel is-recursive)
424
+ :else (let [f (macros ch)
425
+ res
426
+ (cond
427
+ f (f reader ch)
428
+ (number-literal? reader ch) (read-number reader ch)
429
+ :else (read-symbol reader ch))]
430
+ (if (identical? res reader)
431
+ (recur reader eof-is-error sentinel is-recursive)
432
+ res)))))
433
+
434
+ (defn read-string
435
+ "Reads one object from the string s"
436
+ [s]
437
+ (let [r (push-back-reader s)]
438
+ (read r true nil false)))
439
+
440
+
441
+ ;; read instances
442
+
443
+ (defn ^:private zero-fill-right [s width]
444
+ (cond (= width (count s)) s
445
+ (< width (count s)) (.substring s 0 width)
446
+ :else (loop [b (gstring/StringBuffer. s)]
447
+ (if (< (.getLength b) width)
448
+ (recur (.append b \0))
449
+ (.toString b)))))
450
+
451
+ (defn ^:private divisible?
452
+ [num div]
453
+ (zero? (mod num div)))
454
+
455
+ (defn ^:private indivisible?
456
+ [num div]
457
+ (not (divisible? num div)))
458
+
459
+ (defn ^:private leap-year?
460
+ [year]
461
+ (and (divisible? year 4)
462
+ (or (indivisible? year 100)
463
+ (divisible? year 400))))
464
+
465
+ (def ^:private days-in-month
466
+ (let [dim-norm [nil 31 28 31 30 31 30 31 31 30 31 30 31]
467
+ dim-leap [nil 31 29 31 30 31 30 31 31 30 31 30 31]]
468
+ (fn [month leap-year?]
469
+ (get (if leap-year? dim-leap dim-norm) month))))
470
+
471
+ (def ^:private parse-and-validate-timestamp
472
+ (let [timestamp #"(\d\d\d\d)(?:-(\d\d)(?:-(\d\d)(?:[T](\d\d)(?::(\d\d)(?::(\d\d)(?:[.](\d+))?)?)?)?)?)?(?:[Z]|([-+])(\d\d):(\d\d))?"
473
+ check (fn [low n high msg]
474
+ (assert (<= low n high) (str msg " Failed: " low "<=" n "<=" high))
475
+ n)]
476
+ (fn [ts]
477
+ (when-let [[[_ years months days hours minutes seconds milliseconds] [_ _ _] :as V]
478
+ (->> ts
479
+ (re-matches timestamp)
480
+ (split-at 8)
481
+ (map vec))]
482
+ (let [[[_ y mo d h m s ms] [offset-sign offset-hours offset-minutes]]
483
+ (->> V
484
+ (map #(update-in %2 [0] %)
485
+ [(constantly nil) #(if (= % "-") "-1" "1")])
486
+ (map (fn [v] (map #(js/parseInt % 10) v))))
487
+ offset (* offset-sign (+ (* offset-hours 60) offset-minutes))]
488
+ [(if-not years 1970 y)
489
+ (if-not months 1 (check 1 mo 12 "timestamp month field must be in range 1..12"))
490
+ (if-not days 1 (check 1 d (days-in-month mo (leap-year? y)) "timestamp day field must be in range 1..last day in month"))
491
+ (if-not hours 0 (check 0 h 23 "timestamp hour field must be in range 0..23"))
492
+ (if-not minutes 0 (check 0 m 59 "timestamp minute field must be in range 0..59"))
493
+ (if-not seconds 0 (check 0 s (if (= m 59) 60 59) "timestamp second field must be in range 0..60"))
494
+ (if-not milliseconds 0 (check 0 ms 999 "timestamp millisecond field must be in range 0..999"))
495
+ offset])))))
496
+
497
+ (defn parse-timestamp
498
+ [ts]
499
+ (if-let [[years months days hours minutes seconds ms offset]
500
+ (parse-and-validate-timestamp ts)]
501
+ (js/Date.
502
+ (- (.UTC js/Date years (dec months) days hours minutes seconds ms)
503
+ (* offset 60 1000)))
504
+ (reader-error nil (str "Unrecognized date/time syntax: " ts))))
505
+
506
+ (defn ^:private read-date
507
+ [s]
508
+ (if (string? s)
509
+ (parse-timestamp s)
510
+ (reader-error nil "Instance literal expects a string for its timestamp.")))
511
+
512
+
513
+ (defn ^:private read-queue
514
+ [elems]
515
+ (if (vector? elems)
516
+ (into cljs.core.PersistentQueue/EMPTY elems)
517
+ (reader-error nil "Queue literal expects a vector for its elements.")))
518
+
519
+
520
+ (defn ^:private read-uuid
521
+ [uuid]
522
+ (if (string? uuid)
523
+ (UUID. uuid)
524
+ (reader-error nil "UUID literal expects a string as its representation.")))
525
+
526
+ (def *tag-table* (atom {"inst" read-date
527
+ "uuid" read-uuid
528
+ "queue" read-queue}))
529
+
530
+ (defn maybe-read-tagged-type
531
+ [rdr initch]
532
+ (let [tag (read-symbol rdr initch)]
533
+ (if-let [pfn (get @*tag-table* (name tag))]
534
+ (pfn (read rdr true nil false))
535
+ (reader-error rdr
536
+ "Could not find tag parser for " (name tag)
537
+ " in " (pr-str (keys @*tag-table*))))))
538
+
539
+ (defn register-tag-parser!
540
+ [tag f]
541
+ (let [tag (name tag)
542
+ old-parser (get @*tag-table* tag)]
543
+ (swap! *tag-table* assoc tag f)
544
+ old-parser))
545
+
546
+ (defn deregister-tag-parser!
547
+ [tag]
548
+ (let [tag (name tag)
549
+ old-parser (get @*tag-table* tag)]
550
+ (swap! *tag-table* dissoc tag)
551
+ old-parser))