Last active
September 7, 2024 17:42
Revisions
-
Dave Herman revised this gist
Feb 24, 2014 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -113,7 +113,7 @@ console.log(r.eval("eval('99')")); // INTERCEPTING DIRECT EVAL // 1000 ``` ### 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: -
Dave Herman revised this gist
Feb 24, 2014 . 1 changed file with 56 additions and 52 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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, 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 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 } ``` 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 `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. ## Realm Properties ### stdlib 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 Object.defineProperties(global, realm.stdlib) ``` ### intrinsics 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. 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 A realm object can hook into the semantics of code evaluation using the three overrideable `eval` methods. ## Indirect eval 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 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 special direct `eval` syntax delegates to the `directEval` method to translate its source. For example: ```javascript class MyRealm extends Realm { directEval() { console.log("INTERCEPTING DIRECT EVAL"); return "1000"; } } console.log(r.eval("eval('99')")); // INTERCEPTING DIRECT EVAL // 1000 ``` ### NonEval 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 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 NON-EVAL // true ``` -
dherman revised this gist
Dec 13, 2013 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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. -
dherman revised this gist
Dec 13, 2013 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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`. -
dherman revised this gist
Dec 13, 2013 . 1 changed file with 4 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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: ```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: ```javascript var r = new Realm({ -
dherman revised this gist
Dec 13, 2013 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -64,7 +64,7 @@ Synchronously execute a top-level script. 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. -
dherman revised this gist
Dec 13, 2013 . 1 changed file with 58 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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 ``` -
dherman revised this gist
Dec 13, 2013 . 1 changed file with 4 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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(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 -
dherman revised this gist
Nov 22, 2013 . 1 changed file with 0 additions and 24 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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) ``` -
dherman revised this gist
Nov 22, 2013 . 1 changed file with 19 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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); // { // 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: ```javascript 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 -
dherman created this gist
Nov 20, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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.