Skip to content

Instantly share code, notes, and snippets.

@dherman
Last active September 7, 2024 17:42

Revisions

  1. Dave Herman revised this gist Feb 24, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion realms-api.md
    Original file line number Diff line number Diff line change
    @@ -113,7 +113,7 @@ console.log(r.eval("eval('99')")); // INTERCEPTING DIRECT EVAL
    // 1000
    ```
    ### NonEval
    ### Non-eval
    The special direct `eval` syntax delegates to the `nonEval` method when the callee turns out not to be the builtin `eval` function. For example:
  2. Dave Herman revised this gist Feb 24, 2014. 1 changed file with 56 additions and 52 deletions.
    108 changes: 56 additions & 52 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -8,44 +8,57 @@ A type `T?` should be read as `T | undefined` -- that is, an optional value that

    # Realms

    A *realm object* abstracts the notion of a distinct global environment.
    A *realm object* abstracts the notion of a distinct global environment, with its own global object, copy of the standard library, and "intrinsics" (standard objects that are not bound to global variables, like the initial value of `Object.prototype`).

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

    ## Realm Constructor

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

    // intended to be overridden by subclasses
    indirectEval(...any) -> stringable, // default: no translation
    directEval(self: any, ...any) -> stringable, // default: no translation
    nonEval(self: any, callee: any, ...any) -> any, // default: call callee on args
    init() -> void, // default: make global instanceof global.Object and define standard globals

    // accessor methods
    get stdlib() -> PropertyDescriptorMap, // property descriptor map for standard globals
    get intrinsics() -> { string: any, ... }, // original values of standard %foo% intrinsics

    // inherited accessor properties
    get global() -> object, // access this realm's global object

    // public methods
    eval(stringable) -> any // do an indirect eval in this realm
    }
    ```
    Every component of the constructor argument is optional (meaning that it can be `undefined` and will be provided with a default behavior).
    The constructor arguments are optional and have the same signature as the arguments to `new Proxy`. If at least one is provided, then the global object of the realm is created as if via `new Proxy` within the new realm. Otherwise, the global object of the realm is an ordinary object with the new realm's intrinsic `%ObjectPrototype%` as its [[Prototype]].
    The `indirectEval` method allows custom evaluation behavior for indirect calls to the `eval` function. By default, it simply returns the source unmodified.
    The `directEval` method allows custom evaluation behavior for direct calls to the `eval` function. By default, it simply returns the source unmodified.
    The `nonEval` method allows custom evaluation behavior for direct function calls that appear to be direct calls to `eval` but whose callee turns out not to be the `eval` function. By default, it simply calls the callee on the arguments, using the `self` parameter as the `this` binding.
    The `indirectEval` hook allows custom evaluation behavior for indirect calls to the `eval` function.
    The `init` method allows custom initialization of the global state of the realm at construction time. By default, the `init` method defines the standard library on the global object with standard values and attributes.
    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.
    ## Realm Properties
    ### stdlib
    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:
    A property descriptor map containing this realm's standard global bindings, with their standard attributes, of the ECMAScript standard library. These can be easily copied to a global object via
    ```javascript
    var realm = new Realm({
    init: function(realm, builtins) {
    extend(realm.global, builtins);
    }
    });
    Object.defineProperties(global, realm.stdlib)
    ```
    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]].
    ### intrinsics
    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
    A dictionary object containing the initial values of this realm's intrinsics. For each intrinsic `%Foo%` there is an entry `Foo` in the dictionary. For example, the `%ObjectPrototype%` and `%GeneratorFunction%` intrinsics are mapped as `ObjectPrototype` and `GeneratorFunction`, respectively.
    ### global
    @@ -55,7 +68,7 @@ The global object associated with the realm.
    ### eval
    Synchronously execute a top-level script.
    Synchronously execute a top-level script. The source is interpreted as a *Script* and evaluated with `this` bound to the realm's global object.
    *Extensible web*: This is the dynamic equivalent of a `<script>` in HTML.
    @@ -66,61 +79,52 @@ 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.
    A realm object can hook into the semantics of code evaluation using the three overrideable `eval` methods.
    ## 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:
    The standard builtin `eval` function, when called indirectly as a first-class function, delegates to the `indirectEval` method to translate its source. For example:
    ```javascript
    var r = new Realm({
    indirectEval: function(src) {
    class MyRealm extends Realm {
    indirectEval(src) {
    console.log("HELLO WORLD I AM INTERCEPTING YOUR TRANSMISSION");
    return src.replace(/foo/, "42");
    }
    });
    }
    var r = new MyRealm();
    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:
    The special direct `eval` syntax delegates to the `directEval` method to translate its source. For example:
    ```javascript
    var r = new Realm({
    directEval: {
    translate: function(src) {
    console.log("INTERCEPTING DIRECT EVAL");
    return "1000";
    }
    class MyRealm extends Realm {
    directEval() {
    console.log("INTERCEPTING DIRECT EVAL");
    return "1000";
    }
    });
    }
    console.log(r.eval("eval('99')")); // INTERCEPTING DIRECT EVAL
    // 1000
    ```
    ### Invalid direct eval
    ### NonEval
    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:
    The special direct `eval` syntax delegates to the `nonEval` method when the callee turns out not to be the builtin `eval` function. For example:
    ```javascript
    var r = new Realm({
    directEval: {
    fallback: function(self, callee, ...args) {
    console.log("INTERCEPTING INVALID DIRECT EVAL");
    return callee.apply(self, args);
    }
    class MyRealm extends Realm {
    nonEval(self, callee, ...args) {
    console.log("INTERCEPTING NON-EVAL");
    return callee.apply(self, args);
    }
    });
    console.log(r.eval("(function(eval) { return eval(NaN) })(isNaN)")); // INTERCEPTING INVALID DIRECT EVAL
    }
    console.log(r.eval("(function(eval) { return eval(NaN) })(isNaN)")); // INTERCEPTING NON-EVAL
    // true
    ```
  3. dherman revised this gist Dec 13, 2013. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -127,3 +127,5 @@ console.log(r.eval("(function(eval) { return eval(NaN) })(isNaN)")); // INTERCEP
    ## 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`.

    As noted in the [Nov 21, 2013 TC39 meeting notes](https://github.com/rwaldron/tc39-notes/blob/master/es6/2013-11/nov-21.md), this technique has been used for quite some time in the SES project.
  4. dherman revised this gist Dec 13, 2013. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -123,3 +123,7 @@ var r = new Realm({
    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`.
  5. dherman revised this gist Dec 13, 2013. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -88,9 +88,11 @@ console.log(f("foo")); // HELLO WORLD I AM INTERCEPTING YOUR TRANSMISSION

    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:
    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:

    ```javascript
    var r = new Realm({
    @@ -107,7 +109,7 @@ console.log(r.eval("eval('99')")); // INTERCEPTING DIRECT EVAL

    ### 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:
    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:

    ```javascript
    var r = new Realm({
  6. dherman revised this gist Dec 13, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion realms-api.md
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@ Synchronously execute a top-level script.
    v = r.eval(src)
    ```

    # Realm meta-object protocol
    # Meta-object protocol

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

  7. dherman revised this gist Dec 13, 2013. 1 changed file with 58 additions and 0 deletions.
    58 changes: 58 additions & 0 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -63,3 +63,61 @@ Synchronously execute a top-level script.
    // eval : (string) -> any
    v = r.eval(src)
    ```

    # Realm 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:

    ```javascript
    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.

    ### 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:

    ```javascript
    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:

    ```javascript
    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
    ```
  8. dherman revised this gist Dec 13, 2013. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -35,14 +35,16 @@ The `init` callback is passed an object containing the standard ECMAScript built

    ```javascript
    var realm = new Realm({
    init: function(builtins) {
    extend(this.global, builtins);
    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
  9. dherman revised this gist Nov 22, 2013. 1 changed file with 0 additions and 24 deletions.
    24 changes: 0 additions & 24 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -61,27 +61,3 @@ Synchronously execute a top-level script.
    // eval : (string) -> any
    v = r.eval(src)
    ```


    # Loaders

    This section describes how the `Loader` class is extended to integrate with custom realms.

    ## Loader Constructor

    ```javascript
    l = new Loader({
    realm, // Realm?
    ...
    }) // : Loader<ModuleAddress, ModuleSource>
    ```

    ## Loader Properties

    ### realm

    Returns the realm associated with the loader.

    ### global

    Convenience: returns the global associated with the loader's realm.
  10. dherman revised this gist Nov 22, 2013. 1 changed file with 19 additions and 14 deletions.
    33 changes: 19 additions & 14 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -15,29 +15,34 @@ A *realm object* abstracts the notion of a distinct global environment.
    ## Realm Constructor

    ```javascript
    r = new Realm(options, // {
    // eval: {
    // direct: {
    // translate: ((string) -> string)?,
    // fallback: ((any, ...any) -> any)?
    //. }?,
    // indirect: ((string) -> any)?
    // }?,
    // Function: ((string, string, ("function" | "function*")) -> function)?
    // }?
    initializer); // ((object) -> any)?
    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 initializer object is passed an object containing the standard ECMAScript builtins for a global object. 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:
    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:

    ```javascript
    var realm = new Realm(options, function(builtins) {
    Object.mixin(this.global, builtins);
    var realm = new Realm({
    init: function(builtins) {
    extend(this.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]].

    ## Realm Properties

    ### global
  11. dherman created this gist Nov 20, 2013.
    82 changes: 82 additions & 0 deletions realms-api.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    # 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

    ```javascript
    r = new Realm(options, // {
    // eval: {
    // direct: {
    // translate: ((string) -> string)?,
    // fallback: ((any, ...any) -> any)?
    //. }?,
    // indirect: ((string) -> any)?
    // }?,
    // Function: ((string, string, ("function" | "function*")) -> function)?
    // }?
    initializer); // ((object) -> any)?
    ```

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

    The initializer object is passed an object containing the standard ECMAScript builtins for a global object. 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:

    ```javascript
    var realm = new Realm(options, function(builtins) {
    Object.mixin(this.global, builtins);
    });
    ```

    ## 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.

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


    # Loaders

    This section describes how the `Loader` class is extended to integrate with custom realms.

    ## Loader Constructor

    ```javascript
    l = new Loader({
    realm, // Realm?
    ...
    }) // : Loader<ModuleAddress, ModuleSource>
    ```

    ## Loader Properties

    ### realm

    Returns the realm associated with the loader.

    ### global

    Convenience: returns the global associated with the loader's realm.