NAME
JE - Pure-Perl ECMAScript (JavaScript) Engine
"JE" is short for "JavaScript::Engine."
VERSION
Version 0.016 (alpha release)
The API is still subject to change. If you have the time and the interest, please experiment with this module. 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
$j->prop(document => $obj); # set property
$j->prop('document'); # get a property
# Also:
$j->{document} = $obj;
$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 is a pure-Perl JavaScript engine. Here are some of its strengths:
- -
-
Easy to install (no C compiler necessary)
- -
-
Compatible with Data::Dump::Streamer, so the runtime environment can be serialised
- -
-
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)
JE's greatest weakness is that it's slow (well, what did you expect?).
METHODS
See also JE::Object
, which this class inherits from, and JE::Types
.
- $j = JE->new
-
This class method constructs and returns a new JavaScript environment, the JE object itself being the global object.
- $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 JE::Code/FUNCTIONS 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 theexecute
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
andget
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 nameddocument
:$j->eval('this.document')->set({});
Note that I used
this.document
rather than justdocument
, 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->prop('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->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->bind_class( LIST )
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 => { ... }
isa => 'Object',
# OR:
prototype => $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 are as follows (all optional except for package
or name
--you must specify at least one of the two):
- 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 ofpackage
.If it is a coderef, it will be used as the constructor.
If this is omitted, no constructor will be made.
- 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 itsprototype
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. This may change. (Perhaps we should see whether the class has overloading to determine this.)
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 => { ... }
-
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
andstore
keys will be expected to be either coderefs or method names. If onlyfetch
is given, the property will be read-only. If onlystore
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 itsprototype
property. - 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. - wrapper => sub { ... }
-
If
wrapper
is specified, all other arguments will be ignored except forpackage
(orname
ifpackage
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 binding a class, 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), such that operators like typeof
and ===
will work. 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.
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.
If constructor
is not given, a constructor function will be made that throws an error when invoked, unless wrapper
is given.
To use Perl's overloading within JavaScript, specify
to_string => sub { "$_[0]" }
to_number => sub { 0+$_[0] }
- $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).
4 POD Errors
The following errors were encountered while parsing the POD:
- Around line 701:
alternative text 'JE::Code/FUNCTIONS' contains non-escaped | or /
- Around line 874:
You forgot a '=back' before '=head2'
- Around line 1341:
'=item' outside of any '=over'
- Around line 1383:
'=end for me' is invalid. (Stack: =begin for)