mirror of
https://github.com/dyne/FreeJ.git
synced 2026-02-12 07:40:57 +01:00
javascript now statically included git-svn-id: svn://dyne.org/rastasoft/freej/freej@610 383723c8-4afa-0310-b8a8-b1afb83214fc
346 lines
14 KiB
HTML
346 lines
14 KiB
HTML
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=koi8-r">
|
|
<meta name="Author" content="Vladimir Livshits">
|
|
<meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
|
|
<title>PerlConnect Documentation</title>
|
|
<style>
|
|
A:link {text-decoration: none}
|
|
A:visited {text-decoration: none}
|
|
</style>
|
|
</head>
|
|
<body background="bg.jpg">
|
|
|
|
<center>
|
|
<h3>
|
|
P<font size=-1>ERL</font>C<font size=-1>ONNECT AND </font>JS<font size=+0>.PM</font></h3></center>
|
|
|
|
<center>U<font size=-1>SER-LEVEL </font><font size=+1>D</font><font size=-1>OCUMENTATION</font>
|
|
<br><a href="mailto:livshits@cs.stanford.edu">Vladimir Livshits</a>
|
|
<br>
|
|
<hr SIZE=1 NOSHADE WIDTH="100%"></center>
|
|
|
|
<ol>
|
|
<li>
|
|
<a href="#History">Update history</a></li>
|
|
|
|
<li>
|
|
<a href="#Overview">Overview</a></li>
|
|
|
|
<li>
|
|
<a href="#Features">Features</a></li>
|
|
|
|
<li>
|
|
<a href="#Design">Design</a></li>
|
|
|
|
<li>
|
|
<a href="#Installation">Installation</a></li>
|
|
|
|
<li>
|
|
<a href="#Limitations">Current Limitations and Further Work</a></li>
|
|
</ol>
|
|
|
|
<h4>
|
|
<a NAME="History"></a>Update History</h4>
|
|
|
|
<ul>
|
|
<li>
|
|
3/8/99 -- added some more details, especially pertaining to <tt>PerlConnect.pm</tt></li>
|
|
|
|
<li>
|
|
8/98 -- this document created</li>
|
|
</ul>
|
|
|
|
<h4>
|
|
<a NAME="Overview"></a>Overview</h4>
|
|
PerlConnect provides glue for the developer between JavaScript and Perl.
|
|
It currently consists of two parts, PerlConnect implemented in C and JS.pm,
|
|
a Perl module written using XSUBs. PerlConnect and JS.pm allow calling
|
|
Perl from JS and JS from Perl, respectively. Whenever possible, it is attempted
|
|
to achieve the maximum level of transparency for calling one language
|
|
from the other. This is done by converting values between the two languages,
|
|
creating wrappers around objects, and emulating the standard language syntax.
|
|
<h4>
|
|
<a NAME="Features"></a>PerlConnect Features</h4>
|
|
PerlConnect allows running a Perl interpreter concurrently with your JavaScript
|
|
embedding and executing Perl commands from JavaScript. You usually need
|
|
to create a Perl interpreter by doing something like this:
|
|
<blockquote><tt>p = new Perl('Sys::Hostname', 'Test::Harness')</tt></blockquote>
|
|
In addition to creating an interpreter, this will also include the libraries
|
|
you pass to the Perl constructor, which is equivalent to <tt>use Sys::Hostname;
|
|
use Test::Harness</tt>. You can always include libraries explicitly by
|
|
using <tt>p.eval('use Sys::Hostname; use Test::Harness')</tt>. There is
|
|
also another way to do this: <tt>p.use('Sys::Hostname', 'Test::Harness')</tt>.
|
|
As you can see, TMTOWTDI.
|
|
<p><b>Note: </b>If the statements above fail on you saying something about
|
|
libraries not found in the search path, you need to make sure the modules
|
|
PerlConnect uses, JS.pm and PerlConnect.pm live in some directory accessible
|
|
from the search path. Search path can be set by adjusting the value of PERLLIB
|
|
and PERL5LIB environment variables. See <a href="#Installation">installation</a>
|
|
for more details.
|
|
<p><b>Note: </b>Despite the illusion p = new Perl(...) syntax might create,
|
|
there is actually only one version of the Perl interpreter running. I.e.
|
|
if you create two interpreters like this:
|
|
<blockquote><tt>p = new Perl; q = new Perl;</tt>
|
|
<br><tt>p.eval("$a='ha-'x20");</tt></blockquote>
|
|
Now you'll see that <tt>q["$a"]</tt> will give you <tt>$a</tt>'s value
|
|
from <tt>p</tt>.
|
|
<p>Naturally, you will want to look at the result of your function calls
|
|
and <tt>eval</tt> statements. Suppose, you do something like this:
|
|
<blockquote><tt>line = p.eval("'-' x 80")</tt></blockquote>
|
|
Perl's eval returns the last statement evaluated, unless you explicitly
|
|
say <tt>return</tt>. So now <tt>line</tt> contains 80 dashes. You can do
|
|
similar things with non-scalar data types:
|
|
<blockquote><tt>p.use('Time::gmtime');</tt>
|
|
<br><tt>t = p.eval('Time::gmtime::gmtime') // returns
|
|
[49,0,4,24,6,98,5,204,0]</tt></blockquote>
|
|
assigns a Perl array to <tt>t</tt>. You can print <tt>t</tt>, use the <tt>for/in</tt>
|
|
syntax to walk through it, compute its length, etc. You can read and assign
|
|
to individual elements using the standard syntax. However, PerlValues,
|
|
that is, the value we get from Perl, don't support all the standard operations,
|
|
for instance, don't expect <tt>t.reverse()</tt> to work. Hashes can also
|
|
be returned from Perl:
|
|
<blockquote><tt>info=p.eval("{ver=>$], pid=>$$}")</tt></blockquote>
|
|
Now you can look at individual hash keys like this:
|
|
<blockquote><tt>info["ver"]</tt> or <tt>info.pid</tt></blockquote>
|
|
Suppose you want to use Perl to perform pattern-based string replacement.
|
|
Here's how you can do it from JavaScript:
|
|
<blockquote><tt>p.eval("\</tt>
|
|
<br><tt> sub perl_replace(){\</tt>
|
|
<br><tt> my($string, $find, $replace)
|
|
= @_;\</tt>
|
|
<br><tt> eval(\"\\$string =~
|
|
s/$find/$replace/g;\");\</tt>
|
|
<br><tt> return $string;\</tt>
|
|
<br><tt> }"</tt>
|
|
<br><tt>);</tt></blockquote>
|
|
and now
|
|
<blockquote><tt>p.perl_replace('Quick brown fox jumped over a lazy dog',
|
|
'dog', 'rhino')</tt></blockquote>
|
|
produces what you'd expect.
|
|
<p>You can use the same syntax to call procedures defined in modules other
|
|
than<tt> main. </tt>The example with<tt> gmtime </tt>can be rewritten like
|
|
this:
|
|
<blockquote><tt>p.use('Time::gmtime');</tt>
|
|
<br><tt>t = p.Time.gmtime.gmtime() // returns [49,0,4,24,6,98,5,204,0]</tt></blockquote>
|
|
You can reference variables exported by modules other than <tt>main</tt>
|
|
like this:
|
|
<blockquote><tt>a=p.Foo.$bar </tt>or<tt> a=p.Foo["$bar"] </tt>or
|
|
<br><tt>a=p.Foo["@bar"]</tt>or<tt> a=p.Foo["%bar"]</tt></blockquote>
|
|
Each of the above statements return either an immediate JS value, for
|
|
scalar types, or a PerlValue for compound types. <tt>a.type </tt>contains
|
|
the type of the PerlValue in <tt>a</tt>. <i>This may change because we
|
|
may end up separating Perl hashes and arrays into separate classes.</i>
|
|
<h4>
|
|
JS.pm Features</h4>
|
|
<i>JS.pm is much less tested then PerlConnect.</i> You should be able to
|
|
do similar things from Perl. Just say
|
|
<blockquote><tt>use JS;</tt>
|
|
<br><tt>$js = <b>new</b> JS();</tt></blockquote>
|
|
and now you can do something like this:
|
|
<blockquote><tt>$js-><b>eval</b>(q/</tt>
|
|
<blockquote><tt>Object o = {};</tt>
|
|
<br><tt>o.a = 'p';</tt>
|
|
<br><tt>o.b = 'q';</tt>
|
|
<br><tt>return o;</tt></blockquote>
|
|
<tt>/);</tt></blockquote>
|
|
<b>Note:</b> Please see test.js and test.pl, test scripts that test and
|
|
demonstrate various features of PerlConnect and JS.pm, respectively. They
|
|
will help get you started.
|
|
<h4>
|
|
<a NAME="Design"></a>PerlConnect Design</h4>
|
|
PerlConnect is written in C. It uses both JavaScript and Perl APIs and
|
|
implements a mapping between the two. The following JavaScript objects
|
|
are implemented by PerlConnect:
|
|
<br>
|
|
<center><table BORDER COLS=2 WIDTH="80%" >
|
|
<tr ALIGN=CENTER BGCOLOR="#CCCCCC">
|
|
<td ALIGN=CENTER VALIGN=CENTER WIDTH="20%"><b>Object</b></td>
|
|
|
|
<td><b>What it does</b></td>
|
|
</tr>
|
|
|
|
<tr ALIGN=CENTER VALIGN=CENTER>
|
|
<td WIDTH="30"><tt>Perl</tt></td>
|
|
|
|
<td ALIGN=LEFT VALIGN=TOP>Perl Interpreter Object. Its prototype type
|
|
is PerlModule, it corresponds to <tt>main::</tt>. Supports <tt>eval</tt>,
|
|
<tt>call</tt>,
|
|
<tt>use</tt>.</td>
|
|
</tr>
|
|
|
|
<tr ALIGN=CENTER VALIGN=CENTER>
|
|
<td><tt>PerlModule</tt></td>
|
|
|
|
<td ALIGN=LEFT VALIGN=TOP>Implements JS-like syntax for Perl modules. Doesn't
|
|
export provide any methods. <tt>path</tt> property shows the name of the
|
|
Perl module the object represents.</td>
|
|
</tr>
|
|
|
|
<tr ALIGN=CENTER VALIGN=CENTER>
|
|
<td><tt>PerlValue</tt></td>
|
|
|
|
<td ALIGN=LEFT VALIGN=TOP>Represents a value returned from <tt>eval</tt>,
|
|
<tt>call</tt>,
|
|
or obtained by using the subscript notation (<tt>p.Foo["@bar"]</tt>). Its
|
|
Perl type is stored in the <tt>type</tt> property.</td>
|
|
</tr>
|
|
</table></center>
|
|
|
|
<p>See comments in the code, <tt>jsperl.c</tt> and <tt>JS.pm</tt> for more
|
|
info.
|
|
<br><b>Note: </b> PerlConnect heavily relies on PerlConnect.pm, which
|
|
does some background magic for it. PerlConnect.pm should <i>not</i> be
|
|
<tt>use</tt>d. Use JS.pm instead.
|
|
<h4>
|
|
JS.pm Design</h4>
|
|
JSConnect is written using XSUBs, the language in which Perl extensions
|
|
are implemented. See the output of <tt>man perlxs/perlguts/perlembed/perlxstut</tt>
|
|
for more details. The source files are <tt>JS.xs</tt> and <tt>typemap</tt>.
|
|
After processing them using the XSUBs compiler, <tt>xsubpp</tt>, the resulting
|
|
C file should be compiled into a DLL. See <tt>JS.xs</tt> for more details
|
|
on how to to run the XSUBS compiler. You will need a sufficiently recent
|
|
version of Perl to run JS.pm successfully. <tt>JS.pm</tt> provides bootstrapping
|
|
mechanism to load this DLL.
|
|
<p>The following Perl packages (objects) are implemented:
|
|
<br>
|
|
<center><table BORDER COLS=2 WIDTH="80%" >
|
|
<tr ALIGN=CENTER BGCOLOR="#CCCCCC">
|
|
<td ALIGN=CENTER VALIGN=CENTER WIDTH="20%"><b>Package</b></td>
|
|
|
|
<td><b>What it contains</b></td>
|
|
</tr>
|
|
|
|
<tr ALIGN=CENTER VALIGN=CENTER>
|
|
<td><tt>JS</tt></td>
|
|
|
|
<td ALIGN=LEFT VALIGN=TOP>Doesn't do anything in particular at this
|
|
point except defining a constructor. So one can say <tt>$js = <b>new</b>
|
|
JS()</tt>, which will create a new runtime, add a context to it and return
|
|
that Context. JS also defines a bunch of private functions called from
|
|
C by PerlConnect. They are not exposed by default, but pushed onto <tt>@EXPORT_OK</tt>
|
|
array instead.</td>
|
|
</tr>
|
|
|
|
<tr ALIGN=CENTER VALIGN=CENTER>
|
|
<td><tt>JS::Runtime</tt></td>
|
|
|
|
<td ALIGN=LEFT VALIGN=TOP>Corresponds to <tt>JSRuntime*</tt> struct. Provides
|
|
a constructor and destructor. The destructor is invoked automatically,
|
|
so you don't have to worry about Runtime deallocation. Constructor syntax
|
|
is the following: <tt>$rt = <b>new</b> JS::Runtime(10_000)</tt>, where
|
|
the parameter is the same number you pass to <tt>JS_NewRuntime</tt>. There
|
|
are many private functions created in <tt>JS.xs</tt> that are not exported
|
|
by default.</td>
|
|
</tr>
|
|
|
|
<tr ALIGN=CENTER VALIGN=CENTER>
|
|
<td><tt>JS::Context</tt></td>
|
|
|
|
<td ALIGN=LEFT VALIGN=TOP>Corresponds to <tt>JSContext*</tt> struct. Provides
|
|
a constructor and destructor. The destructor is invoked automatically,
|
|
so you don't have to worry about Context deallocation. Constructor syntax
|
|
is the following: <tt>$rt = <b>new</b> JS::Context($rt, 1_000)</tt>, where
|
|
the parameter is the same number you pass to <tt>JS_NewContext</tt>. There
|
|
are many private functions created in <tt>JS.xs</tt> that are not exported
|
|
by default.</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td ALIGN=CENTER><tt>JS::Object</tt></td>
|
|
|
|
<td>Corresponds to <tt>JSObject*</tt> struct. There is not that much here
|
|
yet. This object is intended as a wrapper around the <tt>JSObject* struct</tt>.
|
|
Support for tying hashes and possibly arrays with <tt>JS::Object</tt>s
|
|
is coming.</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td ALIGN=CENTER><i><tt><font color="#000000">[JS::Array]</font></tt></i></td>
|
|
|
|
<td><i>I am not quite sure if this is needed. One might probably get away
|
|
with just <tt>JS::Object</tt> defined. If it's implemented, it will be
|
|
very much similar to <tt>JS::Object</tt> above.</i></td>
|
|
</tr>
|
|
</table></center>
|
|
|
|
<p>All the modules above follow the convention of storing the variable
|
|
they return in the <tt>$this</tt> variable of the current class. So <tt>$JS::Context::this</tt>
|
|
will always be the last context created. <i>Currently, this is where JS
|
|
API function that require contexts get it.</i>
|
|
<h4>
|
|
<a NAME="Installation"></a>PerlConnect Installation</h4>
|
|
PerlConnect requires <tt>js/src</tt> and the Perl libraries and headers.
|
|
The only <tt>js/src</tt> file that must be included in <tt>jsapi.h </tt>in
|
|
the top level directory. You need to compile it together with Perl libraries.
|
|
Refer to the <tt>perlembed</tt> man page for more details.
|
|
<br><b>On WINNT:</b>
|
|
<br>There are MSDEV Workspace and project files in the main PerlConnect
|
|
directory. There are three projects included in the PerlConnect workspace:
|
|
JS, PerlConnect and PerlConnectShell. You can use the latter to test PerlConnect.
|
|
You will probably need to adjust the library and include paths. Set PERL_SRC
|
|
environment variable to point to the directory where you unpacked and compiled
|
|
Perl sources. It is assumed that the directory structure is more or less
|
|
fixed, that is, you have PerlConnect in
|
|
<tt>js/src/perlconnect</tt>. PerlConnect
|
|
project produces <tt>PerlConnect.dll</tt>, you should make sure it and
|
|
<tt>perl.dll</tt> are in your path for PerlConnectShell to work.
|
|
<p>JS also builds a DLL, <tt>JS.dll</tt> which is supposed to reside where
|
|
Perl's DynaLoader can find it. On my machine I put it under <tt>c:\perl\lib\auto\JS\JS.dll</tt>.
|
|
You can also put it in <tt>c:\perl\lib\</tt>. You can probably adjust PERLLIB
|
|
to achieve the desired result. See Perl's DynaLoader documentation for
|
|
more info on how dynamic libraries are found.
|
|
<p><b>On UNIX:</b>
|
|
<br>We are currently working on a UNIX makefile. Please <a href="mailto:livshits@cs.stanford.edu">contact
|
|
me</a> for more details.
|
|
<h4>
|
|
On the MAC:</h4>
|
|
We never really thought of supporting the Mac. If anyone is really interested
|
|
in seeing Mac support, <a href="mailto:livshits@cs.stanford.edu">drop me a line</a>.
|
|
<h4>
|
|
<a NAME="Limitations"></a>Current Limitations and Further Work</h4>
|
|
|
|
<ol>
|
|
<li>
|
|
Perl variables currently can't be assigned to, that is, <tt>p["$a"]=100</tt>
|
|
doesn't do anything.</li>
|
|
|
|
<li>
|
|
You can only have one interpreter running at a time. Despite the fact that
|
|
you can create multiple Perl objects on JavaScript, they all share the
|
|
same namespace. We can probably use <tt>Safe.pm</tt> to implement independent
|
|
namespaces.</li>
|
|
|
|
<li>
|
|
Module name resolution reports an error only when you try to evaluate
|
|
the last element of the resolution chain. Here is what I mean: if you reference
|
|
<tt>p.Foo.Bar.Var</tt> and <tt>For</tt> or <tt>Bar</tt> don't exist, it
|
|
will only complain that p.Foo.Bar.Var is not a valid variable. Perl 5.005
|
|
provides <tt>exists Foo::{Bar::}</tt> to check if Foo::Bar is a valid package.</li>
|
|
|
|
<li>
|
|
Dynamic loading of the Perl interpreter only if it is required.</li>
|
|
|
|
<li>
|
|
Recursive printing of Perl's arrays and hashes can be added. See Data::Dumper.pm</li>
|
|
|
|
<li>
|
|
Full support for tied hashes and arrays in Perl</li>
|
|
|
|
<li>
|
|
Calling JavaScript functions and accessing variables from Perl. JavaScript
|
|
calling syntax support using AUTOLOADing.</li>
|
|
|
|
<li>
|
|
JS can be made a directory with <tt>Object.pm</tt>, <tt>Context.pm</tt>,
|
|
etc. in it. See how C or Tk are organized on CPAN</li>
|
|
|
|
<li>
|
|
Distribution model for JS.pm. Perl provides something by default. See <tt>h2xs</tt>
|
|
man page, for example.</li>
|
|
</ol>
|
|
|
|
</body>
|
|
</html>
|