changeset 190:cb61cc16e2b6

Irccd: update all JavaScript to native code
author David Demelier <markand@malikania.fr>
date Sun, 05 Jun 2016 10:50:55 +0200
parents bb70bb9e41eb
children 3cd17993db82
files lib/irccd/CMakeSources.cmake lib/irccd/duktape.hpp lib/irccd/mod-directory.cpp lib/irccd/mod-elapsed-timer.cpp lib/irccd/mod-file.cpp lib/irccd/mod-file.hpp lib/irccd/mod-irccd.cpp lib/irccd/mod-logger.cpp lib/irccd/mod-plugin.cpp lib/irccd/mod-server.cpp lib/irccd/mod-system.cpp lib/irccd/mod-timer.cpp lib/irccd/mod-util.cpp lib/irccd/plugin-js.cpp tests/js-elapsedtimer/main.cpp tests/js-file/main.cpp tests/js-irccd/main.cpp tests/js-logger/main.cpp tests/js-system/main.cpp tests/js-timer/main.cpp tests/js-unicode/main.cpp tests/js-util/main.cpp
diffstat 22 files changed, 589 insertions(+), 409 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/CMakeSources.cmake	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/CMakeSources.cmake	Sun Jun 05 10:50:55 2016 +0200
@@ -33,7 +33,6 @@
 	${CMAKE_CURRENT_LIST_DIR}/ini.hpp
 	${CMAKE_CURRENT_LIST_DIR}/irccd.hpp
 	${CMAKE_CURRENT_LIST_DIR}/irccdctl.hpp
-	${CMAKE_CURRENT_LIST_DIR}/js.hpp
 	${CMAKE_CURRENT_LIST_DIR}/json.hpp
 	${CMAKE_CURRENT_LIST_DIR}/mod-directory.hpp
 	${CMAKE_CURRENT_LIST_DIR}/mod-elapsed-timer.hpp
--- a/lib/irccd/duktape.hpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/duktape.hpp	Sun Jun 05 10:50:55 2016 +0200
@@ -31,6 +31,7 @@
 #include <string>
 #include <unordered_map>
 #include <utility>
+#include <vector>
 
 #include <duktape.h>
 
@@ -336,7 +337,7 @@
  * \param pop if true, also remove the exception from the stack
  * \return the information
  */
-inline Exception duk_exception(duk_context *ctx, int index, bool pop = true)
+inline Exception dukx_exception(duk_context *ctx, int index, bool pop = true)
 {
 	Exception ex;
 
@@ -370,7 +371,7 @@
  * \param func the function to call for each properties
  */
 template <typename Func>
-void duk_enumerate(duk_context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
+void dukx_enumerate(duk_context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
 {
 	duk_enum(ctx, index, flags);
 
@@ -389,7 +390,7 @@
  * \param ex the exception
  */
 template <typename Exception>
-void duk_throw(duk_context *ctx, const Exception &ex)
+void dukx_throw(duk_context *ctx, const Exception &ex)
 {
 	ex.raise(ctx);
 }
@@ -401,7 +402,7 @@
  * \param index the index
  * \return the string
  */
-inline std::string duk_get_stdstring(duk_context *ctx, int index)
+inline std::string dukx_get_std_string(duk_context *ctx, int index)
 {
 	duk_size_t size;
 	const char *text = duk_get_lstring(ctx, index, &size);
@@ -416,7 +417,7 @@
  * \param index the index
  * \return the string
  */
-inline std::string duk_require_stdstring(duk_context *ctx, int index)
+inline std::string dukx_require_std_string(duk_context *ctx, int index)
 {
 	duk_size_t size;
 	const char *text = duk_require_lstring(ctx, index, &size);
@@ -430,11 +431,54 @@
  * \param ctx the context
  * \param str the string
  */
-inline void duk_push_stdstring(duk_context *ctx, const std::string &str)
+inline void dukx_push_std_string(duk_context *ctx, const std::string &str)
 {
 	duk_push_lstring(ctx, str.data(), str.length());
 }
 
+/**
+ * Get an array.
+ *
+ * \param ctx the context
+ * \param index the array index
+ * \param getter the conversion function (e.g. duk_get_int)
+ */
+template <typename Getter>
+auto dukx_get_array(duk_context *ctx, duk_idx_t index, Getter &&get)
+{
+	using T = decltype(get(ctx, 0));
+
+	std::vector<T> result;
+	std::size_t length = duk_get_length(ctx, index);
+
+	for (std::size_t i = 0; i < length; ++i) {
+		duk_get_prop_index(ctx, -1, i);
+		result.push_back(get(ctx, -1));
+		duk_pop(ctx);
+	}
+
+	return result;
+}
+
+/**
+ * Push an array.
+ *
+ * \param ctx the context
+ * \param values the values
+ * \param push the function to push values
+ */
+template <typename T, typename Pusher>
+void dukx_push_array(duk_context *ctx, const std::vector<T> &values, Pusher &&push)
+{
+	duk_push_array(ctx);
+
+	int i = 0;
+	for (auto x : values) {
+		push(ctx, x);
+		duk_put_prop_index(ctx, -2, i++);
+	}
+}
+
 } // !irccd
 
 #endif // !IRCCD_DUKTAPE_HPP
--- a/lib/irccd/mod-directory.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-directory.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -44,7 +44,7 @@
 	if (duk_get_type(ctx, -1) != DUK_TYPE_STRING)
 		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Directory object");
 
-	auto ret = duk_get_stdstring(ctx, -1);
+	auto ret = dukx_get_std_string(ctx, -1);
 
 	if (ret.empty())
 		duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path");
@@ -151,7 +151,7 @@
 		if (path.empty())
 			return 0;
 
-		duk_push_stdstring(ctx, path);
+		dukx_push_std_string(ctx, path);
 	} catch (const std::exception &ex) {
 		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
 	}
@@ -168,7 +168,7 @@
 duk_ret_t remove(duk_context *ctx, const std::string &path, bool recursive)
 {
 	if (!fs::isDirectory(path))
-		duk_throw(ctx, SystemError(EINVAL, "not a directory"));
+		dukx_throw(ctx, SystemError(EINVAL, "not a directory"));
 
 	if (!recursive) {
 #if defined(_WIN32)
@@ -252,7 +252,7 @@
 		std::int8_t flags = duk_get_uint(ctx, 1);
 
 		if (!fs::isDirectory(path))
-			duk_throw(ctx, SystemError(EINVAL, "not a directory"));
+			dukx_throw(ctx, SystemError(EINVAL, "not a directory"));
 
 		std::vector<fs::Entry> list = fs::readdir(path, flags);
 
@@ -261,14 +261,14 @@
 		duk_push_int(ctx, list.size());
 		duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
 		duk_push_string(ctx, "path");
-		duk_push_stdstring(ctx, path);
+		dukx_push_std_string(ctx, path);
 		duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
 		duk_push_string(ctx, "entries");
 		duk_push_array(ctx);
 
 		for (unsigned i = 0; i < list.size(); ++i) {
 			duk_push_object(ctx);
-			duk_push_stdstring(ctx, list[i].name);
+			dukx_push_std_string(ctx, list[i].name);
 			duk_put_prop_string(ctx, -2, "name");
 			duk_push_int(ctx, list[i].type);
 			duk_put_prop_string(ctx, -2, "type");
@@ -277,7 +277,7 @@
 
 		duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
 	} catch (const std::exception &ex) {
-		duk_throw(ctx, SystemError(errno, ex.what()));
+		dukx_throw(ctx, SystemError(errno, ex.what()));
 	}
 
 	return 0;
@@ -339,27 +339,27 @@
 			duk_is_number(ctx, 1) ? duk_get_int(ctx, 1) : 0700
 		);
 	} catch (const std::exception &ex) {
-		duk_throw(ctx, SystemError(errno, ex.what()));
+		dukx_throw(ctx, SystemError(errno, ex.what()));
 	}
 
 	return 0;
 }
 
 const duk_function_list_entry functions[] = {
-	{ "find",		funcFind,	DUK_VARARGS	},
-	{ "mkdir",		funcMkdir,	DUK_VARARGS	},
-	{ "remove",		funcRemove,	DUK_VARARGS	},
-	{ nullptr,		nullptr,	0		} 
+	{ "find", funcFind, DUK_VARARGS },
+	{ "mkdir", funcMkdir, DUK_VARARGS },
+	{ "remove", funcRemove, DUK_VARARGS },
+	{ nullptr, nullptr, 0 }
 };
 
 const duk_number_list_entry constants[] = {
-	{ "Dot",		static_cast<int>(fs::Dot)			},
-	{ "DotDot",		static_cast<int>(fs::DotDot)			},
-	{ "TypeUnknown",	static_cast<int>(fs::Entry::Unknown)		},
-	{ "TypeDir",		static_cast<int>(fs::Entry::Dir)		},
-	{ "TypeFile",		static_cast<int>(fs::Entry::File)		},
-	{ "TypeLink",		static_cast<int>(fs::Entry::Link)		},
-	{ nullptr,		0						} 
+	{ "Dot", static_cast<int>(fs::Dot) },
+	{ "DotDot", static_cast<int>(fs::DotDot) },
+	{ "TypeUnknown", static_cast<int>(fs::Entry::Unknown) },
+	{ "TypeDir", static_cast<int>(fs::Entry::Dir) },
+	{ "TypeFile", static_cast<int>(fs::Entry::File) },
+	{ "TypeLink", static_cast<int>(fs::Entry::Link) },
+	{ nullptr, 0 }
 };
 
 } // !namespace
@@ -377,7 +377,7 @@
 	duk_push_c_function(plugin.context(), constructor, 2);
 	duk_put_number_list(plugin.context(), -1, constants);
 	duk_put_function_list(plugin.context(), -1, functions);
-	duk_push_stdstring(plugin.context(), std::string{fs::separator()});
+	dukx_push_std_string(plugin.context(), std::string{fs::separator()});
 	duk_put_prop_string(plugin.context(), -2, "separator");
 	duk_push_object(plugin.context());
 	duk_put_function_list(plugin.context(), -1, methods);
--- a/lib/irccd/mod-elapsed-timer.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-elapsed-timer.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -107,7 +107,7 @@
 	duk_push_this(ctx);
 	duk_push_pointer(ctx, new ElapsedTimer);
 	duk_put_prop_string(ctx, -2, Signature);
-	duk_pop_2(ctx);
+	duk_pop(ctx);
 
 	return 0;
 }
@@ -129,11 +129,11 @@
 }
 
 const duk_function_list_entry methods[] = {
-	{ "elapsed",	elapsed,	0 },
-	{ "pause",	pause,		0 },
-	{ "reset",	reset,		0 },
-	{ "restart",	restart,	0 },
-	{ nullptr,	nullptr,	0 }
+	{ "elapsed", elapsed, 0 },
+	{ "pause", pause, 0 },
+	{ "reset", reset, 0 },
+	{ "restart", restart, 0 },
+	{ nullptr, nullptr, 0 }
 };
 
 } // !namespace
--- a/lib/irccd/mod-file.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-file.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -119,16 +119,19 @@
 	return input;
 }
 
-inline File *self(duk_context *ctx)
+File *self(duk_context *ctx)
 {
 	StackAssert sa(ctx);
 
 	duk_push_this(ctx);
 	duk_get_prop_string(ctx, -1, Signature);
-	File *file = static_cast<File *>(duk_to_pointer(ctx, -1));
+	auto ptr = static_cast<File *>(duk_to_pointer(ctx, -1));
 	duk_pop_2(ctx);
 
-	return file;
+	if (!ptr)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
+
+	return ptr;
 }
 
 /*
@@ -147,7 +150,7 @@
  */
 duk_ret_t methodBasename(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, fs::baseName(self(ctx)->path()));
+	dukx_push_std_string(ctx, fs::baseName(self(ctx)->path()));
 
 	return 1;
 }
@@ -176,7 +179,7 @@
  */
 duk_ret_t methodDirname(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, fs::dirName(self(ctx)->path()));
+	dukx_push_std_string(ctx, fs::dirName(self(ctx)->path()));
 
 	return 1;
 }
@@ -207,7 +210,7 @@
 		auto pos = buffer.find('\n');
 
 		if (pos != std::string::npos) {
-			duk_push_stdstring(ctx, clearCr(buffer.substr(0, pos)));
+			dukx_push_std_string(ctx, clearCr(buffer.substr(0, pos)));
 			duk_put_prop_index(ctx, -2, i++);
 
 			buffer.erase(0, pos + 1);
@@ -216,11 +219,11 @@
 
 	// Maybe an error in the stream.
 	if (std::ferror(fp))
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
 	// Missing '\n' in end of file.
 	if (!buffer.empty()) {
-		duk_push_stdstring(ctx, clearCr(buffer));
+		dukx_push_std_string(ctx, clearCr(buffer));
 		duk_put_prop_index(ctx, -2, i++);
 	}
 
@@ -260,7 +263,7 @@
 				nread = std::fread(&buffer[0], sizeof (buffer[0]), buffer.size(), file->handle());
 
 				if (std::ferror(file->handle()))
-					duk_throw(ctx, SystemError());
+					dukx_throw(ctx, SystemError());
 
 				std::copy(buffer.begin(), buffer.begin() + nread, std::back_inserter(data));
 				total += nread;
@@ -270,14 +273,14 @@
 			total = std::fread(&data[0], sizeof (data[0]), (std::size_t)amount, file->handle());
 
 			if (std::ferror(file->handle()))
-				duk_throw(ctx, SystemError());
+				dukx_throw(ctx, SystemError());
 
 			data.resize(total);
 		}
 
-		duk_push_stdstring(ctx, data);
+		dukx_push_std_string(ctx, data);
 	} catch (const std::exception &) {
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 	}
 
 	return 1;
@@ -304,9 +307,9 @@
 	for (int ch; (ch = std::fgetc(fp)) != EOF && ch != '\n'; )
 		result += (char)ch;
 	if (std::ferror(fp))
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
-	duk_push_stdstring(ctx, clearCr(result));
+	dukx_push_std_string(ctx, clearCr(result));
 
 	return 1;
 }
@@ -323,7 +326,7 @@
 duk_ret_t methodRemove(duk_context *ctx)
 {
 	if (::remove(self(ctx)->path().c_str()) < 0)
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
 	return 0;
 }
@@ -347,7 +350,7 @@
 	auto amount = duk_require_int(ctx, 1);
 
 	if (fp != nullptr && std::fseek(fp, amount, type) != 0)
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
 	return 0;
 }
@@ -371,7 +374,7 @@
 	struct stat st;
 
 	if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0)
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 	else
 		pushStat(ctx, st);
 
@@ -400,7 +403,7 @@
 		return 0;
 
 	if ((pos = std::ftell(fp)) == -1L)
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 	else
 		duk_push_int(ctx, pos);
 
@@ -431,7 +434,7 @@
 	std::size_t nwritten = std::fwrite(data.c_str(), 1, data.length(), fp);
 
 	if (std::ferror(fp))
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
 	duk_push_uint(ctx, nwritten);
 
@@ -439,20 +442,20 @@
 }
 
 const duk_function_list_entry methods[] = {
-	{ "basename",	methodBasename,		0	},
-	{ "close",	methodClose,		0	},
-	{ "dirname",	methodDirname,		0	},
-	{ "lines",	methodLines,		0	},
-	{ "read",	methodRead,		1	},
-	{ "readline",	methodReadline,		0	},
-	{ "remove",	methodRemove,		0	},
-	{ "seek",	methodSeek,		2	},
+	{ "basename", methodBasename, 0 },
+	{ "close", methodClose, 0 },
+	{ "dirname", methodDirname, 0 },
+	{ "lines", methodLines, 0 },
+	{ "read", methodRead, 1 },
+	{ "readline", methodReadline, 0 },
+	{ "remove", methodRemove, 0 },
+	{ "seek", methodSeek, 2 },
 #if defined(HAVE_STAT)
-	{ "stat",	methodStat,		0	},
+	{ "stat", methodStat, 0 },
 #endif
-	{ "tell",	methodTell,		0	},
-	{ "write",	methodWrite,		1	},
-	{ nullptr,	nullptr,		0	}
+	{ "tell", methodTell, 0 },
+	{ "write", methodWrite, 1 },
+	{ nullptr, nullptr, 0 }
 };
 
 /*
@@ -478,9 +481,9 @@
 		return 0;
 
 	try {
-		duk_new_file(ctx, new File(duk_require_string(ctx, 0), duk_require_string(ctx, 1)));
+		dukx_new_file(ctx, new File(duk_require_string(ctx, 0), duk_require_string(ctx, 1)));
 	} catch (const std::exception &) {
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 	}
 
 	return 0;
@@ -515,7 +518,7 @@
  */
 duk_ret_t functionBasename(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, fs::baseName(duk_require_string(ctx, 0)));
+	dukx_push_std_string(ctx, fs::baseName(duk_require_string(ctx, 0)));
 
 	return 1;
 }
@@ -533,7 +536,7 @@
  */
 duk_ret_t functionDirname(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, fs::dirName(duk_require_string(ctx, 0)));
+	dukx_push_std_string(ctx, fs::dirName(duk_require_string(ctx, 0)));
 
 	return 1;
 }
@@ -572,7 +575,7 @@
 duk_ret_t functionRemove(duk_context *ctx)
 {
 	if (::remove(duk_require_string(ctx, 0)) < 0)
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
 	return 0;
 }
@@ -597,7 +600,7 @@
 	struct stat st;
 
 	if (::stat(duk_require_string(ctx, 0), &st) < 0)
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
 	pushStat(ctx, st);
 
@@ -607,20 +610,20 @@
 #endif // !HAVE_STAT
 
 const duk_function_list_entry functions[] = {
-	{ "basename",	functionBasename,	1 },
-	{ "dirname",	functionDirname,	1 },
-	{ "exists",	functionExists,		1 },
-	{ "remove",	functionRemove,		1 },
+	{ "basename", functionBasename, 1 },
+	{ "dirname", functionDirname, 1 },
+	{ "exists", functionExists, 1 },
+	{ "remove", functionRemove, 1 },
 #if defined(HAVE_STAT)
-	{ "stat",	functionStat,		1 },
+	{ "stat", functionStat, 1 },
 #endif
-	{ nullptr,	nullptr,		0 } 
+	{ nullptr, nullptr, 0 }
 };
 
 const duk_number_list_entry constants[] = {
-	{ "SeekCur",	SEEK_CUR },
-	{ "SeekEnd",	SEEK_END },
-	{ "SeekSet",	SEEK_SET },
+	{ "SeekCur", SEEK_CUR },
+	{ "SeekEnd", SEEK_END },
+	{ "SeekSet", SEEK_SET },
 };
 
 } // !namespace
@@ -643,13 +646,13 @@
 	duk_push_c_function(plugin.context(), destructor, 1);
 	duk_set_finalizer(plugin.context(), -2);
 	duk_dup(plugin.context(), -1);
-	duk_get_global_string(plugin.context(), Prototype);
+	duk_put_global_string(plugin.context(), Prototype);
 	duk_put_prop_string(plugin.context(), -2, "prototype");
 	duk_put_prop_string(plugin.context(), -2, "File");
 	duk_pop(plugin.context());
 }
 
-void duk_new_file(duk_context *ctx, File *fp)
+void dukx_new_file(duk_context *ctx, File *fp)
 {
 	assert(ctx);
 	assert(fp);
@@ -662,7 +665,7 @@
 	duk_pop(ctx);
 }
 
-void duk_push_file(duk_context *ctx, File *fp)
+void dukx_push_file(duk_context *ctx, File *fp)
 {
 	assert(ctx);
 	assert(fp);
@@ -676,7 +679,7 @@
 	duk_set_prototype(ctx, -2);
 }
 
-File *duk_require_file(duk_context *ctx, duk_idx_t index)
+File *dukx_require_file(duk_context *ctx, duk_idx_t index)
 {
 	if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature))
 		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
--- a/lib/irccd/mod-file.hpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-file.hpp	Sun Jun 05 10:50:55 2016 +0200
@@ -162,7 +162,7 @@
  * \param ctx the the context
  * \param fp the file
  */
-IRCCD_EXPORT void duk_new_file(duk_context *ctx, File *fp);
+IRCCD_EXPORT void dukx_new_file(duk_context *ctx, File *fp);
 
 /**
  * Push a file.
@@ -171,7 +171,7 @@
  * \param ctx the the context
  * \param fp the file
  */
-IRCCD_EXPORT void duk_push_file(duk_context *ctx, File *fp);
+IRCCD_EXPORT void dukx_push_file(duk_context *ctx, File *fp);
 
 /**
  * Require a file. Raises a JavaScript error if not a File.
@@ -179,7 +179,7 @@
  * \param ctx the context
  * \param index the index
  */
-IRCCD_EXPORT File *duk_require_file(duk_context *ctx, duk_idx_t index);
+IRCCD_EXPORT File *dukx_require_file(duk_context *ctx, duk_idx_t index);
 
 } // !irccd
 
--- a/lib/irccd/mod-irccd.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-irccd.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -60,7 +60,7 @@
 	duk_get_prop_string(ctx, -1, "SystemError");
 	duk_remove(ctx, -2);
 	duk_push_int(ctx, m_errno);
-	duk_push_stdstring(ctx, m_message);
+	dukx_push_std_string(ctx, m_message);
 	duk_new(ctx, 2);
 	duk_throw(ctx);
 }
@@ -91,7 +91,7 @@
 	duk_push_c_function(plugin.context(), constructor, 2);
 	duk_push_object(plugin.context());
 	duk_get_global_string(plugin.context(), "Error");
-	duk_put_prop_string(plugin.context(), -1, "prototype");
+	duk_get_prop_string(plugin.context(), -1, "prototype");
 	duk_remove(plugin.context(), -2);
 	duk_set_prototype(plugin.context(), -2);
 	duk_put_prop_string(plugin.context(), -2, "prototype");
--- a/lib/irccd/mod-logger.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-logger.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -75,10 +75,10 @@
 }
 
 const duk_function_list_entry functions[] = {
-	{ "info",	info,		1 },
-	{ "warning",	warning,	1 },
-	{ "debug",	debug,		1 },
-	{ nullptr,	nullptr,	0 }
+	{ "info", info, 1 },
+	{ "warning", warning, 1 },
+	{ "debug", debug, 1 },
+	{ nullptr, nullptr, 0 }
 };
 
 } // !namespace
--- a/lib/irccd/mod-plugin.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-plugin.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -43,9 +43,9 @@
 	try {
 		func(duk_get_irccd(ctx), name);
 	} catch (const std::out_of_range &ex) {
-		duk_throw(ctx, ReferenceError(ex.what()));
+		dukx_throw(ctx, ReferenceError(ex.what()));
 	} catch (const std::exception &ex) {
-		duk_throw(ctx, Error(ex.what()));
+		dukx_throw(ctx, Error(ex.what()));
 	}
 
 	return nret;
@@ -83,15 +83,15 @@
 		return 0;
 
 	duk_push_object(ctx);
-	duk_push_stdstring(ctx, plugin->name());
+	dukx_push_std_string(ctx, plugin->name());
 	duk_put_prop_string(ctx, -2, "name");
-	duk_push_stdstring(ctx, plugin->author());
+	dukx_push_std_string(ctx, plugin->author());
 	duk_put_prop_string(ctx, -2, "author");
-	duk_push_stdstring(ctx, plugin->license());
+	dukx_push_std_string(ctx, plugin->license());
 	duk_put_prop_string(ctx, -2, "license");
-	duk_push_stdstring(ctx, plugin->summary());
+	dukx_push_std_string(ctx, plugin->summary());
 	duk_put_prop_string(ctx, -2, "summary");
-	duk_push_stdstring(ctx, plugin->version());
+	dukx_push_std_string(ctx, plugin->version());
 	duk_put_prop_string(ctx, -2, "version");
 
 	return 1;
@@ -108,13 +108,9 @@
  */
 duk_idx_t list(duk_context *ctx)
 {
-	duk_push_array(ctx);
-
-	int i = 0;
-	for (const auto &plugin : duk_get_irccd(ctx).pluginService().plugins()) {
-		duk_push_stdstring(ctx, plugin->name());
-		duk_put_prop_index(ctx, -1, i++);
-	}
+	dukx_push_array(ctx, duk_get_irccd(ctx).pluginService().plugins(), [] (auto ctx, auto plugin) {
+		dukx_push_std_string(ctx, plugin->name());
+	});
 
 	return 1;
 }
@@ -177,12 +173,12 @@
 }
 
 const duk_function_list_entry functions[] = {
-	{ "info",	info,		DUK_VARARGS	},
-	{ "list",	list,		0		},
-	{ "load",	load,		1		},
-	{ "reload",	reload,		1		},
-	{ "unload",	unload,		1		},
-	{ nullptr,	nullptr,	0		}
+	{ "info", info, DUK_VARARGS },
+	{ "list", list, 0 },
+	{ "load", load, 1 },
+	{ "reload", reload, 1 },
+	{ "unload", unload, 1 },
+	{ nullptr, nullptr, 0 }
 };
 
 } // !namespace
--- a/lib/irccd/mod-server.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-server.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -49,6 +49,109 @@
 	return *static_cast<std::shared_ptr<Server> *>(ptr);
 }
 
+std::string readName(duk_context *ctx)
+{
+	duk_get_prop_string(ctx, 0, "name");
+	auto name = dukx_get_std_string(ctx, -1);
+	duk_pop(ctx);
+
+	if (!util::isIdentifierValid(name))
+		duk_error(ctx, DUK_ERR_ERROR, "invalid 'name' property");
+
+	return name;
+}
+
+ServerInfo readInfo(duk_context *ctx)
+{
+	ServerInfo info;
+
+	// 'host' property.
+	duk_get_prop_string(ctx, 0, "host");
+	info.host = duk_is_string(ctx, -1) ? dukx_get_std_string(ctx, -1) : info.host;
+	duk_pop(ctx);
+
+	// 'port' property.
+	duk_get_prop_string(ctx, 0, "port");
+	info.port = duk_is_number(ctx, -1) ? duk_get_int(ctx, -1) : info.port;
+	duk_pop(ctx);
+
+	// 'password' property.
+	duk_get_prop_string(ctx, 0, "password");
+	info.password = duk_is_string(ctx, -1) ? dukx_get_std_string(ctx, -1) : info.password;
+	duk_pop(ctx);
+
+	// 'ipv6' property.
+	duk_get_prop_string(ctx, 0, "ipv6");
+	if (duk_get_boolean(ctx, -1))
+		info.flags |= ServerInfo::Ipv6;
+	duk_pop(ctx);
+
+	return info;
+}
+
+ServerIdentity readIdentity(duk_context *ctx)
+{
+	ServerIdentity identity;
+
+	// 'nickname' property.
+	duk_get_prop_string(ctx, 0, "nickname");
+	identity.nickname = duk_is_string(ctx, -1) ? dukx_get_std_string(ctx, -1) : identity.nickname;
+	duk_pop(ctx);
+
+	// 'username' property.
+	duk_get_prop_string(ctx, 0, "username");
+	identity.username = duk_is_string(ctx, -1) ? dukx_get_std_string(ctx, -1) : identity.username;
+	duk_pop(ctx);
+
+	// 'realname' property.
+	duk_get_prop_string(ctx, 0, "realname");
+	identity.realname = duk_is_string(ctx, -1) ? dukx_get_std_string(ctx, -1) : identity.realname;
+	duk_pop(ctx);
+
+	// 'ctcpversion' property.
+	duk_get_prop_string(ctx, 0, "version");
+	identity.ctcpversion = duk_is_string(ctx, -1) ? dukx_get_std_string(ctx, -1) : identity.ctcpversion;
+	duk_pop(ctx);
+
+	return identity;
+}
+
+ServerSettings readSettings(duk_context *ctx)
+{
+	ServerSettings settings;
+
+	// 'channels' property.
+	duk_get_prop_string(ctx, 0, "channels");
+	settings.channels = dukx_get_array(ctx, -1, [] (auto ctx, auto) {
+		return Server::splitChannel(dukx_get_std_string(ctx, -1));
+	});
+	duk_pop(ctx);
+
+	// 'recoTries' property.
+	duk_get_prop_string(ctx, 0, "recoTries");
+	settings.reconnectTries = duk_is_number(ctx, -1) ? duk_get_int(ctx, -1) : settings.reconnectTries;
+	duk_pop(ctx);
+
+	// 'recoTimeout' property.
+	duk_get_prop_string(ctx, 0, "recoTimeout");
+	settings.reconnectDelay = duk_is_number(ctx, -1) ? duk_get_int(ctx, -1) : settings.reconnectDelay;
+	duk_pop(ctx);
+
+	// 'joinInvite' property.
+	duk_get_prop_string(ctx, 0, "joinInvite");
+	if (duk_get_boolean(ctx, -1))
+		settings.flags |= ServerSettings::JoinInvite;
+	duk_pop(ctx);
+
+	// 'autoRejoin' property.
+	duk_get_prop_string(ctx, 0, "autoRejoin");
+	if (duk_get_boolean(ctx, -1))
+		settings.flags |= ServerSettings::AutoRejoin;
+	duk_pop(ctx);
+
+	return settings;
+}
+
 /*
  * Method: Server.cmode(channel, mode)
  * ------------------------------------------------------------------
@@ -101,9 +204,9 @@
 	auto server = self(ctx);
 
 	duk_push_object(ctx);
-	duk_push_stdstring(ctx, server->name());
+	dukx_push_std_string(ctx, server->name());
 	duk_put_prop_string(ctx, -2, "name");
-	duk_push_stdstring(ctx, server->info().host);
+	dukx_push_std_string(ctx, server->info().host);
 	duk_put_prop_string(ctx, -2, "host");
 	duk_push_int(ctx, server->info().port);
 	duk_put_prop_string(ctx, -2, "port");
@@ -111,13 +214,13 @@
 	duk_put_prop_string(ctx, -2, "ssl");
 	duk_push_boolean(ctx, server->info().flags & ServerInfo::SslVerify);
 	duk_put_prop_string(ctx, -2, "sslVerify");
-	duk_push_stdstring(ctx, server->settings().command);
+	dukx_push_std_string(ctx, server->settings().command);
 	duk_put_prop_string(ctx, -2, "commandChar");
-	duk_push_stdstring(ctx, server->identity().realname);
+	dukx_push_std_string(ctx, server->identity().realname);
 	duk_put_prop_string(ctx, -2, "realname");
-	duk_push_stdstring(ctx, server->identity().nickname);
+	dukx_push_std_string(ctx, server->identity().nickname);
 	duk_put_prop_string(ctx, -2, "nickname");
-	duk_push_stdstring(ctx, server->identity().username);
+	dukx_push_std_string(ctx, server->identity().username);
 	duk_put_prop_string(ctx, -2, "username");
 
 	// Channels.
@@ -125,8 +228,8 @@
 
 	int i = 0;
 	for (const auto &channel : server->settings().channels) {
-		duk_push_stdstring(ctx, channel.name);
-		duk_put_prop_index(ctx, -1, i++);
+		dukx_push_std_string(ctx, channel.name);
+		duk_put_prop_index(ctx, -2, i++);
 	}
 
 	duk_put_prop_string(ctx, -2, "channels");
@@ -363,7 +466,7 @@
  */
 duk_ret_t toString(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, self(ctx)->name());
+	dukx_push_std_string(ctx, self(ctx)->name());
 
 	return 1;
 }
@@ -391,51 +494,19 @@
  */
 duk_ret_t constructor(duk_context *ctx)
 {
-#if 0
-	if (!isConstructorCall(ctx))
+	if (!duk_is_constructor_call(ctx))
 		return 0;
 
-	std::string name;
-	ServerInfo info;
-	ServerIdentity identity;
-	ServerSettings settings;
-
-	// Information part.
-	name = getProperty<std::string>(ctx, 0, "name");
-	info.host = getProperty<std::string>(ctx, 0, "host");
-	info.port = optionalProperty<int>(ctx, 0, "port", static_cast<int>(info.port));
-	info.password = optionalProperty<std::string>(ctx, 0, "password", "");
-
-	if (optionalProperty<bool>(ctx, 0, "ipv6", false))
-		info.flags |= ServerInfo::Ipv6;
-
-	// Identity part.
-	identity.nickname = optionalProperty<std::string>(ctx, 0, "nickname", identity.nickname);
-	identity.username = optionalProperty<std::string>(ctx, 0, "username", identity.username);
-	identity.realname = optionalProperty<std::string>(ctx, 0, "realname", identity.realname);
-	identity.ctcpversion = optionalProperty<std::string>(ctx, 0, "version", identity.ctcpversion);
+	try {
+		auto s = std::make_shared<Server>(readName(ctx), readInfo(ctx), readIdentity(ctx), readSettings(ctx));
 
-	// Settings part.
-	for (const auto &chan: getProperty<std::vector<std::string>>(ctx, 0, "channels"))
-		settings.channels.push_back(Server::splitChannel(chan));
-
-	settings.reconnectTries = optionalProperty<int>(ctx, 0, "recoTries", (int)settings.reconnectTries);
-	settings.reconnectDelay = optionalProperty<int>(ctx, 0, "recoTimeout", (int)settings.reconnectDelay);
-
-	if (optionalProperty<bool>(ctx, 0, "joinInvite", false))
-		settings.flags |= ServerSettings::JoinInvite;
-	if (optionalProperty<bool>(ctx, 0, "autoRejoin", false))
-		settings.flags |= ServerSettings::AutoRejoin;
-
-	try {
-		push(ctx, This());
-		pushPointer(ctx, new std::shared_ptr<Server>(std::move(name), std::move(info), std::move(identity), std::move(settings)));
-		putProperty(ctx, -2, Signature);
-		pop(ctx);
+		duk_push_this(ctx);
+		duk_push_pointer(ctx, new std::shared_ptr<Server>(std::move(s)));
+		duk_put_prop_string(ctx, -2, Signature);
+		duk_pop(ctx);
 	} catch (const std::exception &ex) {
-		raise(ctx, Error(ex.what()));
+		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
 	}
-#endif
 
 	return 0;
 }
@@ -533,32 +604,32 @@
 }
 
 const duk_function_list_entry methods[] = {
-	{ "cmode",	cmode,		2		},
-	{ "cnotice",	cnotice,	2		},
-	{ "info",	info,		0		},
-	{ "invite",	invite,		2		},
-	{ "join",	join,		DUK_VARARGS	},
-	{ "kick",	kick,		DUK_VARARGS	},
-	{ "me",		me,		2		},
-	{ "message",	message,	2		},
-	{ "mode",	mode,		1		},
-	{ "names",	names,		1		},
-	{ "nick",	nick,		1		},
-	{ "notice",	notice,		2		},
-	{ "part",	part,		DUK_VARARGS	},
-	{ "send",	send,		1		},
-	{ "topic",	topic,		2		},
-	{ "whois",	whois,		1		},
-	{ "toString",	toString,	0		},
-	{ nullptr,	nullptr,	0		}
+	{ "cmode", cmode, 2 },
+	{ "cnotice", cnotice, 2 },
+	{ "info", info, 0 },
+	{ "invite", invite, 2 },
+	{ "join", join, DUK_VARARGS },
+	{ "kick", kick, DUK_VARARGS },
+	{ "me", me, 2 },
+	{ "message", message, 2 },
+	{ "mode", mode, 1 },
+	{ "names", names, 1 },
+	{ "nick", nick, 1 },
+	{ "notice", notice, 2 },
+	{ "part", part, DUK_VARARGS },
+	{ "send", send, 1 },
+	{ "topic", topic, 2 },
+	{ "whois", whois, 1 },
+	{ "toString", toString, 0 },
+	{ nullptr, nullptr, 0 }
 };
 
 const duk_function_list_entry functions[] = {
-	{ "add",	add,		1		},
-	{ "find",	find,		1		},
-	{ "list",	list,		0		},
-	{ "remove",	remove,		1		},
-	{ nullptr,	nullptr,	0		}
+	{ "add", add, 1 },
+	{ "find", find, 1 },
+	{ "list", list, 0 },
+	{ "remove", remove, 1 },
+	{ nullptr, nullptr, 0 }
 };
 
 } // !namespace
@@ -580,7 +651,7 @@
 	duk_push_c_function(plugin.context(), destructor, 1);
 	duk_set_finalizer(plugin.context(), -2);
 	duk_dup_top(plugin.context());
-	duk_get_global_string(plugin.context(), Prototype);
+	duk_put_global_string(plugin.context(), Prototype);
 	duk_put_prop_string(plugin.context(), -2, "prototype");
 	duk_put_prop_string(plugin.context(), -2, "Server");
 	duk_pop(plugin.context());
@@ -600,7 +671,7 @@
 	duk_set_finalizer(ctx, -2);
 }
 
-std::shared_ptr<Server> require(duk_context *ctx, duk_idx_t index)
+std::shared_ptr<Server> duk_require_server(duk_context *ctx, duk_idx_t index)
 {
 	if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature))
 		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
--- a/lib/irccd/mod-system.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-system.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -49,7 +49,7 @@
  */
 duk_ret_t env(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, sys::env(duk_get_string(ctx, 0)));
+	dukx_push_std_string(ctx, sys::env(duk_get_string(ctx, 0)));
 
 	return 1;
 }
@@ -81,7 +81,7 @@
  */
 duk_ret_t home(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, sys::home());
+	dukx_push_std_string(ctx, sys::home());
 
 	return 1;
 }
@@ -97,7 +97,7 @@
  */
 duk_ret_t name(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, sys::name());
+	dukx_push_std_string(ctx, sys::name());
 
 	return 1;
 }
@@ -123,9 +123,9 @@
 	auto fp = ::popen(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	if (fp == nullptr)
-		duk_throw(ctx, SystemError());
+		dukx_throw(ctx, SystemError());
 
-	duk_push_file(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); }));
+	dukx_push_file(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); }));
 
 	return 1;
 }
@@ -201,7 +201,7 @@
  */
 duk_ret_t version(duk_context *ctx)
 {
-	duk_push_stdstring(ctx, sys::version());
+	dukx_push_std_string(ctx, sys::version());
 
 	return 1;
 }
--- a/lib/irccd/mod-timer.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-timer.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -53,7 +53,7 @@
 
 		if (duk_is_callable(plugin->context(), -1)) {
 			if (duk_pcall(plugin->context(), 0) != 0)
-				log::warning("plugin {}: {}"_format(plugin->name(), duk_exception(plugin->context(), -1).stack));
+				log::warning("plugin {}: {}"_format(plugin->name(), dukx_exception(plugin->context(), -1).stack));
 			else
 				duk_pop(plugin->context());
 		} else
@@ -63,7 +63,17 @@
 
 std::shared_ptr<Timer> self(duk_context *ctx)
 {
-	return nullptr;
+	StackAssert sa(ctx);
+
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, Signature);
+	auto ptr = duk_to_pointer(ctx, -1);
+	duk_pop_2(ctx);
+
+	if (!ptr)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Timer object");
+
+	return *static_cast<std::shared_ptr<Timer> *>(ptr);
 }
 
 /*
@@ -139,22 +149,24 @@
 	duk_put_prop_string(ctx, -2, Signature);
 	duk_push_string(ctx, hash.c_str());
 	duk_put_prop_string(ctx, -2, "\xff""\xff""timer-key");
-
-#if 0
-	push(ctx, Function{[] (duk_context *ctx) -> duk_ret_t {
+	duk_push_c_function(ctx, [] (duk_context *ctx) -> duk_ret_t {
 		StackAssert sa(ctx);
 
-		require<std::shared_ptr<Timer>>(ctx, 0)->stop();
-		delete static_cast<std::shared_ptr<Timer> *>(getProperty<void *>(ctx, 0, Signature));
-		getGlobal<void>(ctx, CallbackTable);
-		deleteProperty(ctx, -1, getProperty<std::string>(ctx, 0, "\xff""\xff""timer-key"));
-		pop(ctx);
+		duk_get_prop_string(ctx, 0, "\xff""\xff""timer-key");
+		auto hash = duk_get_string(ctx, -1);
+		duk_pop(ctx);
+		duk_get_prop_string(ctx, 0, Signature);
+		static_cast<std::shared_ptr<Timer> *>(duk_to_pointer(ctx, -1))->get()->stop();
+		delete static_cast<std::shared_ptr<Timer> *>(duk_to_pointer(ctx, -1));
+		duk_pop(ctx);
+		duk_get_global_string(ctx, CallbackTable);
+		duk_del_prop_string(ctx, -1, hash);
+		duk_pop(ctx);
 		log::debug("plugin: timer destroyed");
 
 		return 0;
-	}, 1});
-	setFinalizer(ctx, -2);
-#endif
+	}, 1);
+	duk_set_finalizer(ctx, -2);
 
 	// Save a callback function into the callback table.
 	duk_get_global_string(ctx, CallbackTable);
--- a/lib/irccd/mod-util.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/mod-util.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -44,8 +44,8 @@
 	if (!duk_is_object(ctx, index))
 		return params;
 
-	duk_enumerate(ctx, index, 0, true, [&] (duk_context *) {
-		if (duk_get_stdstring(ctx, -2) == "date")
+	dukx_enumerate(ctx, index, 0, true, [&] (duk_context *) {
+		if (dukx_get_std_string(ctx, -2) == "date")
 			params.time = static_cast<time_t>(duk_get_number(ctx, -1) / 1000);
 		else
 			params.keywords.insert({duk_get_string(ctx, -2), duk_get_string(ctx, -1)});
@@ -69,9 +69,9 @@
 duk_ret_t format(duk_context *ctx)
 {
 	try {
-		duk_push_stdstring(ctx, util::format(duk_get_stdstring(ctx, 0), getSubstitution(ctx, 1)));
+		dukx_push_std_string(ctx, util::format(dukx_get_std_string(ctx, 0), getSubstitution(ctx, 1)));
 	} catch (const std::exception &ex) {
-		duk_throw(ctx, SyntaxError(ex.what()));
+		dukx_throw(ctx, SyntaxError(ex.what()));
 	}
 
 	return 1;
--- a/lib/irccd/plugin-js.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/lib/irccd/plugin-js.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -46,7 +46,7 @@
 		duk_insert(m_context, -nargs - 1);
 
 		if (duk_pcall(m_context, nargs) != 0)
-			throw duk_exception(m_context, -1, true);
+			throw dukx_exception(m_context, -1, true);
 
 		duk_pop(m_context);
 	}
@@ -63,10 +63,10 @@
 	StackAssert sa(m_context);
 
 	duk_push_pointer(m_context, this);
-	duk_get_global_string(m_context, "\xff""\xff""plugin");
-	duk_push_stdstring(m_context, name());
+	duk_put_global_string(m_context, "\xff""\xff""plugin");
+	dukx_push_std_string(m_context, name());
 	duk_put_global_string(m_context, "\xff""\xff""name");
-	duk_push_stdstring(m_context, path());
+	dukx_push_std_string(m_context, path());
 	duk_put_global_string(m_context, "\xff""\xff""path");
 }
 
@@ -92,10 +92,10 @@
 		foundpath = path::clean(path::get(type, path::OwnerSystem) + append);
 
 	duk_get_global_string(m_context, "Irccd");
-	duk_get_prop_string(m_context, -2, "Plugin");
-	duk_push_stdstring(m_context, foundpath);
+	duk_get_prop_string(m_context, -1, "Plugin");
+	dukx_push_std_string(m_context, foundpath);
 	duk_put_prop_string(m_context, -2, varname.c_str());
-	duk_pop_n(m_context, 2);
+	duk_pop_2(m_context);
 }
 
 void JsPlugin::putConfig(const PluginConfig &config)
@@ -111,7 +111,7 @@
 	duk_get_prop_string(m_context, -1, "config");
 
 	for (const auto &pair : config) {
-		duk_push_stdstring(m_context, pair.second);
+		dukx_push_std_string(m_context, pair.second);
 		duk_put_prop_string(m_context, -2, pair.first.c_str());
 	}
 
@@ -128,7 +128,7 @@
 	duk_get_prop_string(m_context, -1, "format");
 
 	for (const auto &pair : formats()) {
-		duk_push_stdstring(m_context, pair.second);
+		dukx_push_std_string(m_context, pair.second);
 		duk_put_prop_string(m_context, -1, pair.first.c_str());
 	}
 
@@ -150,10 +150,10 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, mode);
-	duk_push_stdstring(m_context, arg);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, mode);
+	dukx_push_std_string(m_context, arg);
 	call("onChannelMode", 5);
 }
 
@@ -166,9 +166,9 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, notice);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, notice);
 	call("onChannelNotice", 4);
 }
 
@@ -181,9 +181,9 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, message);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, message);
 	call("onCommand", 4);
 }
 
@@ -200,8 +200,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
 	call("onInvite", 3);
 }
 
@@ -210,8 +210,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
 	call("onJoin", 3);
 }
 
@@ -225,10 +225,10 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, target);
-	duk_push_stdstring(m_context, reason);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, target);
+	dukx_push_std_string(m_context, reason);
 	call("onKick", 5);
 }
 
@@ -259,7 +259,7 @@
 
 	// Try to load the file (does not call onLoad yet).
 	if (duk_peval_file(m_context, path().c_str()) != 0)
-		throw duk_exception(m_context, -1, true);
+		throw dukx_exception(m_context, -1, true);
 
 	duk_pop(m_context);
 
@@ -292,9 +292,9 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, message);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, message);
 	call("onMessage", 4);
 }
 
@@ -307,9 +307,9 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, message);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, message);
 	call("onMe", 4);
 }
 
@@ -318,8 +318,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, mode);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, mode);
 	call("onMode", 3);
 }
 
@@ -328,9 +328,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, channel);
-	// TODO
-	// duk_push_stdstring(m_context, names);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_array(m_context, names, dukx_push_std_string);
 	call("onNames", 3);
 }
 
@@ -339,8 +338,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, oldnick);
-	duk_push_stdstring(m_context, newnick);
+	dukx_push_std_string(m_context, oldnick);
+	dukx_push_std_string(m_context, newnick);
 	call("onNick", 3);
 }
 
@@ -349,8 +348,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, notice);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, notice);
 	call("onNotice", 3);
 }
 
@@ -363,9 +362,9 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, reason);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, reason);
 	call("onPart", 4);
 }
 
@@ -377,8 +376,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, message);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, message);
 	call("onQuery", 3);
 }
 
@@ -390,8 +389,8 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, message);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, message);
 	call("onQueryCommand", 3);
 }
 
@@ -411,9 +410,9 @@
 	StackAssert sa(m_context);
 
 	duk_push_server(m_context, server);
-	duk_push_stdstring(m_context, origin);
-	duk_push_stdstring(m_context, channel);
-	duk_push_stdstring(m_context, topic);
+	dukx_push_std_string(m_context, origin);
+	dukx_push_std_string(m_context, channel);
+	dukx_push_std_string(m_context, topic);
 	call("onTopic", 4);
 }
 
@@ -433,13 +432,13 @@
 
 	duk_push_server(m_context, server);
 	duk_push_object(m_context);
-	duk_push_stdstring(m_context, whois.nick);
+	dukx_push_std_string(m_context, whois.nick);
 	duk_put_prop_string(m_context, -2, "nickname");
-	duk_push_stdstring(m_context, whois.user);
+	dukx_push_std_string(m_context, whois.user);
 	duk_put_prop_string(m_context, -2, "username");
-	duk_push_stdstring(m_context, whois.realname);
+	dukx_push_std_string(m_context, whois.realname);
 	duk_put_prop_string(m_context, -2, "realname");
-	duk_push_stdstring(m_context, whois.host);
+	dukx_push_std_string(m_context, whois.host);
 	duk_put_prop_string(m_context, -2, "host");
 	// TODO
 	// duk_put_prop_string(m_context, -2, "channels", whois.channels);
--- a/tests/js-elapsedtimer/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-elapsedtimer/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -45,16 +45,17 @@
 TEST_F(TestElapsedTimer, standard)
 {
 	try {
-		if (duk::pevalString(m_plugin->context(), "timer = new Irccd.ElapsedTimer();") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "timer = new Irccd.ElapsedTimer();") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
 		std::this_thread::sleep_for(300ms);
 
-		if (duk::pevalString(m_plugin->context(), "result = timer.elapsed();") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "result = timer.elapsed();") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_GE(duk::getGlobal<int>(m_plugin->context(), "result"), 250);
-		ASSERT_LE(duk::getGlobal<int>(m_plugin->context(), "result"), 350);
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_GE(duk_get_int(m_plugin->context(), -1), 250);
+		ASSERT_LE(duk_get_int(m_plugin->context(), -1), 350);
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -63,15 +64,16 @@
 TEST_F(TestElapsedTimer, reset)
 {
 	try {
-		if (duk::pevalString(m_plugin->context(), "timer = new Irccd.ElapsedTimer();") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "timer = new Irccd.ElapsedTimer();") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
 		std::this_thread::sleep_for(300ms);
 
-		if (duk::pevalString(m_plugin->context(), "timer.reset(); result = timer.elapsed();") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "timer.reset(); result = timer.elapsed();") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_LE(duk::getGlobal<int>(m_plugin->context(), "result"), 100);
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_LE(duk_get_int(m_plugin->context(), -1), 100);
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
--- a/tests/js-file/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-file/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -44,10 +44,11 @@
 TEST_F(TestJsFile, functionBasename)
 {
 	try {
-		if (duk::pevalString(m_plugin->context(), "result = Irccd.File.basename('/usr/local/etc/irccd.conf');") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "result = Irccd.File.basename('/usr/local/etc/irccd.conf');") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ("irccd.conf", duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("irccd.conf", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -56,9 +57,10 @@
 TEST_F(TestJsFile, functionDirname)
 {
 	try {
-		duk::pevalString(m_plugin->context(), "result = Irccd.File.dirname('/usr/local/etc/irccd.conf');");
+		duk_peval_string(m_plugin->context(), "result = Irccd.File.dirname('/usr/local/etc/irccd.conf');");
 
-		ASSERT_EQ("/usr/local/etc", duk::getGlobal<std::string>(m_plugin->context(),"result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("/usr/local/etc", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -67,10 +69,12 @@
 TEST_F(TestJsFile, functionExists)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
-		duk::pevalString(m_plugin->context(), "result = Irccd.File.exists(directory + '/file.txt')");
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
+		duk_peval_string(m_plugin->context(), "result = Irccd.File.exists(directory + '/file.txt')");
 
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(),"result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -79,9 +83,10 @@
 TEST_F(TestJsFile, functionExists2)
 {
 	try {
-		duk::pevalString(m_plugin->context(), "result = Irccd.File.exists('file_which_does_not_exist.txt')");
+		duk_peval_string(m_plugin->context(), "result = Irccd.File.exists('file_which_does_not_exist.txt')");
 
-		ASSERT_FALSE(duk::getGlobal<bool>(m_plugin->context(),"result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_FALSE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -93,8 +98,8 @@
 	std::ofstream("test-js-fs.remove");
 
 	try {
-		if (duk::pevalString(m_plugin->context(), "Irccd.File.remove('test-js-fs.remove');") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "Irccd.File.remove('test-js-fs.remove');") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -107,17 +112,19 @@
 TEST_F(TestJsFile, methodBasename)
 {
 	try {
-		duk::putGlobal(m_plugin->context(),"directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/level-1/file-1.txt', 'r');"
 			"result = f.basename();"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ("file-1.txt", duk::getGlobal<std::string>(m_plugin->context(),"result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("file-1.txt", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -126,18 +133,20 @@
 TEST_F(TestJsFile, methodBasenameClosed)
 {
 	try {
-		duk::putGlobal(m_plugin->context(),"directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/level-1/file-1.txt', 'r');"
 			"f.close();"
 			"result = f.basename();"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ("file-1.txt", duk::getGlobal<std::string>(m_plugin->context(),"result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("file-1.txt", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -146,17 +155,19 @@
 TEST_F(TestJsFile, methodDirname)
 {
 	try {
-		duk::putGlobal(m_plugin->context(),"directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/level-1/file-1.txt', 'r');"
 			"result = f.dirname();"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(std::string{IRCCD_TESTS_DIRECTORY "/level-1"}, duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ(IRCCD_TESTS_DIRECTORY "/level-1", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -165,18 +176,20 @@
 TEST_F(TestJsFile, methodDirnameClosed)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/level-1/file-1.txt', 'r');"
 			"f.close();"
 			"result = f.dirname();"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(std::string{IRCCD_TESTS_DIRECTORY "/level-1"}, duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ(IRCCD_TESTS_DIRECTORY "/level-1", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -185,18 +198,20 @@
 TEST_F(TestJsFile, methodLines)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
-			"lines = new Irccd.File(directory + '/lines.txt', 'r').lines();"
+		auto ret = duk_peval_string(m_plugin->context(),
+			"result = new Irccd.File(directory + '/lines.txt', 'r').lines();"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
 		std::vector<std::string> expected{"a", "b", "c"};
 
-		ASSERT_EQ(expected, duk::getGlobal<std::vector<std::string>>(m_plugin->context(), "lines"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_EQ(expected, dukx_get_array(m_plugin->context(), -1, dukx_get_std_string));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -205,18 +220,20 @@
 TEST_F(TestJsFile, methodSeek1)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/file.txt', 'r');"
 			"f.seek(Irccd.File.SeekSet, 4);"
 			"result = f.read(1);"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(".", duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_EQ(".", dukx_get_std_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -225,9 +242,10 @@
 TEST_F(TestJsFile, methodSeek1Closed)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/file.txt', 'r');"
 			"f.close();"
 			"f.seek(Irccd.File.SeekSet, 4);"
@@ -236,9 +254,10 @@
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -247,9 +266,10 @@
 TEST_F(TestJsFile, methodSeek2)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/file.txt', 'r');"
 			"f.seek(Irccd.File.SeekSet, 2);"
 			"f.seek(Irccd.File.SeekCur, 2);"
@@ -257,9 +277,10 @@
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(".", duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_EQ(".", dukx_get_std_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -268,9 +289,10 @@
 TEST_F(TestJsFile, methodSeek2Closed)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/file.txt', 'r');"
 			"f.close();"
 			"f.seek(Irccd.File.SeekSet, 2);"
@@ -280,9 +302,10 @@
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -291,18 +314,20 @@
 TEST_F(TestJsFile, methodSeek3)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/file.txt', 'r');"
 			"f.seek(Irccd.File.SeekEnd, -2);"
 			"result = f.read(1);"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ("x", duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("x", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -311,9 +336,10 @@
 TEST_F(TestJsFile, methodSeek3Closed)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = new Irccd.File(directory + '/file.txt', 'r');"
 			"f.close();"
 			"f.seek(Irccd.File.SeekEnd, -2);"
@@ -322,9 +348,10 @@
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -333,22 +360,24 @@
 TEST_F(TestJsFile, methodReadline)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
-			"lines = [];"
+		auto ret = duk_peval_string(m_plugin->context(),
+			"result = [];"
 			"f = new Irccd.File(directory + '/lines.txt', 'r');"
 			"for (var s; s = f.readline(); ) {"
-			"  lines.push(s);"
+			"  result.push(s);"
 			"}"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
 		std::vector<std::string> expected{"a", "b", "c"};
 
-		ASSERT_EQ(expected, duk::getGlobal<std::vector<std::string>>(m_plugin->context(), "lines"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_EQ(expected, dukx_get_array(m_plugin->context(), -1, dukx_get_std_string));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -357,23 +386,25 @@
 TEST_F(TestJsFile, methodReadlineClosed)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "directory", IRCCD_TESTS_DIRECTORY);
+		duk_push_string(m_plugin->context(), IRCCD_TESTS_DIRECTORY);
+		duk_put_global_string(m_plugin->context(), "directory");
 
-		auto ret = duk::pevalString(m_plugin->context(),
-			"lines = [];"
+		auto ret = duk_peval_string(m_plugin->context(),
+			"result = [];"
 			"f = new Irccd.File(directory + '/lines.txt', 'r');"
 			"f.close();"
 			"for (var s; s = f.readline(); ) {"
-			"  lines.push(s);"
+			"  result.push(s);"
 			"}"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
 		std::vector<std::string> expected;
 
-		ASSERT_EQ(expected, duk::getGlobal<std::vector<std::string>>(m_plugin->context(), "lines"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_EQ(expected, dukx_get_array(m_plugin->context(), -1, dukx_get_std_string));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
--- a/tests/js-irccd/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-irccd/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -41,18 +41,21 @@
 TEST_F(TestJsIrccd, version)
 {
 	try {
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"major = Irccd.version.major;"
 			"minor = Irccd.version.minor;"
 			"patch = Irccd.version.patch;"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(IRCCD_VERSION_MAJOR, duk::getGlobal<int>(m_plugin->context(), "major"));
-		ASSERT_EQ(IRCCD_VERSION_MINOR, duk::getGlobal<int>(m_plugin->context(), "minor"));
-		ASSERT_EQ(IRCCD_VERSION_PATCH, duk::getGlobal<int>(m_plugin->context(), "patch"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "major"));
+		ASSERT_EQ(IRCCD_VERSION_MAJOR, duk_get_int(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "minor"));
+		ASSERT_EQ(IRCCD_VERSION_MINOR, duk_get_int(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "patch"));
+		ASSERT_EQ(IRCCD_VERSION_PATCH, duk_get_int(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -61,7 +64,7 @@
 TEST_F(TestJsIrccd, fromJavascript)
 {
 	try {
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"try {"
 			"  throw new Irccd.SystemError(1, 'test');"
 			"} catch (e) {"
@@ -74,13 +77,18 @@
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(1, duk::getGlobal<int>(m_plugin->context(), "errno"));
-		ASSERT_EQ("SystemError", duk::getGlobal<std::string>(m_plugin->context(), "name"));
-		ASSERT_EQ("test", duk::getGlobal<std::string>(m_plugin->context(), "message"));
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "v1"));
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "v2"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "errno"));
+		ASSERT_EQ(1, duk_get_int(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "name"));
+		ASSERT_STREQ("SystemError", duk_get_string(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "message"));
+		ASSERT_STREQ("test", duk_get_string(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "v1"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "v2"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -89,15 +97,15 @@
 TEST_F(TestJsIrccd, fromNative)
 {
 	try {
-		duk::push(m_plugin->context(), duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::raise(ctx, SystemError{EINVAL, "hey"});
+		duk_push_c_function(m_plugin->context(), [] (duk_context *ctx) -> duk_ret_t {
+			dukx_throw(ctx, SystemError(EINVAL, "hey"));
 
 			return 0;
-		}});
+		}, 0);
 
-		duk::putGlobal(m_plugin->context(), "f");
+		duk_put_global_string(m_plugin->context(), "f");
 
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"try {"
 			"  f();"
 			"} catch (e) {"
@@ -110,13 +118,18 @@
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(EINVAL, duk::getGlobal<int>(m_plugin->context(), "errno"));
-		ASSERT_EQ("SystemError", duk::getGlobal<std::string>(m_plugin->context(), "name"));
-		ASSERT_EQ("hey", duk::getGlobal<std::string>(m_plugin->context(), "message"));
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "v1"));
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "v2"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "errno"));
+		ASSERT_EQ(EINVAL, duk_get_int(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "name"));
+		ASSERT_STREQ("SystemError", duk_get_string(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "message"));
+		ASSERT_STREQ("hey", duk_get_string(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "v1"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "v2"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
--- a/tests/js-logger/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-logger/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -60,9 +60,10 @@
 	std::shared_ptr<JsPlugin> m_plugin;
 
 	TestJsLogger()
-		: m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
+		: m_plugin(std::make_shared<JsPlugin>("test", SOURCEDIR "/empty.js"))
 	{
 		m_irccd.moduleService().get("Irccd")->load(m_irccd, *m_plugin);
+		m_irccd.moduleService().get("Irccd.Plugin")->load(m_irccd, *m_plugin);
 		m_irccd.moduleService().get("Irccd.Logger")->load(m_irccd, *m_plugin);
 	}
 };
@@ -70,10 +71,8 @@
 TEST_F(TestJsLogger, info)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "\xff""\xff""name", "test");
-
-		if (duk::pevalString(m_plugin->context(), "Irccd.Logger.info(\"hello!\");") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "Irccd.Logger.info(\"hello!\");") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("plugin test: hello!", lineInfo);
 	} catch (const std::exception &ex) {
@@ -84,10 +83,8 @@
 TEST_F(TestJsLogger, warning)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "\xff""\xff""name", "test");
-
-		if (duk::pevalString(m_plugin->context(), "Irccd.Logger.warning(\"FAIL!\");") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "Irccd.Logger.warning(\"FAIL!\");") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("plugin test: FAIL!", lineWarning);
 	} catch (const std::exception &ex) {
@@ -100,10 +97,8 @@
 TEST_F(TestJsLogger, debug)
 {
 	try {
-		duk::putGlobal(m_plugin->context(), "\xff""\xff""name", "test");
-
-		if (duk::pevalString(m_plugin->context(), "Irccd.Logger.debug(\"starting\");") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "Irccd.Logger.debug(\"starting\");") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("plugin test: starting", lineDebug);
 	} catch (const std::exception &ex) {
--- a/tests/js-system/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-system/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -45,9 +45,10 @@
 TEST_F(TestJsSystem, home)
 {
 	try {
-		duk::pevalString(m_plugin->context(), "result = Irccd.System.home();");
+		duk_peval_string_noresult(m_plugin->context(), "result = Irccd.System.home();");
 
-		ASSERT_EQ(sys::home(), duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_EQ(sys::home(), duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -58,15 +59,16 @@
 TEST_F(TestJsSystem, popen)
 {
 	try {
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"f = Irccd.System.popen(\"" IRCCD_EXECUTABLE " --version\", \"r\");"
 			"r = f.readline();"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ(IRCCD_VERSION, duk::getGlobal<std::string>(m_plugin->context(), "r"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "r"));
+		ASSERT_STREQ(IRCCD_VERSION, duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
--- a/tests/js-timer/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-timer/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -42,7 +42,8 @@
 		irccd.dispatch();
 	}
 
-	ASSERT_EQ(1, duk::getGlobal<int>(plugin->context(), "count"));
+	ASSERT_TRUE(duk_get_global_string(plugin->context(), "count"));
+	ASSERT_EQ(1, duk_get_int(plugin->context(), -1));
 }
 
 TEST(Basic, repeat)
@@ -60,7 +61,8 @@
 		irccd.dispatch();
 	}
 
-	ASSERT_GE(duk::getGlobal<int>(plugin->context(), "count"), 5);
+	ASSERT_TRUE(duk_get_global_string(plugin->context(), "count"));
+	ASSERT_GE(duk_get_int(plugin->context(), -1), 5);
 }
 
 #if 0
--- a/tests/js-unicode/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-unicode/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -47,11 +47,13 @@
 TEST_F(TestJsUnicode, isLetter)
 {
 	try {
-		duk::pevalString(m_plugin->context(), "result = Irccd.Unicode.isLetter(String('é').charCodeAt(0));");
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		duk_peval_string_noresult(m_plugin->context(), "result = Irccd.Unicode.isLetter(String('é').charCodeAt(0));");
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 
-		duk::pevalString(m_plugin->context(), "result = Irccd.Unicode.isLetter(String('€').charCodeAt(0));");
-		ASSERT_FALSE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		duk_peval_string_noresult(m_plugin->context(), "result = Irccd.Unicode.isLetter(String('€').charCodeAt(0));");
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_FALSE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -60,11 +62,13 @@
 TEST_F(TestJsUnicode, isLower)
 {
 	try {
-		duk::pevalString(m_plugin->context(), "result = Irccd.Unicode.isLower(String('é').charCodeAt(0));");
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		duk_peval_string_noresult(m_plugin->context(), "result = Irccd.Unicode.isLower(String('é').charCodeAt(0));");
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 
-		duk::pevalString(m_plugin->context(), "result = Irccd.Unicode.isLower(String('É').charCodeAt(0));");
-		ASSERT_FALSE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		duk_peval_string_noresult(m_plugin->context(), "result = Irccd.Unicode.isLower(String('É').charCodeAt(0));");
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_FALSE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -73,11 +77,13 @@
 TEST_F(TestJsUnicode, isUpper)
 {
 	try {
-		duk::pevalString(m_plugin->context(), "result = Irccd.Unicode.isUpper(String('É').charCodeAt(0));");
-		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		duk_peval_string_noresult(m_plugin->context(), "result = Irccd.Unicode.isUpper(String('É').charCodeAt(0));");
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_boolean(m_plugin->context(), -1));
 
-		duk::pevalString(m_plugin->context(), "result = Irccd.Unicode.isUpper(String('é').charCodeAt(0));");
-		ASSERT_FALSE(duk::getGlobal<bool>(m_plugin->context(), "result"));
+		duk_peval_string_noresult(m_plugin->context(), "result = Irccd.Unicode.isUpper(String('é').charCodeAt(0));");
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_FALSE(duk_get_boolean(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
--- a/tests/js-util/main.cpp	Fri Jun 03 13:28:10 2016 +0200
+++ b/tests/js-util/main.cpp	Sun Jun 05 10:50:55 2016 +0200
@@ -43,12 +43,15 @@
 TEST_F(TestJsUtil, formatSimple)
 {
 	try {
-		auto ret = duk::pevalString(m_plugin->context(),
+		auto ret = duk_peval_string(m_plugin->context(),
 			"result = Irccd.Util.format(\"#{target}\", { target: \"markand\" })"
 		);
 
 		if (ret != 0)
-			throw duk::exception(m_plugin->context(), -1);
+			throw dukx_exception(m_plugin->context(), -1);
+
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("markand", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -57,10 +60,11 @@
 TEST_F(TestJsUtil, splituser)
 {
 	try {
-		if (duk::pevalString(m_plugin->context(), "result = Irccd.Util.splituser(\"user!~user@hyper/super/host\");") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "result = Irccd.Util.splituser(\"user!~user@hyper/super/host\");") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ("user", duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("user", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -69,10 +73,11 @@
 TEST_F(TestJsUtil, splithost)
 {
 	try {
-		if (duk::pevalString(m_plugin->context(), "result = Irccd.Util.splithost(\"user!~user@hyper/super/host\");") != 0)
-			throw duk::exception(m_plugin->context(), -1);
+		if (duk_peval_string(m_plugin->context(), "result = Irccd.Util.splithost(\"user!~user@hyper/super/host\");") != 0)
+			throw dukx_exception(m_plugin->context(), -1);
 
-		ASSERT_EQ("!~user@hyper/super/host", duk::getGlobal<std::string>(m_plugin->context(), "result"));
+		ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
+		ASSERT_STREQ("!~user@hyper/super/host", duk_get_string(m_plugin->context(), -1));
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}