Fork me on GitHub
#squint
<
2023-12-20
>
Oliver Marshall16:12:53

Hey šŸ‘‹, I'm trying to play around with https://motioncanvas.io/ in squint. It requires using function* generators with yield*s. I can write a macro to output yield*s but I can't figure out how to output a function* with a inline body. Any tips on that? Pointers in more sane directions are also appreciated šŸ˜…

borkdude16:12:31

This is currently not well supported in squint yet

borkdude16:12:01

you can hack around it with js* perhaps:

(js* "function* () {}")

borkdude16:12:15

issue welcome

Oliver Marshall16:12:54

That's what I've been trying, but I'm not sure how to actually get a body into the function :thinking_face: This get's close:

(defmacro my-fn [[& params] & body]
  `(js* "function* ~{} {\n~{}\n}"
        ~params
        (do ~@body)))
But there's an extra (function() {xxx})() wrapper

borkdude16:12:31

I think you need to write ~'js* in the macro, else js* will get namespaced

borkdude16:12:09

this won't solve your issue though

borkdude16:12:24

I think it would be better to solve this in squint than hack around it

Oliver Marshall16:12:42

It actually produced the same output without un-namespacing the *js :thinking_face:

Oliver Marshall16:12:50

I'm opening an issue now šŸ™‚

Oliver Marshall16:12:55

Thanks for your time šŸ™

borkdude16:12:00

for now you can make use (js/eval "function* ...) or write the function in JS

Oliver Marshall16:12:44

At that point it's better to just not use squint for now. I'm only playing so I can come back to it later šŸ™‚

borkdude16:12:27

sure. the function* might be difficult in combination with do and let expressions since they use IIFEs. I haven't tested this yes, but something like:

(defn ^:* foo []
  (js-yield 1)
  (js-yield* [1 2 3])
  (let [x 1 _ (js-yield 2)]
    (js-yield x)
  (do 1 2 (js-yield 3) 4))

borkdude16:12:59

will compile into:

function* foo() {
  yield 1;
  yield* [1 2 3];
  (function() ...)()
  (function() ...)()
}
 

borkdude16:12:29

and I'm. not sure if you can use yield in those IIFEs

Oliver Marshall16:12:34

Yeah, that's not ideal :thinking_face:

Oliver Marshall16:12:48

I don't think you can, my editor complains at the very least

borkdude16:12:07

the same is true for async but that is a solved problem, the solution in squint it to make those IIFEs async too

borkdude16:12:23

but for yield that may not work well

Oliver Marshall16:12:01

If that were the route you went down I think you could prefix the iife with a yield* too

borkdude16:12:22

yeah perhaps

borkdude18:12:50

it is a similar problem with async, except with a generator IIFE I don't know for sure if a user is going to be using the return value of the IIFE or simple will use yield. e.g.:

(let [x (let [y (do (js-yield 1) 5)] y)] (js-yield x))

borkdude18:12:21

in the async case I simply added a await before the IIFE which is sufficient to cover all cases, even if you don't use js-await inside of the IIFE

borkdude18:12:35

This could be a solution for the return value:

borkdude18:12:38

function* foo () {
  yield 1;
  yield* [2, 3];
  let x = (function* () {
    yield 6;
    yield* [7, 8, 9];
    return "This is X";
  })();
  while(true) {
    const { value, done } = x.next();
    if (done) {
      x = value;
      break;
    } else {
      yield value;
    }
  }
  console.log('x', x);
}

borkdude18:12:13

so x is the IIFE that we don't know if it contains yields or not

borkdude18:12:33

yeah that's it

Oliver Marshall10:12:08

Some thoughts: ā€¢ Would it be possible for a user to have access to x while it's still a generator, say if something in it threw an exception? ā€¢ If a js-yield is the last statement in the do would it generate return yield value? This is fine but x ends up undefined

borkdude10:12:35

If it's possible: this depends on how it gets implemented. Write out the JS and we'll find out :)

borkdude10:12:09

I liked your expansion into

(function () {
yield ...
x = /* return value */
})()

borkdude10:12:51

(let [x (do (js-yield ..) 1)] ...)
in this code there is no way to see x as a generator so I don't think that makes sense

borkdude10:12:15

if you want that, then explicitly define a ^:gen function yourself

Oliver Marshall10:12:06

Wrapping the do with a try seemed like a problem case :thinking_face:

Oliver Marshall10:12:16

But maybe I'm missing something better

Oliver Marshall11:12:28

I suppose in that case I would expect the catch to set the value of x so that should be fine too :thinking_face:

borkdude11:12:54

I think your try/catch case works like expected, since in the catch there is no return value so x remains undefined

Oliver Marshall11:12:42

Yup, if I put a 7 at the end of the catch then I can see how that'd work as I expected šŸ‘

Panel23:12:48

I'm trying to get the repl working with the vite example, but inf-clojure exit straight away. Is it supposed to work ?

user=>
Process inf-clojure exited abnormally with code 1

borkdude23:12:41

there's now also an nrepl server, maybe this works better for you

borkdude23:12:53

gotta catch some šŸ’¤ but will check back tomorrow

ā¤ļø 1