Skip to content

Instantly share code, notes, and snippets.

@dherman
Last active September 7, 2024 17:42
Show Gist options
  • Save dherman/7568885 to your computer and use it in GitHub Desktop.
Save dherman/7568885 to your computer and use it in GitHub Desktop.
ES6 Realms API

Notational Conventions

This section describes the conventions used here to describe type signatures.

A [T] is an array-like value (only ever used read-only in this API), i.e., one with an integer length and whose indexed properties from 0 to length - 1 are of type T.

A type T? should be read as T | undefined -- that is, an optional value that may be undefined.

Realms

A realm object abstracts the notion of a distinct global environment.

Extensible web: This is the dynamic equivalent of a same-origin <iframe> without DOM.

Realm Constructor

r = new Realm(options); // {
                        //   indirectEval: ((...any) -> string)?,
                        //   directEval: {
                        //     translate: ((...any) -> string)?,
                        //     fallback: ((any, any, ...any) -> any)?
                        //.  }?,
                        //   init: ((object) -> void)?
                        // }?

Every component of the constructor argument is optional (meaning that it can be undefined and will be provided with a default behavior).

The indirectEval hook allows custom evaluation behavior for indirect calls to the eval function.

The directEval hooks allow custom evaluation behavior for direct calls to the eval function. The translate hook is used when a true direct eval is performed, that is, when a call to an apparent direct eval turns out to be calling the true eval function. The fallback hook is used when an apparent direct eval turns out to be calling something other than the true eval function. The first argument passed to the fallback hook is the this binding, the second argument is the callee, and the remaining arguments are the arguments that were passed to the call.

The init callback is passed an object containing the standard ECMAScript builtins for the realm. A host environment may also provide additional builtins specific to the host environment. (For example, the browser would provide atob and btoa and other standard browser globals that are not tied to the DOM.) The this binding of the initializer function is provided as the new realm object. This can be used to initialize the realm, for example:

var realm = new Realm({
    init: function(realm, builtins) {
        extend(realm.global, builtins);
    }
});

If the init callback is provided, the global object is initialized to an empty object with a null [[Prototype]]. If it is not provided, the global object defaults to containing the complete set of normal builtins, with their standard attributes as specified in the standard library, and with the realm's Object.prototype intrinsic as the [[Prototype]].

The init callback is called with the newly created realm object as its first parameter and with an object containing the normal builtins. The builtins object has the new realm's Object.prototype as its [[Prototype]].

Realm Properties

global

The global object associated with the realm.

Realm Methods

eval

Synchronously execute a top-level script.

Extensible web: This is the dynamic equivalent of a <script> in HTML.

// eval : (string) -> any
v = r.eval(src)

Meta-object protocol

The configuration of a realm via the Realm constructor affects two aspects of the semantics of code run within that realm.

Indirect eval

The builtin eval function, when called indirectly as a first-class function, delegates to the indirectEval hook to translate its source. For example:

var r = new Realm({
  indirectEval: function(src) {
    console.log("HELLO WORLD I AM INTERCEPTING YOUR TRANSMISSION");
    return src.replace(/foo/, "42");
  }
});
var f = r.eval("eval"); // return the realm's global eval function
console.log(f("foo"));  // HELLO WORLD I AM INTERCEPTING YOUR TRANSMISSION
                        // 42

Direct eval

The direct eval syhtax goes through one of two hooks depending on whether the dynamic value of the callee turns out to be the realm's intrinsic eval function.

Question: Are the terms "valid" and "invalid" good here? If so, should we change directEval.translate to directEval.valid and directEval.fallback to directEval.invalid?

Valid direct eval

When the direct eval is valid, that is, its callee evaluates to the realm's intrinsic eval function, the realm's directEval.translate hook is invoked. For example:

var r = new Realm({
  directEval: {
    translate: function(src) {
      console.log("INTERCEPTING DIRECT EVAL");
      return "1000";
    }
  }
});
console.log(r.eval("eval('99')")); // INTERCEPTING DIRECT EVAL
                                   // 1000

Invalid direct eval

When a direct eval is invalid, that is, its callee evaluates to anything other than the realm's intrinsic eval function, then the directEval.fallback hook is triggered. It is passed the current this value, the callee's actual value, and then the actual arguments. For example:

var r = new Realm({
  directEval: {
    fallback: function(self, callee, ...args) {
      console.log("INTERCEPTING INVALID DIRECT EVAL");
      return callee.apply(self, args);
    }
  }
});
console.log(r.eval("(function(eval) { return eval(NaN) })(isNaN)")); // INTERCEPTING INVALID DIRECT EVAL
                                                                     // true

A note on Function

The Function constructor doesn't need any special meta-object protocol, since it can be configured simply by replacing the global binding of Function and the value of Function.prototype.constructor to point to a new function. Similarly, the constructor for generator functions can be replaced by modifying Object.getPrototypeOf(function*(){}).constructor.

@zloirock
Copy link

Is this proposal alive?

@trusktr
Copy link

trusktr commented Apr 18, 2016

This is the dynamic equivalent of a same-origin <iframe> without DOM.

Is there access to the same DOM as in the main global scope? Or just no DOM at all like a Web Worker?

@azu
Copy link

azu commented Apr 24, 2016

@caridy
Copy link

caridy commented Apr 30, 2016

yeah, we are actually moving to https://github.com/caridy/proposal-realms, where https://github.com/FUDCo/proposal-frozen-realms is a related (dependent of realms) effort, we will be working on both at the same time :)

@erights
Copy link

erights commented Apr 30, 2016

Does https://github.com/caridy/proposal-realms subsume this proposal? Can we just consider that one to be the latest?

@caridy
Copy link

caridy commented Aug 2, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment