Narcissus/Development: Difference between revisions
(more on host-JS feature requirements) |
No edit summary |
||
| (4 intermediate revisions by the same user not shown) | |||
| Line 5: | Line 5: | ||
* '''host''' ("host code," "host JS," etc): JS code in the implementation of Narcissus | * '''host''' ("host code," "host JS," etc): JS code in the implementation of Narcissus | ||
* '''user''' ("user code," "user JS," etc): JS code being interpreted by Narcissus | * '''user''' ("user code," "user JS," etc): JS code being interpreted by Narcissus | ||
== Narcissus global object == | |||
Loading the Narcissus source files creates a global variable <code>Narcissus</code>. | |||
<code>Narcissus.options</code> is an object which can be used to set some global configuration options for Narcissus. Currently there is just one configuration option: | |||
{| border="1" | |||
! Property || Options | |||
|- | |||
| <code>version</code> || <code>185</code>, <code>"harmony"</code> | |||
|} | |||
== Narcissus modules == | == Narcissus modules == | ||
| Line 10: | Line 22: | ||
Narcissus is divided into four "modules" (using the [http://yuiblog.com/blog/2007/06/12/module-pattern/ module pattern]): | Narcissus is divided into four "modules" (using the [http://yuiblog.com/blog/2007/06/12/module-pattern/ module pattern]): | ||
* | * <code>Narcissus.definitions</code> (jsdefs.js): basic definitions shared by the other modules | ||
* | * <code>Narcissus.lexer</code> (jslex.js): lexer | ||
* | * <code>Narcissus.parser</code> (jsparse.js): parser | ||
* | * <code>Narcissus.interpreter</code> (jsexec.js): interpreter | ||
The | The <code>Narcissus.interpreter</code> module is optional; that is, it's possible to load just the first three files to obtain a JavaScript parser written in portable JavaScript. | ||
== Host language versions == | == Host language versions == | ||
These are the host language versions required by each module: | These are the host language versions required by each module/source file: | ||
* | * jsdefs.js: ES3 + <code>const</code> + <code>Object.defineProperty</code> | ||
* | * jslex.js: ES3 + <code>const</code> + <code>Object.defineProperty</code> | ||
* | * jsparse.js: ES3 + <code>const</code> + <code>Object.defineProperty</code> | ||
* | * jsexec.js: SpiderMonkey JS 1.9: | ||
** <code>const</code> (Harmony) | ** <code>const</code> (Harmony) | ||
** <code>catch</code> guards (replaceable with <code>catch</code> + <code>if</code>) | ** <code>catch</code> guards (replaceable with <code>catch</code> + <code>if</code>) | ||
| Line 34: | Line 46: | ||
** <code>Object.getOwnPropertyNames</code> (ES5) | ** <code>Object.getOwnPropertyNames</code> (ES5) | ||
** <code>__proto__ = null</code> (replaceable with [http://wiki.ecmascript.org/doku.php?id=strawman:simple_maps_and_sets Harmony maps]) | ** <code>__proto__ = null</code> (replaceable with [http://wiki.ecmascript.org/doku.php?id=strawman:simple_maps_and_sets Harmony maps]) | ||
** <code>__proto__ = obj</code> (replaceable with <code>Object.create</code>) | |||
The first three modules are web-portable. Only | The first three modules are web-portable. Only jsexec.js depends on SpiderMonkey extensions. | ||
== User language versions == | == User language versions == | ||
| Line 43: | Line 56: | ||
'''TODO:''' tighten this up as it stabilizes | '''TODO:''' tighten this up as it stabilizes | ||
== | == Interpreter == | ||
Narcissus is a meta-circular JavaScript interpreter with a very direct representation of values: primitives are self-representing, objects are represented as objects (with their properties accessible via usual property access), and functions are represented as functions. The interpreter is designed this way to allow existing JavaScript functions and objects (such as the standard libraries) to interface directly with Narcissus code without following any special protocol or requiring wrapping and unwrapping. | |||
=== Values === | |||
User-JS primitive values are represented in host-JS directly as themselves. | |||
User-JS objects are represented directly as host-JS objects; each user-property <code>foo</code> is directly represented as a host-property <code>foo</code>. | |||
User-JS functions are represented as proxy functions that wrap a <code>FunctionObject</code>, which encapsulates the <code>Node</code> and <code>ExecutionContext</code> for the closure. | |||
=== Control flow === | |||
Code is always executed with a current <code>ExecutionContext</code>, which contains the current scope chain and <code>this</code> binding. Execution contexts also contain a <code>result</code> property, which is used for the completion value of the current statement or expression or the result of returning from a function or throwing an exception. | |||
= | Calling a user-JS function is represented by calling the host-JS <code>__call__</code> method. Narcissus patches the host-JS <code>Function.prototype</code> to add a default <code>__call__</code> method. Similarly, calling a user-JS function as a constructor (i.e., from <code>new</code>) is represented by calling the host-JS <code>__construct__</code> method. (This is leaky and would be better implemented with private names; see [https://bugzilla.mozilla.org/show_bug.cgi?id=586095 bug 586095].) | ||
Returning from a function via <code>return</code> is represented by throwing the constant <code>RETURN</code>. The return value is stored in the <code>result</code> property of the current execution context. | |||
Throwing a user-JS exception is represented by throwing the constant <code>THROW</code>. The exception value is stored in the <code>result</code> property of the current execution context. | |||
Breaking or continuing a loop is represented by throwing the constant <code>BREAK</code> or <code>CONTINUE</code>, respectively. | |||
Latest revision as of 00:11, 11 August 2010
Terminology
Since JavaScript is both the language of the implementation and the language being implemented, it's helpful to distinguish the two levels conceptually:
- host ("host code," "host JS," etc): JS code in the implementation of Narcissus
- user ("user code," "user JS," etc): JS code being interpreted by Narcissus
Narcissus global object
Loading the Narcissus source files creates a global variable Narcissus.
Narcissus.options is an object which can be used to set some global configuration options for Narcissus. Currently there is just one configuration option:
| Property | Options |
|---|---|
version |
185, "harmony"
|
Narcissus modules
Narcissus is divided into four "modules" (using the module pattern):
Narcissus.definitions(jsdefs.js): basic definitions shared by the other modulesNarcissus.lexer(jslex.js): lexerNarcissus.parser(jsparse.js): parserNarcissus.interpreter(jsexec.js): interpreter
The Narcissus.interpreter module is optional; that is, it's possible to load just the first three files to obtain a JavaScript parser written in portable JavaScript.
Host language versions
These are the host language versions required by each module/source file:
- jsdefs.js: ES3 +
const+Object.defineProperty - jslex.js: ES3 +
const+Object.defineProperty - jsparse.js: ES3 +
const+Object.defineProperty - jsexec.js: SpiderMonkey JS 1.9:
const(Harmony)catchguards (replaceable withcatch+if)letdeclarations (Harmony)Proxy(Harmony)Object.defineProperty(ES5)Object.getOwnPropertyDescriptor(ES5)Object.getPrototypeOf(ES5)Object.getOwnPropertyNames(ES5)__proto__ = null(replaceable with Harmony maps)__proto__ = obj(replaceable withObject.create)
The first three modules are web-portable. Only jsexec.js depends on SpiderMonkey extensions.
User language versions
The versions of JavaScript interpreted by Narcissus are under development. Currently, the interpreter works reasonably well on ES3 code, with support for a few SpiderMonkey extensions.
TODO: tighten this up as it stabilizes
Interpreter
Narcissus is a meta-circular JavaScript interpreter with a very direct representation of values: primitives are self-representing, objects are represented as objects (with their properties accessible via usual property access), and functions are represented as functions. The interpreter is designed this way to allow existing JavaScript functions and objects (such as the standard libraries) to interface directly with Narcissus code without following any special protocol or requiring wrapping and unwrapping.
Values
User-JS primitive values are represented in host-JS directly as themselves.
User-JS objects are represented directly as host-JS objects; each user-property foo is directly represented as a host-property foo.
User-JS functions are represented as proxy functions that wrap a FunctionObject, which encapsulates the Node and ExecutionContext for the closure.
Control flow
Code is always executed with a current ExecutionContext, which contains the current scope chain and this binding. Execution contexts also contain a result property, which is used for the completion value of the current statement or expression or the result of returning from a function or throwing an exception.
Calling a user-JS function is represented by calling the host-JS __call__ method. Narcissus patches the host-JS Function.prototype to add a default __call__ method. Similarly, calling a user-JS function as a constructor (i.e., from new) is represented by calling the host-JS __construct__ method. (This is leaky and would be better implemented with private names; see bug 586095.)
Returning from a function via return is represented by throwing the constant RETURN. The return value is stored in the result property of the current execution context.
Throwing a user-JS exception is represented by throwing the constant THROW. The exception value is stored in the result property of the current execution context.
Breaking or continuing a loop is represented by throwing the constant BREAK or CONTINUE, respectively.