| JavaScript-Lite documentation | Contained in the JavaScript-Lite distribution. |
JavaScript::Lite - Bare-bones interface to SpiderMonkey ECMAscript API
use JavaScript::Lite;
my $js = JavaScript::Lite->new;
$js->assign(numbers => [ 2, 4, 6, 8, 10 ]);
$js->assign(start => 1);
$js->eval(q{
function add_next() {
var n;
if(n = numbers.shift()) {
start = start + n;
return start;
} else {
return;
}
}
});
while(my $next = $js->invoke("add_next")) {
print "$next\n";
}
JavaScript::Lite is a bare-bones interface to the SpiderMonkey
ECMAscript engine. It aims to provide as little functionality (and
therefore as little overhead) as is neccessary to connect perl with
ECMAscript. Efficiency is the goal here; the intended environments
are places where you are going to be calling from perl into
ECMAscript thousands (or millions) of times in succession (such as
using ECMAscript to drive the NPC logic in a perl-based MMORPG,
or writing a spam filter in perl where the end users can write
custom spam rules in ECMAscript, or...)
NOTE: This is very, very alpha software. I intend to keep the API more-or-less stable, but there may be quirks, and new features will be added in future releases (so long as they do not slow the existing features down!).
If you want powerful, flexible, full-featured blending of ECMAscript with
perl, please see the JavaScript package. So why would you want to use
JavaScript::Lite?
JavaScript::Lite can run much, much faster than the JavaScript
distribution. This is because the flexibility that JavaScript
offers you comes at a cost; class/object translations are expensive,
and due to the fact that each language has different memory management, allowing
both perl to call ECMA, and ECMA to call perl can cause irrecoverable
memory leaks (as can allowing complex data structures to flow in both
directions); the ECMA garbage collector can be expensive to run
(even in "maybe" mode), and just the additional overhead of tracking
all of this object/function binding/linking can be expensive.
In other words, here are some more features;
Constructor; creates and returns a new JavaScript::Lite object
(and underlying runtime/context). $max_mem is the maximum
memory (in bytes) the JavaScript environment should be allowed to
consume. Defaults to 1MB.
(If you go over this limit, JavaScript::Lite should raise
an exception. Unfortunately, it doesn't yet... it causes a
segmentation fault instead. :-( So be careful.)
Evaluate a block of JavaScript code, returning the result as a
scalar. If $filename is specified, tells the javascript
interpreter that the code came from this file. Otherwise,
the default filename "(eval)" is used.
If the code fails to compile, an exception is raised, which must
be cleared if you want to keep using your JavaScript context;
see "clear_error" below.
Note that this will not return JavaScript objects/structures; only strings, numbers, or undef.
Evaluate a block of ECMAscript, returning nothing.
If you don't care about the return value of the script, this
method works slightly faster than eval above. $filename
is required.
Reads the file $filename from your filesystem and evaluates
it as ECMAscript, returning any scalar result.
Same as eval_file, except that no result is returned to perl.
Invoke the global ECMAscript function called $name.
Invoking methods on ECMAscript objects is not yet supported.
Passing arguments into the ECMAscript function is not yet
supported, but should be in the next release.
Like eval, returns any scalar return value that the
function may have returned.
Tell the SpiderMonkey garbage collector that it may run if it so wishes. If you don't do this every so often, your ECMAscript context will run out of memory and crash. This is not done automatically because even considering running the garbage collector can add significant overhead.
Clear any error condition that may have been raised in
ECMAscript. You must do this if you want to continue using your
JavaScript::Lite object after an eval or invoke raises
an error.
Assign $value to the global ECMAscript variable $name.
$value may be a scalar, hashref, arrayref, or any nested
combination. The entire structure passed into $value will
be copied into ECMAscript. Globs and coderefs are not supported.
$value must not be a self-referencing structure, or else
JavaScript::Lite will crash (see BUGS below).
Assign $value to the property $name on the global
ECMAscript object called $object. As with assign,
$value may be a scalar, hashref, arrayref, or any nested
combination.
$object must be a top-level ECMAscript global object.
Nesting more than one layer deep (eg; "some_object.some.deep.property")
is not supported. For that functionality, see the JavaScript
distribution.
Run $callback every $interval branches in the javascript.
Branches are caused by things such as for() or while() loop invocation.
$callback should a a subroutine reference; if the subroutine returns
a true value, the javascript will continue running. If it returns a false
value or dies, the javascript will terminate and an exception will be thrown.
If you do not specify $interval, the callback will be executed during
every branch in javascript. This will slow down the script considerably;
for best results, you should use a value at least in the several thousands.
Explicitly resets the branch counter to zero
If your JavaScript::Lite object runs out of memory (as defined by
$max_mem when you create the object), it can cause a
segmentation fault. I want it to raise an exception instead,
I just haven't figured out how yet. :-(
JavaScript::Lite does not detect self-referencing
data structures. And since it tries to make a copy of the data
you pass in, if you pass in a self-referencing structure, it
will consume all available memory until it crashes. For example,
this will always crash:
my $insane_hash = { foo => "bar" };
$insane_hash->{baz} = $insane_hash;
$cx->assign(insane_hash => $insane_hash);
I haven't quite decided if this is a bug or a feature yet... there is
RAM and CPU overhead in tracking self-referencing structures,
so doing so would slow JavaScript::Lite down. If you need to use
them, use the JavaScript module instead, which will let you
bind directly to them instead of copying.
for the original JavaScript module.
for creating a situation where I would need to write this.
for hosting YAPC::NA 2008, where this was hacked together.
This is free software, you may use and distribute it under the same terms as perl itself.
This software uses mozilla's SpiderMonkey JSAPI for it's ECMAscript implementation, so in order for it to be useful to you, you must accept the terms of the mozilla license as well.
Tyler "Crackerjack" MacDonald <japh@crackerjack.net>
| JavaScript-Lite documentation | Contained in the JavaScript-Lite distribution. |
package JavaScript::Lite; use 5.006; use strict; use warnings; use Carp qw(croak); our $VERSION = '0.04'; require XSLoader; XSLoader::load('JavaScript::Lite', $VERSION); return 1; sub new { my $class = shift; my $maxmem = shift || 1048576; my $self = $class->create($maxmem); return bless $self, $class; } sub eval_file { my($self, $file) = @_; my $fh; open($fh, '<', $file) or croak "$file: $!"; my $script = join('', <$fh>); return $self->eval($script, $file); } sub eval_file_void { my($self, $file) = @_; my $fh; open($fh, '<', $file) or croak "$file: $!"; my $script = join('', <$fh>); $self->eval_void($script, $file); } sub eval { my($self, $code, $file) = @_; $file ||= "(eval)"; $self->eval_js($code, $file); }