summaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/mozjs/MozJsScriptEngine.cpp218
-rw-r--r--src/plugins/mozjs/MozJsScriptEngine.hpp76
2 files changed, 294 insertions, 0 deletions
diff --git a/src/plugins/mozjs/MozJsScriptEngine.cpp b/src/plugins/mozjs/MozJsScriptEngine.cpp
new file mode 100644
index 0000000..b7ff002
--- /dev/null
+++ b/src/plugins/mozjs/MozJsScriptEngine.cpp
@@ -0,0 +1,218 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "MozJsScriptEngine.hpp"
+
+namespace ousia {
+namespace script {
+
+/*
+ * Some important links to the SpiderMonkey (mozjs) documentation:
+ *
+ * Documentation overview:
+ * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/
+ *
+ * User Guide:
+ * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_User_Guide
+ *
+ * API Reference:
+ * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference
+ */
+
+/* Constants */
+
+static const uint32_t MOZJS_RT_MEMSIZE = 64L * 1024L * 1024L;
+static const uint32_t MOZJS_CTX_STACK_CHUNK_SIZE = 8192;
+
+/* Class MozJsScriptEngineScope */
+
+/**
+ * The class of the global object.
+ */
+static JSClass globalClass = {
+ "global", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub,
+ JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr};
+
+MozJsScriptEngineScope::MozJsScriptEngineScope(JSRuntime *rt) : rt(rt)
+{
+ // Create the execution context
+ cx = JS_NewContext(rt, MOZJS_CTX_STACK_CHUNK_SIZE);
+ if (!cx) {
+ throw ScriptEngineException{"MozJs JS_NewContext failed"};
+ }
+
+ // Start a context request
+ JS_BeginRequest(cx);
+
+ // Set some context options
+ JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_EXTRA_WARNINGS |
+ JSOPTION_VAROBJFIX | JSOPTION_DONT_REPORT_UNCAUGHT);
+
+ // Create the rooted global object
+ global =
+ new JS::RootedObject(cx, JS_NewGlobalObject(cx, &globalClass, nullptr));
+
+ // Enter a compartment (heap memory region) surrounding the global object
+ oldCompartment = JS_EnterCompartment(cx, *global);
+
+ // Populate the global object with the standard classes
+ if (!JS_InitStandardClasses(cx, *global)) {
+ throw ScriptEngineException{"MozJS JS_InitStandardClasses failed"};
+ }
+}
+
+MozJsScriptEngineScope::~MozJsScriptEngineScope()
+{
+ // Leave the compartment
+ JS_LeaveCompartment(cx, oldCompartment);
+
+ // Free the reference to the local object
+ delete global;
+
+ // End the request
+ JS_EndRequest(cx);
+
+ // Destroy the execution context
+ JS_DestroyContext(cx);
+}
+
+Variant MozJsScriptEngineScope::toVariant(const JS::Value &val)
+{
+ if (val.isBoolean()) {
+ return Variant{val.toBoolean()};
+ }
+ if (val.isInt32()) {
+ return Variant{(int64_t)val.toInt32()};
+ }
+ if (val.isDouble()) {
+ return Variant{val.toDouble()};
+ }
+ if (val.isString()) {
+ // TODO: Remove the need for using "c_str"!
+ return Variant{toString(val.toString()).c_str()};
+ }
+ return Variant::Null;
+}
+
+void MozJsScriptEngineScope::handleErr(bool ok)
+{
+ if (!ok && JS_IsExceptionPending(cx)) {
+ JS::Value exception;
+ if (JS_GetPendingException(cx, &exception)) {
+ // Fetch messgage string, line and column
+ JS::Value msg, line, col;
+ JS_GetPendingException(cx, &exception);
+ JS_GetProperty(cx, JSVAL_TO_OBJECT(exception), "message", &msg);
+ JS_GetProperty(cx, JSVAL_TO_OBJECT(exception), "lineNumber", &line);
+ JS_GetProperty(cx, JSVAL_TO_OBJECT(exception), "columnNumber",
+ &col);
+
+ // Clear the exception
+ JS_ClearPendingException(cx);
+
+ // Produce a nice error message in case the caught exception is of
+ // the "Error" class
+ if (msg.isString() && line.isInt32() && col.isInt32()) {
+ // Throw a script engine exception with the corresponding line,
+ // column and string
+ throw ScriptEngineException{line.toInt32(), col.toInt32(),
+ toString(msg)};
+ }
+
+ // Otherwise simply convert the exception to a string
+ throw ScriptEngineException{toString(exception)};
+ }
+ }
+}
+
+std::string MozJsScriptEngineScope::toString(const JS::Value &val)
+{
+ // If the given value already is a Javascript string, return it directly.
+ if (val.isString()) {
+ return toString(val.toString());
+ }
+
+ // The given value is not really a string, so convert it to one first
+ JSString *str = JS_ValueToString(cx, val);
+ if (!str) {
+ throw ScriptEngineException{"Cannot convert value to string"};
+ }
+
+ return toString(str);
+}
+
+std::string MozJsScriptEngineScope::toString(JSString *str)
+{
+ // Encode the string
+ char *buf = JS_EncodeStringToUTF8(cx, str);
+ if (!buf) {
+ throw ScriptEngineException{"JS_EncodeStringToUTF8 failed"};
+ }
+
+ // Copy the string into a std::string, free the original buffer and return
+ std::string res{buf};
+ JS_free(cx, buf);
+ return res;
+}
+
+Variant MozJsScriptEngineScope::doRun(const std::string &code)
+{
+ JS::Value rval;
+ handleErr(JS_EvaluateScript(cx, *global, code.c_str(), code.length(), "", 0,
+ &rval));
+ return toVariant(rval);
+}
+
+void MozJsScriptEngineScope::doSetVariable(const std::string &name,
+ const Variant &val, bool constant)
+{
+ // TODO
+}
+
+Variant MozJsScriptEngineScope::doGetVariable(const std::string &name)
+{
+ // TODO
+ return Variant::Null;
+}
+
+/* Class MozJsScriptEngine */
+
+MozJsScriptEngine::MozJsScriptEngine()
+{
+ rt = JS_NewRuntime(MOZJS_RT_MEMSIZE, JS_NO_HELPER_THREADS);
+ if (!rt) {
+ throw ScriptEngineException{"MozJs JS_NewRuntime failed"};
+ }
+}
+
+MozJsScriptEngine::~MozJsScriptEngine()
+{
+ JS_DestroyRuntime(rt);
+ JS_ShutDown();
+}
+
+MozJsScriptEngineScope *MozJsScriptEngine::createScope()
+{
+ return new MozJsScriptEngineScope(rt);
+}
+}
+}
+
diff --git a/src/plugins/mozjs/MozJsScriptEngine.hpp b/src/plugins/mozjs/MozJsScriptEngine.hpp
new file mode 100644
index 0000000..68eee46
--- /dev/null
+++ b/src/plugins/mozjs/MozJsScriptEngine.hpp
@@ -0,0 +1,76 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _MOZ_JS_SCRIPT_ENGINE_HPP_
+#define _MOZ_JS_SCRIPT_ENGINE_HPP_
+
+#include <jsapi.h>
+
+#include <core/script/ScriptEngine.hpp>
+
+namespace ousia {
+namespace script {
+
+class MozJsScriptEngineScope : public ScriptEngineScope {
+
+private:
+ JSRuntime *rt;
+ JSContext *cx;
+ JSCompartment *oldCompartment;
+ JS::RootedObject *global;
+
+ void handleErr(bool ok);
+
+ Variant toVariant(const JS::Value &val);
+
+ std::string toString(const JS::Value &val);
+
+ std::string toString(JSString *str);
+
+protected:
+ Variant doRun(const std::string &code) override;
+ void doSetVariable(const std::string &name, const Variant &val,
+ bool constant) override;
+ Variant doGetVariable(const std::string &name) override;
+
+public:
+ MozJsScriptEngineScope(JSRuntime *rt);
+
+ ~MozJsScriptEngineScope() override;
+
+};
+
+class MozJsScriptEngine : public ScriptEngine {
+
+private:
+ JSRuntime *rt;
+
+public:
+
+ MozJsScriptEngine();
+
+ ~MozJsScriptEngine();
+
+ MozJsScriptEngineScope *createScope() override;
+
+};
+}
+}
+
+#endif /* _MOZ_JS_SCRIPT_ENGINE_HPP_ */
+