Advertisement
Guest User

Untitled

a guest
Feb 21st, 2019
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.66 KB | None | 0 0
  1. (ns polydact.core
  2. (:import (clojure.lang IFn)
  3. (org.graalvm.polyglot Context Value)
  4. (org.graalvm.polyglot.proxy ProxyArray ProxyExecutable ProxyObject)))
  5.  
  6. (set! *warn-on-reflection* true)
  7.  
  8. (comment
  9. (do
  10. (def context
  11. (.build (Context/newBuilder (into-array ["js"]))))
  12.  
  13. (defn ^Value eval-js [code]
  14. (.eval ^Context context "js" code)))
  15.  
  16. (.as (eval-js "Number.MAX_VALUE") Object)
  17. ;=> 1.7976931348623157E308
  18. (type *1)
  19. ;=> java.lang.Double
  20.  
  21. (.as (eval-js "[{}]") Object)
  22. ;=> {"0" {}}
  23. (.as (eval-js "[{}]") java.util.List)
  24. ;=> ({})
  25.  
  26. #_cool!)
  27.  
  28. (defn- execute
  29. [^Value execable & args]
  30. (.execute execable (object-array args)))
  31.  
  32. (declare value->clj)
  33.  
  34. (defmacro ^:private reify-ifn
  35. "Convenience macro for reifying IFn for executable polyglot Values."
  36. [v]
  37. (let [invoke-arity
  38. (fn [n]
  39. (let [args (map #(symbol (str "arg" (inc %))) (range n))]
  40. (if (seq args)
  41. ;; TODO test edge case for final `invoke` arity w/varargs
  42. `(~'invoke [this# ~@args] (value->clj (execute ~v ~@args)))
  43. `(~'invoke [this#] (value->clj (execute ~v))))))]
  44. `(reify IFn
  45. ~@(map invoke-arity (range 22))
  46. (~'applyTo [this# args#] (value->clj (apply execute ~v args#))))))
  47. (macroexpand '(reify-ifn v))
  48.  
  49. (defn proxy-fn
  50. "Returns a ProxyExecutable instance for given function, allowing it to be
  51. invoked from polyglot contexts."
  52. [f]
  53. (reify ProxyExecutable
  54. (execute [_this args]
  55. (apply f (map value->clj args)))))
  56.  
  57. (defn value->clj
  58. "Returns a Clojure (or Java) value for given polyglot Value if possible,
  59. otherwise throws."
  60. [^Value v]
  61. (cond
  62. (.isNull v) nil
  63. (.isHostObject v) (.asHostObject v)
  64. (.isBoolean v) (.asBoolean v)
  65. (.isString v) (.asString v)
  66. (.isNumber v) (.as v Number)
  67. (.canExecute v) (reify-ifn v)
  68. (.hasArrayElements v) (into []
  69. (for [i (range (.getArraySize v))]
  70. (value->clj (.getArrayElement v i))))
  71. (.hasMembers v) (into {}
  72. (for [k (.getMemberKeys v)]
  73. [k (value->clj (.getMember v k))]))
  74. :else (throw (Exception. "Unsupported value"))))
  75.  
  76. (comment
  77. (def js->clj (comp value->clj eval-js))
  78.  
  79. (js->clj "[{}]")
  80. ;=> [{}]
  81.  
  82. (js->clj "false")
  83. ;=> false
  84. (js->clj "3 / 3.33")
  85. ;=> 0.9009009009009009
  86. (js->clj "123123123123123123123123123123123")
  87. ;=> 1.2312312312312312E32
  88.  
  89. (def doubler (js->clj "(n) => {return n * 2;}"))
  90. (doubler 2)
  91. ;=> 4
  92.  
  93. (js->clj "m = {foo: 1, bar: '2', baz: {0: false}};")
  94. ;=> {"foo" 1, "bar" "2", "baz" {"0" false}}
  95.  
  96. (def factorial
  97. (eval-js "
  98. var m = [];
  99. function factorial (n) {
  100. if (n == 0 || n == 1) return 1;
  101. if (m[n] > 0) return m[n];
  102. return m[n] = factorial(n - 1) * n;
  103. }
  104. x = {fn: factorial, memos: m};"))
  105. ((get (value->clj factorial) "fn") 12)
  106. ;=> 479001600
  107. (get (value->clj factorial) "memos")
  108. ;=> [nil nil 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600]
  109. ((get (value->clj factorial) "fn") 24)
  110. ;=> 6.204484017332394E23
  111. (get (value->clj factorial) "memos")
  112. ;=> [nil nil 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600 ... truncated for brevity]
  113.  
  114. (eval-js "var foo = 0xFFFF")
  115. (eval-js "console.log(foo);")
  116. ;=> #object[org.graalvm.polyglot.Value 0x3f9d2028 "undefined"]
  117. ;65535
  118.  
  119. (js->clj "1 + '1'")
  120. ;=> "11"
  121. (js->clj "['foo', 10, 2].sort()")
  122. ;=> [10 2 "foo"]
  123.  
  124. (def js-aset
  125. (js->clj "(arr, idx, val) => { arr[idx] = val; return arr; }"))
  126. (js-aset (ProxyArray/fromArray (object-array [1 2 3])) 1 nil)
  127. ;=> [1 nil 3]
  128.  
  129. (sort [{:b nil} \a 1 "a" "A" #{\a} :foo -1 0 {:a nil} "bar"])
  130. (def js-sort
  131. (js->clj "(...vs) => { return vs.sort(); }"))
  132. (apply js-sort [{:b nil} \a 1 "a" "A" #{\a} :foo -1 0 {:a nil} "bar"])
  133. ;=> [-1 0 1 "A" #{\a} :foo {:a nil} {:b nil} "a" "a" "bar"]
  134.  
  135. (def variadic-fn
  136. (js->clj "(x, y, ...z) => { return [x, y, z]; }"))
  137. (apply variadic-fn :foo :bar (range 3))
  138. ;=> [:foo :bar [0 1 2]]
  139.  
  140. (def ->json
  141. (js->clj "(x) => { return JSON.stringify(x); }"))
  142. (->json [1 2 3])
  143. ;=> "[1,2,3]"
  144. (->json (ProxyObject/fromMap {"foo" 1, "bar" nil}))
  145. ;=> "{\"foo\":1,\"bar\":null}"
  146. (def json->
  147. (js->clj "(x) => { return JSON.parse(x); }"))
  148. (json-> (->json [1 2 3]))
  149. ;=> [1 2 3]
  150. (json-> (->json (ProxyObject/fromMap {"foo" 1})))
  151. ;=> {"foo" 1}
  152.  
  153. (def json-object
  154. (js->clj "(m) => { return m.foo + m.foo; }"))
  155. (json-object (ProxyObject/fromMap {"foo" 1}))
  156. ;=> 2
  157.  
  158. (def clj-lambda
  159. (js->clj "
  160. m = {foo: [1, 2, 3],
  161. bar: {
  162. baz: ['a', 'z']
  163. }};
  164. (fn) => { return fn(m); }
  165. "))
  166. (clj-lambda
  167. (proxy-fn #(clojure.walk/prewalk
  168. (fn [v] (if (and (vector? v)
  169. (not (map-entry? v)))
  170. (vec (reverse v))
  171. v))
  172. %)))
  173. ;=> {"foo" [3 2 1], "bar" {"baz" ["z" "a"]}}
  174.  
  175. (def js-reduce
  176. (let [reduce (js->clj "(f, coll) => { return coll.reduce(f); }")
  177. reduce-init (js->clj "(f, coll, init) => { return coll.reduce(f, init); }")]
  178. (fn
  179. ([f coll] (reduce f coll))
  180. ([f init coll] (reduce-init f coll init)))))
  181. (js-reduce + (range 10))
  182. ;=> 45
  183. (js-reduce + -5.5 (range 10))
  184. ;=> 39.5
  185. (js-reduce (fn [acc elem]
  186. (assoc acc (keyword (str elem)) (doubler elem)))
  187. {}
  188. (range 5))
  189. ;=> {:0 0, :1 2, :2 4, :3 6, :4 8}
  190.  
  191. (def log-coll
  192. (js->clj "(coll) => { for (i in coll) console.log(coll[i]); }"))
  193. (log-coll (repeatedly 3 #(do (prn 'sleeping)
  194. (Thread/sleep 100)
  195. (rand))))
  196.  
  197. (log-coll (range))
  198.  
  199. "nice")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement