How to embed the JavaScript engine

  • Revision slug: How_to_embed_the_JavaScript_engine
  • Revision title: How to embed the JavaScript engine
  • Revision id: 49804
  • Created:
  • Creator: Pmash
  • Is current revision? No
  • Comment added category

Revision Content

A Bare Bones Tutorial

How to start up the VM and Execute a Script

Without any error checking for:

  • null returns from JS_ functions that return pointers
  • false returns from JS_ functions that return booleans

(errors are conventionally saved in a JSBool variable named ok).

JSRuntime *rt;
JSContext *cx;
JSObject *global;
JSClass global_class = {
	"global",0,
	JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
	JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub
};

/*
 * You always need:
 *        a runtime per process,
 *        a context per thread,
 *        a global object per context,
 *        standard classes (e.g. Date).
 */
rt = JS_NewRuntime(0x100000);
cx = JS_NewContext(rt, 0x1000);
global = JS_NewObject(cx, &global_class, NULL, NULL);
JS_InitStandardClasses(cx, global);

/*
 * Now suppose script contains some JS to evaluate, say "22/7" as a
 * bad approximation for Math.PI, or something longer, such as this:
 * "(function fact(n){if (n <= 1) return 1; return n * fact(n-1)})(5)"
 * to compute 5!
 */
char *script = "...";
jsval rval;
JSString *str;
JSBool ok;

ok = JS_EvaluateScript(cx, global, script, strlen(script),
					   filename, lineno, &rval);
str = JS_ValueToString(cx, rval);
printf("script result: %s\n", JS_GetStringBytes(str));

How to call C functions from JavaScript

Say the C function is named doit and it would like at least two actual parameters when called (if the caller supplies fewer, the JS engine should ensure that undefined is passed for the missing ones):

#define DOIT_MINARGS 2

static JSBool
doit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	/*
	 * Look in argv for argc actual parameters, set *rval to return a
	 * value to the caller.
	 */
	...
}

Then to wire it up to JS, you could write:

ok = JS_DefineFunction(cx, global, "doit", doit, DOIT_MINARGS, 0);

Or, if you had a bunch of native functions to define, you would probably put them in a table:

static JSFunctionSpec my_functions[] = {
	{"doit", doit, DOIT_MINARGS, 0, 0},
	etc...
	{0,0,0,0,0},
};

(the final, all-zeroes function specifier terminates the table) and say:

ok = JS_DefineFunctions(cx, global, my_functions);

How to call JavaScript functions from C (such as "onClick") Say the click event is for the top-most or focused UI element at position (x, y):

JSObject *target, *event;
jsval argv[1], rval;

/*
* Find event target and make event object to represent this click.
* Pass cx to NewEventObject so JS_NewObject can be called.
*/
target = FindEventTargetAt(cx, global, x, y);
event = NewEventObject(cx, "click", x, y);
argv[0] = OBJECT_TO_JSVAL(event);

/* To emulate the DOM, you might want to try "onclick" too. */
ok = JS_CallFunctionName(cx, target, "onClick", 1, argv, &rval);

/* Now test rval to see whether we should cancel the event. */
if (JSVAL_IS_BOOLEAN(rval) && !JSVAL_TO_BOOLEAN(rval))
	CancelEvent(event);

Again, I've elided error checking (such as testing for !ok after the call), and I've faked up some C event management routines that emulate the DOM's convention of canceling an event if its handler returns false.

Original Document Information

  • Author: Brendan Eich
  • Last Updated Date: 21 February, 2000

Revision Source

<h2 name="A_Bare_Bones_Tutorial">A Bare Bones Tutorial</h2>
<h4 name="How_to_start_up_the_VM_and_Execute_a_Script">How to start up the VM and Execute a Script</h4>
<p>Without any error checking for:
</p>
<ul><li> null returns from JS_ functions that return pointers
</li><li> false returns from JS_ functions that return booleans
</li></ul>
<p>(errors are conventionally saved in a JSBool variable named ok).
</p>
<pre>JSRuntime *rt;
JSContext *cx;
JSObject *global;
JSClass global_class = {
	"global",0,
	JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
	JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub
};

/*
 * You always need:
 *        a runtime per process,
 *        a context per thread,
 *        a global object per context,
 *        standard classes (e.g. Date).
 */
rt = JS_NewRuntime(0x100000);
cx = JS_NewContext(rt, 0x1000);
global = JS_NewObject(cx, &amp;global_class, NULL, NULL);
JS_InitStandardClasses(cx, global);

/*
 * Now suppose script contains some JS to evaluate, say "22/7" as a
 * bad approximation for Math.PI, or something longer, such as this:
 * "(function fact(n){if (n &lt;= 1) return 1; return n * fact(n-1)})(5)"
 * to compute 5!
 */
char *script = "...";
jsval rval;
JSString *str;
JSBool ok;

ok = JS_EvaluateScript(cx, global, script, strlen(script),
					   filename, lineno, &amp;rval);
str = JS_ValueToString(cx, rval);
printf("script result: %s\n", JS_GetStringBytes(str));
</pre>
<h4 name="How_to_call_C_functions_from_JavaScript">How to call C functions from JavaScript</h4>
<p>Say the C function is named doit and it would like at least two actual parameters when called (if the caller supplies fewer, the JS engine should ensure that undefined is passed for the missing ones):
</p>
<pre>#define DOIT_MINARGS 2

static JSBool
doit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	/*
	 * Look in argv for argc actual parameters, set *rval to return a
	 * value to the caller.
	 */
	...
}
</pre>
<p>Then to wire it up to JS, you could write:
</p>
<pre>ok = JS_DefineFunction(cx, global, "doit", doit, DOIT_MINARGS, 0);
</pre>
<p>Or, if you had a bunch of native functions to define, you would probably put them in a table:
</p>
<pre>static JSFunctionSpec my_functions[] = {
	{"doit", doit, DOIT_MINARGS, 0, 0},
	etc...
	{0,0,0,0,0},
};
</pre>
<p>(the final, all-zeroes function specifier terminates the table) and say:
</p>
<pre>ok = JS_DefineFunctions(cx, global, my_functions);
</pre>
<p>How to call JavaScript functions from C (such as "onClick")
Say the click event is for the top-most or focused UI element at position (x, y):
</p>
<pre>JSObject *target, *event;
jsval argv[1], rval;

/*
* Find event target and make event object to represent this click.
* Pass cx to NewEventObject so JS_NewObject can be called.
*/
target = FindEventTargetAt(cx, global, x, y);
event = NewEventObject(cx, "click", x, y);
argv[0] = OBJECT_TO_JSVAL(event);

/* To emulate the DOM, you might want to try "onclick" too. */
ok = JS_CallFunctionName(cx, target, "onClick", 1, argv, &amp;rval);

/* Now test rval to see whether we should cancel the event. */
if (JSVAL_IS_BOOLEAN(rval) &amp;&amp; !JSVAL_TO_BOOLEAN(rval))
	CancelEvent(event);
</pre>
<p>Again, I've elided error checking (such as testing for !ok after the call), and I've faked up some C event management routines that emulate the DOM's convention of canceling an event if its handler returns false.
</p>
<div class="originaldocinfo">
<h2 name="Original_Document_Information"> Original Document Information </h2>
<ul><li> Author: Brendan Eich
</li><li> Last Updated Date: 21 February, 2000
</li></ul>
</div>
Revert to this revision