This essay explains how the ES6 Realm API makes it possible to create robust language abstractions that allow hooking into the behavior of eval, and how this can be used to implement different dialects of JavaScript.
Imagine we want to add Doug Crockford's ?? operator, which acts like a short-circuiting logical OR operator, except instead of checking truthiness, it returns the first argument's value if the first argument is any value other than undefined.
Since it makes everything simpler and cleaner, I'm going to assume I can use do-expressions for the implementation. (They're looking good for ES7!) So with that said, when we "crockpile" EXPR1 ?? EXPR2 we should get:
do {
let tmp = EXPR1;
(typeof tmp !== 'undefined') ? tmp : EXPR2
}except that tmp has to be a fresh variable every time an instance of ?? is crockpiled, to avoid accidental name collisions.
The challenge is that even if you choose a fresh variable that isn't in scope, you can't be sure that an instance of direct eval won't accidentally discover the variable name you chose. For example, if a particular instance of ?? crockpiles to a generated variable name tmp$1, a naive crockpilation would still allow this to be discovered with direct eval. For example, this code:
undefined ?? eval("tmp$1")would naively crockpile to:
do {
let tmp$1 = undefined;
(typeof tmp$1 !== 'undefined') ? tmp$1 : eval("tmp$1")
}but the real program should actually produce a reference to a global variable called tmp$1, since the user's program does not actually create a local variable called tmp$1. So the correct crockpilation needs some way of communicating to the direct eval that it should ignore references to tmp$1 and treat them as global references.
The solution is for the crockpiler to inject a representation of the crockpiler environment at all direct eval sites, so that the direct eval can use that environment for its own crockpilation. So the above example crockpiles instead to:
do {
let tmp$1 = undefined;
(typeof tmp$1 !== 'undefined') ? tmp$1 : eval([{"tmp$1":"GENSYM"}], "tmp$1")
}Now when the direct eval is performed, it has a reified representation of the crockpilation environment to start in, so it knows when it comes across a reference to tmp$1 to replace it with something like window.tmp$1.
Does the realm API used here correspond to what's proposed in https://gist.github.com/caridy/311ad2c17a0cd875ae17ac11ffb597a9 ?