-
Notifications
You must be signed in to change notification settings - Fork 118
Narcissus internals
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
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.
Property | Options | Meaning |
---|---|---|
version |
"185" (default), "harmony"
|
JavaScript language version |
ecma3OnlyMode |
false (default), true
|
strict adherence to ES3 syntax |
parenFreeMode |
false (default), true
|
experimental "paren-free" syntactic extensions |
Currently there is just one configuration option, version
, which selects the user language version.
Narcissus is divided into four "modules" (using the module pattern):
-
Narcissus.definitions
(jsdefs.js
): basic definitions shared by the other modules -
Narcissus.lexer
(jslex.js
): lexer -
Narcissus.parser
(jsparse.js
): parser -
Narcissus.interpreter
(jsexec.js
): interpreter -
Narcissus.decompiler
(jsdecomp.js
): decompiler
The Narcissus.interpreter
and Narcissus.decompiler
modules are optional; that is, it's possible to load just the first three files to obtain a JavaScript parser written in portable JavaScript.
These are the host language versions required by each module/source file:
- jsdefs.js: ES3 +
const
+__proto__ = null
+Object.defineProperty
- jslex.js: ES3 +
const
+__proto__ = null
+Object.defineProperty
- jsparse.js: ES3 +
const
+__proto__ = null
+Object.defineProperty
- jsdecomp.js: not yet specified
- jsssa.js: not yet specified
- jsexec.js: SpiderMonkey JS 1.8.5:
-
const
(Harmony) -
catch
guards (replaceable withcatch
+if
) -
let
declarations (Harmony) -
Proxy
(Harmony) -
Object.defineProperty
(ES5) -
Object.getOwnPropertyDescriptor
(ES5) -
Object.getPrototypeOf
(ES5) -
Object.getOwnPropertyNames
(ES5) -
__proto__ = null
(replaceable with ES5Object.create
or Harmony maps) -
__proto__ = obj
(replaceable with ES5Object.create
)
-
The first four modules are fairly web-portable, except for IE. The jsssa.js
and jsexec.js
files depend on SpiderMonkey extensions.
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. We will soon be including support for various Harmony proposals as well.
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.
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.
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.