summaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c9266
1 files changed, 0 insertions, 9266 deletions
diff --git a/eval.c b/eval.c
deleted file mode 100644
index 32f7972c39..0000000000
--- a/eval.c
+++ /dev/null
@@ -1,9266 +0,0 @@
-/**********************************************************************
-
- eval.c -
-
- $Author$
- $Date$
- created at: Thu Jun 10 14:22:17 JST 1993
-
- Copyright (C) 1993-2002 Yukihiro Matsumoto
- Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
- Copyright (C) 2000 Information-technology Promotion Agency, Japan
-
-**********************************************************************/
-
-#include "ruby.h"
-#include "node.h"
-#include "env.h"
-#include "util.h"
-#include "rubysig.h"
-
-#include <stdio.h>
-#include <setjmp.h>
-#include "st.h"
-#include "dln.h"
-
-/* Make alloca work the best possible way. */
-#ifdef __GNUC__
-# ifndef atarist
-# ifndef alloca
-# define alloca __builtin_alloca
-# endif
-# endif /* atarist */
-#else
-# if defined(HAVE_ALLOCA_H)
-# include <alloca.h>
-# elif !defined(alloca)
-char *alloca();
-# endif
-#endif /* __GNUC__ */
-
-#ifdef _AIX
-#pragma alloca
-#endif
-
-#ifdef HAVE_STDARG_PROTOTYPES
-#include <stdarg.h>
-#define va_init_list(a,b) va_start(a,b)
-#else
-#include <varargs.h>
-#define va_init_list(a,b) va_start(a)
-#endif
-
-#ifndef HAVE_STRING_H
-char *strrchr _((const char*,const char));
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef __BEOS__
-#include <net/socket.h>
-#endif
-
-#ifdef __MACOS__
-#include "macruby_private.h"
-#endif
-
-#ifndef setjmp
-#ifdef HAVE__SETJMP
-#define setjmp(env) _setjmp(env)
-#define longjmp(env,val) _longjmp(env,val)
-#endif
-#endif
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#else
-#ifndef NT
-struct timeval {
- long tv_sec; /* seconds */
- long tv_usec; /* and microseconds */
-};
-#endif /* NT */
-#endif
-#include <signal.h>
-#include <errno.h>
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#include <sys/stat.h>
-
-VALUE rb_cProc;
-static VALUE rb_cBinding;
-static VALUE proc_invoke _((VALUE,VALUE,int,VALUE));
-static VALUE rb_f_binding _((VALUE));
-static void rb_f_END _((void));
-static VALUE rb_f_block_given_p _((void));
-static VALUE block_pass _((VALUE,NODE*));
-static VALUE rb_cMethod;
-static VALUE method_proc _((VALUE));
-static VALUE method_call _((int, VALUE*, VALUE));
-static VALUE rb_cUnboundMethod;
-static VALUE umethod_bind _((VALUE, VALUE));
-static VALUE rb_mod_define_method _((int, VALUE*, VALUE));
-
-static int scope_vmode;
-#define SCOPE_PUBLIC 0
-#define SCOPE_PRIVATE 1
-#define SCOPE_PROTECTED 2
-#define SCOPE_MODFUNC 5
-#define SCOPE_MASK 7
-#define SCOPE_SET(f) do {scope_vmode=(f);} while(0)
-#define SCOPE_TEST(f) (scope_vmode&(f))
-
-int ruby_safe_level = 0;
-/* safe-level:
- 0 - strings from streams/environment/ARGV are tainted (default)
- 1 - no dangerous operation by tainted value
- 2 - process/file operations prohibited
- 3 - all genetated objects are tainted
- 4 - no global (non-tainted) variable modification/no direct output
-*/
-
-static VALUE safe_getter _((void));
-static void safe_setter _((VALUE val));
-
-void
-rb_secure(level)
- int level;
-{
- if (level <= ruby_safe_level) {
- rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d",
- rb_id2name(ruby_frame->last_func), ruby_safe_level);
- }
-}
-
-void
-rb_check_safe_str(x)
- VALUE x;
-{
- if (ruby_safe_level > 0 && OBJ_TAINTED(x)){
- if (ruby_frame->last_func) {
- rb_raise(rb_eSecurityError, "Insecure operation - %s",
- rb_id2name(ruby_frame->last_func));
- }
- else {
- rb_raise(rb_eSecurityError, "Insecure operation: -r");
- }
- }
- rb_secure(4);
- if (TYPE(x)!= T_STRING) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected String)",
- rb_class2name(CLASS_OF(x)));
- }
-}
-
-NORETURN(static void print_undef _((VALUE, ID)));
-static void
-print_undef(klass, id)
- VALUE klass;
- ID id;
-{
- rb_name_error(id, "undefined method `%s' for %s `%s'",
- rb_id2name(id),
- (TYPE(klass) == T_MODULE) ? "module" : "class",
- rb_class2name(klass));
-}
-
-static ID removed, singleton_removed, undefined, singleton_undefined;
-
-#define CACHE_SIZE 0x800
-#define CACHE_MASK 0x7ff
-#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
-
-struct cache_entry { /* method hash table. */
- ID mid; /* method's id */
- ID mid0; /* method's original id */
- VALUE klass; /* receiver's class */
- VALUE origin; /* where method defined */
- NODE *method;
- int noex;
-};
-
-static struct cache_entry cache[CACHE_SIZE];
-
-void
-rb_clear_cache()
-{
- struct cache_entry *ent, *end;
-
- ent = cache; end = ent + CACHE_SIZE;
- while (ent < end) {
- ent->mid = 0;
- ent++;
- }
-}
-
-static void
-rb_clear_cache_by_id(id)
- ID id;
-{
- struct cache_entry *ent, *end;
-
- ent = cache; end = ent + CACHE_SIZE;
- while (ent < end) {
- if (ent->mid == id) {
- ent->mid = 0;
- }
- ent++;
- }
-}
-
-void
-rb_add_method(klass, mid, node, noex)
- VALUE klass;
- ID mid;
- NODE *node;
- int noex;
-{
- NODE *body;
-
- if (NIL_P(klass)) klass = rb_cObject;
- if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
- rb_raise(rb_eSecurityError, "Insecure: can't define method");
- }
- if (OBJ_FROZEN(klass)) rb_error_frozen("class/module");
- rb_clear_cache_by_id(mid);
- body = NEW_METHOD(node, noex);
- st_insert(RCLASS(klass)->m_tbl, mid, body);
-}
-
-static NODE*
-search_method(klass, id, origin)
- VALUE klass, *origin;
- ID id;
-{
- NODE *body;
-
- if (!klass) return 0;
- while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) {
- klass = RCLASS(klass)->super;
- if (!klass) return 0;
- }
-
- if (origin) *origin = klass;
- return body;
-}
-
-static NODE*
-rb_get_method_body(klassp, idp, noexp)
- VALUE *klassp;
- ID *idp;
- int *noexp;
-{
- ID id = *idp;
- VALUE klass = *klassp;
- VALUE origin;
- NODE * volatile body;
- struct cache_entry *ent;
-
- if ((body = search_method(klass, id, &origin)) == 0 || !body->nd_body) {
- /* store empty info in cache */
- ent = cache + EXPR1(klass, id);
- ent->klass = klass;
- ent->origin = klass;
- ent->mid = ent->mid0 = id;
- ent->noex = 0;
- ent->method = 0;
-
- return 0;
- }
-
- /* store in cache */
- ent = cache + EXPR1(klass, id);
- ent->klass = klass;
- ent->noex = body->nd_noex;
- body = body->nd_body;
- if (nd_type(body) == NODE_FBODY) {
- ent->mid = id;
- *klassp = body->nd_orig;
- ent->origin = body->nd_orig;
- *idp = ent->mid0 = body->nd_mid;
- body = ent->method = body->nd_head;
- }
- else {
- *klassp = origin;
- ent->origin = origin;
- ent->mid = ent->mid0 = id;
- ent->method = body;
- }
-
- if (noexp) *noexp = ent->noex;
- return body;
-}
-
-static void
-remove_method(klass, mid)
- VALUE klass;
- ID mid;
-{
- NODE *body;
-
- if (klass == rb_cObject) {
- rb_secure(4);
- }
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
- rb_raise(rb_eSecurityError, "Insecure: can't remove method");
- }
- if (OBJ_FROZEN(klass)) rb_error_frozen("class/module");
- if (!st_delete(RCLASS(klass)->m_tbl, &mid, &body) || !body->nd_body) {
- rb_name_error(mid, "method `%s' not defined in %s",
- rb_id2name(mid), rb_class2name(klass));
- }
- rb_clear_cache_by_id(mid);
- if (FL_TEST(klass, FL_SINGLETON)) {
- rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, ID2SYM(mid));
- }
- else {
- rb_funcall(klass, removed, 1, ID2SYM(mid));
- }
-}
-
-void
-rb_remove_method(klass, name)
- VALUE klass;
- const char *name;
-{
- remove_method(klass, rb_intern(name));
-}
-
-static VALUE
-rb_mod_remove_method(mod, name)
- VALUE mod, name;
-{
- remove_method(mod, rb_to_id(name));
- return mod;
-}
-
-void
-rb_disable_super(klass, name)
- VALUE klass;
- const char *name;
-{
- VALUE origin;
- NODE *body;
- ID mid = rb_intern(name);
-
- body = search_method(klass, mid, &origin);
- if (!body || !body->nd_body) {
- print_undef(klass, mid);
- }
- if (origin == klass) {
- body->nd_noex |= NOEX_UNDEF;
- }
- else {
- rb_add_method(klass, mid, 0, NOEX_UNDEF);
- }
-}
-
-void
-rb_enable_super(klass, name)
- VALUE klass;
- const char *name;
-{
- VALUE origin;
- NODE *body;
- ID mid = rb_intern(name);
-
- body = search_method(klass, mid, &origin);
- if (!body) {
- print_undef(klass, mid);
- }
- if (!body->nd_body) {
- remove_method(klass, mid);
- }
- else {
- body->nd_noex &= ~NOEX_UNDEF;
- }
-}
-
-static void
-rb_export_method(klass, name, noex)
- VALUE klass;
- ID name;
- ID noex;
-{
- NODE *body;
- VALUE origin;
-
- if (klass == rb_cObject) {
- rb_secure(4);
- }
- body = search_method(klass, name, &origin);
- if (!body && TYPE(klass) == T_MODULE) {
- body = search_method(rb_cObject, name, &origin);
- }
- if (!body) {
- print_undef(klass, name);
- }
- if (body->nd_noex != noex) {
- if (klass == origin) {
- body->nd_noex = noex;
- }
- else {
- rb_add_method(klass, name, NEW_ZSUPER(), noex);
- }
- }
-}
-
-int
-rb_method_boundp(klass, id, ex)
- VALUE klass;
- ID id;
- int ex;
-{
- struct cache_entry *ent;
- int noex;
-
- /* is it in the method cache? */
- ent = cache + EXPR1(klass, id);
- if (ent->mid == id && ent->klass == klass) {
- if (ex && (ent->noex & NOEX_PRIVATE))
- return Qfalse;
- if (!ent->method) return Qfalse;
- return Qtrue;
- }
- if (rb_get_method_body(&klass, &id, &noex)) {
- if (ex && (noex & NOEX_PRIVATE))
- return Qfalse;
- return Qtrue;
- }
- return Qfalse;
-}
-
-static ID init, alloc, eqq, each, aref, aset, match, to_ary, missing;
-static ID added, singleton_added;
-static ID __id__, __send__;
-
-void
-rb_attr(klass, id, read, write, ex)
- VALUE klass;
- ID id;
- int read, write, ex;
-{
- const char *name;
- char *buf;
- ID attriv;
- int noex;
-
- if (!ex) noex = NOEX_PUBLIC;
- else {
- if (SCOPE_TEST(SCOPE_PRIVATE)) {
- noex = NOEX_PRIVATE;
- rb_warning((scope_vmode == SCOPE_MODFUNC) ?
- "attribute accessor as module_function" :
- "private attribute?");
- }
- else if (SCOPE_TEST(SCOPE_PROTECTED)) {
- noex = NOEX_PROTECTED;
- }
- else {
- noex = NOEX_PUBLIC;
- }
- }
-
- name = rb_id2name(id);
- if (!name) {
- rb_raise(rb_eArgError, "argument needs to be symbol or string");
- }
- buf = ALLOCA_N(char,strlen(name)+2);
- sprintf(buf, "@%s", name);
- attriv = rb_intern(buf);
- if (read) {
- rb_add_method(klass, id, NEW_IVAR(attriv), noex);
- rb_funcall(klass, added, 1, ID2SYM(id));
- }
- if (write) {
- sprintf(buf, "%s=", name);
- id = rb_intern(buf);
- rb_add_method(klass, id, NEW_ATTRSET(attriv), noex);
- rb_funcall(klass, added, 1, ID2SYM(id));
- }
-}
-
-extern int ruby_in_compile;
-
-VALUE ruby_errinfo = Qnil;
-extern NODE *ruby_eval_tree_begin;
-extern NODE *ruby_eval_tree;
-extern int ruby_nerrs;
-
-static VALUE rb_eLocalJumpError;
-static VALUE rb_eSysStackError;
-
-extern VALUE ruby_top_self;
-
-struct FRAME *ruby_frame;
-struct SCOPE *ruby_scope;
-static struct FRAME *top_frame;
-static struct SCOPE *top_scope;
-
-#define PUSH_FRAME() { \
- struct FRAME _frame; \
- _frame.prev = ruby_frame; \
- _frame.tmp = 0; \
- _frame.file = ruby_sourcefile; \
- _frame.line = ruby_sourceline; \
- _frame.iter = ruby_iter->iter; \
- _frame.cbase = ruby_frame->cbase; \
- _frame.argc = 0; \
- _frame.argv = 0; \
- _frame.flags = FRAME_ALLOCA; \
- ruby_frame = &_frame; \
-
-#define POP_FRAME() \
- ruby_sourcefile = _frame.file; \
- ruby_sourceline = _frame.line; \
- ruby_frame = _frame.prev; }
-
-struct BLOCKTAG {
- struct RBasic super;
- long dst;
- long flags;
-};
-
-struct BLOCK {
- NODE *var;
- NODE *body;
- VALUE self;
- struct FRAME frame;
- struct SCOPE *scope;
- struct BLOCKTAG *tag;
- VALUE klass;
- int iter;
- int vmode;
- int flags;
- struct RVarmap *dyna_vars;
- VALUE orig_thread;
- VALUE wrapper;
- struct BLOCK *prev;
-};
-
-#define BLOCK_D_SCOPE 1
-#define BLOCK_DYNAMIC 2
-#define BLOCK_ORPHAN 4
-
-static struct BLOCK *ruby_block;
-
-static struct BLOCKTAG*
-new_blktag()
-{
- NEWOBJ(blktag, struct BLOCKTAG);
- OBJSETUP(blktag, 0, T_BLKTAG);
- blktag->dst = 0;
- blktag->flags = 0;
- return blktag;
-}
-
-#define PUSH_BLOCK(v,b) { \
- struct BLOCK _block; \
- _block.tag = new_blktag(); \
- _block.var = v; \
- _block.body = b; \
- _block.self = self; \
- _block.frame = *ruby_frame; \
- _block.klass = ruby_class; \
- _block.frame.file = ruby_sourcefile;\
- _block.frame.line = ruby_sourceline;\
- _block.scope = ruby_scope; \
- _block.prev = ruby_block; \
- _block.iter = ruby_iter->iter; \
- _block.vmode = scope_vmode; \
- _block.flags = BLOCK_D_SCOPE; \
- _block.dyna_vars = ruby_dyna_vars; \
- _block.wrapper = ruby_wrapper; \
- ruby_block = &_block;
-
-#define POP_BLOCK() \
- if (_block.tag->flags & (BLOCK_DYNAMIC)) \
- _block.tag->flags |= BLOCK_ORPHAN; \
- else if (!(_block.scope->flags & SCOPE_DONT_RECYCLE)) \
- rb_gc_force_recycle((VALUE)_block.tag); \
- ruby_block = _block.prev; \
-}
-
-struct RVarmap *ruby_dyna_vars;
-#define PUSH_VARS() { \
- struct RVarmap * volatile _old; \
- _old = ruby_dyna_vars; \
- ruby_dyna_vars = 0;
-
-#define POP_VARS() \
- if (_old && (ruby_scope->flags & SCOPE_DONT_RECYCLE)) {\
- if (RBASIC(_old)->flags) /* unless it's already recycled */ \
- FL_SET(_old, DVAR_DONT_RECYCLE); \
- }\
- ruby_dyna_vars = _old; \
-}
-
-#define DVAR_DONT_RECYCLE FL_USER2
-
-static struct RVarmap*
-new_dvar(id, value, prev)
- ID id;
- VALUE value;
- struct RVarmap *prev;
-{
- NEWOBJ(vars, struct RVarmap);
- OBJSETUP(vars, 0, T_VARMAP);
- vars->id = id;
- vars->val = value;
- vars->next = prev;
-
- return vars;
-}
-
-VALUE
-rb_dvar_defined(id)
- ID id;
-{
- struct RVarmap *vars = ruby_dyna_vars;
-
- while (vars) {
- if (vars->id == id) return Qtrue;
- vars = vars->next;
- }
- return Qfalse;
-}
-
-VALUE
-rb_dvar_curr(id)
- ID id;
-{
- struct RVarmap *vars = ruby_dyna_vars;
-
- while (vars) {
- if (vars->id == 0) break;
- if (vars->id == id) return Qtrue;
- vars = vars->next;
- }
- return Qfalse;
-}
-
-VALUE
-rb_dvar_ref(id)
- ID id;
-{
- struct RVarmap *vars = ruby_dyna_vars;
-
- while (vars) {
- if (vars->id == id) {
- return vars->val;
- }
- vars = vars->next;
- }
- return Qnil;
-}
-
-void
-rb_dvar_push(id, value)
- ID id;
- VALUE value;
-{
- ruby_dyna_vars = new_dvar(id, value, ruby_dyna_vars);
-}
-
-static void
-dvar_asgn_internal(id, value, curr)
- ID id;
- VALUE value;
- int curr;
-{
- int n = 0;
- struct RVarmap *vars = ruby_dyna_vars;
-
- while (vars) {
- if (curr && vars->id == 0) {
- /* first null is a dvar header */
- n++;
- if (n == 2) break;
- }
- if (vars->id == id) {
- vars->val = value;
- return;
- }
- vars = vars->next;
- }
- if (!ruby_dyna_vars) {
- ruby_dyna_vars = new_dvar(id, value, 0);
- }
- else {
- vars = new_dvar(id, value, ruby_dyna_vars->next);
- ruby_dyna_vars->next = vars;
- }
-}
-
-static inline void
-dvar_asgn(id, value)
- ID id;
- VALUE value;
-{
- dvar_asgn_internal(id, value, 0);
-}
-
-static inline void
-dvar_asgn_curr(id, value)
- ID id;
- VALUE value;
-{
- dvar_asgn_internal(id, value, 1);
-}
-
-VALUE *
-rb_svar(cnt)
- int cnt;
-{
- struct RVarmap *vars = ruby_dyna_vars;
- ID id;
-
- if (!ruby_scope->local_tbl) return NULL;
- if (cnt >= ruby_scope->local_tbl[0]) return NULL;
- id = ruby_scope->local_tbl[cnt+1];
- while (vars) {
- if (vars->id == id) return &vars->val;
- vars = vars->next;
- }
- if (ruby_scope->local_vars == 0) return NULL;
- return &ruby_scope->local_vars[cnt];
-}
-
-struct iter {
- int iter;
- struct iter *prev;
-};
-static struct iter *ruby_iter;
-
-#define ITER_NOT 0
-#define ITER_PRE 1
-#define ITER_CUR 2
-
-#define PUSH_ITER(i) { \
- struct iter _iter; \
- _iter.prev = ruby_iter; \
- _iter.iter = (i); \
- ruby_iter = &_iter; \
-
-#define POP_ITER() \
- ruby_iter = _iter.prev; \
-}
-
-struct tag {
- jmp_buf buf;
- struct FRAME *frame;
- struct iter *iter;
- ID tag;
- VALUE retval;
- struct SCOPE *scope;
- int dst;
- struct tag *prev;
-};
-static struct tag *prot_tag;
-
-#define PUSH_TAG(ptag) { \
- struct tag _tag; \
- _tag.retval = Qnil; \
- _tag.frame = ruby_frame; \
- _tag.iter = ruby_iter; \
- _tag.prev = prot_tag; \
- _tag.scope = ruby_scope; \
- _tag.tag = ptag; \
- _tag.dst = 0; \
- prot_tag = &_tag;
-
-#define PROT_NONE 0
-#define PROT_FUNC -1
-#define PROT_THREAD -2
-
-#define EXEC_TAG() setjmp(prot_tag->buf)
-
-#define JUMP_TAG(st) { \
- ruby_frame = prot_tag->frame; \
- ruby_iter = prot_tag->iter; \
- longjmp(prot_tag->buf,(st)); \
-}
-
-#define POP_TAG() \
- if (_tag.prev) \
- _tag.prev->retval = _tag.retval;\
- prot_tag = _tag.prev; \
-}
-
-#define POP_TMPTAG() \
- prot_tag = _tag.prev; \
-}
-
-#define TAG_RETURN 0x1
-#define TAG_BREAK 0x2
-#define TAG_NEXT 0x3
-#define TAG_RETRY 0x4
-#define TAG_REDO 0x5
-#define TAG_RAISE 0x6
-#define TAG_THROW 0x7
-#define TAG_FATAL 0x8
-#define TAG_MASK 0xf
-
-VALUE ruby_class;
-static VALUE ruby_wrapper; /* security wrapper */
-
-#define PUSH_CLASS() { \
- VALUE _class = ruby_class; \
-
-#define POP_CLASS() ruby_class = _class; }
-
-static NODE *ruby_cref = 0;
-static NODE *top_cref;
-#define PUSH_CREF(c) ruby_cref = rb_node_newnode(NODE_CREF,(c),0,ruby_cref)
-#define POP_CREF() ruby_cref = ruby_cref->nd_next
-
-#define PUSH_SCOPE() { \
- volatile int _vmode = scope_vmode; \
- struct SCOPE * volatile _old; \
- NEWOBJ(_scope, struct SCOPE); \
- OBJSETUP(_scope, 0, T_SCOPE); \
- _scope->local_tbl = 0; \
- _scope->local_vars = 0; \
- _scope->flags = 0; \
- _old = ruby_scope; \
- ruby_scope = _scope; \
- scope_vmode = SCOPE_PUBLIC;
-
-typedef struct thread * rb_thread_t;
-static rb_thread_t curr_thread = 0;
-static rb_thread_t main_thread;
-static void scope_dup _((struct SCOPE *));
-
-#define POP_SCOPE() \
- if (ruby_scope->flags & SCOPE_DONT_RECYCLE) {\
- if (_old) scope_dup(_old); \
- } \
- if (!(ruby_scope->flags & SCOPE_MALLOC)) {\
- ruby_scope->local_vars = 0; \
- ruby_scope->local_tbl = 0; \
- if (!(ruby_scope->flags & SCOPE_DONT_RECYCLE) && \
- ruby_scope != top_scope) { \
- rb_gc_force_recycle((VALUE)ruby_scope);\
- } \
- } \
- ruby_scope->flags |= SCOPE_NOSTACK; \
- ruby_scope = _old; \
- scope_vmode = _vmode; \
-}
-
-static VALUE rb_eval _((VALUE,NODE*));
-static VALUE eval _((VALUE,VALUE,VALUE,char*,int));
-static NODE *compile _((VALUE, char*, int));
-
-static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int));
-static VALUE rb_call _((VALUE,VALUE,ID,int,VALUE*,int));
-static VALUE module_setup _((VALUE,NODE*));
-
-static VALUE massign _((VALUE,NODE*,VALUE,int));
-static void assign _((VALUE,NODE*,VALUE,int));
-
-static VALUE trace_func = 0;
-static int tracing = 0;
-static void call_trace_func _((char*,char*,int,VALUE,ID,VALUE));
-
-static void
-error_pos()
-{
- if (ruby_sourcefile) {
- if (ruby_frame->last_func) {
- fprintf(stderr, "%s:%d:in `%s'", ruby_sourcefile, ruby_sourceline,
- rb_id2name(ruby_frame->last_func));
- }
- else if (ruby_sourceline == 0) {
- fprintf(stderr, "%s", ruby_sourcefile);
- }
- else {
- fprintf(stderr, "%s:%d", ruby_sourcefile, ruby_sourceline);
- }
- }
-}
-
-static VALUE
-get_backtrace(info)
- VALUE info;
-{
- if (NIL_P(info)) return Qnil;
- return rb_funcall(info, rb_intern("backtrace"), 0);
-}
-
-static void
-set_backtrace(info, bt)
- VALUE info, bt;
-{
- rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
-}
-
-static void
-error_print()
-{
- VALUE errat = Qnil; /* OK */
- volatile VALUE eclass;
- char *einfo;
- int elen;
-
- if (NIL_P(ruby_errinfo)) return;
-
- PUSH_TAG(PROT_NONE);
- if (EXEC_TAG() == 0) {
- errat = get_backtrace(ruby_errinfo);
- }
- else {
- errat = Qnil;
- }
- POP_TAG();
- if (NIL_P(errat)){
- if (ruby_sourcefile)
- fprintf(stderr, "%s:%d", ruby_sourcefile, ruby_sourceline);
- else
- fprintf(stderr, "%d", ruby_sourceline);
- }
- else if (RARRAY(errat)->len == 0) {
- error_pos();
- }
- else {
- VALUE mesg = RARRAY(errat)->ptr[0];
-
- if (NIL_P(mesg)) error_pos();
- else {
- fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr);
- }
- }
-
- eclass = CLASS_OF(ruby_errinfo);
- PUSH_TAG(PROT_NONE);
- if (EXEC_TAG() == 0) {
- VALUE e = rb_obj_as_string(ruby_errinfo);
- einfo = RSTRING(e)->ptr;
- elen = RSTRING(e)->len;
- }
- else {
- einfo = "";
- elen = 0;
- }
- POP_TAG();
- if (eclass == rb_eRuntimeError && elen == 0) {
- fprintf(stderr, ": unhandled exception\n");
- }
- else {
- VALUE epath;
-
- epath = rb_class_path(eclass);
- if (elen == 0) {
- fprintf(stderr, ": ");
- fwrite(RSTRING(epath)->ptr, 1, RSTRING(epath)->len, stderr);
- putc('\n', stderr);
- }
- else {
- char *tail = 0;
- int len = elen;
-
- if (RSTRING(epath)->ptr[0] == '#') epath = 0;
- if (tail = strchr(einfo, '\n')) {
- len = tail - einfo;
- tail++; /* skip newline */
- }
- fprintf(stderr, ": ");
- fwrite(einfo, 1, len, stderr);
- if (epath) {
- fprintf(stderr, " (");
- fwrite(RSTRING(epath)->ptr, 1, RSTRING(epath)->len, stderr);
- fprintf(stderr, ")\n");
- }
- if (tail) {
- fwrite(tail, 1, elen-len-1, stderr);
- putc('\n', stderr);
- }
- }
- }
-
- if (!NIL_P(errat)) {
- int i;
- struct RArray *ep = RARRAY(errat);
-
-#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
-#define TRACE_HEAD 8
-#define TRACE_TAIL 5
-
- ep = RARRAY(errat);
- for (i=1; i<ep->len; i++) {
- if (TYPE(ep->ptr[i]) == T_STRING) {
- fprintf(stderr, "\tfrom %s\n", RSTRING(ep->ptr[i])->ptr);
- }
- if (i == TRACE_HEAD && ep->len > TRACE_MAX) {
- fprintf(stderr, "\t ... %ld levels...\n",
- ep->len - TRACE_HEAD - TRACE_TAIL);
- i = ep->len - TRACE_TAIL;
- }
- }
- }
-}
-
-#if !defined(NT) && !defined(__MACOS__)
-extern char **environ;
-#endif
-char **rb_origenviron;
-
-void rb_call_inits _((void));
-void Init_stack _((void*));
-void Init_heap _((void));
-void Init_ext _((void));
-
-void
-ruby_init()
-{
- static int initialized = 0;
- static struct FRAME frame;
- static struct iter iter;
- int state;
-
- if (initialized)
- return;
- initialized = 1;
-
- ruby_frame = top_frame = &frame;
- ruby_iter = &iter;
-
-#ifdef __MACOS__
- rb_origenviron = 0;
-#else
- rb_origenviron = environ;
-#endif
-
- Init_stack(0);
- Init_heap();
- PUSH_SCOPE();
- ruby_scope->local_vars = 0;
- ruby_scope->local_tbl = 0;
- top_scope = ruby_scope;
- /* default visibility is private at toplevel */
- SCOPE_SET(SCOPE_PRIVATE);
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- rb_call_inits();
- ruby_class = rb_cObject;
- ruby_frame->self = ruby_top_self;
- top_cref = rb_node_newnode(NODE_CREF,rb_cObject,0,0);
- ruby_cref = top_cref;
- ruby_frame->cbase = (VALUE)ruby_cref;
- rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self));
-#ifdef __MACOS__
- _macruby_init();
-#endif
- ruby_prog_init();
- }
- POP_TAG();
- if (state) error_print();
- POP_SCOPE();
- ruby_scope = top_scope;
-}
-
-static VALUE
-eval_node(self, node)
- VALUE self;
- NODE *node;
-{
- NODE *beg_tree = ruby_eval_tree_begin;
-
- ruby_eval_tree_begin = 0;
- if (beg_tree) {
- rb_eval(self, beg_tree);
- }
-
- if (!node) return Qnil;
- return rb_eval(self, node);
-}
-
-int ruby_in_eval;
-
-static void rb_thread_cleanup _((void));
-static void rb_thread_wait_other_threads _((void));
-
-static int exit_status;
-
-static int
-error_handle(ex)
- int ex;
-{
- switch (ex & TAG_MASK) {
- case 0:
- ex = 0;
- break;
-
- case TAG_RETURN:
- error_pos();
- fprintf(stderr, ": unexpected return\n");
- ex = 1;
- break;
- case TAG_NEXT:
- error_pos();
- fprintf(stderr, ": unexpected next\n");
- ex = 1;
- break;
- case TAG_BREAK:
- error_pos();
- fprintf(stderr, ": unexpected break\n");
- ex = 1;
- break;
- case TAG_REDO:
- error_pos();
- fprintf(stderr, ": unexpected redo\n");
- ex = 1;
- break;
- case TAG_RETRY:
- error_pos();
- fprintf(stderr, ": retry outside of rescue clause\n");
- ex = 1;
- break;
- case TAG_RAISE:
- case TAG_FATAL:
- if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
- ex = exit_status;
- }
- else {
- error_print();
- ex = 1;
- }
- break;
- default:
- rb_bug("Unknown longjmp status %d", ex);
- break;
- }
- return ex;
-}
-
-void
-ruby_options(argc, argv)
- int argc;
- char **argv;
-{
- int state;
-
- PUSH_TAG(PROT_NONE)
- if ((state = EXEC_TAG()) == 0) {
- ruby_process_options(argc, argv);
- }
- POP_TAG();
- if (state) {
- trace_func = 0;
- tracing = 0;
- exit(error_handle(state));
- }
-}
-
-void rb_exec_end_proc _((void));
-
-void
-ruby_finalize()
-{
- int state;
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- rb_trap_exit();
- rb_exec_end_proc();
- rb_gc_call_finalizer_at_exit();
- }
- POP_TAG();
-}
-
-void
-ruby_stop(ex)
- int ex;
-{
- int state;
-
- PUSH_TAG(PROT_NONE);
- PUSH_ITER(ITER_NOT);
- if ((state = EXEC_TAG()) == 0) {
- rb_thread_cleanup();
- rb_thread_wait_other_threads();
- }
- else if (ex == 0) {
- ex = state;
- }
- POP_ITER();
- POP_TAG();
-
- trace_func = 0;
- tracing = 0;
- ex = error_handle(ex);
- ruby_finalize();
- exit(ex);
-}
-
-void
-ruby_run()
-{
- int state;
- static int ex;
- volatile NODE *tmp;
-
- if (ruby_nerrs > 0) exit(ruby_nerrs);
-
- Init_stack((void*)&tmp);
- PUSH_TAG(PROT_NONE);
- PUSH_ITER(ITER_NOT);
- if ((state = EXEC_TAG()) == 0) {
- eval_node(ruby_top_self, ruby_eval_tree);
- }
- POP_ITER();
- POP_TAG();
-
- if (state && !ex) ex = state;
- ruby_stop(ex);
-}
-
-static void
-compile_error(at)
- const char *at;
-{
- VALUE str;
-
- ruby_nerrs = 0;
- str = rb_str_buf_new2("compile error");
- if (at) {
- rb_str_buf_cat2(str, " in ");
- rb_str_buf_cat2(str, at);
- }
- rb_str_buf_cat(str, "\n", 1);
- if (!NIL_P(ruby_errinfo)) {
- rb_str_append(str, ruby_errinfo);
- }
- rb_exc_raise(rb_exc_new3(rb_eSyntaxError, str));
-}
-
-VALUE
-rb_eval_string(str)
- const char *str;
-{
- VALUE v;
- char *oldsrc = ruby_sourcefile;
-
- ruby_sourcefile = rb_source_filename("(eval)");
- v = eval(ruby_top_self, rb_str_new2(str), Qnil, 0, 0);
- ruby_sourcefile = oldsrc;
-
- return v;
-}
-
-VALUE
-rb_eval_string_protect(str, state)
- const char *str;
- int *state;
-{
- VALUE result; /* OK */
- int status;
-
- PUSH_TAG(PROT_NONE);
- if ((status = EXEC_TAG()) == 0) {
- result = rb_eval_string(str);
- }
- POP_TAG();
- if (state) {
- *state = status;
- }
- if (status != 0) {
- return Qnil;
- }
-
- return result;
-}
-
-VALUE
-rb_eval_string_wrap(str, state)
- const char *str;
- int *state;
-{
- int status;
- VALUE self = ruby_top_self;
- VALUE wrapper = ruby_wrapper;
- VALUE val;
-
- PUSH_CLASS();
- ruby_class = ruby_wrapper = rb_module_new();
- ruby_top_self = rb_obj_clone(ruby_top_self);
- rb_extend_object(ruby_top_self, ruby_wrapper);
- PUSH_FRAME();
- ruby_frame->last_func = 0;
- ruby_frame->last_class = 0;
- ruby_frame->self = self;
- ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_wrapper,0,0);
- PUSH_SCOPE();
-
- val = rb_eval_string_protect(str, &status);
- ruby_top_self = self;
-
- POP_SCOPE();
- POP_FRAME();
- POP_CLASS();
- ruby_wrapper = wrapper;
- if (state) {
- *state = status;
- }
- else if (status) {
- JUMP_TAG(status);
- }
- return val;
-}
-
-static void
-localjump_error(mesg, status)
- const char *mesg;
-{
- VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
- rb_iv_set(exc, "@status", status);
- rb_exc_raise(exc);
-}
-
-static VALUE
-localjump_exitstatus(exc)
- VALUE exc;
-{
- return rb_iv_get(exc, "@status");
-}
-
-static void
-jump_tag_but_local_jump(state)
- int state;
-{
- switch (state) {
- case 0:
- break;
- case TAG_RETURN:
- localjump_error("unexpected return", Qnil);
- break;
- case TAG_NEXT:
- localjump_error("unexpected next", Qnil);
- break;
- case TAG_BREAK:
- localjump_error("unexpected break", Qnil);
- break;
- case TAG_REDO:
- localjump_error("unexpected redo", Qnil);
- break;
- case TAG_RETRY:
- localjump_error("retry outside of rescue clause", Qnil);
- break;
- default:
- JUMP_TAG(state);
- break;
- }
-}
-
-VALUE
-rb_eval_cmd(cmd, arg, tcheck)
- VALUE cmd, arg;
- int tcheck;
-{
- int state;
- VALUE val; /* OK */
- struct SCOPE *saved_scope;
- volatile int safe = ruby_safe_level;
-
- if (TYPE(cmd) != T_STRING) {
- PUSH_ITER(ITER_NOT);
- val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr);
- POP_ITER();
- return val;
- }
-
- saved_scope = ruby_scope;
- ruby_scope = top_scope;
- PUSH_FRAME();
- ruby_frame->last_func = 0;
- ruby_frame->last_class = 0;
- ruby_frame->self = ruby_top_self;
- ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,0,0,0);
- RNODE(ruby_frame->cbase)->nd_clss = ruby_wrapper ? ruby_wrapper : rb_cObject;
-
- if (tcheck && OBJ_TAINTED(cmd)) {
- ruby_safe_level = 4;
- }
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- val = eval(ruby_top_self, cmd, Qnil, 0, 0);
- }
-
- if (ruby_scope->flags & SCOPE_DONT_RECYCLE)
- scope_dup(saved_scope);
- ruby_scope = saved_scope;
- ruby_safe_level = safe;
- POP_TAG();
- POP_FRAME();
-
- jump_tag_but_local_jump(state);
- return val;
-}
-
-static VALUE
-rb_trap_eval(cmd, sig)
- VALUE cmd;
- int sig;
-{
- int state;
- VALUE val; /* OK */
-
- PUSH_TAG(PROT_NONE);
- PUSH_ITER(ITER_NOT);
- if ((state = EXEC_TAG()) == 0) {
- val = rb_eval_cmd(cmd, rb_ary_new3(1, INT2FIX(sig)), 0);
- }
- POP_ITER();
- POP_TAG();
- if (state) {
- rb_trap_immediate = 0;
- JUMP_TAG(state);
- }
- return val;
-}
-
-static VALUE
-superclass(self, node)
- VALUE self;
- NODE *node;
-{
- VALUE val; /* OK */
- int state;
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- val = rb_eval(self, node);
- }
- POP_TAG();
- if (state) {
- superclass_error:
- switch (nd_type(node)) {
- case NODE_COLON2:
- rb_raise(rb_eTypeError, "undefined superclass `%s'",
- rb_id2name(node->nd_mid));
- case NODE_CONST:
- rb_raise(rb_eTypeError, "undefined superclass `%s'",
- rb_id2name(node->nd_vid));
- default:
- break;
- }
- JUMP_TAG(state);
- }
- if (TYPE(val) != T_CLASS) goto superclass_error;
- if (FL_TEST(val, FL_SINGLETON)) {
- rb_raise(rb_eTypeError, "can't make subclass of virtual class");
- }
-
- return val;
-}
-
-#define ruby_cbase (RNODE(ruby_frame->cbase)->nd_clss)
-
-static VALUE
-ev_const_defined(cref, id, self)
- NODE *cref;
- ID id;
- VALUE self;
-{
- NODE *cbase = cref;
-
- while (cbase && cbase->nd_next) {
- struct RClass *klass = RCLASS(cbase->nd_clss);
-
- if (NIL_P(klass)) return rb_const_defined(CLASS_OF(self), id);
- if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, 0)) {
- return Qtrue;
- }
- cbase = cbase->nd_next;
- }
- return rb_const_defined(cref->nd_clss, id);
-}
-
-static VALUE
-ev_const_get(cref, id, self)
- NODE *cref;
- ID id;
- VALUE self;
-{
- NODE *cbase = cref;
- VALUE result;
-
- while (cbase && cbase->nd_next) {
- VALUE klass = cbase->nd_clss;
-
- if (NIL_P(klass)) return rb_const_get(CLASS_OF(self), id);
- if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &result)) {
- return result;
- }
- cbase = cbase->nd_next;
- }
- return rb_const_get(cref->nd_clss, id);
-}
-
-static VALUE
-cvar_cbase()
-{
- NODE *cref = RNODE(ruby_frame->cbase);
-
- while (cref && cref->nd_next && FL_TEST(cref->nd_clss, FL_SINGLETON)) {
- cref = cref->nd_next;
- if (!cref->nd_next) {
- rb_warn("class variable access from toplevel singleton method");
- }
- }
- return cref->nd_clss;
-}
-
-static VALUE
-rb_mod_nesting()
-{
- NODE *cbase = RNODE(ruby_frame->cbase);
- VALUE ary = rb_ary_new();
-
- while (cbase && cbase->nd_next) {
- if (!NIL_P(cbase->nd_clss)) rb_ary_push(ary, cbase->nd_clss);
- cbase = cbase->nd_next;
- }
- return ary;
-}
-
-static VALUE
-rb_mod_s_constants()
-{
- NODE *cbase = RNODE(ruby_frame->cbase);
- void *data = 0;
-
- while (cbase) {
- if (!NIL_P(cbase->nd_clss)) {
- data = rb_mod_const_at(cbase->nd_clss, data);
- }
- cbase = cbase->nd_next;
- }
-
- if (!NIL_P(ruby_cbase)) {
- data = rb_mod_const_of(ruby_cbase, data);
- }
- return rb_const_list(data);
-}
-
-void
-rb_frozen_class_p(klass)
- VALUE klass;
-{
- char *desc = "something(?!)";
-
- if (OBJ_FROZEN(klass)) {
- if (FL_TEST(klass, FL_SINGLETON))
- desc = "object";
- else {
- switch (TYPE(klass)) {
- case T_MODULE:
- case T_ICLASS:
- desc = "module"; break;
- case T_CLASS:
- desc = "class"; break;
- }
- }
- rb_error_frozen(desc);
- }
-}
-
-void
-rb_undef(klass, id)
- VALUE klass;
- ID id;
-{
- VALUE origin;
- NODE *body;
-
- if (ruby_class == rb_cObject) {
- rb_secure(4);
- }
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
- rb_raise(rb_eSecurityError, "Insecure: can't undef");
- if (id == __id__ || id == __send__ || id == init) {
- rb_name_error(id, "undefining `%s' prohibited", rb_id2name(id));
- }
- }
- rb_frozen_class_p(klass);
- if (id == __id__ || id == __send__ || id == init) {
- rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
- }
- body = search_method(ruby_class, id, &origin);
- if (!body || !body->nd_body) {
- char *s0 = " class";
- VALUE c = klass;
-
- if (FL_TEST(c, FL_SINGLETON)) {
- VALUE obj = rb_iv_get(klass, "__attached__");
-
- switch (TYPE(obj)) {
- case T_MODULE:
- case T_CLASS:
- c = obj;
- s0 = "";
- }
- }
- else if (TYPE(c) == T_MODULE) {
- s0 = " module";
- }
- rb_name_error(id, "undefined method `%s' for%s `%s'",
- rb_id2name(id),s0,rb_class2name(c));
- }
- rb_add_method(klass, id, 0, NOEX_PUBLIC);
- if (FL_TEST(klass, FL_SINGLETON)) {
- rb_funcall(rb_iv_get(klass, "__attached__"),
- singleton_undefined, 1, ID2SYM(id));
- }
- else {
- rb_funcall(klass, undefined, 1, ID2SYM(id));
- }
-}
-
-static VALUE
-rb_mod_undef_method(mod, name)
- VALUE mod, name;
-{
- rb_undef(mod, rb_to_id(name));
- return mod;
-}
-
-void
-rb_alias(klass, name, def)
- VALUE klass;
- ID name, def;
-{
- VALUE origin;
- NODE *orig, *body;
-
- rb_frozen_class_p(klass);
- if (name == def) return;
- if (klass == rb_cObject) {
- rb_secure(4);
- }
- orig = search_method(klass, def, &origin);
- if (!orig || !orig->nd_body) {
- if (TYPE(klass) == T_MODULE) {
- orig = search_method(rb_cObject, def, &origin);
- }
- }
- if (!orig || !orig->nd_body) {
- print_undef(klass, def);
- }
- body = orig->nd_body;
- orig->nd_cnt++;
- if (nd_type(body) == NODE_FBODY) { /* was alias */
- def = body->nd_mid;
- origin = body->nd_orig;
- body = body->nd_head;
- }
-
- rb_clear_cache_by_id(name);
- st_insert(RCLASS(klass)->m_tbl, name,
- NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
- if (FL_TEST(klass, FL_SINGLETON)) {
- rb_funcall(rb_iv_get(klass, "__attached__"),
- singleton_added, 1, ID2SYM(name));
- }
- else {
- rb_funcall(klass, added, 1, ID2SYM(name));
- }
-}
-
-static VALUE
-rb_mod_alias_method(mod, newname, oldname)
- VALUE mod, newname, oldname;
-{
- rb_alias(mod, rb_to_id(newname), rb_to_id(oldname));
- return mod;
-}
-
-static NODE*
-copy_node_scope(node, rval)
- NODE *node;
- VALUE rval;
-{
- NODE *copy = rb_node_newnode(NODE_SCOPE,0,rval,node->nd_next);
-
- if (node->nd_tbl) {
- copy->nd_tbl = ALLOC_N(ID, node->nd_tbl[0]+1);
- MEMCPY(copy->nd_tbl, node->nd_tbl, ID, node->nd_tbl[0]+1);
- }
- else {
- copy->nd_tbl = 0;
- }
- return copy;
-}
-
-#ifdef C_ALLOCA
-# define TMP_PROTECT NODE * volatile tmp__protect_tmp=0
-# define TMP_ALLOC(n) \
- (tmp__protect_tmp = rb_node_newnode(NODE_ALLOCA, \
- ALLOC_N(VALUE,n),tmp__protect_tmp,n), \
- (void*)tmp__protect_tmp->nd_head)
-#else
-# define TMP_PROTECT typedef int foobazzz
-# define TMP_ALLOC(n) ALLOCA_N(VALUE,n)
-#endif
-
-#define SETUP_ARGS(anode) {\
- NODE *n = anode;\
- if (!n) {\
- argc = 0;\
- argv = 0;\
- }\
- else if (nd_type(n) == NODE_ARRAY) {\
- argc=n->nd_alen;\
- if (argc > 0) {\
- char *file = ruby_sourcefile;\
- int line = ruby_sourceline;\
- int i;\
- n = anode;\
- argv = TMP_ALLOC(argc);\
- for (i=0;i<argc;i++) {\
- argv[i] = rb_eval(self,n->nd_head);\
- n=n->nd_next;\
- }\
- ruby_sourcefile = file;\
- ruby_sourceline = line;\
- }\
- else {\
- argc = 0;\
- argv = 0;\
- }\
- }\
- else {\
- VALUE args = rb_eval(self,n);\
- char *file = ruby_sourcefile;\
- int line = ruby_sourceline;\
- if (TYPE(args) != T_ARRAY)\
- args = rb_ary_to_ary(args);\
- argc = RARRAY(args)->len;\
- argv = ALLOCA_N(VALUE, argc);\
- MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\
- ruby_sourcefile = file;\
- ruby_sourceline = line;\
- }\
-}
-
-#define BEGIN_CALLARGS {\
- struct BLOCK *tmp_block = ruby_block;\
- if (ruby_iter->iter == ITER_PRE) {\
- ruby_block = ruby_block->prev;\
- }\
- PUSH_ITER(ITER_NOT);
-
-#define END_CALLARGS \
- ruby_block = tmp_block;\
- POP_ITER();\
-}
-
-#define MATCH_DATA *rb_svar(node->nd_cnt)
-
-static char* is_defined _((VALUE, NODE*, char*));
-
-static char*
-arg_defined(self, node, buf, type)
- VALUE self;
- NODE *node;
- char *buf;
- char *type;
-{
- int argc;
- int i;
-
- if (!node) return type; /* no args */
- if (nd_type(node) == NODE_ARRAY) {
- argc=node->nd_alen;
- if (argc > 0) {
- for (i=0;i<argc;i++) {
- if (!is_defined(self, node->nd_head, buf))
- return 0;
- node = node->nd_next;
- }
- }
- }
- else if (!is_defined(self, node, buf)) {
- return 0;
- }
- return type;
-}
-
-static char*
-is_defined(self, node, buf)
- VALUE self;
- NODE *node; /* OK */
- char *buf;
-{
- VALUE val; /* OK */
- int state;
-
- again:
- if (!node) return "expression";
- switch (nd_type(node)) {
- case NODE_SUPER:
- case NODE_ZSUPER:
- if (ruby_frame->last_func == 0) return 0;
- else if (ruby_frame->last_class == 0) return 0;
- else if (rb_method_boundp(RCLASS(ruby_frame->last_class)->super,
- ruby_frame->last_func, 0)) {
- if (nd_type(node) == NODE_SUPER) {
- return arg_defined(self, node->nd_args, buf, "super");
- }
- return "super";
- }
- break;
-
- case NODE_VCALL:
- case NODE_FCALL:
- val = self;
- goto check_bound;
-
- case NODE_CALL:
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- val = rb_eval(self, node->nd_recv);
- }
- POP_TAG();
- if (state) {
- ruby_errinfo = Qnil;
- return 0;
- }
- check_bound:
- {
- int call = nd_type(node)== NODE_CALL;
-
- val = CLASS_OF(val);
- if (call) {
- int noex;
- ID id = node->nd_mid;
-
- if (!rb_get_method_body(&val, &id, &noex))
- break;
- if ((noex & NOEX_PRIVATE))
- break;
- if ((noex & NOEX_PROTECTED) &&
- !rb_obj_is_kind_of(self, rb_class_real(val)))
- break;
- }
- else if (!rb_method_boundp(val, node->nd_mid, call))
- break;
- return arg_defined(self, node->nd_args, buf, "method");
- }
- break;
-
- case NODE_MATCH2:
- case NODE_MATCH3:
- return "method";
-
- case NODE_YIELD:
- if (rb_block_given_p()) {
- return "yield";
- }
- break;
-
- case NODE_SELF:
- return "self";
-
- case NODE_NIL:
- return "nil";
-
- case NODE_TRUE:
- return "true";
-
- case NODE_FALSE:
- return "false";
-
- case NODE_ATTRSET:
- case NODE_OP_ASGN1:
- case NODE_OP_ASGN2:
- case NODE_MASGN:
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_DASGN_CURR:
- case NODE_GASGN:
- case NODE_CDECL:
- case NODE_CVDECL:
- case NODE_CVASGN:
- return "assignment";
-
- case NODE_LVAR:
- return "local-variable";
- case NODE_DVAR:
- return "local-variable(in-block)";
-
- case NODE_GVAR:
- if (rb_gvar_defined(node->nd_entry)) {
- return "global-variable";
- }
- break;
-
- case NODE_IVAR:
- if (rb_ivar_defined(self, node->nd_vid)) {
- return "instance-variable";
- }
- break;
-
- case NODE_CONST:
- if (ev_const_defined(RNODE(ruby_frame->cbase), node->nd_vid, self)) {
- return "constant";
- }
- break;
-
- case NODE_CVAR:
- if (rb_cvar_defined(cvar_cbase(), node->nd_vid)) {
- return "class variable";
- }
- break;
-
- case NODE_COLON2:
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- val = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state) {
- ruby_errinfo = Qnil;
- return 0;
- }
- else {
- switch (TYPE(val)) {
- case T_CLASS:
- case T_MODULE:
- if (rb_const_defined_at(val, node->nd_mid))
- return "constant";
- break;
- default:
- if (rb_method_boundp(CLASS_OF(val), node->nd_mid, 1)) {
- return "method";
- }
- }
- }
- break;
-
- case NODE_NTH_REF:
- if (RTEST(rb_reg_nth_defined(node->nd_nth, MATCH_DATA))) {
- sprintf(buf, "$%d", node->nd_nth);
- return buf;
- }
- break;
-
- case NODE_BACK_REF:
- if (RTEST(rb_reg_nth_defined(0, MATCH_DATA))) {
- sprintf(buf, "$%c", node->nd_nth);
- return buf;
- }
- break;
-
- case NODE_NEWLINE:
- node = node->nd_next;
- goto again;
-
- default:
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- rb_eval(self, node);
- }
- POP_TAG();
- if (!state) {
- return "expression";
- }
- ruby_errinfo = Qnil;
- break;
- }
- return 0;
-}
-
-static int handle_rescue _((VALUE,NODE*));
-
-static void blk_free();
-
-static VALUE
-rb_obj_is_block(block)
- VALUE block;
-{
- if (TYPE(block) == T_DATA && RDATA(block)->dfree == (RUBY_DATA_FUNC)blk_free) {
- return Qtrue;
- }
- return Qfalse;
-}
-
-static VALUE
-rb_obj_is_proc(proc)
- VALUE proc;
-{
- if (rb_obj_is_block(proc) && rb_obj_is_kind_of(proc, rb_cProc)) {
- return Qtrue;
- }
- return Qfalse;
-}
-
-static VALUE
-set_trace_func(obj, trace)
- VALUE obj, trace;
-{
- if (NIL_P(trace)) {
- trace_func = 0;
- return Qnil;
- }
- if (!rb_obj_is_proc(trace)) {
- rb_raise(rb_eTypeError, "trace_func needs to be Proc");
- }
- return trace_func = trace;
-}
-
-static void
-call_trace_func(event, file, line, self, id, klass)
- char *event;
- char *file;
- int line;
- VALUE self;
- ID id;
- VALUE klass; /* OK */
-{
- int state;
- struct FRAME *prev;
- char *file_save = ruby_sourcefile;
- int line_save = ruby_sourceline;
- VALUE srcfile;
-
- if (!trace_func) return;
- if (tracing) return;
-
- tracing = 1;
- prev = ruby_frame;
- PUSH_FRAME();
- *ruby_frame = *prev;
- ruby_frame->prev = prev;
- ruby_frame->iter = 0; /* blocks not available anyway */
-
- if (file) {
- ruby_frame->line = ruby_sourceline = line;
- ruby_frame->file = ruby_sourcefile = file;
- }
- if (klass) {
- if (TYPE(klass) == T_ICLASS) {
- klass = RBASIC(klass)->klass;
- }
- else if (FL_TEST(klass, FL_SINGLETON)) {
- klass = self;
- }
- }
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)");
- proc_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event),
- srcfile,
- INT2FIX(ruby_sourceline),
- id?ID2SYM(id):Qnil,
- self?rb_f_binding(self):Qnil,
- klass),
- Qtrue, Qundef);
- }
- POP_TMPTAG(); /* do not propagate retval */
- POP_FRAME();
-
- tracing = 0;
- ruby_sourceline = line_save;
- ruby_sourcefile = file_save;
- if (state) JUMP_TAG(state);
-}
-
-static VALUE
-svalue_to_avalue(v)
- VALUE v;
-{
- if (NIL_P(v)) return rb_ary_new2(0);
- if (TYPE(v) == T_ARRAY) {
- if (RARRAY(v)->len > 1) return v;
- return rb_ary_new3(1, v);
- }
- else {
- v = rb_ary_to_ary(v);
- }
- return v;
-}
-
-static VALUE
-avalue_to_svalue(v)
- VALUE v;
-{
- if (TYPE(v) != T_ARRAY) {
- v = rb_ary_to_ary(v);
- }
- if (RARRAY(v)->len == 0) {
- return Qnil;
- }
- if (RARRAY(v)->len == 1) {
- return RARRAY(v)->ptr[0];
- }
- return v;
-}
-
-static VALUE
-svalue_to_mvalue(v)
- VALUE v;
-{
- if (NIL_P(v)) return rb_ary_new2(0);
- if (TYPE(v) == T_ARRAY) {
- return v;
- }
- else {
- v = rb_ary_to_ary(v);
- }
- return v;
-}
-
-static VALUE
-mvalue_to_svalue(v)
- VALUE v;
-{
- if (TYPE(v) != T_ARRAY) {
- v = rb_ary_to_ary(v);
- }
- if (RARRAY(v)->len == 0) {
- return Qnil;
- }
- if (RARRAY(v)->len == 1 && TYPE(RARRAY(v)->ptr[0]) != T_ARRAY) {
- return RARRAY(v)->ptr[0];
- }
- return v;
-}
-
-static void return_check _((void));
-#define return_value(v) prot_tag->retval = (v)
-
-static VALUE
-rb_eval(self, n)
- VALUE self;
- NODE *n;
-{
- NODE * volatile node = n;
- int state;
- volatile VALUE result = Qnil;
-
-#define RETURN(v) { result = (v); goto finish; }
-
- again:
- if (!node) RETURN(Qnil);
-
- switch (nd_type(node)) {
- case NODE_BLOCK:
- while (node->nd_next) {
- rb_eval(self, node->nd_head);
- node = node->nd_next;
- }
- node = node->nd_head;
- goto again;
-
- case NODE_POSTEXE:
- rb_f_END();
- nd_set_type(node, NODE_NIL); /* exec just once */
- result = Qnil;
- break;
-
- /* begin .. end without clauses */
- case NODE_BEGIN:
- node = node->nd_body;
- goto again;
-
- /* nodes for speed-up(default match) */
- case NODE_MATCH:
- result = rb_reg_match2(node->nd_lit);
- break;
-
- /* nodes for speed-up(literal match) */
- case NODE_MATCH2:
- result = rb_reg_match(rb_eval(self,node->nd_recv),
- rb_eval(self,node->nd_value));
- break;
-
- /* nodes for speed-up(literal match) */
- case NODE_MATCH3:
- {
- VALUE r = rb_eval(self,node->nd_recv);
- VALUE l = rb_eval(self,node->nd_value);
- if (TYPE(l) == T_STRING) {
- result = rb_reg_match(r, l);
- }
- else {
- result = rb_funcall(l, match, 1, r);
- }
- }
- break;
-
- /* node for speed-up(top-level loop for -n/-p) */
- case NODE_OPT_N:
- PUSH_TAG(PROT_NONE);
- switch (state = EXEC_TAG()) {
- case 0:
- opt_n_next:
- while (!NIL_P(rb_gets())) {
- opt_n_redo:
- rb_eval(self, node->nd_body);
- }
- break;
-
- case TAG_REDO:
- state = 0;
- goto opt_n_redo;
- case TAG_NEXT:
- state = 0;
- goto opt_n_next;
- case TAG_BREAK:
- state = 0;
- default:
- break;
- }
- POP_TAG();
- if (state) JUMP_TAG(state);
- RETURN(Qnil);
-
- case NODE_SELF:
- RETURN(self);
-
- case NODE_NIL:
- RETURN(Qnil);
-
- case NODE_TRUE:
- RETURN(Qtrue);
-
- case NODE_FALSE:
- RETURN(Qfalse);
-
- case NODE_IF:
- ruby_sourceline = nd_line(node);
- if (trace_func) {
- call_trace_func("line", node->nd_file, ruby_sourceline, self,
- ruby_frame->last_func,
- ruby_frame->last_class);
- }
- if (RTEST(rb_eval(self, node->nd_cond))) {
- node = node->nd_body;
- }
- else {
- node = node->nd_else;
- }
- goto again;
-
- case NODE_WHEN:
- while (node) {
- NODE *tag;
-
- if (nd_type(node) != NODE_WHEN) goto again;
- tag = node->nd_head;
- while (tag) {
- if (trace_func) {
- call_trace_func("line", tag->nd_file, nd_line(tag), self,
- ruby_frame->last_func,
- ruby_frame->last_class);
- }
- ruby_sourcefile = tag->nd_file;
- ruby_sourceline = nd_line(tag);
- if (nd_type(tag->nd_head) == NODE_WHEN) {
- VALUE v = rb_eval(self, tag->nd_head->nd_head);
- int i;
-
- if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
- for (i=0; i<RARRAY(v)->len; i++) {
- if (RTEST(RARRAY(v)->ptr[i])) {
- node = node->nd_body;
- goto again;
- }
- }
- tag = tag->nd_next;
- continue;
- }
- if (RTEST(rb_eval(self, tag->nd_head))) {
- node = node->nd_body;
- goto again;
- }
- tag = tag->nd_next;
- }
- node = node->nd_next;
- }
- RETURN(Qnil);
-
- case NODE_CASE:
- {
- VALUE val;
-
- val = rb_eval(self, node->nd_head);
- node = node->nd_body;
- while (node) {
- NODE *tag;
-
- if (nd_type(node) != NODE_WHEN) {
- goto again;
- }
- tag = node->nd_head;
- while (tag) {
- if (trace_func) {
- call_trace_func("line", tag->nd_file, nd_line(tag), self,
- ruby_frame->last_func,
- ruby_frame->last_class);
- }
- ruby_sourcefile = tag->nd_file;
- ruby_sourceline = nd_line(tag);
- if (nd_type(tag->nd_head) == NODE_WHEN) {
- VALUE v = rb_eval(self, tag->nd_head->nd_head);
- int i;
-
- if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
- for (i=0; i<RARRAY(v)->len; i++) {
- if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){
- node = node->nd_body;
- goto again;
- }
- }
- tag = tag->nd_next;
- continue;
- }
- if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) {
- node = node->nd_body;
- goto again;
- }
- tag = tag->nd_next;
- }
- node = node->nd_next;
- }
- }
- RETURN(Qnil);
-
- case NODE_WHILE:
- PUSH_TAG(PROT_NONE);
- result = Qnil;
- switch (state = EXEC_TAG()) {
- case 0:
- ruby_sourceline = nd_line(node);
- if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
- goto while_out;
- do {
- while_redo:
- rb_eval(self, node->nd_body);
- while_next:
- ;
- } while (RTEST(rb_eval(self, node->nd_cond)));
- break;
-
- case TAG_REDO:
- state = 0;
- goto while_redo;
- case TAG_NEXT:
- state = 0;
- goto while_next;
- case TAG_BREAK:
- state = 0;
- result = prot_tag->retval;
- default:
- break;
- }
- while_out:
- POP_TAG();
- if (state) JUMP_TAG(state);
- RETURN(result);
-
- case NODE_UNTIL:
- PUSH_TAG(PROT_NONE);
- result = Qnil;
- switch (state = EXEC_TAG()) {
- case 0:
- ruby_sourceline = nd_line(node);
- if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
- goto until_out;
- do {
- until_redo:
- rb_eval(self, node->nd_body);
- until_next:
- ;
- } while (!RTEST(rb_eval(self, node->nd_cond)));
- break;
-
- case TAG_REDO:
- state = 0;
- goto until_redo;
- case TAG_NEXT:
- state = 0;
- goto until_next;
- case TAG_BREAK:
- state = 0;
- result = prot_tag->retval;
- default:
- break;
- }
- until_out:
- POP_TAG();
- if (state) JUMP_TAG(state);
- RETURN(result);
-
- case NODE_BLOCK_PASS:
- result = block_pass(self, node);
- break;
-
- case NODE_ITER:
- case NODE_FOR:
- {
- iter_retry:
- PUSH_TAG(PROT_FUNC);
- PUSH_BLOCK(node->nd_var, node->nd_body);
-
- state = EXEC_TAG();
- if (state == 0) {
- PUSH_ITER(ITER_PRE);
- if (nd_type(node) == NODE_ITER) {
- result = rb_eval(self, node->nd_iter);
- }
- else {
- VALUE recv;
- char *file = ruby_sourcefile;
- int line = ruby_sourceline;
-
- _block.flags &= ~BLOCK_D_SCOPE;
- BEGIN_CALLARGS;
- recv = rb_eval(self, node->nd_iter);
- END_CALLARGS;
- ruby_sourcefile = file;
- ruby_sourceline = line;
- result = rb_call(CLASS_OF(recv),recv,each,0,0,0);
- }
- POP_ITER();
- }
- else if (_block.tag->dst == state) {
- state &= TAG_MASK;
- if (state == TAG_RETURN || state == TAG_BREAK) {
- result = prot_tag->retval;
- }
- }
- POP_BLOCK();
- POP_TAG();
- switch (state) {
- case 0:
- break;
-
- case TAG_RETRY:
- goto iter_retry;
-
- case TAG_BREAK:
- break;
-
- case TAG_RETURN:
- return_value(result);
- /* fall through */
- default:
- JUMP_TAG(state);
- }
- }
- break;
-
- case NODE_BREAK:
- if (node->nd_stts) {
- return_value(avalue_to_svalue(rb_eval(self, node->nd_stts)));
- }
- else {
- return_value(Qnil);
- }
- JUMP_TAG(TAG_BREAK);
- break;
-
- case NODE_NEXT:
- CHECK_INTS;
- if (node->nd_stts) {
- return_value(avalue_to_svalue(rb_eval(self, node->nd_stts)));
- }
- else {
- return_value(Qnil);
- }
- JUMP_TAG(TAG_NEXT);
- break;
-
- case NODE_REDO:
- CHECK_INTS;
- JUMP_TAG(TAG_REDO);
- break;
-
- case NODE_RETRY:
- CHECK_INTS;
- JUMP_TAG(TAG_RETRY);
- break;
-
- case NODE_RESTARGS:
- case NODE_RESTARY:
- result = rb_ary_to_ary(rb_eval(self, node->nd_head));
- break;
-
- case NODE_REXPAND:
- result = avalue_to_svalue(rb_eval(self, node->nd_head));
- break;
-
- case NODE_YIELD:
- if (node->nd_stts) {
- result = avalue_to_svalue(rb_eval(self, node->nd_stts));
- }
- else {
- result = Qnil;
- }
- result = rb_yield_0(result, 0, 0, 0);
- break;
-
- case NODE_RESCUE:
- retry_entry:
- {
- volatile VALUE e_info = ruby_errinfo;
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state == TAG_RAISE) {
- NODE * volatile resq = node->nd_resq;
-
- ruby_sourceline = nd_line(node);
- while (resq) {
- if (handle_rescue(self, resq)) {
- state = 0;
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, resq->nd_body);
- }
- POP_TAG();
- if (state == TAG_RETRY) {
- state = 0;
- ruby_errinfo = Qnil;
- goto retry_entry;
- }
- if (state != TAG_RAISE) {
- ruby_errinfo = e_info;
- }
- break;
- }
- resq = resq->nd_head; /* next rescue */
- }
- }
- else if (node->nd_else) { /* else clause given */
- if (!state) { /* no exception raised */
- result = rb_eval(self, node->nd_else);
- }
- }
- if (state) JUMP_TAG(state);
- }
- break;
-
- case NODE_ENSURE:
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (node->nd_ensr) {
- VALUE retval = prot_tag->retval; /* save retval */
- VALUE errinfo = ruby_errinfo;
-
- rb_eval(self, node->nd_ensr);
- return_value(retval);
- ruby_errinfo = errinfo;
- }
- if (state) JUMP_TAG(state);
- break;
-
- case NODE_AND:
- result = rb_eval(self, node->nd_1st);
- if (!RTEST(result)) break;
- node = node->nd_2nd;
- goto again;
-
- case NODE_OR:
- result = rb_eval(self, node->nd_1st);
- if (RTEST(result)) break;
- node = node->nd_2nd;
- goto again;
-
- case NODE_NOT:
- if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse;
- else result = Qtrue;
- break;
-
- case NODE_DOT2:
- case NODE_DOT3:
- result = rb_range_new(rb_eval(self, node->nd_beg),
- rb_eval(self, node->nd_end),
- nd_type(node) == NODE_DOT3);
- if (node->nd_state) break;
- if (nd_type(node->nd_beg) == NODE_LIT && FIXNUM_P(node->nd_beg->nd_lit) &&
- nd_type(node->nd_end) == NODE_LIT && FIXNUM_P(node->nd_end->nd_lit))
- {
- nd_set_type(node, NODE_LIT);
- node->nd_lit = result;
- }
- else {
- node->nd_state = 1;
- }
- break;
-
- case NODE_FLIP2: /* like AWK */
- {
- VALUE *flip = rb_svar(node->nd_cnt);
- if (!flip) rb_bug("unexpected local variable");
- if (!RTEST(*flip)) {
- if (RTEST(rb_eval(self, node->nd_beg))) {
- *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue;
- result = Qtrue;
- }
- else {
- result = Qfalse;
- }
- }
- else {
- if (RTEST(rb_eval(self, node->nd_end))) {
- *flip = Qfalse;
- }
- result = Qtrue;
- }
- }
- break;
-
- case NODE_FLIP3: /* like SED */
- {
- VALUE *flip = rb_svar(node->nd_cnt);
- if (!flip) rb_bug("unexpected local variable");
- if (!RTEST(*flip)) {
- result = RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse;
- *flip = result;
- }
- else {
- if (RTEST(rb_eval(self, node->nd_end))) {
- *flip = Qfalse;
- }
- result = Qtrue;
- }
- }
- break;
-
- case NODE_RETURN:
- if (node->nd_stts) {
- return_value(avalue_to_svalue(rb_eval(self, node->nd_stts)));
- }
- else {
- return_value(Qnil);
- }
- return_check();
- JUMP_TAG(TAG_RETURN);
- break;
-
- case NODE_ARGSCAT:
- result = rb_ary_concat(rb_eval(self, node->nd_head),
- rb_eval(self, node->nd_body));
- break;
-
- case NODE_ARGSPUSH:
- result = rb_ary_push(rb_ary_dup(rb_eval(self, node->nd_head)),
- rb_eval(self, node->nd_body));
- break;
-
- case NODE_CALL:
- {
- VALUE recv;
- int argc; VALUE *argv; /* used in SETUP_ARGS */
- TMP_PROTECT;
-
- BEGIN_CALLARGS;
- recv = rb_eval(self, node->nd_recv);
- SETUP_ARGS(node->nd_args);
- END_CALLARGS;
-
- result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
- }
- break;
-
- case NODE_FCALL:
- {
- int argc; VALUE *argv; /* used in SETUP_ARGS */
- TMP_PROTECT;
-
- BEGIN_CALLARGS;
- SETUP_ARGS(node->nd_args);
- END_CALLARGS;
-
- result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
- }
- break;
-
- case NODE_VCALL:
- result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
- break;
-
- case NODE_SUPER:
- case NODE_ZSUPER:
- {
- int argc; VALUE *argv; /* used in SETUP_ARGS */
- TMP_PROTECT;
-
- if (ruby_frame->last_class == 0) {
- rb_name_error(ruby_frame->last_func,
- "superclass method `%s' disabled",
- rb_id2name(ruby_frame->last_func));
- }
- if (nd_type(node) == NODE_ZSUPER) {
- argc = ruby_frame->argc;
- argv = ruby_frame->argv;
- }
- else {
- BEGIN_CALLARGS;
- SETUP_ARGS(node->nd_args);
- END_CALLARGS;
- }
-
- PUSH_ITER(ruby_iter->iter?ITER_PRE:ITER_NOT);
- result = rb_call(RCLASS(ruby_frame->last_class)->super,
- ruby_frame->self, ruby_frame->last_func,
- argc, argv, 3);
- POP_ITER();
- }
- break;
-
- case NODE_SCOPE:
- {
- struct FRAME frame;
- NODE *saved_cref = 0;
-
- frame = *ruby_frame;
- frame.tmp = ruby_frame;
- ruby_frame = &frame;
-
- PUSH_SCOPE();
- PUSH_TAG(PROT_NONE);
- if (node->nd_rval) {
- saved_cref = ruby_cref;
- ruby_cref = (NODE*)node->nd_rval;
- ruby_frame->cbase = node->nd_rval;
- }
- if (node->nd_tbl) {
- VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
- *vars++ = (VALUE)node;
- ruby_scope->local_vars = vars;
- rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]);
- ruby_scope->local_tbl = node->nd_tbl;
- }
- else {
- ruby_scope->local_vars = 0;
- ruby_scope->local_tbl = 0;
- }
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, node->nd_next);
- }
- POP_TAG();
- POP_SCOPE();
- ruby_frame = frame.tmp;
- if (saved_cref)
- ruby_cref = saved_cref;
- if (state) JUMP_TAG(state);
- }
- break;
-
- case NODE_OP_ASGN1:
- {
- int argc; VALUE *argv; /* used in SETUP_ARGS */
- VALUE recv, val;
- NODE *rval;
- TMP_PROTECT;
-
- recv = rb_eval(self, node->nd_recv);
- rval = node->nd_args->nd_head;
- SETUP_ARGS(node->nd_args->nd_next);
- val = rb_funcall2(recv, aref, argc-1, argv);
- switch (node->nd_mid) {
- case 0: /* OR */
- if (RTEST(val)) RETURN(val);
- val = rb_eval(self, rval);
- break;
- case 1: /* AND */
- if (!RTEST(val)) RETURN(val);
- val = rb_eval(self, rval);
- break;
- default:
- val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval));
- }
- argv[argc-1] = val;
- rb_funcall2(recv, aset, argc, argv);
- result = val;
- }
- break;
-
- case NODE_OP_ASGN2:
- {
- ID id = node->nd_next->nd_vid;
- VALUE recv, val;
-
- recv = rb_eval(self, node->nd_recv);
- val = rb_funcall(recv, id, 0);
- switch (node->nd_next->nd_mid) {
- case 0: /* OR */
- if (RTEST(val)) RETURN(val);
- val = rb_eval(self, node->nd_value);
- break;
- case 1: /* AND */
- if (!RTEST(val)) RETURN(val);
- val = rb_eval(self, node->nd_value);
- break;
- default:
- val = rb_funcall(val, node->nd_next->nd_mid, 1,
- rb_eval(self, node->nd_value));
- }
-
- rb_funcall2(recv, node->nd_next->nd_aid, 1, &val);
- result = val;
- }
- break;
-
- case NODE_OP_ASGN_AND:
- result = rb_eval(self, node->nd_head);
- if (!RTEST(result)) break;
- node = node->nd_value;
- goto again;
-
- case NODE_OP_ASGN_OR:
- if ((node->nd_aid && !rb_ivar_defined(self, node->nd_aid)) ||
- !RTEST(result = rb_eval(self, node->nd_head))) {
- node = node->nd_value;
- goto again;
- }
- break;
-
- case NODE_MASGN:
- result = massign(self, node, rb_eval(self, node->nd_value),0);
- break;
-
- case NODE_LASGN:
- if (ruby_scope->local_vars == 0)
- rb_bug("unexpected local variable assignment");
- result = rb_eval(self, node->nd_value);
- ruby_scope->local_vars[node->nd_cnt] = result;
- break;
-
- case NODE_DASGN:
- result = rb_eval(self, node->nd_value);
- dvar_asgn(node->nd_vid, result);
- break;
-
- case NODE_DASGN_CURR:
- result = rb_eval(self, node->nd_value);
- dvar_asgn_curr(node->nd_vid, result);
- break;
-
- case NODE_GASGN:
- result = rb_eval(self, node->nd_value);
- rb_gvar_set(node->nd_entry, result);
- break;
-
- case NODE_IASGN:
- result = rb_eval(self, node->nd_value);
- rb_ivar_set(self, node->nd_vid, result);
- break;
-
- case NODE_CDECL:
- if (NIL_P(ruby_class)) {
- rb_raise(rb_eTypeError, "no class/module to define constant");
- }
- result = rb_eval(self, node->nd_value);
- rb_const_set(ruby_class, node->nd_vid, result);
- break;
-
- case NODE_CVDECL:
- if (NIL_P(ruby_cbase)) {
- rb_raise(rb_eTypeError, "no class/module to define class variable");
- }
- result = rb_eval(self, node->nd_value);
- rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qtrue);
- break;
-
- case NODE_CVASGN:
- result = rb_eval(self, node->nd_value);
- rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qfalse);
- break;
-
- case NODE_LVAR:
- if (ruby_scope->local_vars == 0) {
- rb_bug("unexpected local variable");
- }
- result = ruby_scope->local_vars[node->nd_cnt];
- break;
-
- case NODE_DVAR:
- result = rb_dvar_ref(node->nd_vid);
- break;
-
- case NODE_GVAR:
- result = rb_gvar_get(node->nd_entry);
- break;
-
- case NODE_IVAR:
- result = rb_ivar_get(self, node->nd_vid);
- break;
-
- case NODE_CONST:
- result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid, self);
- break;
-
- case NODE_CVAR:
- result = rb_cvar_get(cvar_cbase(), node->nd_vid);
- break;
-
- case NODE_BLOCK_ARG:
- if (ruby_scope->local_vars == 0)
- rb_bug("unexpected block argument");
- if (rb_block_given_p()) {
- result = rb_f_lambda();
- ruby_scope->local_vars[node->nd_cnt] = result;
- }
- else {
- result = Qnil;
- }
- break;
-
- case NODE_COLON2:
- {
- VALUE klass;
-
- klass = rb_eval(self, node->nd_head);
- switch (TYPE(klass)) {
- case T_CLASS:
- case T_MODULE:
- break;
- default:
- return rb_funcall(klass, node->nd_mid, 0, 0);
- }
- result = rb_const_get(klass, node->nd_mid);
- }
- break;
-
- case NODE_COLON3:
- result = rb_const_get_at(rb_cObject, node->nd_mid);
- break;
-
- case NODE_NTH_REF:
- result = rb_reg_nth_match(node->nd_nth, MATCH_DATA);
- break;
-
- case NODE_BACK_REF:
- switch (node->nd_nth) {
- case '&':
- result = rb_reg_last_match(MATCH_DATA);
- break;
- case '`':
- result = rb_reg_match_pre(MATCH_DATA);
- break;
- case '\'':
- result = rb_reg_match_post(MATCH_DATA);
- break;
- case '+':
- result = rb_reg_match_last(MATCH_DATA);
- break;
- default:
- rb_bug("unexpected back-ref");
- }
- break;
-
- case NODE_HASH:
- {
- NODE *list;
- VALUE hash = rb_hash_new();
- VALUE key, val;
-
- list = node->nd_head;
- while (list) {
- key = rb_eval(self, list->nd_head);
- list = list->nd_next;
- if (list == 0)
- rb_bug("odd number list for Hash");
- val = rb_eval(self, list->nd_head);
- list = list->nd_next;
- rb_hash_aset(hash, key, val);
- }
- result = hash;
- }
- break;
-
- case NODE_ZARRAY: /* zero length list */
- result = rb_ary_new();
- break;
-
- case NODE_ARRAY:
- {
- VALUE ary;
- int i;
-
- i = node->nd_alen;
- ary = rb_ary_new2(i);
- for (i=0;node;node=node->nd_next) {
- RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head);
- RARRAY(ary)->len = i;
- }
-
- result = ary;
- }
- break;
-
- case NODE_STR:
- result = rb_str_new3(node->nd_lit);
- break;
-
- case NODE_DSTR:
- case NODE_DXSTR:
- case NODE_DREGX:
- case NODE_DREGX_ONCE:
- {
- VALUE str, str2;
- NODE *list = node->nd_next;
-
- str = rb_str_new3(node->nd_lit);
- while (list) {
- if (list->nd_head) {
- switch (nd_type(list->nd_head)) {
- case NODE_STR:
- str2 = list->nd_head->nd_lit;
- break;
- case NODE_EVSTR:
- result = ruby_errinfo;
- ruby_errinfo = Qnil;
- ruby_sourceline = nd_line(node);
- ruby_in_eval++;
- list->nd_head = compile(list->nd_head->nd_lit,
- ruby_sourcefile,
- ruby_sourceline);
- ruby_eval_tree = 0;
- ruby_in_eval--;
- if (ruby_nerrs > 0) {
- compile_error("string expansion");
- }
- if (!NIL_P(result)) ruby_errinfo = result;
- /* fall through */
- default:
- str2 = rb_obj_as_string(rb_eval(self, list->nd_head));
- break;
- }
- rb_str_append(str, str2);
- OBJ_INFECT(str, str2);
- }
- list = list->nd_next;
- }
- switch (nd_type(node)) {
- case NODE_DREGX:
- result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
- node->nd_cflag);
- break;
- case NODE_DREGX_ONCE: /* regexp expand once */
- result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
- node->nd_cflag);
- nd_set_type(node, NODE_LIT);
- node->nd_lit = result;
- break;
- case NODE_DXSTR:
- result = rb_funcall(self, '`', 1, str);
- break;
- default:
- result = str;
- break;
- }
- }
- break;
-
- case NODE_XSTR:
- result = rb_funcall(self, '`', 1, node->nd_lit);
- break;
-
- case NODE_LIT:
- result = node->nd_lit;
- break;
-
- case NODE_ATTRSET:
- if (ruby_frame->argc != 1)
- rb_raise(rb_eArgError, "wrong number of arguments(%d for 1)",
- ruby_frame->argc);
- result = rb_ivar_set(self, node->nd_vid, ruby_frame->argv[0]);
- break;
-
- case NODE_DEFN:
- if (node->nd_defn) {
- NODE *body, *defn;
- VALUE origin;
- int noex;
-
- if (NIL_P(ruby_class)) {
- rb_raise(rb_eTypeError, "no class/module to add method");
- }
- if (ruby_class == rb_cClass && node->nd_mid == alloc) {
- rb_raise(rb_eNameError, "redefining Class#allocate will cause infinite loop");
- }
- if (ruby_class == rb_cObject && node->nd_mid == init) {
- rb_warn("redefining Object#initialize may cause infinite loop");
- }
- if (node->nd_mid == __id__ || node->nd_mid == __send__) {
- rb_warn("redefining `%s' may cause serious problem",
- rb_id2name(node->nd_mid));
- }
- rb_frozen_class_p(ruby_class);
- body = search_method(ruby_class, node->nd_mid, &origin);
- if (body){
- if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0) {
- rb_warning("discarding old %s", rb_id2name(node->nd_mid));
- }
- if (node->nd_noex) { /* toplevel */
- /* should upgrade to rb_warn() if no super was called inside? */
- rb_warning("overriding global function `%s'",
- rb_id2name(node->nd_mid));
- }
- }
-
- if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) {
- noex = NOEX_PRIVATE;
- }
- else if (SCOPE_TEST(SCOPE_PROTECTED)) {
- noex = NOEX_PROTECTED;
- }
- else if (ruby_class == rb_cObject) {
- noex = node->nd_noex;
- }
- else {
- noex = NOEX_PUBLIC;
- }
- if (body && origin == ruby_class && body->nd_noex & NOEX_UNDEF) {
- noex |= NOEX_UNDEF;
- }
-
- defn = copy_node_scope(node->nd_defn, ruby_cref);
- rb_add_method(ruby_class, node->nd_mid, defn, noex);
- if (scope_vmode == SCOPE_MODFUNC) {
- rb_add_method(rb_singleton_class(ruby_class),
- node->nd_mid, defn, NOEX_PUBLIC);
- rb_funcall(ruby_class, singleton_added, 1, ID2SYM(node->nd_mid));
- }
- if (FL_TEST(ruby_class, FL_SINGLETON)) {
- rb_funcall(rb_iv_get(ruby_class, "__attached__"),
- singleton_added, 1, ID2SYM(node->nd_mid));
- }
- else {
- rb_funcall(ruby_class, added, 1, ID2SYM(node->nd_mid));
- }
- result = Qnil;
- }
- break;
-
- case NODE_DEFS:
- if (node->nd_defn) {
- VALUE recv = rb_eval(self, node->nd_recv);
- VALUE klass;
- NODE *body = 0, *defn;
-
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(recv)) {
- rb_raise(rb_eSecurityError, "Insecure: can't define singleton method");
- }
- if (FIXNUM_P(recv) || SYMBOL_P(recv)) {
- rb_raise(rb_eTypeError,
- "can't define singleton method \"%s\" for %s",
- rb_id2name(node->nd_mid),
- rb_class2name(CLASS_OF(recv)));
- }
-
- if (OBJ_FROZEN(recv)) rb_error_frozen("object");
- klass = rb_singleton_class(recv);
- if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &body)) {
- if (rb_safe_level() >= 4) {
- rb_raise(rb_eSecurityError, "redefining method prohibited");
- }
- if (RTEST(ruby_verbose)) {
- rb_warning("redefine %s", rb_id2name(node->nd_mid));
- }
- }
- defn = copy_node_scope(node->nd_defn, ruby_cref);
- defn->nd_rval = (VALUE)ruby_cref;
- rb_add_method(klass, node->nd_mid, defn,
- NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
- rb_funcall(recv, singleton_added, 1, ID2SYM(node->nd_mid));
- result = Qnil;
- }
- break;
-
- case NODE_UNDEF:
- if (NIL_P(ruby_class)) {
- rb_raise(rb_eTypeError, "no class to undef method");
- }
- rb_undef(ruby_class, node->nd_mid);
- result = Qnil;
- break;
-
- case NODE_ALIAS:
- if (NIL_P(ruby_class)) {
- rb_raise(rb_eTypeError, "no class to make alias");
- }
- rb_alias(ruby_class, node->nd_new, node->nd_old);
- result = Qnil;
- break;
-
- case NODE_VALIAS:
- rb_alias_variable(node->nd_new, node->nd_old);
- result = Qnil;
- break;
-
- case NODE_CLASS:
- {
- VALUE super, klass, tmp;
-
- if (NIL_P(ruby_class)) {
- rb_raise(rb_eTypeError, "no outer class/module");
- }
- if (node->nd_super) {
- super = superclass(self, node->nd_super);
- }
- else {
- super = 0;
- }
-
- klass = 0;
- if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
- rb_autoload_load(node->nd_cname);
- }
- if (rb_const_defined_at(ruby_class, node->nd_cname)) {
- klass = rb_const_get(ruby_class, node->nd_cname);
- }
- if (klass) {
- if (TYPE(klass) != T_CLASS) {
- rb_raise(rb_eTypeError, "%s is not a class",
- rb_id2name(node->nd_cname));
- }
- if (super) {
- tmp = rb_class_real(RCLASS(klass)->super);
- if (tmp != super) {
- goto override_class;
- }
- }
- if (rb_safe_level() >= 4) {
- rb_raise(rb_eSecurityError, "extending class prohibited");
- }
- }
- else {
- override_class:
- if (!super) super = rb_cObject;
- klass = rb_define_class_id(node->nd_cname, super);
- rb_set_class_path(klass,ruby_class,rb_id2name(node->nd_cname));
- rb_class_inherited(super, klass);
- rb_const_set(ruby_class, node->nd_cname, klass);
- }
- if (ruby_wrapper) {
- rb_extend_object(klass, ruby_wrapper);
- rb_include_module(klass, ruby_wrapper);
- }
-
- result = module_setup(klass, node->nd_body);
- }
- break;
-
- case NODE_MODULE:
- {
- VALUE module;
-
- if (NIL_P(ruby_class)) {
- rb_raise(rb_eTypeError, "no outer class/module");
- }
- module = 0;
- if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
- rb_autoload_load(node->nd_cname);
- }
- if (rb_const_defined_at(ruby_class, node->nd_cname)) {
- module = rb_const_get(ruby_class, node->nd_cname);
- }
- if (module) {
- if (TYPE(module) != T_MODULE) {
- rb_raise(rb_eTypeError, "%s is not a module",
- rb_id2name(node->nd_cname));
- }
- if (rb_safe_level() >= 4) {
- rb_raise(rb_eSecurityError, "extending module prohibited");
- }
- }
- else {
- module = rb_define_module_id(node->nd_cname);
- rb_const_set(ruby_class, node->nd_cname, module);
- rb_set_class_path(module,ruby_class,rb_id2name(node->nd_cname));
- }
- if (ruby_wrapper) {
- rb_extend_object(module, ruby_wrapper);
- rb_include_module(module, ruby_wrapper);
- }
-
- result = module_setup(module, node->nd_body);
- }
- break;
-
- case NODE_SCLASS:
- {
- VALUE klass;
-
- result = rb_eval(self, node->nd_recv);
- if (FIXNUM_P(result) || SYMBOL_P(result)) {
- rb_raise(rb_eTypeError, "no virtual class for %s",
- rb_class2name(CLASS_OF(result)));
- }
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(result))
- rb_raise(rb_eSecurityError, "Insecure: can't extend object");
- klass = rb_singleton_class(result);
-
- if (ruby_wrapper) {
- rb_extend_object(klass, ruby_wrapper);
- rb_include_module(klass, ruby_wrapper);
- }
-
- result = module_setup(klass, node->nd_body);
- }
- break;
-
- case NODE_DEFINED:
- {
- char buf[20];
- char *desc = is_defined(self, node->nd_head, buf);
-
- if (desc) result = rb_str_new2(desc);
- else result = Qnil;
- }
- break;
-
- case NODE_NEWLINE:
- ruby_sourcefile = node->nd_file;
- ruby_sourceline = node->nd_nth;
- if (trace_func) {
- call_trace_func("line", ruby_sourcefile, ruby_sourceline, self,
- ruby_frame->last_func,
- ruby_frame->last_class);
- }
- node = node->nd_next;
- goto again;
-
- default:
- rb_bug("unknown node type %d", nd_type(node));
- }
- finish:
- CHECK_INTS;
- return result;
-}
-
-static VALUE
-module_setup(module, n)
- VALUE module;
- NODE *n;
-{
- NODE * volatile node = n;
- int state;
- struct FRAME frame;
- VALUE result; /* OK */
- char *file = ruby_sourcefile;
- int line = ruby_sourceline;
- TMP_PROTECT;
-
- frame = *ruby_frame;
- frame.tmp = ruby_frame;
- ruby_frame = &frame;
-
- PUSH_CLASS();
- ruby_class = module;
- PUSH_SCOPE();
- PUSH_VARS();
-
- if (node->nd_tbl) {
- VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1);
- *vars++ = (VALUE)node;
- ruby_scope->local_vars = vars;
- rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]);
- ruby_scope->local_tbl = node->nd_tbl;
- }
- else {
- ruby_scope->local_vars = 0;
- ruby_scope->local_tbl = 0;
- }
-
- PUSH_CREF(module);
- ruby_frame->cbase = (VALUE)ruby_cref;
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- if (trace_func) {
- call_trace_func("class", file, line, ruby_class,
- ruby_frame->last_func,
- ruby_frame->last_class);
- }
- result = rb_eval(ruby_class, node->nd_next);
- }
- POP_TAG();
- POP_CREF();
- POP_VARS();
- POP_SCOPE();
- POP_CLASS();
-
- ruby_frame = frame.tmp;
- if (trace_func) {
- call_trace_func("end", file, line, 0,
- ruby_frame->last_func, ruby_frame->last_class);
- }
- if (state) JUMP_TAG(state);
-
- return result;
-}
-
-int
-rb_respond_to(obj, id)
- VALUE obj;
- ID id;
-{
- if (rb_method_boundp(CLASS_OF(obj), id, 0)) {
- return Qtrue;
- }
- return Qfalse;
-}
-
-static VALUE
-rb_obj_respond_to(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
-{
- VALUE mid, priv;
- ID id;
-
- rb_scan_args(argc, argv, "11", &mid, &priv);
- id = rb_to_id(mid);
- if (rb_method_boundp(CLASS_OF(obj), id, !RTEST(priv))) {
- return Qtrue;
- }
- return Qfalse;
-}
-
-static VALUE
-rb_mod_method_defined(mod, mid)
- VALUE mod, mid;
-{
- if (rb_method_boundp(mod, rb_to_id(mid), 1)) {
- return Qtrue;
- }
- return Qfalse;
-}
-
-void
-rb_exit(status)
- int status;
-{
- if (prot_tag) {
- VALUE exit;
-
- exit_status = status;
- exit = rb_exc_new2(rb_eSystemExit, "exit");
- rb_iv_set(exit, "status", INT2NUM(status));
- rb_exc_raise(exit);
- }
- ruby_finalize();
- exit(status);
-}
-
-static VALUE
-rb_f_exit(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
-{
- VALUE status;
- int istatus;
-
- rb_secure(4);
- if (rb_scan_args(argc, argv, "01", &status) == 1) {
- istatus = NUM2INT(status);
- }
- else {
- istatus = 0;
- }
- rb_exit(istatus);
- return Qnil; /* not reached */
-}
-
-static void
-rb_abort()
-{
- if (!NIL_P(ruby_errinfo)) {
- error_print();
- }
- rb_exit(1);
-}
-
-static VALUE
-rb_f_abort(argc, argv)
- int argc;
- VALUE *argv;
-{
- rb_secure(4);
- if (argc == 0) {
- rb_abort();
- }
- else {
- VALUE mesg;
-
- rb_scan_args(argc, argv, "01", &mesg);
- rb_io_puts(argc, argv, rb_stderr);
- rb_exit(1);
- }
- return Qnil; /* not reached */
-}
-
-void
-rb_iter_break()
-{
- JUMP_TAG(TAG_BREAK);
-}
-
-NORETURN(static void rb_longjmp _((int, VALUE)));
-static VALUE make_backtrace _((void));
-
-static void
-rb_longjmp(tag, mesg)
- int tag;
- VALUE mesg;
-{
- VALUE at;
-
- if (NIL_P(mesg)) mesg = ruby_errinfo;
- if (NIL_P(mesg)) {
- mesg = rb_exc_new(rb_eRuntimeError, 0, 0);
- }
-
- if (ruby_sourcefile && !NIL_P(mesg)) {
- at = get_backtrace(mesg);
- if (NIL_P(at)) {
- at = make_backtrace();
- set_backtrace(mesg, at);
- }
- }
- if (!NIL_P(mesg)) {
- ruby_errinfo = mesg;
- }
-
- if (RTEST(ruby_debug) && !NIL_P(ruby_errinfo)
- && !rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
- VALUE e = ruby_errinfo;
-
- StringValue(e);
- fprintf(stderr, "Exception `%s' at %s:%d - %s\n",
- rb_class2name(CLASS_OF(ruby_errinfo)),
- ruby_sourcefile, ruby_sourceline,
- RSTRING(e)->ptr);
- }
-
- rb_trap_restore_mask();
- if (trace_func && tag != TAG_FATAL) {
- call_trace_func("raise", ruby_sourcefile, ruby_sourceline,
- ruby_frame->self,
- ruby_frame->last_func,
- ruby_frame->last_class);
- }
- if (!prot_tag) {
- error_print();
- }
- JUMP_TAG(tag);
-}
-
-void
-rb_exc_raise(mesg)
- VALUE mesg;
-{
- rb_longjmp(TAG_RAISE, mesg);
-}
-
-void
-rb_exc_fatal(mesg)
- VALUE mesg;
-{
- rb_longjmp(TAG_FATAL, mesg);
-}
-
-void
-rb_interrupt()
-{
- rb_raise(rb_eInterrupt, "");
-}
-
-static VALUE
-rb_f_raise(argc, argv)
- int argc;
- VALUE *argv;
-{
- VALUE mesg;
- ID exception;
- int n;
-
- mesg = Qnil;
- switch (argc) {
- case 0:
- mesg = Qnil;
- break;
- case 1:
- if (NIL_P(argv[0])) break;
- if (TYPE(argv[0]) == T_STRING) {
- mesg = rb_exc_new3(rb_eRuntimeError, argv[0]);
- break;
- }
- n = 0;
- goto exception_call;
-
- case 2:
- case 3:
- n = 1;
- exception_call:
- exception = rb_intern("exception");
- if (!rb_respond_to(argv[0], exception)) {
- rb_raise(rb_eTypeError, "exception class/object expected");
- }
- mesg = rb_funcall(argv[0], exception, n, argv[1]);
- break;
- default:
- rb_raise(rb_eArgError, "wrong number of arguments");
- break;
- }
- if (argc > 0) {
- if (!rb_obj_is_kind_of(mesg, rb_eException))
- rb_raise(rb_eTypeError, "exception object expected");
- set_backtrace(mesg, (argc>2)?argv[2]:Qnil);
- }
-
- if (ruby_frame != top_frame) {
- PUSH_FRAME(); /* fake frame */
- *ruby_frame = *_frame.prev->prev;
- rb_longjmp(TAG_RAISE, mesg);
- POP_FRAME();
- }
- rb_longjmp(TAG_RAISE, mesg);
-
- return Qnil; /* not reached */
-}
-
-void
-rb_jump_tag(tag)
- int tag;
-{
- JUMP_TAG(tag);
-}
-
-int
-rb_block_given_p()
-{
- if (ruby_frame->iter && ruby_block)
- return Qtrue;
- return Qfalse;
-}
-
-int
-rb_iterator_p()
-{
- return rb_block_given_p();
-}
-
-static VALUE
-rb_f_block_given_p()
-{
- if (ruby_frame->prev && ruby_frame->prev->iter && ruby_block)
- return Qtrue;
- return Qfalse;
-}
-
-static VALUE
-rb_yield_0(val, self, klass, pcall)
- VALUE val, self, klass; /* OK */
- int pcall;
-{
- NODE *node;
- volatile VALUE result = Qnil;
- volatile VALUE old_cref;
- volatile VALUE old_wrapper;
- struct BLOCK * volatile block;
- struct SCOPE * volatile old_scope;
- struct FRAME frame;
- char *const file = ruby_sourcefile;
- int line = ruby_sourceline;
- int state;
- static unsigned serial = 1;
-
- if (!rb_block_given_p()) {
- localjump_error("no block given", Qnil);
- }
-
- PUSH_VARS();
- PUSH_CLASS();
- block = ruby_block;
- frame = block->frame;
- frame.prev = ruby_frame;
- ruby_frame = &(frame);
- old_cref = (VALUE)ruby_cref;
- ruby_cref = (NODE*)ruby_frame->cbase;
- old_wrapper = ruby_wrapper;
- ruby_wrapper = block->wrapper;
- old_scope = ruby_scope;
- ruby_scope = block->scope;
- ruby_block = block->prev;
- if (block->flags & BLOCK_D_SCOPE) {
- /* put place holder for dynamic (in-block) local variables */
- ruby_dyna_vars = new_dvar(0, 0, block->dyna_vars);
- }
- else {
- /* FOR does not introduce new scope */
- ruby_dyna_vars = block->dyna_vars;
- }
- ruby_class = klass?klass:block->klass;
- if (!klass) self = block->self;
- node = block->body;
-
- if (block->var) {
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- if (block->var == (NODE*)1) {
- if (pcall && RARRAY(val)->len != 0) {
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
- RARRAY(val)->len);
- }
- }
- else if (block->var == (NODE*)2) {
- if (TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) {
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
- RARRAY(val)->len);
- }
- }
- else {
- if (nd_type(block->var) == NODE_MASGN) {
- massign(self, block->var, val, pcall);
- }
- else {
- if (pcall) val = avalue_to_svalue(val);
- assign(self, block->var, val, pcall);
- }
- }
- }
- POP_TAG();
- if (state) goto pop_state;
- }
- else if (pcall) {
- val = avalue_to_svalue(val);
- }
-
- PUSH_ITER(block->iter);
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- redo:
- if (!node) {
- result = Qnil;
- }
- else if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) {
- result = (*node->nd_cfnc)(val, node->nd_tval, self);
- }
- else {
- result = rb_eval(self, node);
- }
- }
- else {
- switch (state) {
- case TAG_REDO:
- state = 0;
- CHECK_INTS;
- goto redo;
- case TAG_NEXT:
- state = 0;
- result = prot_tag->retval;
- break;
- case TAG_BREAK:
- case TAG_RETURN:
- state |= (serial++ << 8);
- state |= 0x10;
- block->tag->dst = state;
- break;
- default:
- break;
- }
- }
- POP_TAG();
- pop_state:
- POP_ITER();
- POP_CLASS();
- if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) &&
- !FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) {
- struct RVarmap *vars = ruby_dyna_vars;
-
- if (ruby_dyna_vars->id == 0) {
- vars = ruby_dyna_vars->next;
- rb_gc_force_recycle((VALUE)ruby_dyna_vars);
- while (vars && vars->id != 0) {
- struct RVarmap *tmp = vars->next;
- rb_gc_force_recycle((VALUE)vars);
- vars = tmp;
- }
- }
- }
- POP_VARS();
- ruby_block = block;
- ruby_frame = ruby_frame->prev;
- ruby_cref = (NODE*)old_cref;
- ruby_wrapper = old_wrapper;
- if (ruby_scope->flags & SCOPE_DONT_RECYCLE)
- scope_dup(old_scope);
- ruby_scope = old_scope;
- ruby_sourcefile = file;
- ruby_sourceline = line;
- if (state) {
- if (!block->tag) {
- switch (state & TAG_MASK) {
- case TAG_BREAK:
- case TAG_RETURN:
- jump_tag_but_local_jump(state & TAG_MASK);
- break;
- }
- }
- JUMP_TAG(state);
- }
- return result;
-}
-
-VALUE
-rb_yield(val)
- VALUE val;
-{
- return rb_yield_0(val, 0, 0, 0);
-}
-
-static VALUE
-rb_f_loop()
-{
- for (;;) {
- rb_yield_0(Qnil, 0, 0, 0);
- CHECK_INTS;
- }
- return Qnil; /* dummy */
-}
-
-static VALUE
-massign(self, node, val, pcall)
- VALUE self;
- NODE *node;
- VALUE val;
- int pcall;
-{
- NODE *list;
- int i = 0, len;
-
- if (!pcall) {
- val = svalue_to_mvalue(val);
- }
- len = RARRAY(val)->len;
- list = node->nd_head;
- for (i=0; list && i<len; i++) {
- assign(self, list->nd_head, RARRAY(val)->ptr[i], pcall);
- list = list->nd_next;
- }
- if (pcall && list) goto arg_error;
- if (node->nd_args) {
- if (node->nd_args == (NODE*)-1) {
- /* no check for mere `*' */
- }
- else if (!list && i<len) {
- assign(self, node->nd_args, rb_ary_new4(len-i, RARRAY(val)->ptr+i), pcall);
- }
- else {
- assign(self, node->nd_args, rb_ary_new2(0), pcall);
- }
- }
- else if (pcall && i < len) {
- goto arg_error;
- }
-
- while (list) {
- i++;
- assign(self, list->nd_head, Qnil, pcall);
- list = list->nd_next;
- }
- return val;
-
- arg_error:
- while (list) {
- i++;
- list = list->nd_next;
- }
- rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", len, i);
-}
-
-static void
-assign(self, lhs, val, pcall)
- VALUE self;
- NODE *lhs;
- VALUE val;
- int pcall;
-{
- if (val == Qundef) val = Qnil;
- switch (nd_type(lhs)) {
- case NODE_GASGN:
- rb_gvar_set(lhs->nd_entry, val);
- break;
-
- case NODE_IASGN:
- rb_ivar_set(self, lhs->nd_vid, val);
- break;
-
- case NODE_LASGN:
- if (ruby_scope->local_vars == 0)
- rb_bug("unexpected local variable assignment");
- ruby_scope->local_vars[lhs->nd_cnt] = val;
- break;
-
- case NODE_DASGN:
- dvar_asgn(lhs->nd_vid, val);
- break;
-
- case NODE_DASGN_CURR:
- dvar_asgn_curr(lhs->nd_vid, val);
- break;
-
- case NODE_CDECL:
- rb_const_set(ruby_class, lhs->nd_vid, val);
- break;
-
- case NODE_CVDECL:
- if (ruby_verbose && FL_TEST(ruby_cbase, FL_SINGLETON)) {
- rb_warn("declaring singleton class variable");
- }
- rb_cvar_set(cvar_cbase(), lhs->nd_vid, val, Qtrue);
- break;
-
- case NODE_CVASGN:
- rb_cvar_set(cvar_cbase(), lhs->nd_vid, val, Qfalse);
- break;
-
- case NODE_MASGN:
- massign(self, lhs, val, pcall);
- break;
-
- case NODE_CALL:
- {
- VALUE recv;
- recv = rb_eval(self, lhs->nd_recv);
- if (!lhs->nd_args) {
- /* attr set */
- rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, 0);
- }
- else {
- /* array set */
- VALUE args;
-
- args = rb_eval(self, lhs->nd_args);
- rb_ary_push(args, val);
- rb_call(CLASS_OF(recv), recv, lhs->nd_mid,
- RARRAY(args)->len, RARRAY(args)->ptr, 0);
- }
- }
- break;
-
- default:
- rb_bug("bug in variable assignment");
- break;
- }
-}
-
-VALUE
-rb_iterate(it_proc, data1, bl_proc, data2)
- VALUE (*it_proc) _((VALUE)), (*bl_proc)(ANYARGS);
- VALUE data1, data2;
-{
- int state;
- volatile VALUE retval = Qnil;
- NODE *node = NEW_IFUNC(bl_proc, data2);
- VALUE self = ruby_top_self;
-
- iter_retry:
- PUSH_ITER(ITER_PRE);
- PUSH_BLOCK(0, node);
- PUSH_TAG(PROT_NONE);
-
- state = EXEC_TAG();
- if (state == 0) {
- retval = (*it_proc)(data1);
- }
- if (ruby_block->tag->dst == state) {
- state &= TAG_MASK;
- if (state == TAG_RETURN || state == TAG_BREAK) {
- retval = prot_tag->retval;
- }
- }
- POP_TAG();
- POP_BLOCK();
- POP_ITER();
-
- switch (state) {
- case 0:
- break;
-
- case TAG_RETRY:
- goto iter_retry;
-
- case TAG_BREAK:
- break;
-
- case TAG_RETURN:
- return_value(retval);
- /* fall through */
- default:
- JUMP_TAG(state);
- }
- return retval;
-}
-
-static int
-handle_rescue(self, node)
- VALUE self;
- NODE *node;
-{
- int argc; VALUE *argv; /* used in SETUP_ARGS */
- TMP_PROTECT;
-
- if (!node->nd_args) {
- return rb_obj_is_kind_of(ruby_errinfo, rb_eStandardError);
- }
-
- BEGIN_CALLARGS;
- SETUP_ARGS(node->nd_args);
- END_CALLARGS;
-
- while (argc--) {
- if (!rb_obj_is_kind_of(argv[0], rb_cModule)) {
- rb_raise(rb_eTypeError, "class or module required for rescue clause");
- }
- if (RTEST(rb_funcall(*argv, eqq, 1, ruby_errinfo))) return 1;
- argv++;
- }
- return 0;
-}
-
-VALUE
-#ifdef HAVE_STDARG_PROTOTYPES
-rb_rescue2(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*r_proc)(ANYARGS), VALUE data2, ...)
-#else
-rb_rescue2(b_proc, data1, r_proc, data2, va_alist)
- VALUE (*b_proc)(ANYARGS), (*r_proc)(ANYARGS);
- VALUE data1, data2;
- va_dcl
-#endif
-{
- int state;
- volatile VALUE result;
- volatile VALUE e_info = ruby_errinfo;
- va_list args;
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- retry_entry:
- result = (*b_proc)(data1);
- }
- else if (state == TAG_RAISE) {
- int handle = Qfalse;
- VALUE eclass;
-
- va_init_list(args, data2);
- while (eclass = va_arg(args, VALUE)) {
- if (rb_obj_is_kind_of(ruby_errinfo, eclass)) {
- handle = Qtrue;
- break;
- }
- }
- va_end(args);
-
- if (handle) {
- if (r_proc) {
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- result = (*r_proc)(data2, ruby_errinfo);
- }
- POP_TAG();
- if (state == TAG_RETRY) {
- state = 0;
- ruby_errinfo = Qnil;
- goto retry_entry;
- }
- }
- else {
- result = Qnil;
- state = 0;
- }
- if (state == 0) {
- ruby_errinfo = e_info;
- }
- }
- }
- POP_TAG();
- if (state) JUMP_TAG(state);
-
- return result;
-}
-
-VALUE
-rb_rescue(b_proc, data1, r_proc, data2)
- VALUE (*b_proc)(), (*r_proc)();
- VALUE data1, data2;
-{
- return rb_rescue2(b_proc, data1, r_proc, data2, rb_eStandardError, 0);
-}
-
-VALUE
-rb_protect(proc, data, state)
- VALUE (*proc) _((VALUE));
- VALUE data;
- int *state;
-{
- VALUE result; /* OK */
- int status;
-
- PUSH_TAG(PROT_NONE);
- if ((status = EXEC_TAG()) == 0) {
- result = (*proc)(data);
- }
- POP_TAG();
- if (state) {
- *state = status;
- }
- if (status != 0) {
- return Qnil;
- }
-
- return result;
-}
-
-VALUE
-rb_ensure(b_proc, data1, e_proc, data2)
- VALUE (*b_proc)();
- VALUE data1;
- VALUE (*e_proc)();
- VALUE data2;
-{
- int state;
- volatile VALUE result = Qnil;
- VALUE retval;
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- result = (*b_proc)(data1);
- }
- POP_TAG();
- retval = prot_tag ? prot_tag->retval : Qnil; /* save retval */
- (*e_proc)(data2);
- if (prot_tag) return_value(retval);
-
- if (state) JUMP_TAG(state);
- return result;
-}
-
-VALUE
-rb_with_disable_interrupt(proc, data)
- VALUE (*proc)();
- VALUE data;
-{
- VALUE result; /* OK */
- int status;
-
- DEFER_INTS;
- PUSH_TAG(PROT_NONE);
- if ((status = EXEC_TAG()) == 0) {
- result = (*proc)(data);
- }
- POP_TAG();
- ALLOW_INTS;
- if (status) JUMP_TAG(status);
-
- return result;
-}
-
-static void
-stack_check()
-{
- static int overflowing = 0;
-
- if (!overflowing && ruby_stack_check()) {
- int state;
- overflowing = 1;
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- rb_raise(rb_eSysStackError, "stack level too deep");
- }
- POP_TAG();
- overflowing = 0;
- JUMP_TAG(state);
- }
-}
-
-static int last_call_status;
-
-#define CSTAT_PRIV 1
-#define CSTAT_PROT 2
-#define CSTAT_VCALL 4
-
-static VALUE
-rb_f_missing(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
-{
- ID id;
- VALUE exc = rb_eNoMethodError;
- volatile VALUE d = 0;
- char *format = 0;
- char *desc = "";
- char *file = ruby_sourcefile;
- int line = ruby_sourceline;
-
- if (argc == 0 || !SYMBOL_P(argv[0])) {
- rb_raise(rb_eArgError, "no id given");
- }
-
- stack_check();
-
- id = SYM2ID(argv[0]);
-
- switch (TYPE(obj)) {
- case T_NIL:
- desc = "nil";
- break;
- case T_TRUE:
- desc = "true";
- break;
- case T_FALSE:
- desc = "false";
- break;
- case T_OBJECT:
- d = rb_any_to_s(obj);
- break;
- default:
- d = rb_inspect(obj);
- break;
- }
- if (d) {
- if (RSTRING(d)->len > 65) {
- d = rb_any_to_s(obj);
- }
- desc = RSTRING(d)->ptr;
- }
-
- if (last_call_status & CSTAT_PRIV) {
- format = "private method `%s' called for %s%s%s";
- }
- if (last_call_status & CSTAT_PROT) {
- format = "protected method `%s' called for %s%s%s";
- }
- else if (last_call_status & CSTAT_VCALL) {
- const char *mname = rb_id2name(id);
-
- if (('a' <= mname[0] && mname[0] <= 'z') || mname[0] == '_') {
- format = "undefined local variable or method `%s' for %s%s%s";
- exc = rb_eNameError;
- }
- }
- if (!format) {
- format = "undefined method `%s' for %s%s%s";
- }
-
- ruby_sourcefile = file;
- ruby_sourceline = line;
- PUSH_FRAME(); /* fake frame */
- *ruby_frame = *_frame.prev->prev;
- {
- char buf[BUFSIZ];
- int noclass = (!d || desc[0]=='#');
-
- snprintf(buf, BUFSIZ, format, rb_id2name(id),
- desc, noclass ? "" : ":",
- noclass ? "" : rb_class2name(CLASS_OF(obj)));
- exc = rb_exc_new2(exc, buf);
- rb_iv_set(exc, "name", argv[0]);
- rb_iv_set(exc, "args", rb_ary_new4(argc-1, argv+1));
- rb_exc_raise(exc);
- }
- POP_FRAME();
-
- return Qnil; /* not reached */
-}
-
-static VALUE
-rb_undefined(obj, id, argc, argv, call_status)
- VALUE obj;
- ID id;
- int argc;
- VALUE*argv;
- int call_status;
-{
- VALUE *nargv;
-
- last_call_status = call_status;
-
- if (id == missing) {
- PUSH_FRAME();
- rb_f_missing(argc, argv, obj);
- POP_FRAME();
- }
-
- nargv = ALLOCA_N(VALUE, argc+1);
- nargv[0] = ID2SYM(id);
- MEMCPY(nargv+1, argv, VALUE, argc);
-
- return rb_funcall2(obj, missing, argc+1, nargv);
-}
-
-static VALUE
-call_cfunc(func, recv, len, argc, argv)
- VALUE (*func)();
- VALUE recv;
- int len, argc;
- VALUE *argv;
-{
- if (len >= 0 && argc != len) {
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
- argc, len);
- }
-
- switch (len) {
- case -2:
- return (*func)(recv, rb_ary_new4(argc, argv));
- break;
- case -1:
- return (*func)(argc, argv, recv);
- break;
- case 0:
- return (*func)(recv);
- break;
- case 1:
- return (*func)(recv, argv[0]);
- break;
- case 2:
- return (*func)(recv, argv[0], argv[1]);
- break;
- case 3:
- return (*func)(recv, argv[0], argv[1], argv[2]);
- break;
- case 4:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3]);
- break;
- case 5:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
- break;
- case 6:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5]);
- break;
- case 7:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6]);
- break;
- case 8:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7]);
- break;
- case 9:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8]);
- break;
- case 10:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9]);
- break;
- case 11:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
- break;
- case 12:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9],
- argv[10], argv[11]);
- break;
- case 13:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
- argv[11], argv[12]);
- break;
- case 14:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
- argv[11], argv[12], argv[13]);
- break;
- case 15:
- return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
- argv[11], argv[12], argv[13], argv[14]);
- break;
- default:
- rb_raise(rb_eArgError, "too many arguments(%d)", len);
- break;
- }
- return Qnil; /* not reached */
-}
-
-static VALUE
-rb_call0(klass, recv, id, argc, argv, body, nosuper)
- VALUE klass, recv;
- ID id;
- int argc; /* OK */
- VALUE *argv; /* OK */
- NODE *body; /* OK */
- int nosuper;
-{
- NODE *b2; /* OK */
- volatile VALUE result = Qnil;
- int itr;
- static int tick;
- TMP_PROTECT;
-
- switch (ruby_iter->iter) {
- case ITER_PRE:
- itr = ITER_CUR;
- break;
- case ITER_CUR:
- default:
- itr = ITER_NOT;
- break;
- }
-
- if ((++tick & 0xff) == 0) {
- CHECK_INTS; /* better than nothing */
- stack_check();
- }
- PUSH_ITER(itr);
- PUSH_FRAME();
-
- ruby_frame->last_func = id;
- ruby_frame->last_class = nosuper?0:klass;
- ruby_frame->self = recv;
- ruby_frame->argc = argc;
- ruby_frame->argv = argv;
-
- switch (nd_type(body)) {
- case NODE_CFUNC:
- {
- int len = body->nd_argc;
-
- if (len < -2) {
- rb_bug("bad argc(%d) specified for `%s(%s)'",
- len, rb_class2name(klass), rb_id2name(id));
- }
- if (trace_func) {
- int state;
- char *file = ruby_frame->prev->file;
- int line = ruby_frame->prev->line;
- if (!file) {
- file = ruby_sourcefile;
- line = ruby_sourceline;
- }
-
- call_trace_func("c-call", 0, 0, recv, id, klass);
- PUSH_TAG(PROT_FUNC);
- if ((state = EXEC_TAG()) == 0) {
- result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
- }
- POP_TAG();
- call_trace_func("c-return", 0, 0, recv, id, klass);
- if (state) JUMP_TAG(state);
- }
- else {
- result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
- }
- }
- break;
-
- /* for attr get/set */
- case NODE_IVAR:
- if (argc != 0) {
- rb_raise(rb_eArgError, "wrong number of arguments(%d for 0)", argc);
- }
- case NODE_ATTRSET:
- /* for re-scoped/renamed method */
- case NODE_ZSUPER:
- result = rb_eval(recv, body);
- break;
-
- case NODE_DMETHOD:
- result = method_call(argc, argv, umethod_bind(body->nd_cval, recv));
- break;
-
- case NODE_BMETHOD:
- result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), Qtrue, recv);
- break;
-
- case NODE_SCOPE:
- {
- int state;
- VALUE *local_vars; /* OK */
- NODE *saved_cref = 0;
-
- PUSH_SCOPE();
-
- if (body->nd_rval) {
- saved_cref = ruby_cref;
- ruby_cref = (NODE*)body->nd_rval;
- ruby_frame->cbase = body->nd_rval;
- }
- if (body->nd_tbl) {
- local_vars = TMP_ALLOC(body->nd_tbl[0]+1);
- *local_vars++ = (VALUE)body;
- rb_mem_clear(local_vars, body->nd_tbl[0]);
- ruby_scope->local_tbl = body->nd_tbl;
- ruby_scope->local_vars = local_vars;
- }
- else {
- local_vars = ruby_scope->local_vars = 0;
- ruby_scope->local_tbl = 0;
- }
- b2 = body = body->nd_next;
-
- PUSH_VARS();
- PUSH_TAG(PROT_FUNC);
-
- if ((state = EXEC_TAG()) == 0) {
- NODE *node = 0;
- int i;
-
- if (nd_type(body) == NODE_ARGS) {
- node = body;
- body = 0;
- }
- else if (nd_type(body) == NODE_BLOCK) {
- node = body->nd_head;
- body = body->nd_next;
- }
- if (node) {
- if (nd_type(node) != NODE_ARGS) {
- rb_bug("no argument-node");
- }
-
- i = node->nd_cnt;
- if (i > argc) {
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
- argc, i);
- }
- if (node->nd_rest == -1) {
- int opt = i;
- NODE *optnode = node->nd_opt;
-
- while (optnode) {
- opt++;
- optnode = optnode->nd_next;
- }
- if (opt < argc) {
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
- argc, opt);
- }
- ruby_frame->argc = opt;
- ruby_frame->argv = local_vars+2;
- }
-
- if (local_vars) {
- if (i > 0) {
- /* +2 for $_ and $~ */
- MEMCPY(local_vars+2, argv, VALUE, i);
- }
- argv += i; argc -= i;
- if (node->nd_opt) {
- NODE *opt = node->nd_opt;
-
- while (opt && argc) {
- assign(recv, opt->nd_head, *argv, 1);
- argv++; argc--;
- opt = opt->nd_next;
- }
- if (opt) {
- ruby_sourcefile = opt->nd_file;
- ruby_sourceline = nd_line(opt);
- rb_eval(recv, opt);
- }
- }
- local_vars = ruby_scope->local_vars;
- if (node->nd_rest >= 0) {
- VALUE v;
-
- if (argc > 0)
- v = rb_ary_new4(argc,argv);
- else
- v = rb_ary_new2(0);
- ruby_scope->local_vars[node->nd_rest] = v;
- }
- }
- }
-
- if (trace_func) {
- call_trace_func("call", b2->nd_file, nd_line(b2),
- recv, id, klass);
- }
- result = rb_eval(recv, body);
- }
- else if (state == TAG_RETURN) {
- result = prot_tag->retval;
- state = 0;
- }
- POP_TAG();
- POP_VARS();
- POP_SCOPE();
- ruby_cref = saved_cref;
- if (trace_func) {
- char *file = ruby_frame->prev->file;
- int line = ruby_frame->prev->line;
- if (!file) {
- file = ruby_sourcefile;
- line = ruby_sourceline;
- }
- call_trace_func("return", file, line, recv, id, klass);
- }
- switch (state) {
- case 0:
- break;
-
- case TAG_RETRY:
- if (rb_block_given_p()) {
- JUMP_TAG(state);
- }
- /* fall through */
- default:
- jump_tag_but_local_jump(state);
- break;
- }
- }
- break;
-
- default:
- rb_bug("unknown node type %d", nd_type(body));
- break;
- }
- POP_FRAME();
- POP_ITER();
- return result;
-}
-
-static VALUE
-rb_call(klass, recv, mid, argc, argv, scope)
- VALUE klass, recv;
- ID mid;
- int argc; /* OK */
- VALUE *argv; /* OK */
- int scope;
-{
- NODE *body; /* OK */
- int noex;
- ID id = mid;
- struct cache_entry *ent;
-
- if (!klass) {
- rb_raise(rb_eNotImpError, "method `%s' called on terminated object (0x%x)",
- rb_id2name(mid), recv);
- }
- /* is it in the method cache? */
- ent = cache + EXPR1(klass, mid);
- if (ent->mid == mid && ent->klass == klass) {
- if (!ent->method)
- return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
- klass = ent->origin;
- id = ent->mid0;
- noex = ent->noex;
- body = ent->method;
- }
- else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
- if (scope == 3) {
- rb_name_error(mid, "super: no superclass method `%s'",
- rb_id2name(mid));
- }
- return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
- }
-
- if (mid != missing) {
- /* receiver specified form for private method */
- if ((noex & NOEX_PRIVATE) && scope == 0)
- return rb_undefined(recv, mid, argc, argv, CSTAT_PRIV);
-
- /* self must be kind of a specified form for private method */
- if ((noex & NOEX_PROTECTED)) {
- VALUE defined_class = klass;
-
- if (TYPE(defined_class) == T_ICLASS) {
- defined_class = RBASIC(defined_class)->klass;
- }
- if (!rb_obj_is_kind_of(ruby_frame->self, rb_class_real(defined_class)))
- return rb_undefined(recv, mid, argc, argv, CSTAT_PROT);
- }
- }
-
- return rb_call0(klass, recv, id, argc, argv, body, noex & NOEX_UNDEF);
-}
-
-VALUE
-rb_apply(recv, mid, args)
- VALUE recv;
- ID mid;
- VALUE args;
-{
- int argc;
- VALUE *argv;
-
- argc = RARRAY(args)->len;
- argv = ALLOCA_N(VALUE, argc);
- MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
-}
-
-static VALUE
-rb_f_send(argc, argv, recv)
- int argc;
- VALUE *argv;
- VALUE recv;
-{
- VALUE vid;
-
- if (argc == 0) rb_raise(rb_eArgError, "no method name given");
-
- vid = *argv++; argc--;
- PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
- vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1);
- POP_ITER();
-
- return vid;
-}
-
-
-#ifdef HAVE_STDARG_PROTOTYPES
-#include <stdarg.h>
-#define va_init_list(a,b) va_start(a,b)
-#else
-#include <varargs.h>
-#define va_init_list(a,b) va_start(a)
-#endif
-
-VALUE
-#ifdef HAVE_STDARG_PROTOTYPES
-rb_funcall(VALUE recv, ID mid, int n, ...)
-#else
-rb_funcall(recv, mid, n, va_alist)
- VALUE recv;
- ID mid;
- int n;
- va_dcl
-#endif
-{
- va_list ar;
- VALUE *argv;
-
- if (n > 0) {
- int i;
-
- argv = ALLOCA_N(VALUE, n);
-
- va_init_list(ar, n);
- for (i=0;i<n;i++) {
- argv[i] = va_arg(ar, VALUE);
- }
- va_end(ar);
- }
- else {
- argv = 0;
- }
-
- return rb_call(CLASS_OF(recv), recv, mid, n, argv, 1);
-}
-
-VALUE
-rb_funcall2(recv, mid, argc, argv)
- VALUE recv;
- ID mid;
- int argc;
- VALUE *argv;
-{
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
-}
-
-VALUE
-rb_funcall3(recv, mid, argc, argv)
- VALUE recv;
- ID mid;
- int argc;
- VALUE *argv;
-{
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 0);
-}
-
-VALUE
-rb_call_super(argc, argv)
- int argc;
- VALUE *argv;
-{
- VALUE result;
-
- if (ruby_frame->last_class == 0) {
- rb_name_error(ruby_frame->last_func, "superclass method `%s' must be enabled by rb_enable_super()",
- rb_id2name(ruby_frame->last_func));
- }
-
- PUSH_ITER(ruby_iter->iter?ITER_PRE:ITER_NOT);
- result = rb_call(RCLASS(ruby_frame->last_class)->super,
- ruby_frame->self, ruby_frame->last_func,
- argc, argv, 3);
- POP_ITER();
-
- return result;
-}
-
-static VALUE
-backtrace(lev)
- int lev;
-{
- struct FRAME *frame = ruby_frame;
- char buf[BUFSIZ];
- VALUE ary;
-
- ary = rb_ary_new();
- if (lev < 0) {
- if (frame->last_func) {
- snprintf(buf, BUFSIZ, "%s:%d:in `%s'",
- ruby_sourcefile, ruby_sourceline,
- rb_id2name(frame->last_func));
- }
- else if (ruby_sourceline == 0) {
- snprintf(buf, BUFSIZ, "%s", ruby_sourcefile);
- }
- else {
- snprintf(buf, BUFSIZ, "%s:%d", ruby_sourcefile, ruby_sourceline);
- }
- rb_ary_push(ary, rb_str_new2(buf));
- }
- else {
- while (lev-- > 0) {
- frame = frame->prev;
- if (!frame) {
- ary = Qnil;
- break;
- }
- }
- }
- while (frame && frame->file) {
- if (frame->prev && frame->prev->last_func) {
- snprintf(buf, BUFSIZ, "%s:%d:in `%s'",
- frame->file, frame->line,
- rb_id2name(frame->prev->last_func));
- }
- else {
- snprintf(buf, BUFSIZ, "%s:%d", frame->file, frame->line);
- }
- rb_ary_push(ary, rb_str_new2(buf));
- frame = frame->prev;
- }
-
- return ary;
-}
-
-static VALUE
-rb_f_caller(argc, argv)
- int argc;
- VALUE *argv;
-{
- VALUE level;
- int lev;
-
- rb_scan_args(argc, argv, "01", &level);
-
- if (NIL_P(level)) lev = 1;
- else lev = NUM2INT(level);
- if (lev < 0) rb_raise(rb_eArgError, "negative level(%d)", lev);
-
- return backtrace(lev);
-}
-
-void
-rb_backtrace()
-{
- int i;
- VALUE ary;
-
- ary = backtrace(-1);
- for (i=0; i<RARRAY(ary)->len; i++) {
- printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr);
- }
-}
-
-static VALUE
-make_backtrace()
-{
- return backtrace(-1);
-}
-
-ID
-rb_frame_last_func()
-{
- return ruby_frame->last_func;
-}
-
-static NODE*
-compile(src, file, line)
- VALUE src;
- char *file;
- int line;
-{
- NODE *node;
-
- ruby_nerrs = 0;
- Check_Type(src, T_STRING);
- node = rb_compile_string(file, src, line);
-
- if (ruby_nerrs == 0) return node;
- return 0;
-}
-
-static VALUE
-eval(self, src, scope, file, line)
- VALUE self, src, scope;
- char *file;
- int line;
-{
- struct BLOCK *data;
- volatile VALUE result = Qnil;
- struct SCOPE * volatile old_scope;
- struct BLOCK * volatile old_block;
- struct RVarmap * volatile old_dyna_vars;
- VALUE volatile old_cref;
- int volatile old_vmode;
- volatile VALUE old_wrapper;
- struct FRAME frame;
- char *filesave = ruby_sourcefile;
- int linesave = ruby_sourceline;
- volatile int iter = ruby_frame->iter;
- int state;
-
- if (!NIL_P(scope)) {
- if (!rb_obj_is_block(scope)) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Binding)",
- rb_class2name(CLASS_OF(scope)));
- }
-
- Data_Get_Struct(scope, struct BLOCK, data);
- /* PUSH BLOCK from data */
- frame = data->frame;
- frame.tmp = ruby_frame; /* gc protection */
- ruby_frame = &(frame);
- old_scope = ruby_scope;
- ruby_scope = data->scope;
- old_block = ruby_block;
- ruby_block = data->prev;
- old_dyna_vars = ruby_dyna_vars;
- ruby_dyna_vars = data->dyna_vars;
- old_vmode = scope_vmode;
- scope_vmode = data->vmode;
- old_cref = (VALUE)ruby_cref;
- ruby_cref = (NODE*)ruby_frame->cbase;
- old_wrapper = ruby_wrapper;
- ruby_wrapper = data->wrapper;
- if ((file == 0 || (line == 1 && strcmp(file, "(eval)") == 0)) &&
- data->body && data->body->nd_file) {
- file = data->body->nd_file;
- line = nd_line(data->body);
- }
-
- self = data->self;
- ruby_frame->iter = data->iter;
- }
- else {
- if (ruby_frame->prev) {
- ruby_frame->iter = ruby_frame->prev->iter;
- }
- }
- if (file == 0) {
- file = ruby_sourcefile;
- line = ruby_sourceline;
- }
- PUSH_CLASS();
- ruby_class = ruby_cbase;
-
- ruby_in_eval++;
- if (TYPE(ruby_class) == T_ICLASS) {
- ruby_class = RBASIC(ruby_class)->klass;
- }
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- NODE *node;
-
- result = ruby_errinfo;
- ruby_errinfo = Qnil;
- node = compile(src, file, line);
- if (ruby_nerrs > 0) {
- compile_error(0);
- }
- if (!NIL_P(result)) ruby_errinfo = result;
- result = eval_node(self, node);
- }
- POP_TAG();
- POP_CLASS();
- ruby_in_eval--;
- if (!NIL_P(scope)) {
- int dont_recycle = ruby_scope->flags & SCOPE_DONT_RECYCLE;
-
- ruby_wrapper = old_wrapper;
- ruby_cref = (NODE*)old_cref;
- ruby_frame = frame.tmp;
- ruby_scope = old_scope;
- ruby_block = old_block;
- ruby_dyna_vars = old_dyna_vars;
- data->vmode = scope_vmode; /* write back visibility mode */
- scope_vmode = old_vmode;
- if (dont_recycle) {
- struct tag *tag;
- struct RVarmap *vars;
-
- scope_dup(ruby_scope);
- for (tag=prot_tag; tag; tag=tag->prev) {
- scope_dup(tag->scope);
- }
- if (ruby_block) {
- struct BLOCK *block = ruby_block;
- while (block) {
- block->tag->flags |= BLOCK_DYNAMIC;
- block = block->prev;
- }
- }
- for (vars = ruby_dyna_vars; vars; vars = vars->next) {
- FL_SET(vars, DVAR_DONT_RECYCLE);
- }
- }
- }
- else {
- ruby_frame->iter = iter;
- }
- ruby_sourcefile = filesave;
- ruby_sourceline = linesave;
- if (state) {
- if (state == TAG_RAISE) {
- VALUE err;
- VALUE errat;
-
- if (strcmp(file, "(eval)") == 0) {
- if (ruby_sourceline > 1) {
- errat = get_backtrace(ruby_errinfo);
- err = RARRAY(errat)->ptr[0];
- rb_str_cat2(err, ": ");
- rb_str_append(err, ruby_errinfo);
- }
- else {
- err = rb_str_dup(ruby_errinfo);
- }
- errat = Qnil;
- rb_exc_raise(rb_funcall(ruby_errinfo, rb_intern("exception"), 1, err));
- }
- rb_exc_raise(ruby_errinfo);
- }
- JUMP_TAG(state);
- }
-
- return result;
-}
-
-static VALUE
-rb_f_eval(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE src, scope, vfile, vline;
- char *file = "(eval)";
- int line = 1;
-
- rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline);
- if (ruby_safe_level >= 4) {
- StringValue(src);
- if (!NIL_P(scope) && !OBJ_TAINTED(scope)) {
- rb_raise(rb_eSecurityError, "Insecure: can't modify trusted binding");
- }
- }
- else {
- SafeStringValue(src);
- }
- if (argc >= 3) {
- file = StringValuePtr(vfile);
- }
- if (argc >= 4) {
- line = NUM2INT(vline);
- }
-
- if (NIL_P(scope) && ruby_frame->prev) {
- struct FRAME *prev;
- VALUE val;
-
- prev = ruby_frame;
- PUSH_FRAME();
- *ruby_frame = *prev->prev;
- ruby_frame->prev = prev;
- val = eval(self, src, scope, file, line);
- POP_FRAME();
-
- return val;
- }
- return eval(self, src, scope, file, line);
-}
-
-/* function to call func under the specified class/module context */
-static VALUE
-exec_under(func, under, args)
- VALUE (*func)();
- VALUE under;
- void *args;
-{
- VALUE val; /* OK */
- int state;
- int mode;
-
- PUSH_CLASS();
- ruby_class = under;
- PUSH_FRAME();
- ruby_frame->self = _frame.prev->self;
- ruby_frame->last_func = _frame.prev->last_func;
- ruby_frame->last_class = _frame.prev->last_class;
- ruby_frame->argc = _frame.prev->argc;
- ruby_frame->argv = _frame.prev->argv;
- if (ruby_cbase != under) {
- ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,ruby_frame->cbase);
- }
- PUSH_CREF(under);
-
- mode = scope_vmode;
- SCOPE_SET(SCOPE_PUBLIC);
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- val = (*func)(args);
- }
- POP_TAG();
- POP_CREF();
- SCOPE_SET(mode);
- POP_FRAME();
- POP_CLASS();
- if (state) JUMP_TAG(state);
-
- return val;
-}
-
-static VALUE
-eval_under_i(args)
- VALUE *args;
-{
- return eval(args[0], args[1], Qnil, (char*)args[2], (int)args[3]);
-}
-
-/* string eval under the class/module context */
-static VALUE
-eval_under(under, self, src, file, line)
- VALUE under, self, src;
- const char *file;
- int line;
-{
- VALUE args[4];
-
- if (ruby_safe_level >= 4) {
- StringValue(src);
- }
- else {
- SafeStringValue(src);
- }
- args[0] = self;
- args[1] = src;
- args[2] = (VALUE)file;
- args[3] = (VALUE)line;
- return exec_under(eval_under_i, under, args);
-}
-
-static VALUE
-yield_under_i(self)
- VALUE self;
-{
- if (ruby_block->flags & BLOCK_DYNAMIC) {
- struct BLOCK * volatile old_block = ruby_block;
- struct BLOCK block;
-
- /* cbase should be pointed from volatile local variable */
- /* to be protected from GC. */
- VALUE result;
- int state;
-
- /* copy the block to avoid modifying global data. */
- block = *ruby_block;
- block.frame.cbase = ruby_frame->cbase;
- ruby_block = &block;
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- result = rb_yield_0(self, self, ruby_class, 0);
- }
- POP_TAG();
- ruby_block = old_block;
- if (state) JUMP_TAG(state);
-
- return result;
- }
- /* static block, no need to restore */
- ruby_block->frame.cbase = ruby_frame->cbase;
- return rb_yield_0(self, self, ruby_class, 0);
-}
-
-/* block eval under the class/module context */
-static VALUE
-yield_under(under, self)
- VALUE under, self;
-{
- return exec_under(yield_under_i, under, self);
-}
-
-static VALUE
-specific_eval(argc, argv, klass, self)
- int argc;
- VALUE *argv;
- VALUE klass, self;
-{
- if (rb_block_given_p()) {
- if (argc > 0) {
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
- }
- return yield_under(klass, self);
- }
- else {
- char *file = "(eval)";
- int line = 1;
-
- if (argc == 0) {
- rb_raise(rb_eArgError, "block not supplied");
- }
- else {
- if (ruby_safe_level >= 4) {
- StringValue(argv[0]);
- }
- else {
- SafeStringValue(argv[0]);
- }
- if (argc > 3) {
- rb_raise(rb_eArgError, "wrong number of arguments: %s(src) or %s{..}",
- rb_id2name(ruby_frame->last_func),
- rb_id2name(ruby_frame->last_func));
- }
- if (argc > 1) {
- file = StringValuePtr(argv[1]);
- }
- if (argc > 2) line = NUM2INT(argv[2]);
- }
- return eval_under(klass, self, argv[0], file, line);
- }
-}
-
-VALUE
-rb_obj_instance_eval(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE klass;
-
- if (rb_special_const_p(self)) {
- klass = Qnil;
- }
- else {
- klass = rb_singleton_class(self);
- }
-
- return specific_eval(argc, argv, klass, self);
-}
-
-VALUE
-rb_mod_module_eval(argc, argv, mod)
- int argc;
- VALUE *argv;
- VALUE mod;
-{
- return specific_eval(argc, argv, mod, mod);
-}
-
-VALUE rb_load_path;
-
-void
-rb_load(fname, wrap)
- VALUE fname;
- int wrap;
-{
- VALUE tmp;
- int state;
- volatile ID last_func;
- volatile VALUE wrapper = 0;
- volatile VALUE self = ruby_top_self;
- NODE *saved_cref = ruby_cref;
- TMP_PROTECT;
-
- if (wrap && ruby_safe_level >= 4) {
- StringValue(fname);
- }
- else {
- SafeStringValue(fname);
- }
- tmp = rb_find_file(fname);
- if (!tmp) {
- rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr);
- }
- fname = tmp;
-
- ruby_errinfo = Qnil; /* ensure */
- PUSH_VARS();
- PUSH_CLASS();
- wrapper = ruby_wrapper;
- ruby_cref = top_cref;
- if (!wrap) {
- rb_secure(4); /* should alter global state */
- ruby_class = rb_cObject;
- ruby_wrapper = 0;
- }
- else {
- /* load in anonymous module as toplevel */
- ruby_class = ruby_wrapper = rb_module_new();
- self = rb_obj_clone(ruby_top_self);
- rb_extend_object(self, ruby_class);
- PUSH_CREF(ruby_wrapper);
- }
- PUSH_FRAME();
- ruby_frame->last_func = 0;
- ruby_frame->last_class = 0;
- ruby_frame->self = self;
- ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_class,0,0);
- PUSH_SCOPE();
- /* default visibility is private at loading toplevel */
- SCOPE_SET(SCOPE_PRIVATE);
- PUSH_TAG(PROT_NONE);
- state = EXEC_TAG();
- last_func = ruby_frame->last_func;
- if (state == 0) {
- NODE *node;
-
- DEFER_INTS;
- ruby_in_eval++;
- rb_load_file(RSTRING(fname)->ptr);
- ruby_in_eval--;
- node = ruby_eval_tree;
- ALLOW_INTS;
- if (ruby_nerrs == 0) {
- eval_node(self, node);
- }
- }
- ruby_frame->last_func = last_func;
- if (ruby_scope->flags == SCOPE_ALLOCA && ruby_class == rb_cObject) {
- if (ruby_scope->local_tbl) /* toplevel was empty */
- free(ruby_scope->local_tbl);
- }
- POP_TAG();
- ruby_cref = saved_cref;
- POP_SCOPE();
- POP_FRAME();
- POP_CLASS();
- POP_VARS();
- ruby_wrapper = wrapper;
- if (ruby_nerrs > 0) {
- ruby_nerrs = 0;
- rb_exc_raise(ruby_errinfo);
- }
- if (state) jump_tag_but_local_jump(state);
- if (!NIL_P(ruby_errinfo)) /* exception during load */
- rb_exc_raise(ruby_errinfo);
-}
-
-void
-rb_load_protect(fname, wrap, state)
- VALUE fname;
- int wrap;
- int *state;
-{
- int status;
-
- PUSH_TAG(PROT_NONE);
- if ((status = EXEC_TAG()) == 0) {
- rb_load(fname, wrap);
- }
- POP_TAG();
- if (state) *state = status;
-}
-
-static VALUE
-rb_f_load(argc, argv)
- int argc;
- VALUE *argv;
-{
- VALUE fname, wrap;
-
- rb_scan_args(argc, argv, "11", &fname, &wrap);
- rb_load(fname, RTEST(wrap));
- return Qtrue;
-}
-
-VALUE ruby_dln_librefs;
-static VALUE rb_features;
-static st_table *loading_tbl;
-
-static int
-rb_feature_p(feature, wait)
- const char *feature;
- int wait;
-{
- VALUE v;
- char *f;
- int i, len = strlen(feature);
-
- for (i = 0; i < RARRAY(rb_features)->len; ++i) {
- v = RARRAY(rb_features)->ptr[i];
- f = StringValuePtr(v);
- if (strcmp(f, feature) == 0) {
- goto load_wait;
- }
- if (strncmp(f, feature, len) == 0) {
- if (strcmp(f+len, ".so") == 0) {
- return Qtrue;
- }
- if (strcmp(f+len, ".rb") == 0) {
- if (wait) goto load_wait;
- return Qtrue;
- }
- }
- }
- return Qfalse;
-
- load_wait:
- if (loading_tbl) {
- char *ext = strrchr(f, '.');
- if (ext && strcmp(ext, ".rb") == 0) {
- rb_thread_t th;
-
- while (st_lookup(loading_tbl, f, &th)) {
- if (th == curr_thread) {
- return Qtrue;
- }
- CHECK_INTS;
- rb_thread_schedule();
- }
- }
- }
- return Qtrue;
-}
-
-static const char *const loadable_ext[] = {
- ".rb", DLEXT,
-#ifdef DLEXT2
- DLEXT2,
-#endif
- 0
-};
-
-int
-rb_provided(feature)
- const char *feature;
-{
- VALUE f = rb_str_new2(feature);
-
- if (strrchr(feature, '.') == 0) {
- if (rb_find_file_ext(&f, loadable_ext) == 0) {
- return rb_feature_p(feature, Qfalse);
- }
- }
- return rb_feature_p(RSTRING(f)->ptr, Qfalse);
-}
-
-static void
-rb_provide_feature(feature)
- VALUE feature;
-{
- rb_ary_push(rb_features, feature);
-}
-
-void
-rb_provide(feature)
- const char *feature;
-{
- rb_provide_feature(rb_str_new2(feature));
-}
-
-VALUE
-rb_f_require(obj, fname)
- VALUE obj, fname;
-{
- VALUE feature, tmp;
- char *ext, *ftptr; /* OK */
- volatile VALUE load;
- int state;
- volatile int safe = ruby_safe_level;
-
- SafeStringValue(fname);
- ext = strrchr(RSTRING(fname)->ptr, '.');
- if (ext) {
- if (strcmp(".rb", ext) == 0) {
- feature = rb_str_dup(fname);
- tmp = rb_find_file(fname);
- if (tmp) {
- fname = tmp;
- goto load_rb;
- }
- }
- else if (strcmp(".so", ext) == 0 || strcmp(".o", ext) == 0) {
- fname = rb_str_new(RSTRING(fname)->ptr, ext-RSTRING(fname)->ptr);
-#ifdef DLEXT2
- tmp = fname;
- if (rb_find_file_ext(&tmp, loadable_ext+1)) {
- feature = tmp;
- fname = rb_find_file(tmp);
- goto load_dyna;
- }
-#else
- feature = tmp = rb_str_dup(fname);
- rb_str_cat2(tmp, DLEXT);
- tmp = rb_find_file(tmp);
- if (tmp) {
- fname = tmp;
- goto load_dyna;
- }
-#endif
- }
- else if (strcmp(DLEXT, ext) == 0) {
- tmp = rb_find_file(fname);
- if (tmp) {
- feature = fname;
- fname = tmp;
- goto load_dyna;
- }
- }
-#ifdef DLEXT2
- else if (strcmp(DLEXT2, ext) == 0) {
- tmp = rb_find_file(fname);
- if (tmp) {
- feature = fname;
- fname = tmp;
- goto load_dyna;
- }
- }
-#endif
- }
- tmp = fname;
- switch (rb_find_file_ext(&tmp, loadable_ext)) {
- case 0:
- break;
-
- case 1:
- feature = fname = tmp;
- goto load_rb;
-
- default:
- feature = tmp;
- fname = rb_find_file(tmp);
- goto load_dyna;
- }
- if (rb_feature_p(RSTRING(fname)->ptr, Qfalse))
- return Qfalse;
- rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr);
-
- load_dyna:
- if (rb_feature_p(RSTRING(feature)->ptr, Qfalse))
- return Qfalse;
- rb_provide_feature(feature);
- {
- int volatile old_vmode = scope_vmode;
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- void *handle;
-
- SCOPE_SET(SCOPE_PUBLIC);
- handle = dln_load(RSTRING(fname)->ptr);
- rb_ary_push(ruby_dln_librefs, INT2NUM((long)handle));
- }
- POP_TAG();
- SCOPE_SET(old_vmode);
- }
- if (state) JUMP_TAG(state);
-
- return Qtrue;
-
- load_rb:
- if (rb_feature_p(RSTRING(feature)->ptr, Qtrue))
- return Qfalse;
- ruby_safe_level = 0;
- rb_provide_feature(feature);
- /* loading ruby library should be serialized. */
- if (!loading_tbl) {
- loading_tbl = st_init_strtable();
- }
- /* partial state */
- ftptr = ruby_strdup(RSTRING(feature)->ptr);
- st_insert(loading_tbl, ftptr, curr_thread);
-
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- rb_load(fname, 0);
- }
- POP_TAG();
- st_delete(loading_tbl, &ftptr, 0); /* loading done */
- free(ftptr);
- ruby_safe_level = safe;
- if (state) JUMP_TAG(state);
-
- return Qtrue;
-}
-
-VALUE
-rb_require(fname)
- const char *fname;
-{
- return rb_f_require(Qnil, rb_str_new2(fname));
-}
-
-static void
-secure_visibility(self)
- VALUE self;
-{
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) {
- rb_raise(rb_eSecurityError, "Insecure: can't change method visibility");
- }
-}
-
-static void
-set_method_visibility(self, argc, argv, ex)
- VALUE self;
- int argc;
- VALUE *argv;
- ID ex;
-{
- int i;
-
- secure_visibility(self);
- for (i=0; i<argc; i++) {
- rb_export_method(self, rb_to_id(argv[i]), ex);
- }
-}
-
-static VALUE
-rb_mod_public(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
-{
- secure_visibility(module);
- if (argc == 0) {
- SCOPE_SET(SCOPE_PUBLIC);
- }
- else {
- set_method_visibility(module, argc, argv, NOEX_PUBLIC);
- }
- return module;
-}
-
-static VALUE
-rb_mod_protected(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
-{
- secure_visibility(module);
- if (argc == 0) {
- SCOPE_SET(SCOPE_PROTECTED);
- }
- else {
- set_method_visibility(module, argc, argv, NOEX_PROTECTED);
- }
- return module;
-}
-
-static VALUE
-rb_mod_private(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
-{
- secure_visibility(module);
- if (argc == 0) {
- SCOPE_SET(SCOPE_PRIVATE);
- }
- else {
- set_method_visibility(module, argc, argv, NOEX_PRIVATE);
- }
- return module;
-}
-
-static VALUE
-rb_mod_public_method(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
-{
- set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
- return obj;
-}
-
-static VALUE
-rb_mod_private_method(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
-{
- set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
- return obj;
-}
-
-static VALUE
-top_public(argc, argv)
- int argc;
- VALUE *argv;
-{
- return rb_mod_public(argc, argv, rb_cObject);
-}
-
-static VALUE
-top_private(argc, argv)
- int argc;
- VALUE *argv;
-{
- return rb_mod_private(argc, argv, rb_cObject);
-}
-
-static VALUE
-rb_mod_modfunc(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
-{
- int i;
- ID id;
- NODE *body;
-
- if (TYPE(module) != T_MODULE) {
- rb_raise(rb_eTypeError, "module_function must be called for modules");
- }
-
- secure_visibility(module);
- if (argc == 0) {
- SCOPE_SET(SCOPE_MODFUNC);
- return module;
- }
-
- set_method_visibility(module, argc, argv, NOEX_PRIVATE);
- for (i=0; i<argc; i++) {
- VALUE m = module;
-
- id = rb_to_id(argv[i]);
- for (;;) {
- body = search_method(m, id, &m);
- if (body == 0 || body->nd_body == 0) {
- rb_bug("undefined method `%s'; can't happen", rb_id2name(id));
- }
- if (nd_type(body->nd_body) != NODE_ZSUPER) {
- break; /* normal case: need not to follow 'super' link */
- }
- m = RCLASS(m)->super;
- }
- rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC);
- rb_funcall(module, singleton_added, 1, ID2SYM(id));
- }
- return module;
-}
-
-static VALUE
-rb_mod_append_features(module, include)
- VALUE module, include;
-{
- switch (TYPE(include)) {
- case T_CLASS:
- case T_MODULE:
- break;
- default:
- Check_Type(include, T_CLASS);
- break;
- }
- rb_include_module(include, module);
-
- return module;
-}
-
-static VALUE
-rb_mod_include(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
-{
- while (argc--) {
- VALUE m = argv[argc];
-
- Check_Type(m, T_MODULE);
- rb_funcall(m, rb_intern("append_features"), 1, module);
- rb_funcall(m, rb_intern("included"), 1, module);
- }
- return module;
-}
-
-void
-rb_obj_call_init(obj, argc, argv)
- VALUE obj;
- int argc;
- VALUE *argv;
-{
- PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
- rb_funcall2(obj, init, argc, argv);
- POP_ITER();
-}
-
-static VALUE
-top_include(argc, argv)
- int argc;
- VALUE *argv;
-{
- rb_secure(4);
- return rb_mod_include(argc, argv, rb_cObject);
-}
-
-void
-rb_extend_object(obj, module)
- VALUE obj, module;
-{
- rb_include_module(rb_singleton_class(obj), module);
-}
-
-static VALUE
-rb_mod_extend_object(mod, obj)
- VALUE mod, obj;
-{
- rb_extend_object(obj, mod);
- return obj;
-}
-
-static VALUE
-rb_obj_extend(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
-{
- int i;
-
- if (argc == 0) {
- rb_raise(rb_eArgError, "wrong number of arguments(0 for 1)");
- }
- for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
- while (argc--) {
- rb_funcall(argv[argc], rb_intern("extend_object"), 1, obj);
- }
- return obj;
-}
-
-VALUE rb_f_trace_var();
-VALUE rb_f_untrace_var();
-
-static void
-errinfo_setter(val, id, var)
- VALUE val;
- ID id;
- VALUE *var;
-{
- if (!NIL_P(val) && !rb_obj_is_kind_of(val, rb_eException)) {
- rb_raise(rb_eTypeError, "assigning non-exception to $!");
- }
- *var = val;
-}
-
-static VALUE
-errat_getter(id)
- ID id;
-{
- return get_backtrace(ruby_errinfo);
-}
-
-static void
-errat_setter(val, id, var)
- VALUE val;
- ID id;
- VALUE *var;
-{
- if (NIL_P(ruby_errinfo)) {
- rb_raise(rb_eArgError, "$! not set");
- }
- set_backtrace(ruby_errinfo, val);
-}
-
-static VALUE
-rb_f_local_variables()
-{
- ID *tbl;
- int n, i;
- VALUE ary = rb_ary_new();
- struct RVarmap *vars;
-
- tbl = ruby_scope->local_tbl;
- if (tbl) {
- n = *tbl++;
- for (i=2; i<n; i++) { /* skip first 2 ($_ and $~) */
- if (!rb_is_local_id(tbl[i])) continue; /* skip flip states */
- rb_ary_push(ary, rb_str_new2(rb_id2name(tbl[i])));
- }
- }
-
- vars = ruby_dyna_vars;
- while (vars) {
- if (vars->id) {
- rb_ary_push(ary, rb_str_new2(rb_id2name(vars->id)));
- }
- vars = vars->next;
- }
-
- return ary;
-}
-
-static VALUE rb_f_catch _((VALUE,VALUE));
-NORETURN(static VALUE rb_f_throw _((int,VALUE*)));
-
-struct end_proc_data {
- void (*func)();
- VALUE data;
- struct end_proc_data *next;
-};
-
-static struct end_proc_data *end_procs, *ephemeral_end_procs;
-
-void
-rb_set_end_proc(func, data)
- void (*func) _((VALUE));
- VALUE data;
-{
- struct end_proc_data *link = ALLOC(struct end_proc_data);
- struct end_proc_data **list;
-
- if (ruby_wrapper) list = &ephemeral_end_procs;
- else list = &end_procs;
- link->next = *list;
- link->func = func;
- link->data = data;
- *list = link;
-}
-
-void
-rb_mark_end_proc()
-{
- struct end_proc_data *link;
-
- link = end_procs;
- while (link) {
- rb_gc_mark(link->data);
- link = link->next;
- }
- link = ephemeral_end_procs;
- while (link) {
- rb_gc_mark(link->data);
- link = link->next;
- }
-}
-
-static void call_end_proc _((VALUE data));
-
-static void
-call_end_proc(data)
- VALUE data;
-{
- PUSH_ITER(ITER_NOT);
- PUSH_FRAME();
- ruby_frame->self = ruby_frame->prev->self;
- ruby_frame->last_func = 0;
- ruby_frame->last_class = 0;
- proc_invoke(data, rb_ary_new2(0), Qfalse, Qundef);
- POP_FRAME();
- POP_ITER();
-}
-
-static void
-rb_f_END()
-{
- PUSH_FRAME();
- ruby_frame->argc = 0;
- rb_set_end_proc(call_end_proc, rb_f_lambda());
- POP_FRAME();
-}
-
-static VALUE
-rb_f_at_exit()
-{
- VALUE proc;
-
- proc = rb_f_lambda();
-
- rb_set_end_proc(call_end_proc, proc);
- return proc;
-}
-
-void
-rb_exec_end_proc()
-{
- struct end_proc_data *link, *save;
- int status;
-
- save = link = end_procs;
- while (link) {
- rb_protect((VALUE(*)_((VALUE)))link->func, link->data, &status);
- if (status) {
- error_handle(status);
- }
- link = link->next;
- }
- link = end_procs;
- while (link != save) {
- rb_protect((VALUE(*)_((VALUE)))link->func, link->data, &status);
- if (status) {
- error_handle(status);
- }
- link = link->next;
- }
- while (ephemeral_end_procs) {
- link = ephemeral_end_procs;
- ephemeral_end_procs = link->next;
- rb_protect((VALUE(*)_((VALUE)))link->func, link->data, &status);
- if (status) {
- error_handle(status);
- }
- free(link);
- }
-}
-
-void
-Init_eval()
-{
- init = rb_intern("initialize");
- alloc = rb_intern("allocate");
- eqq = rb_intern("===");
- each = rb_intern("each");
-
- aref = rb_intern("[]");
- aset = rb_intern("[]=");
- match = rb_intern("=~");
- to_ary = rb_intern("to_ary");
- missing = rb_intern("method_missing");
- added = rb_intern("method_added");
- singleton_added = rb_intern("singleton_method_added");
- removed = rb_intern("method_removed");
- singleton_removed = rb_intern("singleton_method_removed");
- undefined = rb_intern("method_undefined");
- singleton_undefined = rb_intern("singleton_method_undefined");
-
- __id__ = rb_intern("__id__");
- __send__ = rb_intern("__send__");
-
- rb_global_variable((VALUE*)&top_scope);
- rb_global_variable((VALUE*)&ruby_eval_tree_begin);
-
- rb_global_variable((VALUE*)&ruby_eval_tree);
- rb_global_variable((VALUE*)&ruby_dyna_vars);
-
- rb_define_virtual_variable("$@", errat_getter, errat_setter);
- rb_define_hooked_variable("$!", &ruby_errinfo, 0, errinfo_setter);
-
- rb_define_global_function("eval", rb_f_eval, -1);
- rb_define_global_function("iterator?", rb_f_block_given_p, 0);
- rb_define_global_function("block_given?", rb_f_block_given_p, 0);
- rb_define_global_function("method_missing", rb_f_missing, -1);
- rb_define_global_function("loop", rb_f_loop, 0);
-
- rb_define_method(rb_mKernel, "respond_to?", rb_obj_respond_to, -1);
-
- rb_define_global_function("raise", rb_f_raise, -1);
- rb_define_global_function("fail", rb_f_raise, -1);
-
- rb_define_global_function("caller", rb_f_caller, -1);
-
- rb_define_global_function("exit", rb_f_exit, -1);
- rb_define_global_function("abort", rb_f_abort, -1);
-
- rb_define_global_function("at_exit", rb_f_at_exit, 0);
-
- rb_define_global_function("catch", rb_f_catch, 1);
- rb_define_global_function("throw", rb_f_throw, -1);
- rb_define_global_function("global_variables", rb_f_global_variables, 0);
- rb_define_global_function("local_variables", rb_f_local_variables, 0);
-
- rb_define_method(rb_mKernel, "send", rb_f_send, -1);
- rb_define_method(rb_mKernel, "__send__", rb_f_send, -1);
- rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1);
-
- rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
- rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
- rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
- rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
- rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
- rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
- rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
- rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
- rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
- rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
- rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
- rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
-
- rb_undef_method(rb_cClass, "module_function");
-
- rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, 1);
- rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, 1);
- rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
- rb_define_private_method(rb_cModule, "define_method", rb_mod_define_method, -1);
-
- rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
- rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0);
-
- rb_define_singleton_method(ruby_top_self, "include", top_include, -1);
- rb_define_singleton_method(ruby_top_self, "public", top_public, -1);
- rb_define_singleton_method(ruby_top_self, "private", top_private, -1);
-
- rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
-
- rb_define_global_function("trace_var", rb_f_trace_var, -1);
- rb_define_global_function("untrace_var", rb_f_untrace_var, -1);
-
- rb_define_global_function("set_trace_func", set_trace_func, 1);
- rb_global_variable(&trace_func);
-
- rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
-}
-
-VALUE rb_f_autoload();
-
-void
-Init_load()
-{
- rb_load_path = rb_ary_new();
- rb_define_readonly_variable("$:", &rb_load_path);
- rb_define_readonly_variable("$-I", &rb_load_path);
- rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
-
- rb_features = rb_ary_new();
- rb_define_readonly_variable("$\"", &rb_features);
-
- rb_define_global_function("load", rb_f_load, -1);
- rb_define_global_function("require", rb_f_require, 1);
- rb_define_global_function("autoload", rb_f_autoload, 2);
- rb_global_variable(&ruby_wrapper);
-
- ruby_dln_librefs = rb_ary_new();
- rb_global_variable(&ruby_dln_librefs);
-}
-
-static void
-scope_dup(scope)
- struct SCOPE *scope;
-{
- ID *tbl;
- VALUE *vars;
-
- scope->flags |= SCOPE_DONT_RECYCLE;
- if (scope->flags & SCOPE_MALLOC) return;
-
- if (scope->local_tbl) {
- tbl = scope->local_tbl;
- vars = ALLOC_N(VALUE, tbl[0]+1);
- *vars++ = scope->local_vars[-1];
- MEMCPY(vars, scope->local_vars, VALUE, tbl[0]);
- scope->local_vars = vars;
- scope->flags |= SCOPE_MALLOC;
- }
-}
-
-static void
-blk_mark(data)
- struct BLOCK *data;
-{
- while (data) {
- rb_gc_mark_frame(&data->frame);
- rb_gc_mark((VALUE)data->scope);
- rb_gc_mark((VALUE)data->var);
- rb_gc_mark((VALUE)data->body);
- rb_gc_mark((VALUE)data->self);
- rb_gc_mark((VALUE)data->dyna_vars);
- rb_gc_mark((VALUE)data->klass);
- rb_gc_mark((VALUE)data->tag);
- rb_gc_mark(data->wrapper);
- data = data->prev;
- }
-}
-
-static void
-blk_free(data)
- struct BLOCK *data;
-{
- struct FRAME *frame;
- void *tmp;
-
- frame = data->frame.prev;
- while (frame) {
- if (frame->argc > 0 && (frame->flags & FRAME_MALLOC))
- free(frame->argv);
- tmp = frame;
- frame = frame->prev;
- free(tmp);
- }
- while (data) {
- if (data->frame.argc > 0)
- free(data->frame.argv);
- tmp = data;
- data = data->prev;
- free(tmp);
- }
-}
-
-static void
-blk_copy_prev(block)
- struct BLOCK *block;
-{
- struct BLOCK *tmp;
- struct RVarmap* vars;
-
- while (block->prev) {
- tmp = ALLOC_N(struct BLOCK, 1);
- MEMCPY(tmp, block->prev, struct BLOCK, 1);
- if (tmp->frame.argc > 0) {
- tmp->frame.argv = ALLOC_N(VALUE, tmp->frame.argc);
- MEMCPY(tmp->frame.argv, block->prev->frame.argv, VALUE, tmp->frame.argc);
- tmp->frame.flags |= FRAME_MALLOC;
- }
- scope_dup(tmp->scope);
- tmp->tag->flags |= BLOCK_DYNAMIC;
-
- for (vars = tmp->dyna_vars; vars; vars = vars->next) {
- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
- FL_SET(vars, DVAR_DONT_RECYCLE);
- }
-
- block->prev = tmp;
- block = tmp;
- }
-}
-
-static void
-frame_dup(frame)
- struct FRAME *frame;
-{
- VALUE *argv;
- struct FRAME *tmp;
-
- for (;;) {
- if (frame->argc > 0) {
- argv = ALLOC_N(VALUE, frame->argc);
- MEMCPY(argv, frame->argv, VALUE, frame->argc);
- frame->argv = argv;
- frame->flags |= FRAME_MALLOC;
- }
- frame->tmp = 0; /* should not preserve tmp */
- if (!frame->prev) break;
- tmp = ALLOC(struct FRAME);
- *tmp = *frame->prev;
- frame->prev = tmp;
- frame = tmp;
- }
-}
-
-static VALUE
-bind_clone(self)
- VALUE self;
-{
- struct BLOCK *orig, *data;
- VALUE bind;
-
- Data_Get_Struct(self, struct BLOCK, orig);
- bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data);
- CLONESETUP(bind, self);
- MEMCPY(data, orig, struct BLOCK, 1);
- frame_dup(&data->frame);
-
- if (data->iter) {
- blk_copy_prev(data);
- }
- else {
- data->prev = 0;
- }
-
- return bind;
-}
-
-static VALUE
-rb_f_binding(self)
- VALUE self;
-{
- struct BLOCK *data, *p;
- struct RVarmap *vars;
- VALUE bind;
-
- PUSH_BLOCK(0,0);
- bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data);
- *data = *ruby_block;
-
- data->orig_thread = rb_thread_current();
- data->wrapper = ruby_wrapper;
- data->iter = rb_f_block_given_p();
- frame_dup(&data->frame);
- if (ruby_frame->prev) {
- data->frame.last_func = ruby_frame->prev->last_func;
- data->frame.last_class = ruby_frame->prev->last_class;
- }
-
- if (data->iter) {
- blk_copy_prev(data);
- }
- else {
- data->prev = 0;
- }
- data->flags |= BLOCK_DYNAMIC;
- data->tag->flags |= BLOCK_DYNAMIC;
-
- for (p = data; p; p = p->prev) {
- for (vars = p->dyna_vars; vars; vars = vars->next) {
- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
- FL_SET(vars, DVAR_DONT_RECYCLE);
- }
- }
- scope_dup(data->scope);
- POP_BLOCK();
-
- return bind;
-}
-
-#define PROC_T3 FL_USER1
-#define PROC_T4 FL_USER2
-#define PROC_TMAX (FL_USER1|FL_USER2)
-#define PROC_TMASK (FL_USER1|FL_USER2)
-
-static void
-proc_save_safe_level(data)
- VALUE data;
-{
- if (OBJ_TAINTED(data)) {
- switch (rb_safe_level()) {
- case 3:
- FL_SET(data, PROC_T3);
- break;
- case 4:
- FL_SET(data, PROC_T4);
- break;
- default:
- if (rb_safe_level() > 4) {
- FL_SET(data, PROC_TMAX);
- }
- break;
- }
- }
-}
-
-static int
-proc_get_safe_level(data)
- VALUE data;
-{
- if (OBJ_TAINTED(data)) {
- switch (RBASIC(data)->flags & PROC_TMASK) {
- case PROC_T3:
- return 3;
- case PROC_T4:
- return 4;
- case PROC_TMAX:
- return 5;
- }
- return 3;
- }
- return 0;
-}
-
-static void
-proc_set_safe_level(data)
- VALUE data;
-{
- if (OBJ_TAINTED(data)) {
- ruby_safe_level = proc_get_safe_level(data);
- }
-}
-
-static VALUE
-proc_new(klass)
- VALUE klass;
-{
- volatile VALUE proc;
- struct BLOCK *data, *p;
- struct RVarmap *vars;
-
- if (!rb_block_given_p() && !rb_f_block_given_p()) {
- rb_raise(rb_eArgError, "tried to create Proc object without a block");
- }
-
- proc = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data);
- *data = *ruby_block;
-
- data->orig_thread = rb_thread_current();
- data->wrapper = ruby_wrapper;
- data->iter = data->prev?Qtrue:Qfalse;
- frame_dup(&data->frame);
- if (data->iter) {
- blk_copy_prev(data);
- }
- else {
- data->prev = 0;
- }
- data->flags |= BLOCK_DYNAMIC;
- data->tag->flags |= BLOCK_DYNAMIC;
-
- for (p = data; p; p = p->prev) {
- for (vars = p->dyna_vars; vars; vars = vars->next) {
- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
- FL_SET(vars, DVAR_DONT_RECYCLE);
- }
- }
- scope_dup(data->scope);
- proc_save_safe_level(proc);
-
- return proc;
-}
-
-static VALUE
-proc_s_new(argc, argv, klass)
- int argc;
- VALUE *argv;
- VALUE klass;
-{
- VALUE proc = proc_new(klass);
-
- rb_obj_call_init(proc, argc, argv);
- return proc;
-}
-
-VALUE
-rb_f_lambda()
-{
- return proc_new(rb_cProc);
-}
-
-static int
-blk_orphan(data)
- struct BLOCK *data;
-{
- if (!(data->scope->flags & SCOPE_NOSTACK)) {
- return 0;
- }
- if ((data->tag->flags & BLOCK_ORPHAN)) {
- return 1;
- }
- if (data->orig_thread != rb_thread_current()) {
- return 1;
- }
- return 0;
-}
-
-static VALUE
-proc_invoke(proc, args, pcall, self)
- VALUE proc, args; /* OK */
- int pcall;
- VALUE self;
-{
- struct BLOCK * volatile old_block;
- struct BLOCK _block;
- struct BLOCK *data;
- volatile VALUE result = Qnil;
- int state;
- volatile int orphan;
- volatile int safe = ruby_safe_level;
- volatile VALUE old_wrapper = ruby_wrapper;
- struct RVarmap * volatile old_dvars = ruby_dyna_vars;
-
- if (rb_block_given_p() && ruby_frame->last_func) {
- rb_warning("block for %s#%s is useless",
- rb_class2name(CLASS_OF(proc)),
- rb_id2name(ruby_frame->last_func));
- }
-
- Data_Get_Struct(proc, struct BLOCK, data);
- orphan = blk_orphan(data);
-
- ruby_wrapper = data->wrapper;
- ruby_dyna_vars = data->dyna_vars;
- /* PUSH BLOCK from data */
- old_block = ruby_block;
- _block = *data;
- ruby_block = &_block;
-
- PUSH_ITER(ITER_CUR);
- ruby_frame->iter = ITER_CUR;
-
- if (!pcall) {
- args = avalue_to_svalue(args);
- }
- PUSH_TAG(PROT_NONE);
- state = EXEC_TAG();
- if (state == 0) {
- proc_set_safe_level(proc);
- result = rb_yield_0(args, self, self!=Qundef?CLASS_OF(self):0, pcall);
- }
- POP_TAG();
-
- POP_ITER();
- if (ruby_block->tag->dst == state) {
- state &= TAG_MASK;
- }
- ruby_block = old_block;
- ruby_wrapper = old_wrapper;
- ruby_dyna_vars = old_dvars;
- ruby_safe_level = safe;
-
- switch (state) {
- case 0:
- break;
- case TAG_BREAK:
- if (!pcall && orphan) {
- localjump_error("break from proc-closure", prot_tag->retval);
- }
- result = prot_tag->retval;
- break;
- case TAG_RETRY:
- localjump_error("retry from proc-closure", Qnil);
- break;
- case TAG_RETURN:
- if (orphan) { /* orphan procedure */
- localjump_error("return from proc-closure", prot_tag->retval);
- }
- /* fall through */
- default:
- JUMP_TAG(state);
- }
- return result;
-}
-
-static VALUE
-proc_call(proc, args)
- VALUE proc, args; /* OK */
-{
- return proc_invoke(proc, args, Qtrue, Qundef);
-}
-
-static VALUE
-proc_yield(proc, args)
- VALUE proc, args; /* OK */
-{
- return proc_invoke(proc, args, Qfalse, Qundef);
-}
-
-static VALUE
-proc_arity(proc)
- VALUE proc;
-{
- struct BLOCK *data;
- NODE *list;
- int n;
-
- Data_Get_Struct(proc, struct BLOCK, data);
- if (data->var == 0) return INT2FIX(-1);
- if (data->var == (NODE*)1) return INT2FIX(0);
- if (data->var == (NODE*)2) return INT2FIX(0);
- switch (nd_type(data->var)) {
- default:
- return INT2FIX(-1);
- case NODE_MASGN:
- list = data->var->nd_head;
- n = 0;
- while (list) {
- n++;
- list = list->nd_next;
- }
- if (data->var->nd_args) return INT2FIX(-n-1);
- return INT2FIX(n);
- }
-}
-
-static VALUE
-proc_eq(self, other)
- VALUE self, other;
-{
- struct BLOCK *data, *data2;
-
- if (self == other) return Qtrue;
- if (TYPE(other) != T_DATA) return Qfalse;
- if (RDATA(other)->dmark != (RUBY_DATA_FUNC)blk_mark) return Qfalse;
- if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse;
- Data_Get_Struct(self, struct BLOCK, data);
- Data_Get_Struct(other, struct BLOCK, data2);
- if (data->tag == data2->tag) return Qtrue;
- return Qfalse;
-}
-
-static VALUE
-proc_to_s(self, other)
- VALUE self, other;
-{
- struct BLOCK *data;
- char *cname = rb_class2name(CLASS_OF(self));
- VALUE str;
-
- Data_Get_Struct(self, struct BLOCK, data);
- str = rb_str_new(0, strlen(cname)+6+16+1); /* 6:tags 16:addr 1:nul */
- sprintf(RSTRING(str)->ptr, "#<%s:0x%lx>", cname, data->tag);
- RSTRING(str)->len = strlen(RSTRING(str)->ptr);
- if (OBJ_TAINTED(self)) OBJ_TAINT(str);
-
- return str;
-}
-
-static VALUE
-block_pass(self, node)
- VALUE self;
- NODE *node;
-{
- VALUE block = rb_eval(self, node->nd_body); /* OK */
- struct BLOCK * volatile old_block;
- struct BLOCK _block;
- struct BLOCK *data;
- volatile VALUE result = Qnil;
- int state;
- volatile int orphan;
- volatile int safe = ruby_safe_level;
-
- if (NIL_P(block)) {
- PUSH_ITER(ITER_NOT);
- result = rb_eval(self, node->nd_iter);
- POP_ITER();
- return result;
- }
- if (rb_obj_is_kind_of(block, rb_cMethod)) {
- block = method_proc(block);
- }
- else if (!rb_obj_is_proc(block)) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)",
- rb_class2name(CLASS_OF(block)));
- }
-
- if (rb_safe_level() >= 1 && OBJ_TAINTED(block)) {
- if (rb_safe_level() > proc_get_safe_level(block)) {
- rb_raise(rb_eSecurityError, "Insecure: tainted block value");
- }
- }
-
- Data_Get_Struct(block, struct BLOCK, data);
- orphan = blk_orphan(data);
-
- retry:
- /* PUSH BLOCK from data */
- old_block = ruby_block;
- _block = *data;
- ruby_block = &_block;
- PUSH_ITER(ITER_PRE);
- ruby_frame->iter = ITER_PRE;
-
- PUSH_TAG(PROT_NONE);
- state = EXEC_TAG();
- if (state == 0) {
- proc_set_safe_level(block);
- if (safe > ruby_safe_level)
- ruby_safe_level = safe;
- result = rb_eval(self, node->nd_iter);
- }
- POP_TAG();
- POP_ITER();
- if (_block.tag->dst == state) {
- if (orphan) {
- state &= TAG_MASK;
- }
- else {
- struct BLOCK *ptr = old_block;
-
- while (ptr) {
- if (ptr->scope == _block.scope) {
- ptr->tag->dst = state;
- break;
- }
- ptr = ptr->prev;
- }
- if (!ptr) {
- state &= TAG_MASK;
- }
- }
- }
- ruby_block = old_block;
- ruby_safe_level = safe;
-
- switch (state) {/* escape from orphan procedure */
- case 0:
- break;
- case TAG_BREAK:
- result = prot_tag->retval;
- break;
- case TAG_RETRY:
- goto retry;
- case TAG_RETURN:
- if (orphan) {
- localjump_error("return from proc-closure", prot_tag->retval);
- }
- default:
- JUMP_TAG(state);
- }
-
- return result;
-}
-
-struct METHOD {
- VALUE klass, rklass;
- VALUE recv;
- ID id, oid;
- NODE *body;
-};
-
-static void
-bm_mark(data)
- struct METHOD *data;
-{
- rb_gc_mark(data->rklass);
- rb_gc_mark(data->klass);
- rb_gc_mark(data->recv);
- rb_gc_mark((VALUE)data->body);
-}
-
-static VALUE
-mnew(klass, obj, id, mklass)
- VALUE klass, obj, mklass;
- ID id;
-{
- VALUE method;
- NODE *body;
- int noex;
- struct METHOD *data;
- VALUE rklass = klass;
- ID oid = id;
-
- again:
- if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
- print_undef(rklass, oid);
- }
-
- if (nd_type(body) == NODE_ZSUPER) {
- klass = RCLASS(klass)->super;
- goto again;
- }
-
- method = Data_Make_Struct(mklass, struct METHOD, bm_mark, free, data);
- data->klass = klass;
- data->recv = obj;
- data->id = id;
- data->body = body;
- data->rklass = rklass;
- data->oid = oid;
- OBJ_INFECT(method, klass);
-
- return method;
-}
-
-static VALUE
-method_eq(method, other)
- VALUE method, other;
-{
- struct METHOD *m1, *m2;
-
- if (TYPE(other) != T_DATA || RDATA(other)->dmark != (RUBY_DATA_FUNC)bm_mark)
- return Qfalse;
- if (CLASS_OF(method) != CLASS_OF(other))
- return Qfalse;
-
- Data_Get_Struct(method, struct METHOD, m1);
- Data_Get_Struct(other, struct METHOD, m2);
-
- if (m1->klass != m2->klass || m1->rklass != m2->rklass ||
- m1->recv != m2->recv || m1->body != m2->body)
- return Qfalse;
-
- return Qtrue;
-}
-
-static VALUE
-method_unbind(obj)
- VALUE obj;
-{
- VALUE method;
- struct METHOD *orig, *data;
-
- Data_Get_Struct(obj, struct METHOD, orig);
- method = Data_Make_Struct(rb_cUnboundMethod, struct METHOD, bm_mark, free, data);
- data->klass = orig->klass;
- data->recv = Qundef;
- data->id = orig->id;
- data->body = orig->body;
- data->rklass = orig->rklass;
- data->oid = orig->oid;
- OBJ_INFECT(method, obj);
-
- return method;
-}
-
-static VALUE
-umethod_unbind(obj)
- VALUE obj;
-{
- return obj;
-}
-
-static VALUE
-rb_obj_method(obj, vid)
- VALUE obj;
- VALUE vid;
-{
- return mnew(CLASS_OF(obj), obj, rb_to_id(vid), rb_cMethod);
-}
-
-static VALUE
-rb_mod_method(mod, vid)
- VALUE mod;
- VALUE vid;
-{
- return mnew(mod, Qundef, rb_to_id(vid), rb_cUnboundMethod);
-}
-
-static VALUE
-method_clone(self)
- VALUE self;
-{
- VALUE clone;
- struct METHOD *orig, *data;
-
- Data_Get_Struct(self, struct METHOD, orig);
- clone = Data_Make_Struct(CLASS_OF(self),struct METHOD, bm_mark, free, data);
- CLONESETUP(clone, self);
- *data = *orig;
-
- return clone;
-}
-
-static VALUE
-method_call(argc, argv, method)
- int argc;
- VALUE *argv;
- VALUE method;
-{
- VALUE result;
- struct METHOD *data;
- int state;
- volatile int safe = ruby_safe_level;
-
- Data_Get_Struct(method, struct METHOD, data);
- PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
- PUSH_TAG(PROT_NONE);
- if (OBJ_TAINTED(method) && ruby_safe_level < 4) {
- ruby_safe_level = 4;
- }
- if ((state = EXEC_TAG()) == 0) {
- result = rb_call0(data->klass,data->recv,data->id,argc,argv,data->body,0);
- }
- POP_TAG();
- POP_ITER();
- ruby_safe_level = safe;
- if (state) JUMP_TAG(state);
- return result;
-}
-
-static VALUE
-umethod_call(argc, argv, method)
- int argc;
- VALUE *argv;
- VALUE method;
-{
- rb_raise(rb_eTypeError, "you cannot call unbound method; bind first");
- return Qnil; /* not reached */
-}
-
-static VALUE
-umethod_bind(method, recv)
- VALUE method, recv;
-{
- struct METHOD *data, *bound;
-
- Data_Get_Struct(method, struct METHOD, data);
- if (data->rklass != CLASS_OF(recv)) {
- if (FL_TEST(data->rklass, FL_SINGLETON)) {
- rb_raise(rb_eTypeError, "singleton method called for a different object");
- }
- if (FL_TEST(CLASS_OF(recv), FL_SINGLETON) &&
- st_lookup(RCLASS(CLASS_OF(recv))->m_tbl, data->oid, 0)) {
- rb_raise(rb_eTypeError, "method `%s' overridden", rb_id2name(data->oid));
- }
- if (!((TYPE(data->rklass) == T_MODULE) ?
- rb_obj_is_kind_of(recv, data->rklass) :
- rb_obj_is_instance_of(recv, data->rklass))) {
- rb_raise(rb_eTypeError, "bind argument must be an instance of %s",
- rb_class2name(data->rklass));
- }
- }
-
- method = Data_Make_Struct(rb_cMethod,struct METHOD,bm_mark,free,bound);
- *bound = *data;
- bound->recv = recv;
- bound->rklass = CLASS_OF(recv);
-
- return method;
-}
-
-static VALUE
-method_arity(method)
- VALUE method;
-{
- struct METHOD *data;
- NODE *body;
- int n;
-
- Data_Get_Struct(method, struct METHOD, data);
-
- body = data->body;
- switch (nd_type(body)) {
- case NODE_CFUNC:
- if (body->nd_argc < 0) return INT2FIX(-1);
- return INT2FIX(body->nd_argc);
- case NODE_ZSUPER:
- return INT2FIX(-1);
- case NODE_ATTRSET:
- return INT2FIX(1);
- case NODE_IVAR:
- return INT2FIX(0);
- default:
- body = body->nd_next; /* skip NODE_SCOPE */
- if (nd_type(body) == NODE_BLOCK)
- body = body->nd_head;
- if (!body) return INT2FIX(0);
- n = body->nd_cnt;
- if (body->nd_opt || body->nd_rest != -1)
- n = -n-1;
- return INT2FIX(n);
- }
-}
-
-static VALUE
-method_inspect(method)
- VALUE method;
-{
- struct METHOD *data;
- VALUE str;
- const char *s;
- char *sharp = "#";
-
- Data_Get_Struct(method, struct METHOD, data);
- str = rb_str_buf_new2("#<");
- s = rb_class2name(CLASS_OF(method));
- rb_str_buf_cat2(str, s);
- rb_str_buf_cat2(str, ": ");
-
- if (FL_TEST(data->klass, FL_SINGLETON)) {
- VALUE v = rb_iv_get(data->klass, "__attached__");
-
- if (data->recv == Qundef) {
- rb_str_buf_append(str, rb_inspect(data->klass));
- }
- else if (data->recv == v) {
- rb_str_buf_append(str, rb_inspect(v));
- sharp = ".";
- }
- else {
- rb_str_buf_append(str, rb_inspect(data->recv));
- rb_str_buf_cat2(str, "(");
- rb_str_buf_append(str, rb_inspect(v));
- rb_str_buf_cat2(str, ")");
- sharp = ".";
- }
- }
- else {
- rb_str_buf_cat2(str, rb_class2name(data->rklass));
- if (data->rklass != data->klass) {
- rb_str_buf_cat2(str, "(");
- rb_str_buf_cat2(str, rb_class2name(data->klass));
- rb_str_buf_cat2(str, ")");
- }
- }
- rb_str_buf_cat2(str, sharp);
- rb_str_buf_cat2(str, rb_id2name(data->oid));
- rb_str_buf_cat2(str, ">");
-
- return str;
-}
-
-static VALUE
-mproc()
-{
- VALUE proc;
-
- /* emulate ruby's method call */
- PUSH_ITER(ITER_CUR);
- PUSH_FRAME();
- proc = rb_f_lambda();
- POP_FRAME();
- POP_ITER();
-
- return proc;
-}
-
-static VALUE
-bmcall(args, method)
- VALUE args, method;
-{
- args = svalue_to_avalue(args);
- return method_call(RARRAY(args)->len, RARRAY(args)->ptr, method);
-}
-
-static VALUE
-umcall(args, method)
- VALUE args, method;
-{
- return umethod_call(0, 0, method);
-}
-
-static VALUE
-method_proc(method)
- VALUE method;
-{
- return rb_iterate((VALUE(*)_((VALUE)))mproc, 0, bmcall, method);
-}
-
-static VALUE
-umethod_proc(method)
- VALUE method;
-{
- return rb_iterate((VALUE(*)_((VALUE)))mproc, 0, umcall, method);
-}
-
-static VALUE
-rb_mod_define_method(argc, argv, mod)
- int argc;
- VALUE *argv;
- VALUE mod;
-{
- ID id;
- VALUE body;
- NODE *node;
- int noex;
-
- if (argc == 1) {
- id = rb_to_id(argv[0]);
- body = rb_f_lambda();
- }
- else if (argc == 2) {
- id = rb_to_id(argv[0]);
- body = argv[1];
- if (!rb_obj_is_kind_of(body, rb_cMethod) && !rb_obj_is_proc(body)) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Method)",
- rb_class2name(CLASS_OF(body)));
- }
- }
- else {
- rb_raise(rb_eArgError, "wrong number of arguments(%d for 1)", argc);
- }
- if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) {
- node = NEW_DMETHOD(method_unbind(body));
- }
- else if (RDATA(body)->dmark == (RUBY_DATA_FUNC)blk_mark) {
- node = NEW_BMETHOD(body);
- }
- else {
- /* type error */
- rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)");
- }
-
- if (SCOPE_TEST(SCOPE_PRIVATE)) {
- noex = NOEX_PRIVATE;
- }
- else if (SCOPE_TEST(SCOPE_PROTECTED)) {
- noex = NOEX_PROTECTED;
- }
- else {
- noex = NOEX_PUBLIC;
- }
- rb_add_method(mod, id, node, noex);
- if (scope_vmode == SCOPE_MODFUNC) {
- rb_add_method(rb_singleton_class(mod), id, node, NOEX_PUBLIC);
- rb_funcall(mod, singleton_added, 1, ID2SYM(id));
- }
- if (FL_TEST(mod, FL_SINGLETON)) {
- rb_funcall(rb_iv_get(mod, "__attached__"), singleton_added, 1, ID2SYM(id));
- }
- else {
- rb_funcall(mod, added, 1, ID2SYM(id));
- }
- return body;
-}
-
-void
-Init_Proc()
-{
- rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError);
- rb_define_method(rb_eLocalJumpError, "exitstatus", localjump_exitstatus, 0);
-
- rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError);
-
- rb_cProc = rb_define_class("Proc", rb_cObject);
- rb_undef_method(CLASS_OF(rb_cProc), "allocate");
- rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1);
-
- rb_define_method(rb_cProc, "call", proc_call, -2);
- rb_define_method(rb_cProc, "yield", proc_yield, -2);
- rb_define_method(rb_cProc, "arity", proc_arity, 0);
- rb_define_method(rb_cProc, "[]", proc_call, -2);
- rb_define_method(rb_cProc, "==", proc_eq, 1);
- rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
- rb_define_global_function("proc", rb_f_lambda, 0);
- rb_define_global_function("lambda", rb_f_lambda, 0);
- rb_define_global_function("binding", rb_f_binding, 0);
- rb_cBinding = rb_define_class("Binding", rb_cObject);
- rb_undef_method(CLASS_OF(rb_cBinding), "allocate");
- rb_undef_method(CLASS_OF(rb_cBinding), "new");
- rb_define_method(rb_cBinding, "clone", bind_clone, 0);
-
- rb_cMethod = rb_define_class("Method", rb_cObject);
- rb_undef_method(CLASS_OF(rb_cMethod), "allocate");
- rb_undef_method(CLASS_OF(rb_cMethod), "new");
- rb_define_method(rb_cMethod, "==", method_eq, 1);
- rb_define_method(rb_cMethod, "clone", method_clone, 0);
- rb_define_method(rb_cMethod, "call", method_call, -1);
- rb_define_method(rb_cMethod, "[]", method_call, -1);
- rb_define_method(rb_cMethod, "arity", method_arity, 0);
- rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
- rb_define_method(rb_cMethod, "to_s", method_inspect, 0);
- rb_define_method(rb_cMethod, "to_proc", method_proc, 0);
- rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
- rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
-
- rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cMethod);
- rb_define_method(rb_cUnboundMethod, "call", umethod_call, -1);
- rb_define_method(rb_cUnboundMethod, "[]", umethod_call, -1);
- rb_define_method(rb_cUnboundMethod, "to_proc", umethod_proc, 0);
- rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
- rb_define_method(rb_cUnboundMethod, "unbind", umethod_unbind, 0);
- rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1);
-}
-
-static VALUE rb_eThreadError;
-
-int rb_thread_pending = 0;
-
-VALUE rb_cThread;
-
-extern VALUE rb_last_status;
-
-enum thread_status {
- THREAD_TO_KILL,
- THREAD_RUNNABLE,
- THREAD_STOPPED,
- THREAD_KILLED
-};
-
-#define WAIT_FD (1<<0)
-#define WAIT_SELECT (1<<1)
-#define WAIT_TIME (1<<2)
-#define WAIT_JOIN (1<<3)
-#define WAIT_PID (1<<4)
-
-/* +infty, for this purpose */
-#define DELAY_INFTY 1E30
-
-/* typedef struct thread * rb_thread_t; */
-
-struct thread {
- struct thread *next, *prev;
- jmp_buf context;
-
- VALUE result;
-
- int stk_len;
- int stk_max;
- VALUE*stk_ptr;
- VALUE*stk_pos;
-
- struct FRAME *frame;
- struct SCOPE *scope;
- struct RVarmap *dyna_vars;
- struct BLOCK *block;
- struct iter *iter;
- struct tag *tag;
- VALUE klass;
- VALUE wrapper;
- NODE *cref;
-
- int flags; /* misc. states (vmode/rb_trap_immediate/raised) */
-
- char *file;
- int line;
-
- int tracing;
- VALUE errinfo;
- VALUE last_status;
- VALUE last_line;
- VALUE last_match;
-
- int safe;
-
- enum thread_status status;
- int wait_for;
- int fd;
- fd_set readfds;
- fd_set writefds;
- fd_set exceptfds;
- int select_value;
- double delay;
- rb_thread_t join;
-
- int abort;
- int priority;
- int gid;
-
- st_table *locals;
-
- VALUE thread;
-};
-
-#define THREAD_RAISED 0x200 /* temporary flag */
-#define THREAD_TERMINATING 0x400 /* persistent flag */
-#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */
-
-#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
-#define END_FOREACH_FROM(f,x) } while (x != f)
-
-#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
-#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x)
-
-static const char *
-thread_status_name(status)
- enum thread_status status;
-{
- switch (status) {
- case THREAD_RUNNABLE:
- return "run";
- case THREAD_STOPPED:
- return "sleep";
- case THREAD_TO_KILL:
- return "aborting";
- case THREAD_KILLED:
- return "dead";
- default:
- return "unknown";
- }
-}
-
-/* $SAFE accessor */
-void
-rb_set_safe_level(level)
- int level;
-{
- if (level > ruby_safe_level) {
- ruby_safe_level = level;
- curr_thread->safe = level;
- }
-}
-
-static VALUE
-safe_getter()
-{
- return INT2NUM(ruby_safe_level);
-}
-
-static void
-safe_setter(val)
- VALUE val;
-{
- int level = NUM2INT(val);
-
- if (level < ruby_safe_level) {
- rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d",
- ruby_safe_level, level);
- }
- ruby_safe_level = level;
- curr_thread->safe = level;
-}
-
-/* Return the current time as a floating-point number */
-static double
-timeofday()
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
-}
-
-#define STACK(addr) (th->stk_pos<(VALUE*)(addr) && (VALUE*)(addr)<th->stk_pos+th->stk_len)
-#define ADJ(addr) (void*)(STACK(addr)?(((VALUE*)(addr)-th->stk_pos)+th->stk_ptr):(VALUE*)(addr))
-
-static void
-thread_mark(th)
- rb_thread_t th;
-{
- struct FRAME *frame;
- struct BLOCK *block;
-
- rb_gc_mark(th->result);
- rb_gc_mark(th->thread);
- if (th->join) rb_gc_mark(th->join->thread);
-
- rb_gc_mark(th->klass);
- rb_gc_mark(th->wrapper);
- rb_gc_mark((VALUE)th->cref);
-
- rb_gc_mark((VALUE)th->scope);
- rb_gc_mark((VALUE)th->dyna_vars);
- rb_gc_mark(th->errinfo);
- rb_gc_mark(th->last_line);
- rb_gc_mark(th->last_match);
- rb_mark_tbl(th->locals);
-
- /* mark data in copied stack */
- if (th == curr_thread) return;
- if (th->status == THREAD_KILLED) return;
- if (th->stk_len == 0) return; /* stack not active, no need to mark. */
- if (th->stk_ptr) {
- rb_gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
-#if defined(THINK_C) || defined(__human68k__)
- rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
-#endif
- }
- frame = th->frame;
- while (frame && frame != top_frame) {
- frame = ADJ(frame);
- rb_gc_mark_frame(frame);
- if (frame->tmp) {
- struct FRAME *tmp = frame->tmp;
-
- while (tmp && tmp != top_frame) {
- tmp = ADJ(tmp);
- rb_gc_mark_frame(tmp);
- tmp = tmp->prev;
- }
- }
- frame = frame->prev;
- }
- block = th->block;
- while (block) {
- block = ADJ(block);
- rb_gc_mark_frame(&block->frame);
- block = block->prev;
- }
-}
-
-void
-rb_gc_mark_threads()
-{
- rb_thread_t th;
-
- /* static global mark */
- rb_gc_mark((VALUE)ruby_cref);
-
- if (!curr_thread) return;
- FOREACH_THREAD(th) {
- rb_gc_mark(th->thread);
- } END_FOREACH(th);
-}
-
-static void
-thread_free(th)
- rb_thread_t th;
-{
- if (th->stk_ptr) free(th->stk_ptr);
- th->stk_ptr = 0;
- if (th->locals) st_free_table(th->locals);
- if (th->status != THREAD_KILLED) {
- if (th->prev) th->prev->next = th->next;
- if (th->next) th->next->prev = th->prev;
- }
- if (th != main_thread) free(th);
-}
-
-static rb_thread_t
-rb_thread_check(data)
- VALUE data;
-{
- if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)thread_mark) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
- rb_class2name(CLASS_OF(data)));
- }
- return (rb_thread_t)RDATA(data)->data;
-}
-
-static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t));
-
-static int th_raise_argc;
-static VALUE th_raise_argv[2];
-static char *th_raise_file;
-static int th_raise_line;
-static VALUE th_cmd;
-static int th_sig;
-static char *th_signm;
-
-#define RESTORE_NORMAL 1
-#define RESTORE_FATAL 2
-#define RESTORE_INTERRUPT 3
-#define RESTORE_TRAP 4
-#define RESTORE_RAISE 5
-#define RESTORE_SIGNAL 6
-
-extern VALUE *rb_gc_stack_start;
-
-static void
-rb_thread_save_context(th)
- rb_thread_t th;
-{
- VALUE *pos;
- int len;
- static VALUE tval;
-
- len = ruby_stack_length(&pos);
- th->stk_len = 0;
- th->stk_pos = (rb_gc_stack_start<pos)?rb_gc_stack_start
- :rb_gc_stack_start - len;
- if (len > th->stk_max) {
- REALLOC_N(th->stk_ptr, VALUE, len);
- th->stk_max = len;
- }
- th->stk_len = len;
- FLUSH_REGISTER_WINDOWS;
- MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len);
-
- th->frame = ruby_frame;
- th->scope = ruby_scope;
- th->klass = ruby_class;
- th->wrapper = ruby_wrapper;
- th->cref = ruby_cref;
- th->dyna_vars = ruby_dyna_vars;
- th->block = ruby_block;
- th->flags &= THREAD_FLAGS_MASK;
- th->flags |= (rb_trap_immediate<<8) | scope_vmode;
- th->iter = ruby_iter;
- th->tag = prot_tag;
- th->tracing = tracing;
- th->errinfo = ruby_errinfo;
- th->last_status = rb_last_status;
- tval = rb_lastline_get();
- rb_lastline_set(th->last_line);
- th->last_line = tval;
- tval = rb_backref_get();
- rb_backref_set(th->last_match);
- th->last_match = tval;
- th->safe = ruby_safe_level;
-
- th->file = ruby_sourcefile;
- th->line = ruby_sourceline;
-}
-
-static int
-thread_switch(n)
- int n;
-{
- switch (n) {
- case 0:
- return 0;
- case RESTORE_FATAL:
- JUMP_TAG(TAG_FATAL);
- break;
- case RESTORE_INTERRUPT:
- rb_interrupt();
- break;
- case RESTORE_TRAP:
- rb_trap_eval(th_cmd, th_sig);
- errno = EINTR;
- break;
- case RESTORE_RAISE:
- ruby_frame->last_func = 0;
- ruby_sourcefile = th_raise_file;
- ruby_sourceline = th_raise_line;
- rb_f_raise(th_raise_argc, th_raise_argv);
- break;
- case RESTORE_SIGNAL:
- rb_raise(rb_eSignal, "SIG%s", th_signm);
- break;
- case RESTORE_NORMAL:
- default:
- break;
- }
- return 1;
-}
-
-#define THREAD_SAVE_CONTEXT(th) \
- (rb_thread_save_context(th),thread_switch(setjmp((th)->context)))
-
-static void rb_thread_restore_context _((rb_thread_t,int));
-
-static void
-stack_extend(th, exit)
- rb_thread_t th;
- int exit;
-{
- VALUE space[1024];
-
- memset(space, 0, 1); /* prevent array from optimization */
- rb_thread_restore_context(th, exit);
-}
-
-static void
-rb_thread_restore_context(th, exit)
- rb_thread_t th;
- int exit;
-{
- VALUE v;
- static rb_thread_t tmp;
- static int ex;
- static VALUE tval;
-
- if (!th->stk_ptr) rb_bug("unsaved context");
-
- if (&v < rb_gc_stack_start) {
- /* Stack grows downward */
- if (&v > th->stk_pos) stack_extend(th, exit);
- }
- else {
- /* Stack grows upward */
- if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit);
- }
-
- ruby_frame = th->frame;
- ruby_scope = th->scope;
- ruby_class = th->klass;
- ruby_wrapper = th->wrapper;
- ruby_cref = th->cref;
- ruby_dyna_vars = th->dyna_vars;
- ruby_block = th->block;
- scope_vmode = th->flags&SCOPE_MASK;
- rb_trap_immediate = (th->flags&0x100)?1:0;
- ruby_iter = th->iter;
- prot_tag = th->tag;
- tracing = th->tracing;
- ruby_errinfo = th->errinfo;
- rb_last_status = th->last_status;
- ruby_safe_level = th->safe;
-
- ruby_sourcefile = th->file;
- ruby_sourceline = th->line;
-
- tmp = th;
- ex = exit;
- FLUSH_REGISTER_WINDOWS;
- MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len);
-
- tval = rb_lastline_get();
- rb_lastline_set(tmp->last_line);
- tmp->last_line = tval;
- tval = rb_backref_get();
- rb_backref_set(tmp->last_match);
- tmp->last_match = tval;
-
- longjmp(tmp->context, ex);
-}
-
-static void
-rb_thread_ready(th)
- rb_thread_t th;
-{
- th->wait_for = 0;
- th->status = THREAD_RUNNABLE;
-}
-
-static void
-rb_thread_remove(th)
- rb_thread_t th;
-{
- if (th->status == THREAD_KILLED) return;
-
- rb_thread_ready(th);
- th->status = THREAD_KILLED;
- th->prev->next = th->next;
- th->next->prev = th->prev;
-}
-
-static int
-rb_thread_dead(th)
- rb_thread_t th;
-{
- return th->status == THREAD_KILLED;
-}
-
-void
-rb_thread_fd_close(fd)
- int fd;
-{
- rb_thread_t th;
-
- FOREACH_THREAD(th) {
- if ((th->wait_for & WAIT_FD) && fd == th->fd) {
- VALUE exc = rb_exc_new2(rb_eIOError, "stream closed");
- rb_thread_raise(1, &exc, th);
- }
- }
- END_FOREACH(th);
-}
-
-static void
-rb_thread_deadlock()
-{
- if (curr_thread == main_thread) {
- rb_raise(rb_eFatal, "Thread: deadlock");
- }
- curr_thread = main_thread;
- th_raise_argc = 1;
- th_raise_argv[0] = rb_exc_new2(rb_eFatal, "Thread: deadlock");
- th_raise_file = ruby_sourcefile;
- th_raise_line = ruby_sourceline;
- rb_thread_restore_context(main_thread, RESTORE_RAISE);
-}
-
-static void
-copy_fds(dst, src, max)
- fd_set *dst, *src;
- int max;
-{
- int n = 0;
- int i;
-
- for (i=0; i<=max; i++) {
- if (FD_ISSET(i, src)) {
- n = i;
- FD_SET(i, dst);
- }
- }
-}
-
-static int
-match_fds(dst, src, max)
- fd_set *dst, *src;
- int max;
-{
- int i;
-
- for (i=0; i<=max; i++) {
- if (FD_ISSET(i, src) && FD_ISSET(i, dst)) {
- return Qtrue;
- }
- }
- return Qfalse;
-}
-
-static int
-intersect_fds(src, dst, max)
- fd_set *src, *dst;
- int max;
-{
- int i, n = 0;
-
- for (i=0; i<=max; i++) {
- if (FD_ISSET(i, dst)) {
- if (FD_ISSET(i, src)) {
- /* Wake up only one thread per fd. */
- FD_CLR(i, src);
- ++n;
- }
- else {
- FD_CLR(i, dst);
- }
- }
- }
- return n;
-}
-
-static int
-find_bad_fds(dst, src, max)
- fd_set *dst, *src;
- int max;
-{
- int i, test = Qfalse;
-
- for (i=0; i<=max; i++) {
- if (FD_ISSET(i, src) && !FD_ISSET(i, dst)) {
- FD_CLR(i, src);
- test = Qtrue;
- }
- }
- return test;
-}
-
-void
-rb_thread_schedule()
-{
- rb_thread_t next; /* OK */
- rb_thread_t th;
- rb_thread_t curr;
- int found = 0;
-
- fd_set readfds;
- fd_set writefds;
- fd_set exceptfds;
- struct timeval delay_tv, *delay_ptr;
- double delay, now; /* OK */
- int n, max;
- int need_select = 0;
- int select_timeout = 0;
-
- rb_thread_pending = 0;
- if (curr_thread == curr_thread->next
- && curr_thread->status == THREAD_RUNNABLE)
- return;
-
- next = 0;
- curr = curr_thread; /* starting thread */
-
- while (curr->status == THREAD_KILLED) {
- curr = curr->prev;
- }
-
- again:
- max = -1;
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_ZERO(&exceptfds);
- delay = DELAY_INFTY;
- now = -1.0;
-
- FOREACH_THREAD_FROM(curr, th) {
- if (!found && th->status <= THREAD_RUNNABLE) {
- found = 1;
- }
- if (th->status != THREAD_STOPPED) continue;
- if (th->wait_for & WAIT_JOIN) {
- if (rb_thread_dead(th->join)) {
- th->status = THREAD_RUNNABLE;
- found = 1;
- }
- }
- if (th->wait_for & WAIT_FD) {
- FD_SET(th->fd, &readfds);
- if (max < th->fd) max = th->fd;
- need_select = 1;
- }
- if (th->wait_for & WAIT_SELECT) {
- copy_fds(&readfds, &th->readfds, th->fd);
- copy_fds(&writefds, &th->writefds, th->fd);
- copy_fds(&exceptfds, &th->exceptfds, th->fd);
- if (max < th->fd) max = th->fd;
- need_select = 1;
- if (th->wait_for & WAIT_TIME) {
- select_timeout = 1;
- }
- th->select_value = 0;
- }
- if (th->wait_for & WAIT_TIME) {
- double th_delay;
-
- if (now < 0.0) now = timeofday();
- th_delay = th->delay - now;
- if (th_delay <= 0.0) {
- th->status = THREAD_RUNNABLE;
- found = 1;
- }
- else if (th_delay < delay) {
- delay = th_delay;
- need_select = 1;
- }
- else if (th->delay == DELAY_INFTY) {
- need_select = 1;
- }
- }
- }
- END_FOREACH_FROM(curr, th);
-
- /* Do the select if needed */
- if (need_select) {
- /* Convert delay to a timeval */
- /* If a thread is runnable, just poll */
- if (found) {
- delay_tv.tv_sec = 0;
- delay_tv.tv_usec = 0;
- delay_ptr = &delay_tv;
- }
- else if (delay == DELAY_INFTY) {
- delay_ptr = 0;
- }
- else {
- delay_tv.tv_sec = delay;
- delay_tv.tv_usec = (delay - (double)delay_tv.tv_sec)*1e6;
- delay_ptr = &delay_tv;
- }
-
- n = select(max+1, &readfds, &writefds, &exceptfds, delay_ptr);
- if (n < 0) {
- if (rb_trap_pending) rb_trap_exec();
- if (errno == EINTR) goto again;
- FOREACH_THREAD_FROM(curr, th) {
- if (th->wait_for & WAIT_SELECT) {
- int v = 0;
-
- v |= find_bad_fds(&readfds, &th->readfds, th->fd);
- v |= find_bad_fds(&writefds, &th->writefds, th->fd);
- v |= find_bad_fds(&exceptfds, &th->exceptfds, th->fd);
- if (v) {
- th->select_value = n;
- n = max;
- }
- }
- }
- END_FOREACH_FROM(curr, th);
- }
- if (select_timeout && n == 0) {
- if (now < 0.0) now = timeofday();
- FOREACH_THREAD_FROM(curr, th) {
- if (((th->wait_for&(WAIT_SELECT|WAIT_TIME)) == (WAIT_SELECT|WAIT_TIME)) &&
- th->delay <= now) {
- th->status = THREAD_RUNNABLE;
- th->wait_for = 0;
- th->select_value = 0;
- found = 1;
- intersect_fds(&readfds, &th->readfds, max);
- intersect_fds(&writefds, &th->writefds, max);
- intersect_fds(&exceptfds, &th->exceptfds, max);
- }
- }
- END_FOREACH_FROM(curr, th);
- }
- if (n > 0) {
- now = -1.0;
- /* Some descriptors are ready.
- Make the corresponding threads runnable. */
- FOREACH_THREAD_FROM(curr, th) {
- if ((th->wait_for&WAIT_FD) && FD_ISSET(th->fd, &readfds)) {
- /* Wake up only one thread per fd. */
- FD_CLR(th->fd, &readfds);
- th->status = THREAD_RUNNABLE;
- th->fd = 0;
- th->wait_for = 0;
- found = 1;
- }
- if ((th->wait_for&WAIT_SELECT) &&
- (match_fds(&readfds, &th->readfds, max) ||
- match_fds(&writefds, &th->writefds, max) ||
- match_fds(&exceptfds, &th->exceptfds, max))) {
- /* Wake up only one thread per fd. */
- th->status = THREAD_RUNNABLE;
- th->wait_for = 0;
- n = intersect_fds(&readfds, &th->readfds, max) +
- intersect_fds(&writefds, &th->writefds, max) +
- intersect_fds(&exceptfds, &th->exceptfds, max);
- th->select_value = n;
- found = 1;
- }
- }
- END_FOREACH_FROM(curr, th);
- }
- /* The delays for some of the threads should have expired.
- Go through the loop once more, to check the delays. */
- if (!found && delay != DELAY_INFTY)
- goto again;
- }
-
- FOREACH_THREAD_FROM(curr, th) {
- if (th->status == THREAD_TO_KILL) {
- next = th;
- break;
- }
- if (th->status == THREAD_RUNNABLE && th->stk_ptr) {
- if (!next || next->priority < th->priority)
- next = th;
- }
- }
- END_FOREACH_FROM(curr, th);
-
- if (!next) {
- /* raise fatal error to main thread */
- curr_thread->file = ruby_sourcefile;
- curr_thread->line = ruby_sourceline;
- FOREACH_THREAD_FROM(curr, th) {
- fprintf(stderr, "deadlock 0x%lx: %d:%d %s - %s:%d\n",
- th->thread, th->status,
- th->wait_for, th==main_thread ? "(main)" : "",
- th->file, th->line);
- }
- END_FOREACH_FROM(curr, th);
- next = main_thread;
- next->gid = 0;
- rb_thread_ready(next);
- next->status = THREAD_TO_KILL;
- rb_thread_save_context(curr_thread);
- rb_thread_deadlock();
- }
- next->wait_for = 0;
- if (next->status == THREAD_RUNNABLE && next == curr_thread) {
- return;
- }
-
- /* context switch */
- if (curr == curr_thread) {
- if (THREAD_SAVE_CONTEXT(curr)) {
- return;
- }
- }
-
- curr_thread = next;
- if (next->status == THREAD_TO_KILL) {
- if (!(next->flags & THREAD_TERMINATING)) {
- next->flags |= THREAD_TERMINATING;
- /* terminate; execute ensure-clause if any */
- rb_thread_restore_context(next, RESTORE_FATAL);
- }
- }
- rb_thread_restore_context(next, RESTORE_NORMAL);
-}
-
-void
-rb_thread_wait_fd(fd)
- int fd;
-{
- if (rb_thread_critical) return;
- if (curr_thread == curr_thread->next) return;
- if (curr_thread->status == THREAD_TO_KILL) return;
-
- curr_thread->status = THREAD_STOPPED;
- curr_thread->fd = fd;
- curr_thread->wait_for = WAIT_FD;
- rb_thread_schedule();
-}
-
-int
-rb_thread_fd_writable(fd)
- int fd;
-{
- if (rb_thread_critical) return Qtrue;
- if (curr_thread == curr_thread->next) return Qtrue;
- if (curr_thread->status == THREAD_TO_KILL) return Qtrue;
-
- curr_thread->status = THREAD_STOPPED;
- FD_ZERO(&curr_thread->readfds);
- FD_ZERO(&curr_thread->writefds);
- FD_SET(fd, &curr_thread->writefds);
- FD_ZERO(&curr_thread->exceptfds);
- curr_thread->fd = fd+1;
- curr_thread->wait_for = WAIT_SELECT;
- rb_thread_schedule();
- return Qfalse;
-}
-
-void
-rb_thread_wait_for(time)
- struct timeval time;
-{
- double date;
-
- if (rb_thread_critical ||
- curr_thread == curr_thread->next ||
- curr_thread->status == THREAD_TO_KILL) {
- int n;
-#ifndef linux
- double d, limit;
- limit = timeofday()+(double)time.tv_sec+(double)time.tv_usec*1e-6;
-#endif
- for (;;) {
- TRAP_BEG;
- n = select(0, 0, 0, 0, &time);
- TRAP_END;
- if (n == 0) return;
- if (n < 0) {
- switch (errno) {
- case EINTR:
-#ifdef ERESTART
- case ERESTART:
-#endif
- return;
- default:
- rb_sys_fail("sleep");
- }
- }
-#ifndef linux
- d = limit - timeofday();
-
- time.tv_sec = (int)d;
- time.tv_usec = (int)((d - (int)d)*1e6);
- if (time.tv_usec < 0) {
- time.tv_usec += (long)1e6;
- time.tv_sec -= 1;
- }
- if (time.tv_sec < 0) return;
-#endif
- }
- }
-
- date = timeofday() + (double)time.tv_sec + (double)time.tv_usec*1e-6;
- curr_thread->status = THREAD_STOPPED;
- curr_thread->delay = date;
- curr_thread->wait_for = WAIT_TIME;
- rb_thread_schedule();
-}
-
-void rb_thread_sleep_forever _((void));
-
-int
-rb_thread_alone()
-{
- return curr_thread == curr_thread->next;
-}
-
-int
-rb_thread_select(max, read, write, except, timeout)
- int max;
- fd_set *read, *write, *except;
- struct timeval *timeout;
-{
- double limit;
- int n;
-
- if (!read && !write && !except) {
- if (!timeout) {
- rb_thread_sleep_forever();
- return 0;
- }
- rb_thread_wait_for(*timeout);
- return 0;
- }
-
- if (timeout) {
- limit = timeofday()+
- (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
- }
-
- if (rb_thread_critical ||
- curr_thread == curr_thread->next ||
- curr_thread->status == THREAD_TO_KILL) {
-#ifndef linux
- struct timeval tv, *tvp = timeout;
-
- if (timeout) {
- tv = *timeout;
- tvp = &tv;
- }
- for (;;) {
- TRAP_BEG;
- n = select(max, read, write, except, tvp);
- TRAP_END;
- if (n < 0) {
- switch (errno) {
- case EINTR:
-#ifdef ERESTART
- case ERESTART:
-#endif
- if (timeout) {
- double d = limit - timeofday();
-
- tv.tv_sec = (unsigned int)d;
- tv.tv_usec = (long)((d-(double)tv.tv_sec)*1e6);
- if (tv.tv_sec < 0) tv.tv_sec = 0;
- if (tv.tv_usec < 0) tv.tv_usec = 0;
- }
- continue;
- default:
- break;
- }
- }
- return n;
- }
-#else
- for (;;) {
- TRAP_BEG;
- n = select(max, read, write, except, timeout);
- TRAP_END;
- if (n < 0) {
- switch (errno) {
- case EINTR:
-#ifdef ERESTART
- case ERESTART:
-#endif
- continue;
- }
- }
- return n;
- }
-#endif
-
- }
-
- curr_thread->status = THREAD_STOPPED;
- if (read) curr_thread->readfds = *read;
- else FD_ZERO(&curr_thread->readfds);
- if (write) curr_thread->writefds = *write;
- else FD_ZERO(&curr_thread->writefds);
- if (except) curr_thread->exceptfds = *except;
- else FD_ZERO(&curr_thread->exceptfds);
- curr_thread->fd = max;
- curr_thread->wait_for = WAIT_SELECT;
- if (timeout) {
- curr_thread->delay = timeofday() +
- (double)timeout->tv_sec + (double)timeout->tv_usec*1e-6;
- curr_thread->wait_for |= WAIT_TIME;
- }
- rb_thread_schedule();
- if (read) *read = curr_thread->readfds;
- if (write) *write = curr_thread->writefds;
- if (except) *except = curr_thread->exceptfds;
- return curr_thread->select_value;
-}
-
-static VALUE
-rb_thread_join(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
- enum thread_status last_status = THREAD_RUNNABLE;
-
- if (rb_thread_critical) rb_thread_deadlock();
- if (!rb_thread_dead(th)) {
- if (th == curr_thread)
- rb_raise(rb_eThreadError, "thread tried to join itself");
- if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread)
- rb_raise(rb_eThreadError, "Thread#join: deadlock - mutual join");
- if (curr_thread->status == THREAD_TO_KILL)
- last_status = THREAD_TO_KILL;
- curr_thread->status = THREAD_STOPPED;
- curr_thread->join = th;
- curr_thread->wait_for = WAIT_JOIN;
- rb_thread_schedule();
- curr_thread->status = last_status;
- }
-
- if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED)) {
- VALUE oldbt = get_backtrace(th->errinfo);
- VALUE errat = make_backtrace();
-
- if (TYPE(oldbt) == T_ARRAY && RARRAY(oldbt)->len > 0) {
- rb_ary_unshift(errat, rb_ary_entry(oldbt, 0));
- }
- set_backtrace(th->errinfo, errat);
- rb_exc_raise(th->errinfo);
- }
-
- return thread;
-}
-
-VALUE
-rb_thread_current()
-{
- return curr_thread->thread;
-}
-
-VALUE
-rb_thread_main()
-{
- return main_thread->thread;
-}
-
-VALUE
-rb_thread_list()
-{
- rb_thread_t th;
- VALUE ary = rb_ary_new();
-
- FOREACH_THREAD(th) {
- switch (th->status) {
- case THREAD_RUNNABLE:
- case THREAD_STOPPED:
- rb_ary_push(ary, th->thread);
- default:
- break;
- }
- }
- END_FOREACH(th);
-
- return ary;
-}
-
-VALUE
-rb_thread_wakeup(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (th->status == THREAD_KILLED)
- rb_raise(rb_eThreadError, "killed thread");
- rb_thread_ready(th);
-
- return thread;
-}
-
-VALUE
-rb_thread_run(thread)
- VALUE thread;
-{
- rb_thread_wakeup(thread);
- if (!rb_thread_critical) rb_thread_schedule();
-
- return thread;
-}
-
-static VALUE
-rb_thread_kill(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (th != curr_thread && th->safe < 4) {
- rb_secure(4);
- }
- if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
- return thread;
- if (th == th->next || th == main_thread) rb_exit(0);
-
- rb_thread_ready(th);
- th->gid = 0;
- th->status = THREAD_TO_KILL;
- if (!rb_thread_critical) rb_thread_schedule();
- return thread;
-}
-
-static VALUE
-rb_thread_s_kill(obj, th)
- VALUE obj, th;
-{
- return rb_thread_kill(th);
-}
-
-static VALUE
-rb_thread_exit()
-{
- return rb_thread_kill(curr_thread->thread);
-}
-
-static VALUE
-rb_thread_pass()
-{
- rb_thread_schedule();
- return Qnil;
-}
-
-VALUE
-rb_thread_stop()
-{
- enum thread_status last_status = THREAD_RUNNABLE;
-
- rb_thread_critical = 0;
- if (curr_thread == curr_thread->next) {
- rb_raise(rb_eThreadError, "stopping only thread\n\tnote: use sleep to stop forever");
- }
- if (curr_thread->status == THREAD_TO_KILL)
- last_status = THREAD_TO_KILL;
- curr_thread->status = THREAD_STOPPED;
- rb_thread_schedule();
- curr_thread->status = last_status;
-
- return Qnil;
-}
-
-struct timeval rb_time_timeval();
-
-void
-rb_thread_polling()
-{
- if (curr_thread != curr_thread->next) {
- curr_thread->status = THREAD_STOPPED;
- curr_thread->delay = timeofday() + (double)0.06;
- curr_thread->wait_for = WAIT_TIME;
- rb_thread_schedule();
- }
-}
-
-void
-rb_thread_sleep(sec)
- int sec;
-{
- if (curr_thread == curr_thread->next) {
- TRAP_BEG;
- sleep(sec);
- TRAP_END;
- return;
- }
- rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
-}
-
-#if !defined HAVE_PAUSE
-# if defined _WIN32 && !defined __CYGWIN__
-# define pause() Sleep(INFINITE)
-# else
-# define pause() sleep(0x7fffffff)
-# endif
-#endif
-
-void
-rb_thread_sleep_forever()
-{
- if (curr_thread == curr_thread->next ||
- curr_thread->status == THREAD_TO_KILL) {
- TRAP_BEG;
- pause();
- TRAP_END;
- return;
- }
-
- curr_thread->delay = DELAY_INFTY;
- curr_thread->wait_for = WAIT_TIME;
- curr_thread->status = THREAD_STOPPED;
- rb_thread_schedule();
-}
-
-static VALUE
-rb_thread_priority(thread)
- VALUE thread;
-{
- return INT2NUM(rb_thread_check(thread)->priority);
-}
-
-static VALUE
-rb_thread_priority_set(thread, prio)
- VALUE thread, prio;
-{
- rb_thread_t th;
-
- rb_secure(4);
- th = rb_thread_check(thread);
-
- th->priority = NUM2INT(prio);
- rb_thread_schedule();
- return prio;
-}
-
-static VALUE
-rb_thread_safe_level(thread)
- VALUE thread;
-{
- rb_thread_t th;
-
- th = rb_thread_check(thread);
- if (th == curr_thread) {
- return INT2NUM(rb_safe_level());
- }
- return INT2NUM(th->safe);
-}
-
-static int thread_abort;
-
-static VALUE
-rb_thread_s_abort_exc()
-{
- return thread_abort?Qtrue:Qfalse;
-}
-
-static VALUE
-rb_thread_s_abort_exc_set(self, val)
- VALUE self, val;
-{
- rb_secure(4);
- thread_abort = RTEST(val);
- return val;
-}
-
-static VALUE
-rb_thread_abort_exc(thread)
- VALUE thread;
-{
- return rb_thread_check(thread)->abort?Qtrue:Qfalse;
-}
-
-static VALUE
-rb_thread_abort_exc_set(thread, val)
- VALUE thread, val;
-{
- rb_secure(4);
- rb_thread_check(thread)->abort = RTEST(val);
- return val;
-}
-
-#define THREAD_ALLOC(th) do {\
- th = ALLOC(struct thread);\
-\
- th->next = 0;\
- th->prev = 0;\
-\
- th->status = THREAD_RUNNABLE;\
- th->result = 0;\
- th->flags = 0;\
-\
- th->stk_ptr = 0;\
- th->stk_len = 0;\
- th->stk_max = 0;\
- th->wait_for = 0;\
- FD_ZERO(&th->readfds);\
- FD_ZERO(&th->writefds);\
- FD_ZERO(&th->exceptfds);\
- th->delay = 0.0;\
- th->join = 0;\
-\
- th->frame = 0;\
- th->scope = 0;\
- th->klass = 0;\
- th->wrapper = 0;\
- th->cref = ruby_cref;\
- th->dyna_vars = ruby_dyna_vars;\
- th->block = 0;\
- th->iter = 0;\
- th->tag = 0;\
- th->tracing = 0;\
- th->errinfo = Qnil;\
- th->last_status = 0;\
- th->last_line = 0;\
- th->last_match = Qnil;\
- th->abort = 0;\
- th->priority = 0;\
- th->gid = 1;\
- th->locals = 0;\
-} while(0)
-
-static rb_thread_t
-rb_thread_alloc(klass)
- VALUE klass;
-{
- rb_thread_t th;
- struct RVarmap *vars;
-
- THREAD_ALLOC(th);
- th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th);
-
- for (vars = th->dyna_vars; vars; vars = vars->next) {
- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
- FL_SET(vars, DVAR_DONT_RECYCLE);
- }
- return th;
-}
-
-#if defined(HAVE_SETITIMER)
-static void
-catch_timer(sig)
- int sig;
-{
-#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
- signal(sig, catch_timer);
-#endif
- if (!rb_thread_critical) {
- if (rb_trap_immediate) {
- rb_thread_schedule();
- }
- else rb_thread_pending = 1;
- }
-}
-#else
-int rb_thread_tick = THREAD_TICK;
-#endif
-
-#if defined(HAVE_SETITIMER)
-static int thread_init = 0;
-
-void
-rb_thread_start_timer()
-{
- struct itimerval tval;
-
- if (!thread_init) return;
- tval.it_interval.tv_sec = 0;
- tval.it_interval.tv_usec = 10000;
- tval.it_value = tval.it_interval;
- setitimer(ITIMER_VIRTUAL, &tval, NULL);
-}
-
-void
-rb_thread_stop_timer()
-{
- struct itimerval tval;
-
- if (!thread_init) return;
- tval.it_interval.tv_sec = 0;
- tval.it_interval.tv_usec = 0;
- tval.it_value = tval.it_interval;
- setitimer(ITIMER_VIRTUAL, &tval, NULL);
-}
-#endif
-
-static VALUE
-rb_thread_start_0(fn, arg, th_arg)
- VALUE (*fn)();
- void *arg;
- rb_thread_t th_arg;
-{
- volatile rb_thread_t th = th_arg;
- volatile VALUE thread = th->thread;
- struct BLOCK* saved_block = 0;
- enum thread_status status;
- int state;
-
-#if defined(HAVE_SETITIMER)
- if (!thread_init) {
-#ifdef POSIX_SIGNAL
- posix_signal(SIGVTALRM, catch_timer);
-#else
- signal(SIGVTALRM, catch_timer);
-#endif
-
- thread_init = 1;
- rb_thread_start_timer();
- }
-#endif
-
- if (THREAD_SAVE_CONTEXT(curr_thread)) {
- return thread;
- }
-
- if (ruby_block) { /* should nail down higher blocks */
- struct BLOCK dummy;
-
- dummy.prev = ruby_block;
- blk_copy_prev(&dummy);
- saved_block = ruby_block = dummy.prev;
- }
- scope_dup(ruby_scope);
-
- if (!th->next) {
- /* merge in thread list */
- th->prev = curr_thread;
- curr_thread->next->prev = th;
- th->next = curr_thread->next;
- curr_thread->next = th;
- th->priority = curr_thread->priority;
- th->gid = curr_thread->gid;
- }
-
- PUSH_TAG(PROT_THREAD);
- if ((state = EXEC_TAG()) == 0) {
- if (THREAD_SAVE_CONTEXT(th) == 0) {
- curr_thread = th;
- th->result = (*fn)(arg, th);
- }
- }
- POP_TAG();
- status = th->status;
-
- if (th == main_thread) ruby_stop(state);
- rb_thread_remove(th);
-
- while (saved_block) {
- struct BLOCK *tmp = saved_block;
-
- if (tmp->frame.argc > 0)
- free(tmp->frame.argv);
- saved_block = tmp->prev;
- free(tmp);
- }
-
- if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) {
- th->flags |= THREAD_RAISED;
- if (state == TAG_FATAL) {
- /* fatal error within this thread, need to stop whole script */
- main_thread->errinfo = ruby_errinfo;
- rb_thread_cleanup();
- }
- else if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
- if (th->safe >= 4) {
- char buf[32];
-
- sprintf(buf, "Insecure exit at level %d", th->safe);
- th->errinfo = rb_exc_new2(rb_eSecurityError, buf);
- }
- else {
- /* delegate exception to main_thread */
- rb_thread_raise(1, &ruby_errinfo, main_thread);
- }
- }
- else if (th->safe < 4 && (thread_abort || th->abort || RTEST(ruby_debug))) {
- VALUE err = rb_exc_new(rb_eSystemExit, 0, 0);
- error_print();
- /* exit on main_thread */
- rb_thread_raise(1, &err, main_thread);
- }
- else {
- th->errinfo = ruby_errinfo;
- }
- }
- rb_thread_schedule();
- return 0; /* not reached */
-}
-
-VALUE
-rb_thread_create(fn, arg)
- VALUE (*fn)();
- void *arg;
-{
- return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
-}
-
-static VALUE
-rb_thread_yield(arg, th)
- VALUE arg;
- rb_thread_t th;
-{
- const ID *tbl;
-
- scope_dup(ruby_block->scope);
-
- tbl = ruby_scope->local_tbl;
- if (tbl) {
- int n = *tbl++;
- for (tbl += 2, n -= 2; n > 0; --n) { /* skip first 2 ($_ and $~) */
- ID id = *tbl++;
- if (id != 0 && !rb_is_local_id(id)) /* push flip states */
- rb_dvar_push(id, Qfalse);
- }
- }
- rb_dvar_push('_', Qnil);
- rb_dvar_push('~', Qnil);
- ruby_block->dyna_vars = ruby_dyna_vars;
-
- return rb_yield_0(mvalue_to_svalue(arg), 0, 0, Qtrue);
-}
-
-static VALUE
-rb_thread_s_new(argc, argv, klass)
- int argc;
- VALUE *argv;
- VALUE klass;
-{
- rb_thread_t th = rb_thread_alloc(klass);
- volatile VALUE *pos;
-
- pos = th->stk_pos;
- rb_obj_call_init(th->thread, argc, argv);
- if (th->stk_pos == 0) {
- rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
- rb_class2name(klass));
- }
-
- return th->thread;
-}
-
-static VALUE
-rb_thread_initialize(thread, args)
- VALUE thread, args;
-{
- if (!rb_block_given_p()) {
- rb_raise(rb_eThreadError, "must be called with a block");
- }
- return rb_thread_start_0(rb_thread_yield, args, rb_thread_check(thread));
-}
-
-static VALUE
-rb_thread_start(klass, args)
- VALUE klass, args;
-{
- if (!rb_block_given_p()) {
- rb_raise(rb_eThreadError, "must be called with a block");
- }
- return rb_thread_start_0(rb_thread_yield, args, rb_thread_alloc(klass));
-}
-
-static VALUE
-rb_thread_value(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- rb_thread_join(thread);
-
- return th->result;
-}
-
-static VALUE
-rb_thread_status(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (rb_thread_dead(th)) {
- if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED))
- return Qnil;
- return Qfalse;
- }
-
- return rb_str_new2(thread_status_name(th->status));
-}
-
-static VALUE
-rb_thread_alive_p(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (rb_thread_dead(th)) return Qfalse;
- return Qtrue;
-}
-
-static VALUE
-rb_thread_stop_p(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (rb_thread_dead(th)) return Qtrue;
- if (th->status == THREAD_STOPPED) return Qtrue;
- return Qfalse;
-}
-
-static void
-rb_thread_wait_other_threads()
-{
- rb_thread_t th;
- int found;
-
- /* wait other threads to terminate */
- while (curr_thread != curr_thread->next) {
- found = 0;
- FOREACH_THREAD(th) {
- if (th != curr_thread && th->status != THREAD_STOPPED) {
- found = 1;
- break;
- }
- }
- END_FOREACH(th);
- if (!found) return;
- rb_thread_schedule();
- }
-}
-
-static void
-rb_thread_cleanup()
-{
- rb_thread_t th;
-
- while (curr_thread->status == THREAD_KILLED) {
- curr_thread = curr_thread->prev;
- }
-
- FOREACH_THREAD(th) {
- if (th != curr_thread && th->status != THREAD_KILLED) {
- rb_thread_ready(th);
- th->gid = 0;
- th->priority = 0;
- th->status = THREAD_TO_KILL;
- RDATA(th->thread)->dfree = NULL;
- }
- }
- END_FOREACH(th);
-}
-
-int rb_thread_critical;
-
-static VALUE
-rb_thread_critical_get()
-{
- return rb_thread_critical?Qtrue:Qfalse;
-}
-
-static VALUE
-rb_thread_critical_set(obj, val)
- VALUE obj, val;
-{
- rb_thread_critical = RTEST(val);
- return val;
-}
-
-void
-rb_thread_interrupt()
-{
- rb_thread_critical = 0;
- rb_thread_ready(main_thread);
- if (curr_thread == main_thread) {
- rb_interrupt();
- }
- if (THREAD_SAVE_CONTEXT(curr_thread)) {
- return;
- }
- curr_thread = main_thread;
- rb_thread_restore_context(curr_thread, RESTORE_INTERRUPT);
-}
-
-void
-rb_thread_signal_raise(sig)
- char *sig;
-{
- if (sig == 0) return; /* should not happen */
- rb_thread_critical = 0;
- if (curr_thread == main_thread) {
- rb_thread_ready(curr_thread);
- rb_raise(rb_eSignal, "SIG%s", sig);
- }
- rb_thread_ready(main_thread);
- if (THREAD_SAVE_CONTEXT(curr_thread)) {
- return;
- }
- th_signm = sig;
- curr_thread = main_thread;
- rb_thread_restore_context(curr_thread, RESTORE_SIGNAL);
-}
-
-void
-rb_thread_trap_eval(cmd, sig)
- VALUE cmd;
- int sig;
-{
-#if 0
- rb_thread_critical = 0;
- if (!rb_thread_dead(curr_thread)) {
- rb_thread_ready(curr_thread);
- rb_trap_eval(cmd, sig);
- return;
- }
- rb_thread_ready(main_thread);
- if (THREAD_SAVE_CONTEXT(curr_thread)) {
- return;
- }
- th_cmd = cmd;
- th_sig = sig;
- curr_thread = main_thread;
- rb_thread_restore_context(curr_thread, RESTORE_TRAP);
-#else
- rb_thread_critical = 0;
- if (!rb_thread_dead(curr_thread)) {
- if (THREAD_SAVE_CONTEXT(curr_thread)) {
- return;
- }
- }
- rb_thread_ready(main_thread);
- th_cmd = cmd;
- th_sig = sig;
- curr_thread = main_thread;
- rb_thread_restore_context(curr_thread, RESTORE_TRAP);
-#endif
-}
-
-static VALUE
-rb_thread_raise(argc, argv, th)
- int argc;
- VALUE *argv;
- rb_thread_t th;
-{
- if (rb_thread_dead(th)) return Qnil;
- if (curr_thread == th) {
- rb_f_raise(argc, argv);
- }
-
- if (THREAD_SAVE_CONTEXT(curr_thread)) {
- return th->thread;
- }
-
- rb_scan_args(argc, argv, "11", &th_raise_argv[0], &th_raise_argv[1]);
- rb_thread_ready(th);
- curr_thread = th;
-
- th_raise_argc = argc;
- th_raise_file = ruby_sourcefile;
- th_raise_line = ruby_sourceline;
- rb_thread_restore_context(curr_thread, RESTORE_RAISE);
- return Qnil; /* not reached */
-}
-
-static VALUE
-rb_thread_raise_m(argc, argv, thread)
- int argc;
- VALUE *argv;
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (ruby_safe_level > th->safe) {
- rb_secure(4);
- }
- rb_thread_raise(argc, argv, th);
- return Qnil; /* not reached */
-}
-
-VALUE
-rb_thread_local_aref(thread, id)
- VALUE thread;
- ID id;
-{
- rb_thread_t th;
- VALUE val;
-
- th = rb_thread_check(thread);
- if (rb_safe_level() >= 4 && th != curr_thread) {
- rb_raise(rb_eSecurityError, "Insecure: thread locals");
- }
- if (!th->locals) return Qnil;
- if (st_lookup(th->locals, id, &val)) {
- return val;
- }
- return Qnil;
-}
-
-static VALUE
-rb_thread_aref(thread, id)
- VALUE thread, id;
-{
- return rb_thread_local_aref(thread, rb_to_id(id));
-}
-
-VALUE
-rb_thread_local_aset(thread, id, val)
- VALUE thread;
- ID id;
- VALUE val;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (rb_safe_level() >= 4 && th != curr_thread) {
- rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
- }
- if (OBJ_FROZEN(thread)) rb_error_frozen("thread locals");
-
- if (!th->locals) {
- th->locals = st_init_numtable();
- }
- if (NIL_P(val)) {
- st_delete(th->locals, &id, 0);
- return Qnil;
- }
- st_insert(th->locals, id, val);
-
- return val;
-}
-
-static VALUE
-rb_thread_aset(thread, id, val)
- VALUE thread, id, val;
-{
- return rb_thread_local_aset(thread, rb_to_id(id), val);
-}
-
-static VALUE
-rb_thread_key_p(thread, id)
- VALUE thread, id;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (!th->locals) return Qfalse;
- if (st_lookup(th->locals, rb_to_id(id), 0))
- return Qtrue;
- return Qfalse;
-}
-
-static int
-thread_keys_i(key, value, ary)
- ID key;
- VALUE value, ary;
-{
- rb_ary_push(ary, ID2SYM(key));
- return ST_CONTINUE;
-}
-
-static VALUE
-rb_thread_keys(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
- VALUE ary = rb_ary_new();
-
- if (th->locals) {
- st_foreach(th->locals, thread_keys_i, ary);
- }
- return ary;
-}
-
-static VALUE
-rb_thread_inspect(thread)
- VALUE thread;
-{
- char *cname = rb_class2name(CLASS_OF(thread));
- rb_thread_t th = rb_thread_check(thread);
- const char *status = thread_status_name(th->status);
- VALUE str;
-
- str = rb_str_new(0, strlen(cname)+7+16+9+1); /* 7:tags 16:addr 9:status 1:nul */
- sprintf(RSTRING(str)->ptr, "#<%s:0x%lx %s>", cname, thread, status);
- RSTRING(str)->len = strlen(RSTRING(str)->ptr);
- OBJ_INFECT(str, thread);
-
- return str;
-}
-
-void
-rb_thread_atfork()
-{
-#if 1 /* enable on 1.7 */
- rb_thread_t th;
-
- if (rb_thread_alone()) return;
- FOREACH_THREAD(th) {
- if (th != curr_thread) {
- th->status = THREAD_KILLED;
- }
- }
- END_FOREACH(th);
- main_thread = curr_thread;
- curr_thread->next = curr_thread;
- curr_thread->prev = curr_thread;
-#endif
-}
-
-static VALUE rb_cCont;
-
-static VALUE
-rb_callcc(self)
- VALUE self;
-{
- volatile VALUE cont;
- rb_thread_t th;
- struct tag *tag;
- struct RVarmap *vars;
-
- THREAD_ALLOC(th);
- cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th);
-
- scope_dup(ruby_scope);
- for (tag=prot_tag; tag; tag=tag->prev) {
- scope_dup(tag->scope);
- }
- if (ruby_block) {
- struct BLOCK *block = ruby_block;
-
- while (block) {
- block->tag->flags |= BLOCK_DYNAMIC;
- block = block->prev;
- }
- }
- th->thread = curr_thread->thread;
-
- for (vars = th->dyna_vars; vars; vars = vars->next) {
- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
- FL_SET(vars, DVAR_DONT_RECYCLE);
- }
-
- if (THREAD_SAVE_CONTEXT(th)) {
- return th->result;
- }
- else {
- return rb_yield(cont);
- }
-}
-
-static VALUE
-rb_cont_call(argc, argv, cont)
- int argc;
- VALUE *argv;
- VALUE cont;
-{
- rb_thread_t th = rb_thread_check(cont);
-
- if (th->thread != curr_thread->thread) {
- rb_raise(rb_eRuntimeError, "continuation called across threads");
- }
- switch (argc) {
- case 0:
- th->result = Qnil;
- break;
- case 1:
- th->result = *argv;
- break;
- default:
- th->result = rb_ary_new4(argc, argv);
- break;
- }
-
- rb_thread_restore_context(th, RESTORE_NORMAL);
- return Qnil;
-}
-
-struct thgroup {
- int gid;
-};
-
-static VALUE
-thgroup_s_alloc(klass)
- VALUE klass;
-{
- VALUE group;
- struct thgroup *data;
- static int serial = 1;
-
- group = Data_Make_Struct(klass, struct thgroup, 0, free, data);
- data->gid = serial++;
-
- return group;
-}
-
-static VALUE
-thgroup_list(group)
- VALUE group;
-{
- struct thgroup *data;
- rb_thread_t th;
- VALUE ary;
-
- Data_Get_Struct(group, struct thgroup, data);
- ary = rb_ary_new();
-
- FOREACH_THREAD(th) {
- if (th->gid == data->gid) {
- rb_ary_push(ary, th->thread);
- }
- }
- END_FOREACH(th);
-
- return ary;
-}
-
-static VALUE
-thgroup_add(group, thread)
- VALUE group, thread;
-{
- rb_thread_t th;
- struct thgroup *data;
-
- rb_secure(4);
- th = rb_thread_check(thread);
- Data_Get_Struct(group, struct thgroup, data);
-
- th->gid = data->gid;
- return group;
-}
-
-void
-Init_Thread()
-{
- VALUE cThGroup;
-
- rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
- rb_cThread = rb_define_class("Thread", rb_cObject);
- rb_undef_method(CLASS_OF(rb_cThread), "allocate");
-
- rb_define_singleton_method(rb_cThread, "new", rb_thread_s_new, -1);
- rb_define_method(rb_cThread, "initialize", rb_thread_initialize, -2);
- rb_define_singleton_method(rb_cThread, "start", rb_thread_start, -2);
- rb_define_singleton_method(rb_cThread, "fork", rb_thread_start, -2);
-
- rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
- rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
- rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
- rb_define_singleton_method(rb_cThread, "pass", rb_thread_pass, 0);
- rb_define_singleton_method(rb_cThread, "current", rb_thread_current, 0);
- rb_define_singleton_method(rb_cThread, "main", rb_thread_main, 0);
- rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0);
-
- rb_define_singleton_method(rb_cThread, "critical", rb_thread_critical_get, 0);
- rb_define_singleton_method(rb_cThread, "critical=", rb_thread_critical_set, 1);
-
- rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
- rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
-
- rb_define_method(rb_cThread, "run", rb_thread_run, 0);
- rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
- rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
- rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
- rb_define_method(rb_cThread, "value", rb_thread_value, 0);
- rb_define_method(rb_cThread, "status", rb_thread_status, 0);
- rb_define_method(rb_cThread, "join", rb_thread_join, 0);
- rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
- rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
- rb_define_method(rb_cThread, "raise", rb_thread_raise_m, -1);
-
- rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
- rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
-
- rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
- rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
- rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
-
- rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
- rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
- rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
- rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
-
- rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
-
- /* allocate main thread */
- main_thread = rb_thread_alloc(rb_cThread);
- curr_thread = main_thread->prev = main_thread->next = main_thread;
-
- rb_cCont = rb_define_class("Continuation", rb_cObject);
- rb_undef_method(CLASS_OF(rb_cCont), "allocate");
- rb_undef_method(CLASS_OF(rb_cCont), "new");
- rb_define_method(rb_cCont, "call", rb_cont_call, -1);
- rb_define_global_function("callcc", rb_callcc, 0);
-
- cThGroup = rb_define_class("ThreadGroup", rb_cObject);
- rb_define_singleton_method(cThGroup, "allocate", thgroup_s_alloc, 0);
- rb_define_method(cThGroup, "list", thgroup_list, 0);
- rb_define_method(cThGroup, "add", thgroup_add, 1);
- rb_define_const(cThGroup, "Default", rb_obj_alloc(cThGroup));
-}
-
-static VALUE
-rb_f_catch(dmy, tag)
- VALUE dmy, tag;
-{
- int state;
- ID t;
- VALUE val; /* OK */
-
- t = rb_to_id(tag);
- PUSH_TAG(t);
- if ((state = EXEC_TAG()) == 0) {
- val = rb_yield_0(tag, 0, 0, 0);
- }
- else if (state == TAG_THROW && t == prot_tag->dst) {
- val = prot_tag->retval;
- state = 0;
- }
- POP_TAG();
- if (state) JUMP_TAG(state);
-
- return val;
-}
-
-static VALUE
-catch_i(tag)
- ID tag;
-{
- return rb_funcall(Qnil, rb_intern("catch"), 1, ID2SYM(tag));
-}
-
-VALUE
-rb_catch(tag, proc, data)
- const char *tag;
- VALUE (*proc)();
- VALUE data;
-{
- return rb_iterate((VALUE(*)_((VALUE)))catch_i, rb_intern(tag), proc, data);
-}
-
-static VALUE
-rb_f_throw(argc, argv)
- int argc;
- VALUE *argv;
-{
- VALUE tag, value;
- ID t;
- struct tag *tt = prot_tag;
-
- rb_scan_args(argc, argv, "11", &tag, &value);
- t = rb_to_id(tag);
-
- while (tt) {
- if (tt->tag == t) {
- tt->dst = t;
- break;
- }
- if (tt->tag == PROT_THREAD) {
- rb_raise(rb_eThreadError, "uncaught throw `%s' in thread 0x%x",
- rb_id2name(t),
- curr_thread);
- }
- tt = tt->prev;
- }
- if (!tt) {
- rb_name_error(t, "uncaught throw `%s'", rb_id2name(t));
- }
- return_value(value);
- rb_trap_restore_mask();
- JUMP_TAG(TAG_THROW);
-}
-
-void
-rb_throw(tag, val)
- const char *tag;
- VALUE val;
-{
- VALUE argv[2];
- ID t = rb_intern(tag);
-
- argv[0] = ID2SYM(t);
- argv[1] = val;
- rb_f_throw(2, argv);
-}
-
-static void
-return_check()
-{
- struct tag *tt = prot_tag;
-
- while (tt) {
- if (tt->tag == PROT_FUNC) {
- break;
- }
- if (tt->tag == PROT_THREAD) {
- rb_raise(rb_eThreadError, "return from within thread 0x%x",
- curr_thread);
- }
- tt = tt->prev;
- }
-}