clementine 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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))