NAME¶
JE - Pure-Perl ECMAScript (JavaScript) Engine
VERSION¶
Version 0.065 (alpha release)
The API is still subject to change. If you have the time and the interest,
please experiment with this module (or even lend a hand :-). If you have any
ideas for the API, or would like to help with development, please e-mail the
author.
SYNOPSIS¶
use JE;
$j = new JE; # create a new global object
$j->eval('({"this": "that", "the": "other"}["this"])');
# returns "that"
$parsed = $j->parse('new Array(1,2,3)');
$rv = $parsed->execute; # returns a JE::Object::Array
$rv->value; # returns a Perl array ref
$obj = $j->eval('new Object');
# create a new object
$foo = $j->{document}; # get property
$j->{document} = $obj; # set property
$j->{document} = {}; # gets converted to a JE::Object
$j->{document}{location}{href}; # autovivification
$j->method(alert => "text"); # invoke a method
# create global function from a Perl subroutine:
$j->new_function(print => sub { print @_, "\n" } );
$j->eval(<<'--end--');
function correct(s) {
s = s.replace(/[EA]/g, function(s){
return ['E','A'][+(s=='E')]
})
return s.charAt(0) +
s.substring(1,4).toLowerCase() +
s.substring(4)
}
print(correct("ECMAScript")) // :-)
--end--
DESCRIPTION¶
JE, short for JavaScript::Engine (imaginative, isn't it?), is a pure-Perl
JavaScript engine. Here are some of its strengths:
- -
- Easy to install (no C compiler necessary*)
- -
- The parser can be extended/customised to support extra (or fewer) language
features (not yet complete)
- -
- All JavaScript datatypes can be manipulated directly from Perl (they all
have overloaded operators)
- -
- The JavaScript datatypes provide "TO_JSON" methods for
compatibility with JSON.pm.
JE's greatest weakness is that it's slow (well, what did you expect?). It also
uses and leaks lots of memory. (There is an experimental JE::Destroyer (q.v.)
module that solves this if you load it first and then call
"JE::Destroyer::destroy($j)" on the JE object when you have finished
with it.)
* If you are using perl 5.9.3 or lower, then Tie::RefHash::Weak is required.
Recent versions of it require Variable::Magic, an XS module (which requires a
compiler of course), but version 0.02 of the former is just pure Perl with no
XS dependencies.
There is currently an experimental version of the run-time engine, which is
supposed to be faster, although it currently makes compilation slower. (If you
serialise the compiled code and use that, you should notice a speed-up.) It
will eventually replace the current one when it is complete. (It does not yet
respect tainting or max_ops, or report line numbers correctly.) You can
activate it by setting to 1 the ridiculously named YES_I_WANT_JE_TO_OPTIMISE
environment variable, which is just a temporary hack that will later be
removed.
USAGE¶
Simple Use¶
If you simply need to run a few JS functions from Perl, create a new JS
environment like this:
my $je = new JE;
If necessary, make Perl subroutines available to JavaScript:
$je->new_function(warn => sub { warn @_ });
$je->new_function(ok => \&Test::More::ok);
Then pass the JavaScript functions to "eval":
$je->eval(<<'___');
function foo() {
return 42
}
// etc.
___
# or perhaps:
use File::Slurp;
$je->eval(scalar read_file 'functions.js');
Then you can access those function from Perl like this:
$return_val = $je->{foo}->();
$return_val = $je->eval('foo()');
The return value will be a special object that, when converted to a string,
boolean or number, will behave exactly as in JavaScript. You can also use it
as a hash, to access or modify its properties. (Array objects can be used as
arrays, too.) To call one of its JS methods, you should use the
"method" method: "$return_val->method('foo')". See
JE::Types for more information.
Custom Global Objects¶
To create a custom global object, you have to subclass JE. For instance, if all
you need to do is add a "self" property that refers to the global
object, then override the "new" method like this:
package JEx::WithSelf;
@ISA = 'JE';
sub new {
my $self = shift->SUPER::new(@_);
$self->{self} = $self;
return $self;
}
Using Perl Objects from JS¶
See "bind_class", below.
Writing Custom Data Types¶
See JE::Types.
METHODS¶
See also "JE::Object", which this class inherits from, and
"JE::Types".
- $j = JE->new( %opts )
- This class method constructs and returns a new JavaScript environment, the
JE object itself being the global object.
The (optional) options it can take are "max_ops" and
"html_mode", which correspond to the methods listed below.
- $j->parse( $code, $filename, $first_line_no )
- "parse" parses the code contained in $code and returns a parse
tree (a JE::Code object).
If the syntax is not valid, "undef" will be returned and $@ will
contain an error message. Otherwise $@ will be a null string.
The JE::Code class provides the method "execute" for executing the
pre-compiled syntax tree.
$filename and $first_line_no, which are both optional, will be stored inside
the JE::Code object and used for JS error messages. (See also
add_line_number in the JE::Code man page.)
- $j->compile( STRING )
- Just an alias for "parse".
- $j->eval( $code, $filename, $lineno )
- "eval" evaluates the JavaScript code contained in $code. E.g.:
$j->eval('[1,2,3]') # returns a JE::Object::Array which can be used as
# an array ref
If $filename and $lineno are specified, they will be used in error messages.
$lineno is the number of the first line; it defaults to 1.
If an error occurs, "undef" will be returned and $@ will contain
the error message. If no error occurs, $@ will be a null string.
This is actually just a wrapper around "parse" and the
"execute" method of the JE::Code class.
If the JavaScript code evaluates to an lvalue, a JE::LValue object will be
returned. You can use this like any other return value (e.g., as an array
ref if it points to a JS array). In addition, you can use the
"set" and "get" methods to set/get the value of the
property to which the lvalue refers. (See also JE::LValue.) E.g., this
will create a new object named "document":
$j->eval('this.document')->set({});
Note that I used "this.document" rather than just
"document", since the latter would throw an error if the
variable did not exist.
- $j->new_function($name, sub { ... })
- $j->new_function(sub { ... })
- This creates and returns a new function object. If $name is given, it will
become a property of the global object.
Use this to make a Perl subroutine accessible from JavaScript.
For more ways to create functions, see JE::Object::Function.
This is actually a method of JE::Object, so you can use it on any object:
$j->{Math}->new_function(double => sub { 2 * shift });
- $j->new_method($name, sub { ... })
- This is just like "new_function", except that, when the function
is called, the subroutine's first argument (number 0) will be the object
with which the function is called. E.g.:
$j->eval('String.prototype')->new_method(
reverse => sub { scalar reverse shift }
);
# ... then later ...
$j->eval(q[ 'a string'.reverse() ]); # returns 'gnirts a'
- $j->max_ops
- $j->max_ops( $new_value )
- Use this to set the maximum number of operations that "eval" (or
JE::Code's "execute") will run before terminating. (You can use
this for runaway scripts.) The exact method of counting operations is
consistent from one run to another, but is not guaranteed to be consistent
between versions of JE. In the current implementation, an operation means
an expression or sub-expression, so a simple "return" statement
with no arguments is not counted.
With no arguments, this method returns the current value.
As shorthand, you can pass "max_ops => $foo" to the
constructor.
If the number of operations is exceeded, then "eval" will return
undef and set $@ to a 'max_ops (xxx) exceeded.
- $j->html_mode
- $j->html_mode( $new_value )
- Use this to turn on 'HTML mode', in which HTML comment delimiters are
treated much like "//". "new_value" is a boolean.
Since this violates ECMAScript, it is off by default.
With no arguments, this method returns the current value.
As shorthand, you can pass "html_mode => 1" to the
constructor.
- $j->upgrade( @values )
- This method upgrades the value or values given to it. See "UPGRADING
VALUES" in JE::Types for more detail.
If you pass it more than one argument in scalar context, it returns the
number of arguments--but that is subject to change, so don't do that.
- $j->undefined
- Returns the JavaScript undefined value.
- $j->null
- Returns the JavaScript null value.
- $j->true
- Returns the JavaScript true value.
- $j->false
- Returns the JavaScript false value.
- $j->bind_class( LIST )
- (This method can create a potential security hole. Please see
"BUGS", below.)
Synopsis¶
$j->bind_class(
package => 'Net::FTP',
name => 'FTP', # if different from package
constructor => 'new', # or sub { Net::FTP->new(@_) }
methods => [ 'login','get','put' ],
# OR:
methods => {
log_me_in => 'login', # or sub { shift->login(@_) }
chicken_out => 'quit',
}
static_methods => {
# etc. etc. etc.
}
to_primitive => \&to_primitive # or a method name
to_number => \&to_number
to_string => \&to_string
props => [ 'status' ],
# OR:
props => {
status => {
fetch => sub { 'this var never changes' }
store => sub { system 'say -vHysterical hah hah' }
},
# OR:
status => \&fetch_store # or method name
},
static_props => { ... }
hash => 1, # Perl obj can be used as a hash
array => 1, # or as an array
# OR (not yet implemented):
hash => 'namedItem', # method name or code ref
array => 'item', # likewise
# OR (not yet implemented):
hash => {
fetch => 'namedItem',
store => sub { shift->{+shift} = shift },
},
array => {
fetch => 'item',
store => sub { shift->[shift] = shift },
},
isa => 'Object',
# OR:
isa => $j->{Object}{prototype},
);
# OR:
$j->bind_class(
package => 'Net::FTP',
wrapper => sub { new JE_Proxy_for_Net_FTP @_ }
);
Description¶
(Some of this is random order, and probably needs to be rearranged.)
This method binds a Perl class to JavaScript. LIST is a hash-style list of
key/value pairs. The keys, listed below, are all optional except for
"package" or "name"--you must specify at least one of the
two.
Whenever it says you can pass a method name to a particular option, and that
method is expected to return a value (i.e., this does not apply to "props
=> { property_name => { store => 'method' } }"), you may append
a colon and a data type (such as ':String') to the method name, to indicate to
what JavaScript type to convert the return value. Actually, this is the name
of a JS function to which the return value will be passed, so 'String' has to
be capitalised. This also means than you can use 'method:eval' to evaluate the
return value of 'method' as JavaScript code. One exception to this is that the
special string ':null' indicates that Perl's "undef" should become
JS's "null", but other values will be converted the default way.
This is useful, for instance, if a method should return an object or
"null", from JavaScript's point of view. This ':' feature does not
stop you from using double colons in method names, so you can write
'Package::method:null' if you like, and rest assured that it will split on the
last colon. Furthermore, just 'Package::method' will also work. It won't split
it at all.
- package
- The name of the Perl class. If this is omitted, "name" will be
used instead.
- name
- The name the class will have in JavaScript. This is used by
"Object.prototype.toString" and as the name of the constructor.
If omitted, "package" will be used.
- constructor => 'method_name'
- constructor => sub { ... }
- If "constructor" is given a string, the constructor will treat
it as the name of a class method of "package".
If it is a coderef, it will be used as the constructor.
If this is omitted, the constructor will raise an error when called. If
there is already a constructor with the same name, however, it will be
left as it is (though methods will still be added to its prototype
object). This allows two Perl classes to be bound to a single JavaScript
class:
$j->bind_class( name => 'Foo', package => 'Class::One', methods => ... );
$j->bind_class( name => 'Foo', package => 'Class::Two' );
- methods => [ ... ]
- methods => { ... }
- If an array ref is supplied, the named methods will be bound to JavaScript
functions of the same names.
If a hash ref is used, the keys will be the names of the methods from
JavaScript's point of view. The values can be either the names of the Perl
methods, or code references.
- static_methods
- Like "methods" but they will become methods of the constructor
itself, not of its "prototype" property.
- to_primitive => sub { ... }
- to_primitive => 'method_name'
- When the object is converted to a primitive value in JavaScript, this
coderef or method will be called. The first argument passed will, of
course, be the object. The second argument will be the hint ('number' or
'string') or will be omitted.
If to_primitive is omitted, the usual valueOf and toString methods will be
tried as with built-in JS objects, if the object does not have overloaded
string/boolean/number conversions. If the object has even one of those
three, then conversion to a primitive will be the same as in Perl.
If "to_primitive => undef" is specified, primitivisation
without a hint (which happens with "<" and "==")
will throw a TypeError.
- to_number
- If this is omitted, "to_primitive($obj, 'number')" will be used.
If set to undef, a TypeError will be thrown whenever the object is
numified.
- to_string
- If this is omitted, "to_primitive($obj, 'string')" will be used.
If set to undef, a TypeError will be thrown whenever the object is
strung.
- props => [ ... ]
- props => { ... }
- Use this to add properties that will trigger the provided methods or
subroutines when accessed. These property definitions can also be
inherited by subclasses, as long as, when the subclass is registered with
"bind_class", the superclass is specified as a string (via
"isa", below).
If this is an array ref, its elements will be the names of the properties.
When a property is retrieved, a method of the same name is called. When a
property is set, the same method is called, with the new value as the
argument.
If a hash ref is given, for each element, if the value is a simple scalar,
the property named by the key will trigger the method named by the value.
If the value is a coderef, it will be called with the object as its
argument when the variable is read, and with the object and the new value
as its two arguments when the variable is set. If the value is a hash ref,
the "fetch" and "store" keys will be expected to be
either coderefs or method names. If only "fetch" is given, the
property will be read-only. If only "store" is given, the
property will be write-only and will appear undefined when accessed. (If
neither is given, it will be a read-only undefined property--really
useful.)
- static_props
- Like "props" but they will become properties of the constructor
itself, not of its "prototype" property.
- hash
- If this option is present, then this indicates that the Perl object can be
used as a hash. An attempt to access a property not defined by
"props" or "methods" will result in the retrieval of a
hash element instead (unless the property name is a number and
"array" is specified as well).
The value you give this option should be one of the strings '1-way' and
'2-way' (also 1 and 2 for short).
If you specify '1-way', only properties corresponding to existing hash
elements will be linked to those elements; properties added to the object
from JavaScript will be JavaScript's own, and will not affect the wrapped
object. (Consider how node lists and collections work in web browsers.)
If you specify '2-way', an attempt to create a property in JavaScript will
be reflected in the underlying object.
To do: Make this accept '1-way:String', etc.
- array
- This is just like "hash", but for arrays. This will also create
a property named 'length'.
To do: Make this accept '1-way:String', etc.
- unwrap => 1
- If you specify this and it's true, objects passed as arguments to the
methods or code refs specified above are 'unwrapped' if they are proxies
for Perl objects (see below). And null and undefined are converted to
"undef".
This is experimental right now. I might actually make this the default.
Maybe this should provide more options for fine-tuning, or maybe what is
currently the default behaviour should be removed. If anyone has any
opinions on this, please e-mail the author.
- isa => 'ClassName'
- isa => $prototype_object
- (Maybe this should be renamed 'super'.)
The name of the superclass. 'Object' is the default. To make this new
class's prototype object have no prototype, specify "undef".
Instead of specifying the name of the superclass, you can provide the
superclass's prototype object.
If you specify a name, a constructor function by that name must already
exist, or an exception will be thrown. (I supposed I could make JE smart
enough to defer retrieving the prototype object until the superclass is
registered. Well, maybe later.)
- wrapper => sub { ... }
- If "wrapper" is specified, all other arguments will be ignored
except for "package" (or "name" if "package"
is not present).
When an object of the Perl class in question is 'upgraded,' this subroutine
will be called with the global object as its first argument and the object
to be 'wrapped' as the second. The subroutine is expected to return an
object compatible with the interface described in JE::Types.
If "wrapper" is supplied, no constructor will be created.
After a class has been bound, objects of the Perl class will, when passed to
JavaScript (or the "upgrade" method), appear as instances of the
corresponding JS class. Actually, they are 'wrapped up' in a proxy object (a
JE::Object::Proxy object), that provides the interface that JS operators
require (see JE::Types). If the object is passed back to Perl, it is the
proxy, not the original object that is returned. The proxy's
"value" method will return the original object.
But, if the
"unwrap" option above is used when a class is bound, the original
Perl object will be passed to any methods or properties belonging to that
class.
This behaviour is still subject to change. See
"unwrap", above.
Note that, if you pass a Perl object to JavaScript before binding its class,
JavaScript's reference to it (if any) will remain as it is, and will not be
wrapped up inside a proxy object.
To use Perl's overloading within JavaScript, well...er, you don't have to do
anything. If the object has "", "0+" or "bool"
overloading, that will automatically be detected and used.
- $j->new_parser
- This returns a parser object (see JE::Parser) which allows you to
customise the way statements are parsed and executed (only partially
implemented).
- $j->prototype_for( $class_name )
- $j->prototype_for( $class_name, $new_val )
- Mostly for internal use, this method is used to store/retrieve the
prototype objects used by JS's built-in data types. The class name should
be 'String', 'Number', etc., but you can actually store anything you like
in here. :-)
TAINTING¶
If a piece of JS code is tainted, you can still run it, but any strings or
numbers returned, assigned or passed as arguments by the tainted code will be
tainted (even if it did not originated from within the code). E.g.,
use Taint::Util;
taint($code = "String.length");
$foo = 0 + new JE ->eval($code); # $foo is now tainted
This does not apply to string or number
objects, but, if the code created
the object, then its internal value
will be tainted, because it created
the object by passing a simple string or number argument to a constructor.
IMPLEMENTATION NOTES¶
Apart from items listed under "BUGS", below, JE follows the ECMAScript
v3 specification. There are cases in which ECMAScript leaves the precise
semantics to the discretion of the implementation. Here is the behaviour in
such cases:
- •
- The global "parseInt" can interpret its first argument either as
decimal or octal if it begins with a 0 not followed by 'x', and the second
argument is omitted. JE uses decimal.
- •
- Array.prototype.toLocaleString uses ',' as the separator.
The spec. states that, whenever it (the spec.), say to throw a SyntaxError, an
implementation may provide other behaviour instead. Here are some instances of
this:
- •
- "return" may be used outside a function. It's like an 'exit'
statement, but it can return a value:
var thing = eval('return "foo"; this = statement(is,not) + executed')
- •
- "break" and "continue" may be used outside of loops.
In which case they act like "return" without arguments.
- •
- Reserved words (except "case" and "break") can be used
as identifiers when there is no ambiguity.
- •
- Regular expression syntax that is not valid ECMAScript in general follows
Perl's behaviour. (See JE::Object::RegExp for the exceptions.)
JE also supports the "escape" and "unescape" global
functions (not part of ECMAScript proper, but in the appendix).
BUGS¶
To report bugs, please e-mail the author.
Bona Fide Bugs¶
- •
- "bind_class" has a security hole: An object methodXs
corresponding Function object can be applied to any Perl object or class
from within JS. (E.g., if you have allowed a Foo object's
"wibbleton" method to be called from JS, then a Bar object's
method of the same name can be, too.)
Fixing this is a bit complicated. If anyone would like to help, please let
me know. (The problem is that the same code would be repeated a dozen
times in "bind_class"'s closures--a maintenance nightmare likely
to result in more security bugs. Is there any way to eliminate all those
closures?)
- •
- The JE::Scope class, which has an "AUTOLOAD" sub that delegates
methods to the global object, does not yet implement the "can"
method, so if you call $scope->can('to_string') you will get a false
return value, even though scope objects can
"to_string".
- •
- "hasOwnProperty" does not work properly with arrays and
arguments objects.
- •
- Sometimes line numbers reported in error messages are off. E.g., in the
following code--
foo(
(4))
--, if "foo" is not a function, line 2 will be reported instead of
line 1.
- •
- Currently, [:blahblahblah:]-style character classes donXt work if followed
by a character class escape (\s, \d, etc.) within the class.
"/[[:alpha:]\d]/" is interpreted as
"/[\[:alph]\d\]/".
- •
- If, in perl 5.8.x, you call the "value" method of a JE::Object
that has a custom fetch subroutine for one of its enumerable properties
that throws an exception, you'll get an 'Attempt to free unreferenced
scalar' warning.
- •
- On Solaris in perl 5.10.0, the Date class can cause an 'Out of memory'
error which I find totally inexplicable. Patches welcome. (I don't have
Solaris, so I can't experiment with it.)
- •
- Case-tolerant regular expressions allow a single character to match
multiple characters, and vice versa, in those cases where a character's
uppercase equivalent is more than one character; e.g., "/ss/"
can match the double S ligature. This is contrary to the ECMAScript spec.
See the source code of JE::Object::RegExp for more details.
- •
- Currently any assignment that causes an error will result in the 'Cannot
assign to a non-lvalue' error message, even if it was for a different
cause. For instance, a custom "fetch" routine might die.
- •
- The parser doesnXt currently support Unicode escape sequences in a regular
expression literalXs flags. It currently passes them through verbatim to
the RegExp constructor, which then croaks.
- •
- Under perl 5.8.8, the following produces a double free; something I need
to look into:
"".new JE ->eval(q| Function('foo','return[a]')() | )
- •
- The "var" statement currently evaluates the rhs before the lhs,
which is wrong. This affects the following, which should return 5, but
returns undefined:
with(o={x:1})var x = (delete x,5); return o.x
- •
- Currently if a try-(catch)-finally statementXs "try" and
"catch" blocks don't return anything, the return value is taken
from the "finally" block. This is incorrect. There should be no
return value. In other words, this should return 3:
eval(' 3; try{}finally{5} ')
- •
- Compound assignment operators (+=, etc.) currently get the value of the
rhs first, which is wrong. The following should produce "1b",
but gives "2b":
a = 1; a += (a=2,"b")
- •
- Serialisation of RegExp objects with Data::Dump::Streamer is currently
broken (and has been since 0.022).
Limitations¶
- •
- JE is not necessarily IEEE 754-compliant. It depends on the OS. For this
reason the Number.MIN_VALUE and Number.MAX_VALUE properties may not have
the same values as ECMAScript, and sometimes rounding (via
"toPrecision", etc.) goes the wrong way.
- •
- A Perl subroutine called from JavaScript can sneak past a
"finally" block and avoid triggering it:
$j = new JE;
$j->new_function(outta_here => sub { last outta });
outta: {
$j->eval('
try { x = 1; outta_here() }
finally { x = 2 }
');
}
print $j->{x}, "\n";
- •
- NaN and Infinity do not work properly on some Windows compilers. 32-bit
ActivePerl seems not to work, but I have been told 64-bit is OK.
Strawberry Perl works fine, which is what most people are using.
Incompatibilities with ECMAScript...¶
...that are probably due to typos in the spec.
- •
- In a try-catch-finally statement, if the 'try' block throws an error and
the 'catch' and 'finally' blocks exit normally--i.e., not as a result of
throw/return/continue/break--, the error originally thrown within the
'try' block is supposed to be propagated, according to the spec. JE does
not re-throw the error. (This is consistent with other ECMAScript
implementations.)
I believe there is a typo in the spec. in clause 12.14, in the '
TryStatement : try Block Catch Finally' algorithm.
Step 5 should probably read 'Let C = Result(4),' rather than
'If Result(4).type is not normal, Let C =
Result(4).'
- •
- If the expression between the two colons in a "for(;;)" loop
header is omitted, the expression before the first colon is not supposed
to be evaluated. JE does evaluate it, regardless of whether the expression
between the two colons is present.
I think this is also a typo in the spec. In the first algorithm in clause
12.6.3, step 1 should probably read 'If ExpressionNoIn is not
present, go to step 4,' rather than 'If the first Expression is not
present, go to step 4.'
- •
- The "setTime" method of a Date object does what one would expect
(it sets the number of milliseconds stored in the Date object and returns
that number). According to the obfuscated definition in the ECMAScript
specification, it should always set it to NaN and return NaN.
I think I've found yet another typo in the spec. In clause 15.9.5.27,
' Result(1)' and and 'Result(2)' are probably supposed to be
' Result(2)' and ' Result(3)', respectively.
PREREQUISITES¶
perl 5.8.4 or higher
Scalar::Util 1.14 or higher
Exporter 5.57 or higher
Tie::RefHash::Weak, for perl versions earlier than 5.9.4
The TimeDate distribution (more precisely, Time::Zone and Date::Parse)
Encode 2.08 or higher
Note: JE will probably end up with Unicode::Collate in the list of
dependencies.
AUTHOR, COPYRIGHT & LICENSE¶
Copyright (C) 2007-14 Father Chrysostomos <sprout [at] cpan [dot] org>
This program is free software; you may redistribute it and/or modify it under
the same terms as perl.
Some of the code was derived from Data::Float, which is copyrighted (C) 2006,
2007, 2008 by Andrew Main (Zefram).
ACKNOWLEDGEMENTS¶
Some of the
Thanks to Max Maischein, Kevin Cameron, Chia-liang Kao and Damyan Ivanov for
their contributions,
to Andy Armstrong, Yair Lenga, Alex Robinson, Christian Forster, Imre Rad, Craig
Mackenna and Toby Inkster for their suggestions,
and to the CPAN Testers for their helpful reports.
SEE ALSO¶
The other JE man pages, especially the following (the rest are listed on the
JE::Types page):
- JE::Destroyer
- JE::Types
- JE::Object
- JE::Object::Function
- JE::LValue
- JE::Scope
- JE::Code
- JE::Parser
ECMAScript Language Specification (ECMA-262)
JavaScript.pm, JavaScript::SpiderMonkey and JavaScript::Lite--all interfaces to
Mozilla's open-source SpiderMonkey JavaScript engine.
JavaScript::V8
WWW::Mechanize::Plugin::JavaScript