How to embed the JavaScript engine
From MDC
Contents |
[edit] A Bare Bones Tutorial
[edit] 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));
[edit] 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);
[edit] How to call JavaScript functions from C
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.