Made this thing: https://github.com/borkdude/grasp It parses the code using sci and then feeds the sexprs to spec.
awesome stuff
Q- is it possible (and it may just work, will try soon) to inject forms like Math/sin directly into an SCI context, instead of wrapping it in a fn?
@sritchie09 you mean like JS interop?
or both Java + JS interop?
both
trying this now...
what was I doing, asking... it just works
well, in JS it does!
I recommend looking at the interop tests: https://github.com/borkdude/sci/blob/master/test/sci/interop_test.cljc At the end there are specific tests for JS as well
Looks like it will work if I manually sub in Math/cos
etc in Clojure, with a postwalk
and "just works" in the JS version, since Math/cos
is a function
but on the JVM, if I provide a bare Math/cos
in the bindings map, I get (of course)
Unable to find static field: cos in class java.lang.Math
and if I quote it:
Execution error (IllegalArgumentException) at sci.impl.interpreter/eval-special-call (interpreter.cljc:546).
No matching clause: Math/cos
@sritchie09 In CLJ you need to add {:classes {'java.lang.Math Math} :imports '{Math java.lang.Math}}
and then you can do interop with those classes
oh nice!
okay, yesss, will try. Thanks @borkdude
in CLJS it works similarly:
$ clj -A:test -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.597"}}}' -m cljs.main -re node
WARNING: When invoking clojure.main, use -M
ClojureScript 1.10.597
cljs.user=> (require '[sci.core :as sci])
nil
cljs.user=> (sci/eval-string "(Math/pow 2 3)" {:classes {'Math js/Math}})
8
interesting, @borkdude giving this a whirl now:
(let [f (->> (sci/init
{:classes {java.lang.Math 'Math}
:imports {'Math java.lang.Math}})
(sci/eval-string "(fn [x] (+ 1 (Math/cos x)))"))]
(f 0.5))
gives me Could not resolve symbol: Math/cos
the quotes aren't exactly as you specified of course
@sritchie09 The imports should be all quoted
Also classes should be symbol -> class
{:classes {'java.lang.Math Math}}
{:imports '{Math java.lang.Math}}
same error
taking a look at the interop tests now
oh, I see -
eval-string
needs the dict
passing an already-initialized context caused the failure
(let [f (sci/eval-string
"(fn [x] (+ 1 (Math/cos x)))"
{:classes {'java.lang.Math Math}
:imports '{Math java.lang.Math}})]
(f 0.5))
this works
these options work with sci/init
as well
for sure, I just mean that the form I just pasted works, but
(let [f (sci/eval-string
"(fn [x] (+ 1 (Math/cos x)))"
(sci/init
{:classes {'java.lang.Math Math}
:imports '{Math java.lang.Math}}))]
(f 0.5))
does not (map wrapped in sci/init
before passing it to eval-string
taking my baby steps
yeah, that doesn't work. eval-string takes a string + opts. eval-string* takes a ctx (produced by init) and a string
eval-string = init + eval-string*
now here is the hail mary:
(let [f (sci/eval-form
(sci/init
{:classes {'java.lang.Math Math}
:imports '{Math java.lang.Math}
:bindings {'cos 'Math/cos}})
'(fn [x] (+ 1 (cos x))))]
(f 0.5))
is it possible to go one step further, and use bindings
to sub in a form like Math/cos
, that's not a fn but a static field
this gives No matching clause: Math/cos
(thanks for the help here, happy to go hunt on my own too)
in that case you should just write wrapper functions {:bindings {'cos (fn [x] (Math/cos x))}}
👍 that's what I'm doing now and it works great. I didn't know if I could get some speedup by not doing this
(which maybe is true in Clojurescript, since I can use a bare Math/cos
@sritchie09 If you're looking to avoid boilerplate, you can write a macro