sci

https://github.com/babashka/SCI - also see #babashka and #nbb
borkdude 2020-10-29T10:32:08.045300Z

Made this thing: https://github.com/borkdude/grasp It parses the code using sci and then feeds the sexprs to spec.

2020-10-29T11:43:55.045700Z

awesome stuff

Sam Ritchie 2020-10-29T15:02:46.047100Z

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?

borkdude 2020-10-29T15:03:50.047300Z

@sritchie09 you mean like JS interop?

borkdude 2020-10-29T15:04:23.047700Z

or both Java + JS interop?

Sam Ritchie 2020-10-29T15:04:57.047900Z

both

Sam Ritchie 2020-10-29T15:05:11.048400Z

trying this now...

Sam Ritchie 2020-10-29T15:05:58.049Z

what was I doing, asking... it just works

Sam Ritchie 2020-10-29T15:06:06.049200Z

well, in JS it does!

borkdude 2020-10-29T15:06:32.049600Z

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

Sam Ritchie 2020-10-29T15:07:34.050300Z

Looks like it will work if I manually sub in Math/cos etc in Clojure, with a postwalk

Sam Ritchie 2020-10-29T15:07:50.050600Z

and "just works" in the JS version, since Math/cos is a function

Sam Ritchie 2020-10-29T15:08:12.051100Z

but on the JVM, if I provide a bare Math/cos in the bindings map, I get (of course)

Sam Ritchie 2020-10-29T15:08:12.051300Z

Unable to find static field: cos in class java.lang.Math

Sam Ritchie 2020-10-29T15:08:18.051700Z

and if I quote it:

Sam Ritchie 2020-10-29T15:08:20.052200Z

Execution error (IllegalArgumentException) at sci.impl.interpreter/eval-special-call (interpreter.cljc:546).
No matching clause: Math/cos

borkdude 2020-10-29T15:08:53.052800Z

@sritchie09 In CLJ you need to add {:classes {'java.lang.Math Math} :imports '{Math java.lang.Math}}

borkdude 2020-10-29T15:09:02.053100Z

and then you can do interop with those classes

Sam Ritchie 2020-10-29T15:09:19.053300Z

oh nice!

Sam Ritchie 2020-10-29T15:09:26.053600Z

okay, yesss, will try. Thanks @borkdude

borkdude 2020-10-29T15:10:25.053900Z

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

Sam Ritchie 2020-10-29T16:28:34.054700Z

interesting, @borkdude giving this a whirl now:

Sam Ritchie 2020-10-29T16:28:45.055200Z

(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))

Sam Ritchie 2020-10-29T16:28:55.055500Z

gives me Could not resolve symbol: Math/cos

Sam Ritchie 2020-10-29T16:29:16.055800Z

the quotes aren't exactly as you specified of course

borkdude 2020-10-29T16:29:57.056400Z

@sritchie09 The imports should be all quoted

borkdude 2020-10-29T16:30:16.056700Z

Also classes should be symbol -> class

borkdude 2020-10-29T16:30:48.057200Z

{:classes {'java.lang.Math Math}}

borkdude 2020-10-29T16:31:00.057600Z

{:imports '{Math java.lang.Math}}

Sam Ritchie 2020-10-29T16:31:27.057800Z

same error

Sam Ritchie 2020-10-29T16:31:32.058100Z

taking a look at the interop tests now

Sam Ritchie 2020-10-29T16:33:36.058300Z

oh, I see -

Sam Ritchie 2020-10-29T16:33:43.058500Z

eval-string needs the dict

Sam Ritchie 2020-10-29T16:33:53.058800Z

passing an already-initialized context caused the failure

Sam Ritchie 2020-10-29T16:34:16.059200Z

(let [f (sci/eval-string
         "(fn [x] (+ 1 (Math/cos x)))"
         {:classes {'java.lang.Math Math}
          :imports '{Math java.lang.Math}})]
  (f 0.5))

Sam Ritchie 2020-10-29T16:34:17.059500Z

this works

borkdude 2020-10-29T16:35:14.059900Z

these options work with sci/init as well

Sam Ritchie 2020-10-29T16:36:38.060300Z

for sure, I just mean that the form I just pasted works, but

Sam Ritchie 2020-10-29T16:36:45.060600Z

(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))

Sam Ritchie 2020-10-29T16:36:58.061Z

does not (map wrapped in sci/init before passing it to eval-string

Sam Ritchie 2020-10-29T16:37:17.061400Z

taking my baby steps

borkdude 2020-10-29T16:37:34.061800Z

yeah, that doesn't work. eval-string takes a string + opts. eval-string* takes a ctx (produced by init) and a string

borkdude 2020-10-29T16:38:12.062400Z

eval-string = init + eval-string*

Sam Ritchie 2020-10-29T16:39:04.062700Z

now here is the hail mary:

Sam Ritchie 2020-10-29T16:39:05.063100Z

(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))

Sam Ritchie 2020-10-29T16:39:33.063900Z

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

Sam Ritchie 2020-10-29T16:39:40.064100Z

this gives No matching clause: Math/cos

Sam Ritchie 2020-10-29T16:40:15.064700Z

(thanks for the help here, happy to go hunt on my own too)

borkdude 2020-10-29T16:40:50.065300Z

in that case you should just write wrapper functions {:bindings {'cos (fn [x] (Math/cos x))}}

Sam Ritchie 2020-10-29T16:41:53.065700Z

👍 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

Sam Ritchie 2020-10-29T16:42:01.066Z

(which maybe is true in Clojurescript, since I can use a bare Math/cos

borkdude 2020-10-29T16:49:00.066800Z

@sritchie09 If you're looking to avoid boilerplate, you can write a macro

👍 1