summaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
authoryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-14 02:22:08 +0000
committeryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-14 02:22:08 +0000
commit8c9a453f2d8ac78943df98c61cdbb9e4a4ad0eda (patch)
tree8c02f7b02f8573a90c761da60315134eb64e8dd4 /eval.c
parentf8601bd903d6c9f288fc39cc9f277c1275291ff3 (diff)
Embedding CRuby interpreter without internal headers has been difficult
for few years because: * NODE is no longer accessible. * rb_iseq_eval_main crashes without preparing with rb_thread_t. * some existing APIs calls exit(3) without giving the opportunity to finalize or handle errors to the client. * No general-purpose function to compile a source to an iseq are published in the public headers. This commit solves the problems. * include/ruby/ruby.h: Grouped APIs for embedding CRuby interpreter. (ruby_setup, ruby_compile_main_from_file, ruby_compile_main_from_string, ruby_eval_main, ruby_set_script_name): new APIs to embed CRuby. (ruby_opaque_t) Opaque pointer to an internal data, to NODE or iseq in particular. * eval.c (ruby_setup): Similar to ruby_init but returns an error code instead of exit(3) on error. (ruby_eval_main): Similar to ruby_exec_node but returns the evaluation result. (ruby_eval_main_internal): renamed from ruby_exec_internal. * ruby.c (toplevel_context): new helper function. (PREPARE_EVAL_MAIN): moved. (process_options): refactored with new functions. (parse_and_compile_main) new helper funciton. (ruby_compile_main_from_file, ruby_compile_main_from_string) new API (ruby_set_script_name): new API. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36079 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c93
1 files changed, 62 insertions, 31 deletions
diff --git a/eval.c b/eval.c
index a706c23dab..499edfbbbf 100644
--- a/eval.c
+++ b/eval.c
@@ -31,16 +31,18 @@ VALUE rb_eSysStackError;
#include "eval_error.c"
#include "eval_jump.c"
-/* initialize ruby */
-
-void
-ruby_init(void)
+/* Initializes the Ruby VM and builtin libraries.
+ * @retval 0 if succeeded.
+ * @retval non-zero an error occured.
+ */
+int
+ruby_setup(void)
{
static int initialized = 0;
int state;
if (initialized)
- return;
+ return 0;
initialized = 1;
ruby_init_stack((void *)&state);
@@ -54,11 +56,22 @@ ruby_init(void)
}
POP_TAG();
+ if (!state) GET_VM()->running = 1;
+ return state;
+}
+
+/* Calls ruby_setup() and check error.
+ *
+ * Prints errors and calls exit(3) if an error occured.
+ */
+void
+ruby_init(void)
+{
+ int state = ruby_setup();
if (state) {
error_print();
exit(EXIT_FAILURE);
}
- GET_VM()->running = 1;
}
/*! Processes command line arguments and compiles the Ruby source to execute.
@@ -71,7 +84,7 @@ ruby_init(void)
* @return an opaque pointer to the compiled source or an internal special value.
* @sa ruby_executable_node().
*/
-void *
+ruby_opaque_t
ruby_options(int argc, char **argv)
{
int state;
@@ -217,26 +230,6 @@ ruby_cleanup(volatile int ex)
return ex;
}
-static int
-ruby_exec_internal(void *n)
-{
- volatile int state;
- VALUE iseq = (VALUE)n;
- rb_thread_t *th = GET_THREAD();
-
- if (!n) return 0;
-
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- SAVE_ROOT_JMPBUF(th, {
- th->base_block = 0;
- rb_iseq_eval_main(iseq);
- });
- }
- POP_TAG();
- return state;
-}
-
/*! Calls ruby_cleanup() and exits the process */
void
ruby_stop(int ex)
@@ -257,7 +250,7 @@ ruby_stop(int ex)
* @retval 0 if the given value is such a special value.
*/
int
-ruby_executable_node(void *n, int *status)
+ruby_executable_node(ruby_opaque_t n, int *status)
{
VALUE v = (VALUE)n;
int s;
@@ -273,12 +266,33 @@ ruby_executable_node(void *n, int *status)
return FALSE;
}
+static int
+ruby_eval_main_internal(VALUE iseqval, VALUE* result)
+{
+ volatile int state;
+ volatile VALUE retval;
+ rb_thread_t *th = GET_THREAD();
+
+ if (!iseqval) return 0;
+
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ SAVE_ROOT_JMPBUF(th, {
+ th->base_block = 0;
+ retval = rb_iseq_eval_main(iseqval);
+ });
+ }
+ POP_TAG();
+ *result = state ? th->errinfo : retval;
+ return state;
+}
+
/*! Runs the given compiled source and exits this process.
* @retval 0 if successfully run thhe source
* @retval non-zero if an error occurred.
*/
int
-ruby_run_node(void *n)
+ruby_run_node(ruby_opaque_t n)
{
int status;
if (!ruby_executable_node(n, &status)) {
@@ -290,10 +304,27 @@ ruby_run_node(void *n)
/*! Runs the given compiled source */
int
-ruby_exec_node(void *n)
+ruby_exec_node(ruby_opaque_t n)
{
+ VALUE dummy;
ruby_init_stack((void *)&n);
- return ruby_exec_internal(n);
+ return ruby_eval_main_internal((VALUE)n, &dummy);
+}
+
+
+/*!
+ * Evaluates the given iseq in the main (toplevel) context.
+ *
+ * @param iseqval a VALUE that wraps an iseq.
+ * @param result Stores the evaluated value if succeeded,
+ * or an exception if failed.
+ * @retval 0 if succeeded
+ * @retval non-zero if failed.
+ */
+int
+ruby_eval_main(ruby_opaque_t n, VALUE *result)
+{
+ return !!ruby_eval_main_internal((VALUE)n, result);
}
/*