sci 2023-11-20

Just joined to say what we've added an experimental automation workflow in our product, built on SCI. The ability to run the code against dummy data in the browser, and also against real data in the server, makes a really nice dev experience. Thank you @borkdude

👍 1

Well, also joined to validate an assumption that I have - if I provide an allow list to the evaluation options, that means essentially a very very restricted environment. The code we'd be running would be untrusted so we want to really limit the available constructs to some basic conditionals and then env-provided functions.

👍 1

I implemented a load-file for the SCI context. foo.ys loads bar.ys But when I move both files into test/ directory, then test/foo.ys can't find bar.ys unless I specify test/bar.ys What's the best way to make sure the loaded file path is relative to the caller?

Perhaps you can use sci/file (available as *file* inside of SCI programs)

Every var has also :file as metadata

(defn ys-load [file]
  (let [file (io/file file)
        ys-code (slurp file)
        clj-code (ys/ys-compile ys-code)]
    (sci/with-bindings
      {sci/ns @sci/ns
       sci/file (.getAbsolutePath file)}
      (sci/eval-string* (sci-ctx) clj-code))))

I got that from the SCI readme

you could maybe make load-file a macro, this way it gets expanded while sci/file is still bound to the file you're processing

and then expand to something like load-file* as a function which then gets the absolute path

oh, you think the path is wrong?

I'll test that

what do you mean, the path is wrong?

The sci/file var is only bound during analysis

and macros are processed during analysis

function calls are too late

hope you get the picture

@ingy Here's a more full example (which I typed out in a REPL)

user=> (defmacro my-load-file [path] (let [current-file @sci/file] `(clojure.core/load-file* ~current-file ~path)))
#'user/my-load-file
user=> (defn load-file* [current-file path] [:do-your-thing current-file path])
#'user/load-file*
user=> (sci/binding [sci/file "user.clj"] (sci/eval-string "(defn foo [] (load-file \"dude.clj\")) (foo)" {:namespaces {'clojure.core {'load-file (sci/copy-var my-load-file nil) 'load-file* (sci/copy-var load-file* nil)}}}))
[:do-your-thing "user.clj" "dude.clj"]

I did get the picture wrt binding time. And the load file path was indeed wrong for me. What I don't get is what sci/file or *file* does. To venture a guess, it affects how slurp works? or maybe how io/file works?

sci/file works exactly the same as *file* on the JVM

ok, but I don't know what *file* does

I get *file* holds the current file path. What I'm trying to suss out is if the file functions resolve relative paths relative to *file* or relative to the current directory.

never relative path

but I can figure it out...

but if you want to implement it like that, you can use the idea I posted above

which is not getting through I'm afraid

functions can't use the value of *file* since that var is only bound during compilation time

I'm saying if *file* is set to /tmp/foo/aaa.clj where does slurp think the "bbb.clj" would be?

so you have to use a macro if you want to capture the file during compilation time

slurp is a function and it never uses *file*

in general JVM Clojure never uses the concept of "load something relative to this file"

everything is based on classpath or current working directory, mostly classpath idea is central though

ok so I need to do that math myself, after getting the starting point right

but this doesn't prevent you from making your own load-file which does use the relative file idea, but then it has to be a macro

like I explained above, so maybe read it again :)

I fully understand the macro binding thing

*file* is just some compile time thing. it is used to set the :file value on var metadata, which is probably the main thing

I gotta run to the airport, but I think I have what I need now. Thanks!

have a good flight!

✅ 1