summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2014-10-25 21:23:38 +0000
committerandreas <andreas@daaaf23c-2e50-4459-9457-1e69db5a47bf>2014-10-25 21:23:38 +0000
commit250d6a4dbe61b6798cd090abeabdc0ece8237dd3 (patch)
tree05a15d388c8b8444b6ddd4c6806cd4f66169c2a0 /src
parentdbb94be50c67ce2d4a132b0811c2a8dac825b49b (diff)
some restructuring, added first version of the mozjs plugin
git-svn-id: file:///var/local/svn/basicwriter@78 daaaf23c-2e50-4459-9457-1e69db5a47bf
Diffstat (limited to 'src')
-rw-r--r--src/core/script/Object.hpp2
-rw-r--r--src/core/script/ScriptEngine.cpp32
-rw-r--r--src/core/script/ScriptEngine.hpp46
-rw-r--r--src/core/utils/RangeSet.hpp (renamed from src/core/model/RangeSet.hpp)0
-rw-r--r--src/plugins/mozjs/MozJsScriptEngine.cpp218
-rw-r--r--src/plugins/mozjs/MozJsScriptEngine.hpp76
6 files changed, 327 insertions, 47 deletions
diff --git a/src/core/script/Object.hpp b/src/core/script/Object.hpp
index fafe632..350f800 100644
--- a/src/core/script/Object.hpp
+++ b/src/core/script/Object.hpp
@@ -27,6 +27,8 @@
namespace ousia {
namespace script {
+// TODO: Check names for being proper identifiers!
+
/**
* The Property struct represents an object property with corresponding getter
* and setter function.
diff --git a/src/core/script/ScriptEngine.cpp b/src/core/script/ScriptEngine.cpp
index f34ccea..99f2d3f 100644
--- a/src/core/script/ScriptEngine.cpp
+++ b/src/core/script/ScriptEngine.cpp
@@ -23,21 +23,27 @@
namespace ousia {
namespace script {
-ScriptEngineException::ScriptEngineException(int line, int col,
- const std::string &msg) :
- line(line), col(col),
- msg(std::to_string(line) + ":" + std::to_string(col) + " " + msg) {}
+/* Class ScriptEngineException */
-ScriptEngineException::ScriptEngineException(const std::string &msg) :
- line(-1), col(-1), msg(msg) {}
+ScriptEngineException::ScriptEngineException(int line, int col,
+ const std::string &msg)
+ : line(line),
+ col(col),
+ msg(std::to_string(line) + ":" + std::to_string(col) + " " + msg)
+{
+}
-const char* ScriptEngineException::what() const noexcept
+ScriptEngineException::ScriptEngineException(const std::string &msg)
+ : line(-1), col(-1), msg(msg)
{
- return msg.c_str();
}
+const char *ScriptEngineException::what() const noexcept { return msg.c_str(); }
+
+/* Class ScriptEngineFactory */
+
void ScriptEngineFactory::registerScriptEngine(const std::string &name,
- ScriptEngine *engine)
+ ScriptEngine *engine)
{
registry[name] = engine;
}
@@ -47,10 +53,8 @@ bool ScriptEngineFactory::unregisterScriptEngine(const std::string &name)
return registry.erase(name) > 0;
}
-/* Class ScriptEngineFactory */
-
-ScriptEngineScope* ScriptEngineFactory::createScope(
- const std::string &name) const
+ScriptEngineScope *ScriptEngineFactory::createScope(
+ const std::string &name) const
{
auto it = registry.find(name);
if (it != registry.end()) {
@@ -58,8 +62,6 @@ ScriptEngineScope* ScriptEngineFactory::createScope(
}
return nullptr;
}
-
-
}
}
diff --git a/src/core/script/ScriptEngine.hpp b/src/core/script/ScriptEngine.hpp
index 5443460..2341beb 100644
--- a/src/core/script/ScriptEngine.hpp
+++ b/src/core/script/ScriptEngine.hpp
@@ -35,7 +35,6 @@ namespace script {
* in the script engine.
*/
class ScriptEngineException : public std::exception {
-
public:
/**
* Line and column at which the exception occured. Set to -1 if the error
@@ -67,18 +66,15 @@ public:
/**
* Returns the error message.
*/
- virtual const char* what() const noexcept override;
-
+ virtual const char *what() const noexcept override;
};
/**
* The ScriptEngineScope class represents an execution scope -- an execution
- * scope is the base class
+ * scope is the base class
*/
class ScriptEngineScope {
-
private:
-
/**
* Helper used to check the given identifiers for their validity.
*
@@ -93,29 +89,27 @@ private:
}
protected:
-
/**
- * Implementation of the @see run function.
+ * Implementation of the run function.
*/
virtual Variant doRun(const std::string &code) = 0;
/**
- * Implementation of the @see setVariable function.
+ * Implementation of the setVariable function.
*/
virtual void doSetVariable(const std::string &name, const Variant &val,
- bool constant) = 0;
+ bool constant) = 0;
/**
- * Implementation of the @see getVariable function.
+ * Implementation of the getVariable function.
*/
virtual Variant doGetVariable(const std::string &name) = 0;
public:
-
/**
* Virtual destructor. Must be overwritten by implementing classes.
*/
- virtual ~ScriptEngineScope() {};
+ virtual ~ScriptEngineScope(){};
/**
* Runs the given code in the excution context.
@@ -124,10 +118,7 @@ public:
* @return a variant containg the result of the executed code.
* @throws ScriptEngineException if an error occured during code execution.
*/
- Variant run(const std::string &code)
- {
- return doRun(code);
- }
+ Variant run(const std::string &code) { return doRun(code); }
/**
* Sets the value of a variable in the scope with the given name.
@@ -140,7 +131,7 @@ public:
* @throws ScriptEngineException if name is not a well-formed identifier.
*/
void setVariable(const std::string &name, const Variant &val,
- bool constant = false)
+ bool constant = false)
{
checkIdentifier(name);
doSetVariable(name, val, constant);
@@ -159,7 +150,6 @@ public:
checkIdentifier(name);
return doGetVariable(name);
}
-
};
/**
@@ -168,14 +158,12 @@ public:
* function which creates an execution scope.
*/
class ScriptEngine {
-
public:
/**
* Requests an execution scope from the script engine implementation. The
* calling code is responsible for disposing the returned pointer.
*/
- virtual ScriptEngineScope* createScope() const = 0;
-
+ virtual ScriptEngineScope *createScope() = 0;
};
/**
@@ -184,16 +172,14 @@ public:
* language.
*/
class ScriptEngineFactory {
-
private:
/**
* Internal map between the script language name and the actual script
* engine instance.
*/
- std::map<std::string, ScriptEngine*> registry;
+ std::map<std::string, ScriptEngine *> registry;
public:
-
/**
* Registers a ScriptEngine instance for a new scripting language.
*
@@ -206,7 +192,7 @@ public:
/**
* Removes a script engine from the registry.
*
- * @param name is the name of the script engine that
+ * @param name is the name of the script engine that
*/
bool unregisterScriptEngine(const std::string &name);
@@ -218,16 +204,12 @@ public:
* is being created.
* @return a pointer to the new execution scope or null if a script engine
* with the given name does not exist. The caller of this function is
- * responsible
+ * responsible
*/
- ScriptEngineScope* createScope(const std::string &name) const;
-
+ ScriptEngineScope *createScope(const std::string &name) const;
};
-
}
}
-
#endif /* _OUSIA_SCRIPT_ENGINE_HPP_ */
-
diff --git a/src/core/model/RangeSet.hpp b/src/core/utils/RangeSet.hpp
index 841d476..841d476 100644
--- a/src/core/model/RangeSet.hpp
+++ b/src/core/utils/RangeSet.hpp
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_ */
+