JS-EVAL and JS-DO

(I knew I'd written this up but couldn't find it...the reason was because it was a git commit message, not a forum post. Reprinting here.)

This is a fun usage of the new @-types, which lets you refer to Rebol values more easily in JS-DO and JS-EVAL expressions. By doing so you not only save on typing, but it finesses what would be hairy escaping situations if your only currency was text:

>> text: { ykcirT" a s'tI}

>> js-eval [{reb.Spell("reverse",} @text {) + "String" + '"'}]
== {It's a "Tricky String"}

So what's going on there is it's generating a temporary API handle to refer to the value fetched from TEXT. This API handle is then used literally as one of the arguments to the variadic/evaluating
extraction routines in the API (mixed here with some JavaScript + string concatenation). The variadic knows to free this handle after it is done processing it, (so it is like a reb.RELEASING() or reb.R()
handle).

This is more powerful than just treating a block as running JS-EVAL UNSPACED [...]. But if you want that, you can still use a plain GROUP!:

>> text: "gnirob"

>> js-eval [{"} (reverse text) { group"}]
== "boring group"

You can use @path/values, @(computed values). Although INTEGER! Rebol values aren't the best example (since you could pass them fine via their string representations), they'll work too (just easier to demo in a PR than Blobs for BINARY! and such...)

>> x: 1000
>> y: 20
>> js-eval [{reb.Unbox(} @(x + y) {)}]
== 1020

And to make things even more succinct, WORD!s in this dialect can be
used to generate the reb.XXX() calls for you:

>> x: 1000
>> js-eval [{20 +} unbox @x]
== 1020

Currently there's support for UNBOX and SPELL, but this could expand.

(Note: JS-DO and JS-EVAL are similar, except JS-EVAL tries to return a result to Rebol translated from the JavaScript it is given...and cannot declare variables in global scope. See technical notes in the implementation if interested.)

If string binding works, we can do better than this...

>> js-eval {reb.Spell("reverse", @text) + "String"}
== {It's a "Tricky String"}

What's going on here isn't a simple string substitution (which would screw up) but actually resolving to an API handle.

That's a lot more readable!

(Though I should point out this requires a JavaScript parser, at least enough of one to know when you're in a string literal or not. You don't want the string "@text" to be substituted.)

1 Like