diff options
author | yugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-06-14 02:22:08 +0000 |
---|---|---|
committer | yugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-06-14 02:22:08 +0000 |
commit | 8c9a453f2d8ac78943df98c61cdbb9e4a4ad0eda (patch) | |
tree | 8c02f7b02f8573a90c761da60315134eb64e8dd4 /eval.c | |
parent | f8601bd903d6c9f288fc39cc9f277c1275291ff3 (diff) | |
download | ruby-8c9a453f2d8ac78943df98c61cdbb9e4a4ad0eda.tar.gz |
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.c | 93 |
1 files changed, 62 insertions, 31 deletions
@@ -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); } /* |