mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
394 lines
15 KiB
394 lines
15 KiB
<h2 id="gettingstarted">Getting started</h2>
|
|
|
|
<h3>Downloading</h3>
|
|
|
|
<p>Download the source distributable from the
|
|
<a href="download.html">Download</a> page.</p>
|
|
|
|
<p>There are currently two distributables: a source distributable
|
|
for using Duktape in your program, and a full distributable for
|
|
Duktape development.</p>
|
|
|
|
<h3>Command line tool</h3>
|
|
|
|
<p>Unpack the distributable:</p>
|
|
<pre>
|
|
$ cd /tmp
|
|
$ tar xvfJ duktape-<version>.tar.xz
|
|
</pre>
|
|
|
|
<p>Compile the command line tool using the provided Makefile (your system
|
|
needs to have <code>readline</code> and <code>ncurses</code> library and headers
|
|
installed):</p>
|
|
<pre>
|
|
# NOTE: ensure you have readline and curses library and headers installed
|
|
$ cd /tmp/duktape-<version>/
|
|
$ make -f Makefile.cmdline
|
|
</pre>
|
|
|
|
<div class="note">
|
|
The command line tool requires <code>readline</code> by default. If it's
|
|
not available or there are other portability issues, try enabling the
|
|
<code>-DDUK_CMDLINE_BAREBONES</code> compile option in the Makefile. The
|
|
option minimizes any non-portable dependencies.
|
|
</div>
|
|
|
|
<p>You can now run Ecmascript code interactively:</p>
|
|
<pre>
|
|
$ ./duk
|
|
((o) Duktape
|
|
[version info]
|
|
duk> print('Hello world!')
|
|
Hello world!
|
|
= undefined
|
|
</pre>
|
|
|
|
<p>You can also run Ecmascript code from a file which is useful for playing with
|
|
features and algorithms. As an example, create <code>fib.js</code>:</p>
|
|
<pre class="ecmascript-code" include="fib.js"></pre>
|
|
|
|
<p>Test the script from the command line:</p>
|
|
<pre>
|
|
$ ./duk fib.js
|
|
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
|
|
Cleaning up...
|
|
</pre>
|
|
|
|
<h3>Integrating Duktape into your program</h3>
|
|
|
|
<p>The command line tool is simply an example of a program which embeds
|
|
Duktape. Embedding Duktape into your program is very simple: just add
|
|
<code>duktape.c</code> and <code>duktape.h</code> to your build, and call the
|
|
Duktape API from elsewhere in your program.</p>
|
|
|
|
<p>The distributable contains a very simple example program, <code>hello.c</code>,
|
|
which illustrates this process. Compile the test program e.g. as:</p>
|
|
<pre>
|
|
$ cd /tmp/duktape-<version>/
|
|
$ gcc -o hello -Isrc/ src/duktape.c examples/hello/hello.c -lm
|
|
</pre>
|
|
|
|
<p>The test program creates a Duktape context and uses it to run some
|
|
Ecmascript code:</p>
|
|
<pre>
|
|
$ ./hello
|
|
Hello world!
|
|
2+3=5
|
|
</pre>
|
|
|
|
<p>Because Duktape is an embeddable interpreter, you don't need to change
|
|
the basic control flow of your program. The basic approach is:</p>
|
|
<ul>
|
|
<li>Create a Duktape context e.g. in program initialization
|
|
(or even on-demand when scripting is needed). Usually you
|
|
would also load your scripts during initialization, though
|
|
that can also be done on-demand.</li>
|
|
<li>Identify points in your code where you would like to use scripting
|
|
and insert calls to script functions there.</li>
|
|
<li>To make a script function call, first push call arguments to the
|
|
Duktape context's <i>value stack</i> using the Duktape API.
|
|
Then, use another Duktape API call to initiate the actual call.</li>
|
|
<li>Once script execution is finished, control is returned to your
|
|
program (the API call returns) and a return value is left on the
|
|
Duktape context's value stack for C code to consume.</li>
|
|
</ul>
|
|
|
|
<p>Let's look at a simple example program. The program reads in a line using
|
|
a C mainloop, calls an Ecmascript helper to transform the line, and prints out
|
|
the transformed line. The line processing function can take advantage of
|
|
Ecmascript goodies like regular expressions, and can be easily modified
|
|
without recompiling the C program.</p>
|
|
|
|
<p>The script code will be placed in <code>process.js</code>. The example
|
|
line processing function converts a plain text line into HTML, and
|
|
automatically bolds text between stars:</p>
|
|
|
|
<pre class="ecmascript-code" include="process.js"></pre>
|
|
|
|
<p>The C code, <code>processlines.c</code> initializes a Duktape context,
|
|
compiles the script, then proceeds to process lines from <code>stdin</code>,
|
|
calling <code>processLine()</code> for every line:</p>
|
|
<pre class="c-code" include="processlines.c"></pre>
|
|
|
|
<p>Let's look at the Duktape specific parts of the example code line by line.
|
|
Here we need to gloss over some details for brevity, see
|
|
<a href="#programming">Programming model</a> for a detailed discussion:</p>
|
|
<ul class="breakdown"> <!-- breakdown -->
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
ctx = duk_create_heap_default();
|
|
if (!ctx) { exit(1); }
|
|
</pre>
|
|
<p>First we create a Duktape context. A context allows us to exchange values
|
|
with Ecmascript code by pushing and popping values to the <b>value stack</b>.
|
|
Most calls in the Duktape API operate with the value stack, pushing, popping,
|
|
and examining values on the stack.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_eval_file(ctx, "process.js");
|
|
duk_pop(ctx); /* pop eval result */
|
|
</pre>
|
|
<p>The first call reads in <code>process.js</code> and evaluates its contents.
|
|
The script registers the <code>processLine()</code> function into the Ecmascript
|
|
global object. The result of the evaluation is pushed on top of the value
|
|
stack. Here we don't need the evaluation result, so we pop the value off
|
|
the stack.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_global_object(ctx);
|
|
duk_get_prop_string(ctx, -1 /*index*/, "processLine");
|
|
</pre>
|
|
<p>The first call pushes the Ecmascript global object to the value stack.
|
|
The second call looks up <code>processLine</code> property of the global object.
|
|
The script in <code>process.js</code> has registered a function into the global
|
|
object with this name. The <code>-1</code> argument is an index to the value
|
|
stack; negative values refer to stack elements starting from the top, so
|
|
<code>-1</code> refers to the topmost element of the stack, the property
|
|
lookup result.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_string(ctx, line);
|
|
</pre>
|
|
<p>Pushes the string pointed to by <code>line</code> to the value stack. The
|
|
string length is automatically determined by scanning for a NUL terminator
|
|
(same as <code>strlen()</code>). Duktape makes a copy of the string when it is
|
|
pushed to the stack, so the <code>line</code> buffer can be freely modified when
|
|
the call returns.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_call(ctx, 1 /*nargs*/);
|
|
</pre>
|
|
<p>At this point the value stack contains: the global object, the processLine
|
|
function, and the <code>line</code> string. This line calls an Ecmascript function
|
|
with the specified number of arguments; here the argument count is 1. The
|
|
target function is expected to reside just before the argument list on the
|
|
value stack. After the API call returns, the arguments have been replaced with
|
|
a single return value, so the stack contains: the global object and the call
|
|
result.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
printf("%s\n", duk_to_string(ctx, -1));
|
|
duk_pop(ctx);
|
|
</pre>
|
|
<p>The <code>duk_to_string()</code> call requests Duktape to convert the value stack
|
|
element at index -1 (the topmost value on the stack, which is the processLine
|
|
function call result here) to a string, returning a <code>const char *</code> pointing
|
|
to the result. This return value is a read-only, NUL terminated UTF-8 value which
|
|
C code can use directly as long as the value resides on the value stack. Here we
|
|
just print out the string. After we've printed the string, we pop the value off
|
|
the value stack.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_destroy_heap(ctx);
|
|
</pre>
|
|
<p>Destroy the Duktape context, freeing all resources held by the context.
|
|
In our example we left the global object on the value stack on purpose.
|
|
This call will free the value stack and all references on the value stack.
|
|
No memory leaks will occur even if the value stack is not empty.</p>
|
|
</li>
|
|
|
|
</ul> <!-- breakdown -->
|
|
|
|
<p>Compile like above:</p>
|
|
<pre>
|
|
$ gcc -o processlines -Isrc/ src/duktape.c processlines.c -lm
|
|
</pre>
|
|
|
|
<p>Test run:</p>
|
|
<pre>
|
|
$ echo "I like *Sam & Max*." | ./processlines
|
|
I like <b>Sam &<!-- avoiding double decode is tricky -->#38; Max</b>.
|
|
</pre>
|
|
|
|
<h3>Calling C code from Ecmascript (Duktape/C bindings)</h3>
|
|
|
|
<p>The integration example illustrated how C code can call into Ecmascript
|
|
to do things which are easy in Ecmascript but difficult in C.</p>
|
|
|
|
<p>Ecmascript also often needs to call into C when the situation is
|
|
reversed. For instance, while scripting is useful for many things, it is
|
|
not optimal for low level byte or character processing. Being able to
|
|
call optimized C helpers allows you to write most of your script logic in
|
|
nice Ecmascript but call into C for the performance critical parts.
|
|
Another reason for using native functions is to provide access to native
|
|
libraries.</p>
|
|
|
|
<p>To implement a native function you write an ordinary C function which
|
|
conforms to a special calling convention, the Duktape/C binding. Duktape/C
|
|
functions take a single argument, a Duktape context, and return a single
|
|
value indicating either error or number of return values. The function
|
|
accesses call arguments and places return values through the Duktape context's
|
|
<i>value stack</i>, manipulated with the Duktape API. We'll go deeper into
|
|
Duktape/C binding and the Duktape API later on. Example:</p>
|
|
<pre class="c-code">
|
|
int my_native_func(duk_context *ctx) {
|
|
double arg = duk_require_number(ctx, 0 /*index*/);
|
|
duk_push_number(ctx, arg * arg);
|
|
return 1;
|
|
}
|
|
</pre>
|
|
|
|
<p>Let's look at this example line by line:</p>
|
|
<ul class="breakdown"> <!-- breakdown -->
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
double arg = duk_require_number(ctx, 0 /*index*/);
|
|
</pre>
|
|
<p>Check that the number at value stack index 0 (bottom of the stack, first
|
|
argument to function call) is a number; if not, throws an error and never
|
|
returns. If the value is a number, return it as a <code>double</code>.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_number(ctx, arg * arg);
|
|
</pre>
|
|
<p>Compute square of argument and push it to the value stack.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
return 1;
|
|
</pre>
|
|
<p>Return from the function call, indicating that there is a (single) return
|
|
value on top of the value stack. You could also return <code>0</code> to indicate
|
|
that no return value is given (in which case Duktape defaults to Ecmascript
|
|
<code>undefined</code>). A negative return value which causes an error to be
|
|
automatically thrown: this is a shorthand for throwing errors conveniently.
|
|
Note that you don't need to pop any values off the stack, Duktape will do that
|
|
for you automatically when the function returns.
|
|
See <a href="#programming">Programming model</a> for more details.</li>
|
|
|
|
</ul> <!-- breakdown -->
|
|
|
|
<p>We'll use a primality test as an example for using native code to speed
|
|
up Ecmascript algorithms. More specifically, our test program searches for
|
|
primes under 1000000 which end with the digits '9999'. The Ecmascript
|
|
version of the program is:</p>
|
|
<pre class="ecmascript-code" include="prime.js"></pre>
|
|
|
|
<p>Note that the program uses the native helper if it's available but falls
|
|
back to an Ecmascript version if it's not. This allows the Ecmascript code
|
|
to be used in other containing programs. Also, if the prime check program
|
|
is ported to another platform where the native version does not compile
|
|
without changes, the program remains functional (though slower) until the
|
|
helper is ported. In this case the native helper detection happens when the
|
|
script is loaded. You can also detect it when the code is actually called
|
|
which is more flexible.</p>
|
|
|
|
<p>A native helper with functionality equivalent to <code>primeCheckEcmascript</code>
|
|
is quite straightforward to implement. Adding a program main we get
|
|
<code>primecheck.c</code>:</p>
|
|
<pre class="c-code" include="primecheck.c"></pre>
|
|
|
|
<p>The new calls here are, line by line:</p>
|
|
<ul class="breakdown"> <!-- breakdown -->
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
int val = duk_require_int(ctx, 0);
|
|
int lim = duk_require_int(ctx, 1);
|
|
</pre>
|
|
<p>These two calls check the two argument values given to the native helper.
|
|
If the values are not of the Ecmascript number type, an error is thrown.
|
|
If they are numbers, their value is converted to an integer and assigned to
|
|
the <code>val</code> and <code>lim</code> locals. The index 0 refers to the first
|
|
function argument and index 1 to the second.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_false(ctx);
|
|
return 1;
|
|
</pre>
|
|
<p>Pushes an Ecmascript <code>false</code> to the value stack. The C return value
|
|
1 indicates that the <code>false</code> value is returned to the Ecmascript caller.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_global_object(ctx);
|
|
duk_push_c_function(ctx, native_prime_check, 2 /*nargs*/);
|
|
duk_put_prop_string(ctx, -2, "primeCheckNative");
|
|
</pre>
|
|
<p>The first call, like before, pushes the Ecmascript global object to the
|
|
value stack. The second call creates an Ecmascript <code>Function</code> object
|
|
and pushes it to the value stack. The function object is bound to the
|
|
Duktape/C function <code>native_prime_check</code>: when the Ecmascript function
|
|
created here is called from Ecmascript, the C function gets invoked.
|
|
The second argument (<code>2</code>) to the call indicates how many arguments
|
|
the C function gets on the value stack. If the caller gives fewer arguments,
|
|
the missing arguments are padded with <code>undefined</code>; if the caller gives
|
|
more arguments, the extra arguments are dropped automatically. Finally, the
|
|
third call registers the function object into the global object with the
|
|
name <code>primeCheckNative</code> and pops the function value off the stack.
|
|
</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_get_prop_string(ctx, -1, "primeTest");
|
|
duk_call(ctx, 0);
|
|
duk_pop(ctx);
|
|
</pre>
|
|
<p>When we come here the value stack already contains the global object
|
|
at the stack top. The first line looks up the <code>primeTest</code> function
|
|
from the global object (which was defined by the loaded script). The
|
|
second line calls the <code>primeTest</code> function with zero arguments.
|
|
The third line pops the call result off the stack; we don't need the return
|
|
value here.</p>
|
|
</li>
|
|
|
|
</ul> <!-- breakdown -->
|
|
|
|
<p>Compile like above:</p>
|
|
<pre>
|
|
$ gcc -o primecheck -Isrc/ src/duktape.c primecheck.c -lm
|
|
</pre>
|
|
|
|
<p>Test run:</p>
|
|
<pre>
|
|
$ time ./primecheck
|
|
Have native helper: true
|
|
49999 59999 79999 139999 179999 199999 239999 289999 329999 379999 389999
|
|
409999 419999 529999 599999 619999 659999 679999 769999 799999 839999 989999
|
|
|
|
real 0m2.985s
|
|
user 0m2.976s
|
|
sys 0m0.000s
|
|
</pre>
|
|
|
|
<p>Because most execution time is spent in the prime check, the speed-up
|
|
compared to plain Ecmascript is significant. You can check this by editing
|
|
<code>prime.js</code> and disabling the use of the native helper:</p>
|
|
<pre class="ecmascript-code">
|
|
// Select available helper at load time
|
|
var primeCheckHelper = primeCheckEcmascript;
|
|
</pre>
|
|
|
|
<p>Re-compiling and re-running the test:</p>
|
|
<pre>
|
|
$ time ./primecheck
|
|
Have native helper: false
|
|
49999 59999 79999 139999 179999 199999 239999 289999 329999 379999 389999
|
|
409999 419999 529999 599999 619999 659999 679999 769999 799999 839999 989999
|
|
|
|
real 0m23.609s
|
|
user 0m23.573s
|
|
sys 0m0.000s
|
|
</pre>
|
|
|
|
|