document is the global object
dialog is the child object
// following code might be needed in some case
// #define __STDC_LIMIT_MACROS
// #include <stdint.h>
#include <mozjs-45/js/TypeDecls.h>
#include <mozjs-45/js/RootingAPI.h>
#include <mozjs-45/js/Class.h>
#include "jsapi.h"
#include "js/Initialization.h"
#include "js/Conversions.h"
using namespace JS;
class JavaScriptEngine {
public:
static JSClass document_class;
static JSClass dialog_class;
JSRuntime *rt = NULL;
JSContext *cx = NULL;
RootedObject* document;
RootedObject* dialog;
RootedObject* anonymous;
JavaScriptEngine() {
JS_Init();
// Create a JS runtime.
rt = JS_NewRuntime(8L * 1024L * 1024L);
// Create a context.
cx = JS_NewContext(rt, 8192);
// Enter a request before running anything in the context.
JSAutoRequest ar(cx);
// Create the global object and a new compartment.
document = new RootedObject(cx, JS_NewGlobalObject(cx, &document_class, nullptr,
JS::DontFireOnNewGlobalHook));
JSAutoCompartment ac(cx, *document);
JS_InitStandardClasses(cx, *document);
JS_SetErrorReporter(rt, reportError);
}
~JavaScriptEngine() {
// Shut everything down.
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();
delete document;
delete dialog;
delete anonymous;
}
static void reportError(JSContext *cx, const char *message, JSErrorReport * report) {
fprintf(stderr, "%s:%u:%s\n",
report->filename ? report->filename : "[no filename]",
(unsigned int) report->lineno,
message);
}
bool run(JSContext *cx, RootedObject *globaloObj, const char *script, const char *filename = "noname", int lineno = 1) {
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, *globaloObj);
JS::RootedValue rval(cx);
JS::CompileOptions opts(cx);
opts.setFileAndLine(filename, lineno);
bool ok = JS::Evaluate(cx, opts, script, strlen(script), &rval);
if (!ok)
return 1;
JSString *str = rval.toString();
if (rval.isObject()) {
char result[500];
strcpy(result, script);
bool ok = JS::Evaluate(cx, opts, strcat(result, " + ' '"), strlen(strcat(result, " + ' '")), &rval);
if (!ok)
return 1;
str = rval.toString();
if (str != NULL)
printf("output: %s\n", JS_EncodeString(cx, str));
} else if (rval.isInt32()) {
size_t i = rval.toInt32();
printf("output: is number %d\n", i);
} else if (rval.isNull()) {
printf("rval.isNull\n");
} else if (rval.isUndefined()) {
printf("rval.undefined()\n");
} else if (str != NULL) {
printf("output: %s\n", JS_EncodeString(cx, str));
} else {
printf("output: no match \n");
}
return true;
}
bool changeScope() {
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, *document);
JS::HandleObject parent = JS::HandleObject::fromMarkedLocation(&document->get());
JS::MutableHandleObject protop = JS::MutableHandleObject::fromMarkedLocation(&document->get());
if (JS_GetPrototype(cx, parent, protop)) {
JS::HandleObject parentprotop = JS::HandleObject::fromMarkedLocation(&protop.get());
dialog = new RootedObject(cx, JS_NewObjectWithGivenProto(cx, &dialog_class, parentprotop));
}
}
};
JSClass JavaScriptEngine::document_class = {
"document",
JSCLASS_GLOBAL_FLAGS,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};
JSClass JavaScriptEngine::dialog_class = {
"dialog",
JSCLASS_GLOBAL_FLAGS,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};
int main(int argc, const char *argv[]) {
JavaScriptEngine e;
e.run(
e.cx, e.document, "var document = this; var x = 5;");
e.run(
e.cx, e.document, "document.x");
e.changeScope();
e.run(
e.cx, e.dialog, "x");
e.run(
e.cx, e.dialog, "var dialog = this;");
e.run(
e.cx, e.dialog, "x=10");
e.run(
e.cx, e.dialog, "dialog.x");
e.run(
e.cx, e.dialog, "document.x");
}