summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/vm_eval.c b/vm_eval.c
index 449e0977976..53ec3ac18dd 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -19,6 +19,7 @@ static inline VALUE vm_backtrace(rb_thread_t *th, int lev);
static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex);
static VALUE vm_exec(rb_thread_t *th);
static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref);
+static int vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *dfp, VALUE ary);
static inline VALUE
vm_call0(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid,
@@ -1322,10 +1323,67 @@ rb_make_backtrace(void)
return vm_backtrace(GET_THREAD(), -1);
}
+/*
+ * call-seq:
+ * local_variables => array
+ *
+ * Returns the names of the current local variables.
+ *
+ * fred = 1
+ * for i in 1..10
+ * # ...
+ * end
+ * local_variables #=> ["fred", "i"]
+ */
+
+static VALUE
+rb_f_local_variables(void)
+{
+ VALUE ary = rb_ary_new();
+ rb_thread_t *th = GET_THREAD();
+ rb_control_frame_t *cfp =
+ vm_get_ruby_level_caller_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp));
+ int i;
+
+ while (cfp) {
+ if (cfp->iseq) {
+ for (i = 0; i < cfp->iseq->local_table_size; i++) {
+ ID lid = cfp->iseq->local_table[i];
+ if (lid) {
+ const char *vname = rb_id2name(lid);
+ /* should skip temporary variable */
+ if (vname) {
+ rb_ary_push(ary, ID2SYM(lid));
+ }
+ }
+ }
+ }
+ if (cfp->lfp != cfp->dfp) {
+ /* block */
+ VALUE *dfp = GC_GUARDED_PTR_REF(cfp->dfp[0]);
+
+ if (vm_collect_local_variables_in_heap(th, dfp, ary)) {
+ break;
+ }
+ else {
+ while (cfp->dfp != dfp) {
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+ }
+ }
+ else {
+ break;
+ }
+ }
+ return ary;
+}
+
void
Init_vm_eval(void)
{
rb_define_global_function("eval", rb_f_eval, -1);
+ rb_define_global_function("local_variables", rb_f_local_variables, 0);
+
rb_define_global_function("catch", rb_f_catch, -1);
rb_define_global_function("throw", rb_f_throw, -1);