Embed API #1099

Closed
wants to merge 2 commits into
from
@@ -0,0 +1,22 @@
+module Rubinius
+ class EmbedLoader
+ def self.load_compiler
+ l = Loader.new
+ l.preamble
+ l.system_load_path
+ CodeLoader.require_compiled "compiler"
+ end
+
+ def self.require_file file
+ Kernel.require file
+ end
+
+ def self.eval_file file
+ CodeLoader.load_script file
+ end
+
+ def self.eval_script code
+ CodeLoader.execute_script code
+ end
+ end
+end
View
@@ -0,0 +1,63 @@
+#include "environment.hpp"
+#include "builtin/object.hpp"
+
+using namespace rubinius;
+
+typedef Environment* rbx_ctx;
+typedef Object* rbx_obj;
+
+#define RUBINIUS_CONST(ctx, n) ctx->state->globals().rubinius.get()->get_const(ctx->state, ctx->state->symbol(n));
+
+extern "C"{
+/**
+ * Create a embedded rubinius environment
+ */
+rbx_ctx rbx_create_context();
+
+/**
+ * Requires a ruby file (like require 'file' in ruby)
+ *
+ * Returns true if it executed without exception, false if there was an error.
+ * Finding out what went wrong will be defined later.
+ */
+bool rbx_require_file(rbx_ctx ctx, const char * file);
+
+/**
+ * Evaulate a ruby file
+ *
+ * Returns true if it executed without exception, false if there was an error.
+ * Finding out what went wrong will be defined later.
+ */
+bool rbx_eval_file(rbx_ctx ctx, const char * file);
+
+/**
+ * Evaluate a ruby string
+ *
+ * Returns true if it executed without exception, false if there was an error.
+ * Finding out what went wrong will be defined later.
+ */
+bool rbx_eval(rbx_ctx ctx, const char * code);
+
+/**
+ * Send a message to an object
+ *
+ * Send +msg+ to object +rcv+ with arguments specified by +argc+ and the
+ * variadic parameters that follow. All arguments *must* be of type rbx_obj.
+ */
+rbx_obj rbx_send(rbx_ctx ctx, rbx_obj recv, const char* msg, int argc, ...);
+
+/**
+ * Acquire global lock
+ */
+void rbx_lock(rbx_ctx ctx);
+
+/**
+ * Release global lock
+ */
+void rbx_unlock(rbx_ctx ctx);
+
+/**
+ * Clean up a context
+ */
+void rbx_close_ctx(rbx_ctx ctx);
+}
View
@@ -0,0 +1,88 @@
+#include "api/embed.h"
+
+#include "builtin/object.hpp"
+#include "builtin/string.hpp"
+#include "builtin/array.hpp"
+#include "builtin/module.hpp"
+
+rbx_ctx rbx_create_context() {
+ Environment* ctx = new Environment(0, NULL);
+ ctx->setup_cpp_terminate();
+
+ const char* runtime = getenv("RBX_RUNTIME");
+ if(!runtime) runtime = RBX_RUNTIME;
+
+ const char* lib_path = getenv("RBX_LIB_PATH");
+ if(!lib_path) lib_path = RBX_LIB_PATH;
+
+ std::string runtime_str(runtime);
+ std::string lib_path_str(lib_path);
+
+ int i = 0;
+ ctx->state->set_stack_start(&i);
+
+ ctx->load_platform_conf(runtime);
+ ctx->boot_vm();
+ ctx->state->initialize_config();
+ ctx->load_tool();
+ ctx->load_kernel(runtime);
+ ctx->start_signals();
+
+ ctx->run_file(runtime_str + "/loader.rbc");
+ ctx->run_file(runtime_str + "/embed_loader.rbc");
+
+ rbx_obj loader = RUBINIUS_CONST(ctx, "EmbedLoader");
+ rbx_send(ctx, loader, "load_compiler", 0);
+
+ return ctx;
+}
+
+bool rbx_require_file(rbx_ctx ctx, const char * file) {
+ rbx_obj loader = RUBINIUS_CONST(ctx, "EmbedLoader");
+ rbx_send(ctx, loader, "require_file", 1, String::create(ctx->state, file));
+
+ return true;
+}
+
+bool rbx_eval_file(rbx_ctx ctx, const char * file) {
+ rbx_obj loader = RUBINIUS_CONST(ctx, "EmbedLoader");
+ rbx_send(ctx, loader, "eval_file", 1, String::create(ctx->state, file));
+
+ return true;
+}
+
+bool rbx_eval(rbx_ctx ctx, const char * code) {
+ rbx_obj loader = RUBINIUS_CONST(ctx, "EmbedLoader");
+ rbx_send(ctx, loader, "eval_script", 1, String::create(ctx->state, code));
+
+ return true;
+}
+
+rbx_obj rbx_send(rbx_ctx ctx, rbx_obj recv, const char* msg, int argc, ...) {
+ rbx_lock(ctx);
+ va_list args;
+ va_start(args, argc);
+
+ Array* arg_ary = Array::create(ctx->state, argc);
+ for(int i=0; i<argc; i++)
+ arg_ary->append(ctx->state, va_arg(args, Object*));
+
+ va_end(args);
+
+ rbx_obj ret = recv->send(ctx->state, 0, ctx->state->symbol(msg), arg_ary);
+ rbx_unlock(ctx);
+ return ret;
+}
+
+void rbx_lock(rbx_ctx ctx) {
+ ctx->state->global_lock().take();
+}
+
+void rbx_unlock(rbx_ctx ctx) {
+ ctx->state->global_lock().drop();
+}
+
+void rbx_close_ctx(rbx_ctx ctx) {
+ ctx->halt();
+ delete ctx;
+}
@@ -0,0 +1,22 @@
+#include "vm/test/test.hpp"
+#include "api/embed.h"
+
+class TestEmbedding : public CxxTest::TestSuite {
+public:
+ void test_create_and_close_context() {
+ rbx_ctx ctx = rbx_create_context();
+ TS_ASSERT(ctx != NULL);
+ rbx_close_ctx(ctx);
+ }
+
+ void test_multiple_sequential_contexts() {
+ TS_FAIL("This is crashing");
+ rbx_ctx ctx1 = rbx_create_context();
+ TS_ASSERT(ctx1 != NULL);
+ rbx_close_ctx(ctx1);
+
+ rbx_ctx ctx2 = rbx_create_context();
+ TS_ASSERT(ctx2 != NULL);
+ rbx_close_ctx(ctx2);
+ }
+};