/**********************************************************************
eval.c -
$Author$
$Date$
created at: Thu Jun 10 14:22:17 JST 1993
Copyright (C) 1993-2003 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"
#ifdef __APPLE__
#include <crt_externs.h>
#endif
/* Make alloca work the best possible way. */
#ifdef __GNUC__
# ifndef atarist
# ifndef alloca
# define alloca __builtin_alloca
# endif
# endif /* atarist */
#else
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
void *alloca ();
# endif
# endif /* AIX */
# endif /* HAVE_ALLOCA_H */
#endif /* __GNUC__ */
#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>
#include <signal.h>
#include <errno.h>
#if defined(__VMS)
#pragma nostandard
#endif
#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,VALUE,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_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) (scope_vmode=(f))
#define SCOPE_TEST(f) (scope_vmode&(f))
NODE* ruby_current_node;
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_secure_update(obj)
VALUE obj;
{
if (!OBJ_TAINTED(obj)) rb_secure(4);
}
void
rb_check_safe_obj(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);
}
void
rb_check_safe_str(x)
VALUE x;
{
rb_check_safe_obj(x);
if (TYPE(x)!= T_STRING) {
rb_raise(rb_eTypeError, "wrong argument type %s (expected String)",
rb_obj_classname(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];
static int ruby_running = 0;
void
rb_clear_cache()
{
struct cache_entry *ent, *end;
if (!ruby_running) return;
ent = cache; end = ent + CACHE_SIZE;
while (ent < end) {
ent->mid = 0;
ent++;
}
}
static void
rb_clear_cache_for_undef(klass, id)
VALUE klass;
ID id;
{
struct cache_entry *ent, *end;
if (!ruby_running) return;
ent = cache; end = ent + CACHE_SIZE;
while (ent < end) {
if (ent->origin == klass && ent->mid == id) {
ent->mid = 0;
}
ent++;
}
}
static void
rb_clear_cache_by_id(id)
ID id;
{
struct cache_entry *ent, *end;
if (!ruby_running) return;
ent = cache; end = ent + CACHE_SIZE;
while (ent < end) {
if (ent->mid == id) {
ent->mid = 0;
}
ent++;
}
}
void
rb_clear_cache_by_class(klass)
VALUE klass;
{
struct cache_entry *ent, *end;
if (!ruby_running) return;
ent = cache; end = ent + CACHE_SIZE;
while (ent < end) {
if (ent->klass == klass || ent->origin == klass) {
ent->mid = 0;
}
ent++;
}
}
static ID init, eqq, each, aref, aset, match, missing;
static ID added, singleton_added;
static ID __id__, __send__;
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 (ruby_safe_level >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
rb_raise(rb_eSecurityError, "Insecure: can't define method");
}
if (!FL_TEST(klass, FL_SINGLETON) &&
node && nd_type(node) != NODE_ZSUPER &&
(mid == rb_intern("initialize" )|| mid == rb_intern("initialize_copy"))) {
noex = NOEX_PRIVATE | noex;
}
else if (FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) == NODE_CFUNC &&
mid == rb_intern("allocate")) {
rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()",
rb_class2name(rb_iv_get(klass, "__attached__")));
mid = ID_ALLOCATOR;
}
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, (st_data_t)body);
if (node && mid != ID_ALLOCATOR && ruby_running) {
if (FL_TEST(klass, FL_SINGLETON)) {
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, ID2SYM(mid));
}
else {
rb_funcall(klass, added, 1, ID2SYM(mid));
}
}
}
void
rb_define_alloc_func(klass, func)
VALUE klass;
VALUE (*func) _((VALUE));
{
Check_Type(klass, T_CLASS);
rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0), NOEX_PRIVATE);
}
void
rb_undef_alloc_func(klass)
VALUE klass;
{
Check_Type(klass, T_CLASS);
rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
}
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, (st_data_t *)&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;
}
if (ruby_running) {
/* store in cache */
if (BUILTIN_TYPE(origin) == T_ICLASS) origin = RBASIC(origin)->klass;
ent = cache + EXPR1(klass, id);
ent->klass = klass;
ent->noex = body->nd_noex;
if (noexp) *noexp = 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;
}
}
else {
if (noexp) *noexp = body->nd_noex;
body = body->nd_body;
if (nd_type(body) == NODE_FBODY) {
*klassp = body->nd_orig;
*idp = body->nd_mid;
body = body->nd_head;
}
else {
*klassp = origin;
}
}
return body;
}
static void
remove_method(klass, mid)
VALUE klass;
ID mid;
{
NODE *body;
if (klass == rb_cObject) {
rb_secure(4);
}
if (ruby_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 (mid == __id__ || mid == __send__ || mid == init) {
rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
}
if (!st_delete(RCLASS(klass)->m_tbl, &mid, (st_data_t *)&body) ||
!body->nd_body) {
rb_name_error(mid, "method `%s' not defined in %s",
rb_id2name(mid), rb_class2name(klass));
}
rb_clear_cache_for_undef(klass, 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(argc, argv, mod)
int argc;
VALUE *argv;
VALUE mod;
{
int i;
for (i=0; i<argc; i++) {
remove_method(mod, rb_to_id(argv[i]));
}
return mod;
}
void
rb_disable_super(klass, name)
VALUE klass;
const char *name;
{
/* obsolete - no use */
}
void
rb_enable_super(klass, name)
VALUE klass;
const char *name;
{
rb_warning("rb_enable_super() is obsolete");
}
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 || !body->nd_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;
}
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);
}
if (write) {
sprintf(buf, "%s=", name);
id = rb_intern(buf);
rb_add_method(klass, id, NEW_ATTRSET(attriv), noex);
}
}
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() do { \
struct FRAME _frame; \
_frame.prev = ruby_frame; \
_frame.tmp = 0; \
_frame.node = ruby_current_node; \
_frame.iter = ruby_iter->iter; \
_frame.argc = 0; \
_frame.argv = 0; \
_frame.flags = FRAME_ALLOCA; \
ruby_frame = &_frame
#define POP_FRAME() \
ruby_current_node = _frame.node; \
ruby_frame = _frame.prev; \
} while (0)
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;
NODE *cref;
int iter;
int vmode;
int flags;
struct RVarmap *dyna_vars;
VALUE orig_thread;
VALUE wrapper;
VALUE block_obj;
struct BLOCK *outer;
struct BLOCK *prev;
};
#define BLOCK_D_SCOPE 1
#define BLOCK_DYNAMIC 2
#define BLOCK_ORPHAN 4
#define BLOCK_LAMBDA 8
#define BLOCK_LEFT 16
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) do { \
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.cref = ruby_cref; \
_block.frame.node = ruby_current_node;\
_block.scope = ruby_scope; \
_block.prev = ruby_block; \
_block.outer = 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; \
_block.block_obj = 0; \
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; \
_block.tag->flags |= BLOCK_LEFT; \
} while (0)
struct RVarmap *ruby_dyna_vars;
#define PUSH_VARS() do { \
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; \
} while (0)
#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) do { \
struct iter _iter; \
_iter.prev = ruby_iter; \
_iter.iter = (i); \
ruby_iter = &_iter
#define POP_ITER() \
ruby_iter = _iter.prev; \
} while (0)
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) do { \
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() (FLUSH_REGISTER_WINDOWS, setjmp(prot_tag->buf))
#define JUMP_TAG(st) do { \
ruby_frame = prot_tag->frame; \
ruby_iter = prot_tag->iter; \
longjmp(prot_tag->buf,(st)); \
} while (0)
#define POP_TAG() \
if (_tag.prev) \
_tag.prev->retval = _tag.retval;\
prot_tag = _tag.prev; \
} while (0)
#define POP_TMPTAG() \
prot_tag = _tag.prev; \
} while (0)
#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(c) do { \
VALUE _class = ruby_class; \
ruby_class = (c)
#define POP_CLASS() ruby_class = _class; \
} while (0)
static NODE *ruby_cref = 0;
static NODE *top_cref;
#define PUSH_CREF(c) ruby_cref = NEW_NODE(NODE_CREF,(c),0,ruby_cref)
#define POP_CREF() ruby_cref = ruby_cref->nd_next
#define PUSH_SCOPE() do { \
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; \
} while (0)
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, int));
#define YIELD_PROC_CALL 1
#define YIELD_PUBLIC_DEF 2
#define YIELD_FUNC_AVALUE 1
#define YIELD_FUNC_SVALUE 2
static VALUE rb_call _((VALUE,VALUE,ID,int,const 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*,NODE*,VALUE,ID,VALUE));
#if 0
#define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \
ruby_sourceline = nd_line(ruby_current_node))
#else
#define SET_CURRENT_SOURCE() ((void)0)
#endif
void
ruby_set_current_source()
{
if (ruby_current_node) {
ruby_sourcefile = ruby_current_node->nd_file;
ruby_sourceline = nd_line(ruby_current_node);
}
}
static void
#ifdef HAVE_STDARG_PROTOTYPES
warn_printf(const char *fmt, ...)
#else
warn_printf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
char buf[BUFSIZ];
va_list args;
va_init_list(args, fmt);
vsnprintf(buf, BUFSIZ, fmt, args);
va_end(args);
rb_write_error(buf);
}
#define warn_print(x) rb_write_error(x)
#define warn_print2(x,l) rb_write_error2(x,l)
static void
error_pos()
{
ruby_set_current_source();
if (ruby_sourcefile) {
if (ruby_frame->last_func) {
warn_printf("%s:%d:in `%s'", ruby_sourcefile, ruby_sourceline,
rb_id2name(ruby_frame->last_func));
}
else if (ruby_sourceline == 0) {
warn_printf("%s", ruby_sourcefile);
}
else {
warn_printf("%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, e;
char *einfo;
long elen;
if (NIL_P(ruby_errinfo)) return;
PUSH_TAG(PROT_NONE);
if (EXEC_TAG() == 0) {
errat = get_backtrace(ruby_errinfo);
}
else {
errat = Qnil;
}
if (EXEC_TAG()) goto error;
if (NIL_P(errat)){
ruby_set_current_source();
if (ruby_sourcefile)
warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline);
else
warn_printf("%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 {
warn_print2(RSTRING(mesg)->ptr, RSTRING(mesg)->len);
}
}
eclass = CLASS_OF(ruby_errinfo);
if (EXEC_TAG() == 0) {
e = rb_obj_as_string(ruby_errinfo);
einfo = RSTRING(e)->ptr;
elen = RSTRING(e)->len;
}
else {
einfo = "";
elen = 0;
}
if (EXEC_TAG()) goto error;
if (eclass == rb_eRuntimeError && elen == 0) {
warn_print(": unhandled exception\n");
}
else {
VALUE epath;
epath = rb_class_path(eclass);
if (elen == 0) {
warn_print(": ");
warn_print2(RSTRING(epath)->ptr, RSTRING(epath)->len);
}
else {
char *tail = 0;
long len = elen;
if (RSTRING(epath)->ptr[0] == '#') epath = 0;
if (tail = memchr(einfo, '\n', elen)) {
len = tail - einfo;
tail++; /* skip newline */
}
warn_print(": ");
warn_print2(einfo, len);
if (epath) {
warn_print(" (");
warn_print2(RSTRING(epath)->ptr, RSTRING(epath)->len);
warn_print(")\n");
}
if (tail) {
warn_print2(tail, elen-len-1);
}
}
}
if (!NIL_P(errat)) {
long 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) {
warn_printf("\tfrom %s\n", RSTRING(ep->ptr[i])->ptr);
}
if (i == TRACE_HEAD && ep->len > TRACE_MAX) {
warn_printf("\t ... %ld levels...\n",
ep->len - TRACE_HEAD - TRACE_TAIL);
i = ep->len - TRACE_TAIL;
}
}
}
error:
POP_TAG();
}
#if defined(__APPLE__)
#define environ (*_NSGetEnviron())
#elif !defined(_WIN32) && !defined(__MACOS__) || defined(_WIN32_WCE)
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((void*)&state);
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;
rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self));
#ifdef __MACOS__
_macruby_init();
#endif
ruby_prog_init();
ALLOW_INTS;
}
POP_TAG();
if (state) {
error_print();
exit(1);
}
POP_SCOPE();
ruby_scope = top_scope;
ruby_running = 1;
}
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 thread_set_raised();
static int thread_reset_raised();
static VALUE exception_error;
static VALUE sysstack_error;
static int
error_handle(ex)
int ex;
{
if (thread_set_raised()) return 1;
switch (ex & TAG_MASK) {
case 0:
ex = 0;
break;
case TAG_RETURN:
error_pos();
warn_print(": unexpected return\n");
ex = 1;
break;
case TAG_NEXT:
error_pos();
warn_print(": unexpected next\n");
ex = 1;
break;
case TAG_BREAK:
error_pos();
warn_print(": unexpected break\n");
ex = 1;
break;
case TAG_REDO:
error_pos();
warn_print(": unexpected redo\n");
ex = 1;
break;
case TAG_RETRY:
error_pos();
warn_print(": retry outside of rescue clause\n");
ex = 1;
break;
case TAG_THROW:
if (prot_tag && prot_tag->frame && prot_tag->frame->node) {
NODE *tag = prot_tag->frame->node;
warn_printf("%s:%d: uncaught throw\n",
tag->nd_file, nd_line(tag));
}
else {
error_pos();
warn_printf(": unexpected throw\n");
}
ex = 1;
break;
case TAG_RAISE:
case TAG_FATAL:
if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
VALUE st = rb_iv_get(ruby_errinfo, "status");
ex = NUM2INT(st);
}
else {
error_print();
ex = 1;
}
break;
default:
rb_bug("Unknown longjmp status %d", ex);
break;
}
thread_reset_raised();
return ex;
}
void
ruby_options(argc, argv)
int argc;
char **argv;
{
int state;
Init_stack((void*)&state);
PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) {
ruby_process_options(argc, argv);
}
if (state) {
trace_func = 0;
tracing = 0;
exit(error_handle(state));
}
POP_TAG();
}
void rb_exec_end_proc _((void));
static void
ruby_finalize_0(exp)
int *exp;
{
ruby_errinfo = 0;
PUSH_TAG(PROT_NONE);
if (EXEC_TAG() == 0) {
rb_trap_exit();
}
POP_TAG();
rb_exec_end_proc();
rb_gc_call_finalizer_at_exit();
if (exp && ruby_errinfo && rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
VALUE st = rb_iv_get(ruby_errinfo, "status");
*exp = NUM2INT(st);
}
trace_func = 0;
tracing = 0;
}
void
ruby_finalize()
{
ruby_finalize_0(0);
}
int
ruby_cleanup(ex)
int ex;
{
int state;
ruby_safe_level = 0;
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();
ex = error_handle(ex);
POP_TAG();
ruby_finalize_0(&ex);
return ex;
}
int
ruby_exec()
{
int state;
volatile NODE *tmp;
Init_stack((void*)&tmp);
PUSH_TAG(PROT_NONE);
PUSH_ITER(ITER_NOT);
/* default visibility is private at toplevel */
SCOPE_SET(SCOPE_PRIVATE);
if ((state = EXEC_TAG()) == 0) {
eval_node(ruby_top_self, ruby_eval_tree);
}
POP_ITER();
POP_TAG();
return state;
}
void
ruby_stop(ex)
int ex;
{
exit(ruby_cleanup(ex));
}
void
ruby_run()
{
int state;
static int ex;
if (ruby_nerrs > 0) exit(ruby_nerrs);
state = ruby_exec();
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, rb_obj_as_string(ruby_errinfo));
}
rb_exc_raise(rb_exc_new3(rb_eSyntaxError, str));
}
VALUE
rb_eval_string(str)
const char *str;
{
VALUE v;
NODE *oldsrc = ruby_current_node;
ruby_current_node = 0;
ruby_sourcefile = rb_source_filename("(eval)");
v = eval(ruby_top_self, rb_str_new2(str), Qnil, 0, 0);
ruby_current_node = oldsrc;
return v;
}
VALUE
rb_eval_string_protect(str, state)
const char *str;
int *state;
{
VALUE result = Qnil; /* 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_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->orig_func = 0;
ruby_frame->last_class = 0;
ruby_frame->self = self;
PUSH_CREF(ruby_wrapper);
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, reason)
const char *mesg;
VALUE status;
int reason;
{
VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
VALUE id;
rb_iv_set(exc, "@exit_value", status);
switch (reason) {
case TAG_BREAK:
id = rb_intern("break"); break;
case TAG_REDO:
id = rb_intern("redo"); break;
case TAG_RETRY:
id = rb_intern("retry"); break;
case TAG_NEXT:
id = rb_intern("next"); break;
case TAG_RETURN:
id = rb_intern("return"); break;
default:
id = rb_intern("noreason"); break;
}
rb_iv_set(exc, "@reason", ID2SYM(id));
rb_exc_raise(exc);
}
static VALUE
localjump_xvalue(exc)
VALUE exc;
{
return rb_iv_get(exc, "@exit_value");
}
static VALUE
localjump_reason(exc)
VALUE exc;
{
return rb_iv_get(exc, "@reason");
}
static void
jump_tag_but_local_jump(state)
int state;
{
VALUE val;
if (prot_tag) val = prot_tag->retval;
else val = Qnil;
switch (state) {
case 0:
break;
case TAG_RETURN:
localjump_error("unexpected return", val, state);
break;
case TAG_NEXT:
localjump_error("unexpected next", val, state);
break;
case TAG_BREAK:
localjump_error("unexpected break", val, state);
break;
case TAG_REDO:
localjump_error("unexpected redo", Qnil, state);
break;
case TAG_RETRY:
localjump_error("retry outside of rescue clause", Qnil, state);
break;
default:
JUMP_TAG(state);
break;
}
}
VALUE
rb_eval_cmd(cmd, arg, tcheck)
VALUE cmd, arg;
int tcheck;
{
int state;
VALUE val = Qnil; /* 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->orig_func = 0;
ruby_frame->last_class = 0;
ruby_frame->self = ruby_top_self;
PUSH_CREF(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
superclass(self, node)
VALUE self;
NODE *node;
{
VALUE val = Qnil; /* OK */
int state;
PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) {
val = rb_eval(self, node);
}
POP_TAG();
if (state) {
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) {
rb_raise(rb_eTypeError, "superclass must be a Class (%s given)",
rb_obj_classname(val));
}
if (FL_TEST(val, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't make subclass of virtual class");
}
return val;
}
#define ruby_cbase (ruby_cref->nd_clss)
static VALUE
ev_const_defined(cref, id, self)
NODE *cref;
ID id;
VALUE self;
{
NODE *cbase = cref;
VALUE result;
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, &result)) {
if (result == Qundef && NIL_P(rb_autoload_p((VALUE)klass, id))) {
return Qfalse;
}
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);
while (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &result)) {
if (result == Qundef) {
rb_autoload_load(klass, id);
continue;
}
return result;
}
cbase = cbase->nd_next;
}
return rb_const_get(cref->nd_clss, id);
}
static VALUE
cvar_cbase()
{
NODE *cref = ruby_cref;
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 = ruby_cref;
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;
}
if (ruby_wrapper && RARRAY(ary)->len == 0) {
rb_ary_push(ary, ruby_wrapper);
}
return ary;
}
static VALUE
rb_mod_s_constants()
{
NODE *cbase = ruby_cref;
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_cbase == rb_cObject && klass == rb_cObject) {
rb_secure(4);
}
if (ruby_safe_level >= 4 && !OBJ_TAINTED(klass)) {
rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", 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(klass, 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(argc, argv, mod)
int argc;
VALUE *argv;
VALUE mod;
{
int i;
for (i=0; i<argc; i++) {
rb_undef(mod, rb_to_id(argv[i]));
}
return mod;
}
void
rb_alias(klass, name, def)
VALUE klass;
ID name, def;
{
VALUE origin;
NODE *orig, *body;
VALUE singleton = 0;
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);
}
if (FL_TEST(klass, FL_SINGLETON)) {
singleton = rb_iv_get(klass, "__attached__");
}
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,
(st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
if (singleton) {
rb_funcall(singleton, 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;
NODE *rval;
{
NODE *copy = NEW_NODE(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_ARGS0(anode,alen) do {\
NODE *n = anode;\
if (!n) {\
argc = 0;\
argv = 0;\
}\
else if (nd_type(n) == NODE_ARRAY) {\
argc=alen;\
if (argc > 0) {\
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;\
}\
}\
else {\
argc = 0;\
argv = 0;\
}\
}\
else {\
VALUE args = rb_eval(self,n);\
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);\
}\
} while (0)
#define SETUP_ARGS(anode) SETUP_ARGS0(anode, anode->nd_alen)
#define BEGIN_CALLARGS do {\
struct BLOCK *tmp_block = ruby_block;\
int tmp_iter = ruby_iter->iter;\
if (tmp_iter == ITER_PRE) {\
ruby_block = ruby_block->outer;\
tmp_iter = ITER_NOT;\
}\
PUSH_ITER(tmp_iter)
#define END_CALLARGS \
ruby_block = tmp_block;\
POP_ITER();\
} while (0)
#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->orig_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->orig_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_ATTRASGN:
val = self;
if (node->nd_recv == (NODE *)1) 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,
nd_type(node) == NODE_ATTRASGN ?
"assignment" : "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(ruby_cref, 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_from(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", (int)node->nd_nth);
return buf;
}
break;
case NODE_BACK_REF:
if (RTEST(rb_reg_nth_defined(0, MATCH_DATA))) {
sprintf(buf, "$%c", (char)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_proc(proc)
VALUE proc;
{
if (TYPE(proc) == T_DATA && RDATA(proc)->dfree == (RUBY_DATA_FUNC)blk_free) {
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, node, self, id, klass)
char *event;
NODE *node;
VALUE self;
ID id;
VALUE klass; /* OK */
{
int state, raised;
struct FRAME *prev;
NODE *node_save;
VALUE srcfile;
if (!trace_func) return;
if (tracing) return;
if (ruby_in_compile) return;
if (id == ID_ALLOCATOR) return;
if (!(node_save = ruby_current_node)) {
node_save = NEW_NEWLINE(0);
}
tracing = 1;
prev = ruby_frame;
PUSH_FRAME();
*ruby_frame = *prev;
ruby_frame->prev = prev;
ruby_frame->iter = 0; /* blocks not available anyway */
if (node) {
ruby_current_node = node;
ruby_frame->node = node;
ruby_sourcefile = node->nd_file;
ruby_sourceline = nd_line(node);
}
if (klass) {
if (TYPE(klass) == T_ICLASS) {
klass = RBASIC(klass)->klass;
}
else if (FL_TEST(klass, FL_SINGLETON)) {
klass = self;
}
}
PUSH_TAG(PROT_NONE);
raised = thread_reset_raised();
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),
Qundef, 0);
}
if (raised) thread_set_raised();
POP_TMPTAG(); /* do not propagate retval */
POP_FRAME();
tracing = 0;
ruby_current_node = node_save;
SET_CURRENT_SOURCE();
if (state) JUMP_TAG(state);
}
static VALUE
avalue_to_svalue(v)
VALUE v;
{
VALUE tmp, top;
tmp = rb_check_array_type(v);
if (NIL_P(tmp)) {
return v;
}
if (RARRAY(tmp)->len == 0) {
return Qundef;
}
if (RARRAY(tmp)->len == 1) {
top = rb_check_array_type(RARRAY(tmp)->ptr[0]);
if (NIL_P(top)) {
return RARRAY(tmp)->ptr[0];
}
if (RARRAY(top)->len > 1) {
return v;
}
return top;
}
return tmp;
}
static VALUE
svalue_to_avalue(v)
VALUE v;
{
VALUE tmp, top;
if (v == Qundef) return rb_ary_new2(0);
tmp = rb_check_array_type(v);
if (NIL_P(tmp)) {
return rb_ary_new3(1, v);
}
if (RARRAY(tmp)->len == 1) {
top = rb_check_array_type(RARRAY(tmp)->ptr[0]);
if (!NIL_P(top) && RARRAY(top)->len > 1) {
return v;
}
return rb_ary_new3(1, v);
}
return tmp;
}
static VALUE
svalue_to_mrhs(v, lhs)
VALUE v;
NODE *lhs;
{
VALUE tmp;
if (v == Qundef) return rb_ary_new2(0);
tmp = rb_check_array_type(v);
if (NIL_P(tmp)) {
return rb_ary_new3(1, v);
}
/* no lhs means splat lhs only */
if (!lhs && RARRAY(tmp)->len <= 1) {
return rb_ary_new3(1, v);
}
return tmp;
}
static VALUE
avalue_splat(v)
VALUE v;
{
if (RARRAY(v)->len == 0) {
return Qundef;
}
if (RARRAY(v)->len == 1) {
return RARRAY(v)->ptr[0];
}
return v;
}
#if 1
VALUE
rb_Array(val)
VALUE val;
{
VALUE tmp = rb_check_array_type(val);
if (NIL_P(tmp)) {
/* hack to avoid invoke Object#to_a */
VALUE origin;
ID id = rb_intern("to_a");
if (search_method(CLASS_OF(val), id, &origin) &&
RCLASS(origin)->m_tbl != RCLASS(rb_mKernel)->m_tbl) { /* exclude Kernel#to_a */
val = rb_funcall(val, id, 0);
if (TYPE(val) != T_ARRAY) {
rb_raise(rb_eTypeError, "`to_a' did not return Array");
}
return val;
}
else {
return rb_ary_new3(1, val);
}
}
return tmp;
}
#endif
static VALUE
splat_value(v)
VALUE v;
{
if (NIL_P(v)) return rb_ary_new3(1, Qnil);
return rb_Array(v);
}
static VALUE
class_prefix(self, cpath)
VALUE self;
NODE *cpath;
{
if (!cpath) {
rb_bug("class path missing");
}
if (cpath->nd_head) {
VALUE c = rb_eval(self, cpath->nd_head);
switch (TYPE(c)) {
case T_CLASS:
case T_MODULE:
break;
default:
rb_raise(rb_eTypeError, "%s is not a class/module",
RSTRING(rb_obj_as_string(c))->ptr);
}
return c;
}
else if (nd_type(cpath) == NODE_COLON2) {
return ruby_cbase;
}
else if (ruby_wrapper) {
return ruby_wrapper;
}
else {
return rb_cObject;
}
}
static void return_check _((void));
#define return_value(v) do {\
if ((prot_tag->retval = (v)) == Qundef) {\
prot_tag->retval = Qnil;\
}\
} while (0)
static VALUE
rb_eval(self, n)
VALUE self;
NODE *n;
{
NODE * volatile contnode = 0;
NODE * volatile node = n;
int state;
volatile VALUE result = Qnil;
#define RETURN(v) do { \
result = (v); \
goto finish; \
} while (0)
again:
if (!node) RETURN(Qnil);
ruby_current_node = node;
switch (nd_type(node)) {
case NODE_BLOCK:
if (contnode) {
result = rb_eval(self, node);
break;
}
contnode = 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);
cas‹€©z4ƒvW7#€í_Úkÿòº‘¨‹ê—™rň¦>øLB®‚¤Õfñ’p¨üîêÏQeOñ:"%ް¸tåƒ/Ì…—@ïÿ R,?"
mñ·%…¶Çä\ÒxÐ÷¿Ðµ/Ìz"Žóžf89æk‡›Lgÿsé´jQ¤ÿÊ«‰Ü_¦¥4öé¡îo奬ß0Câ‰~S¡J!°'ãxR RâNT[Þ¢ä‚é*Þ†9ЬsòQ¸ínzÇâNÉÏ2åPË®Sb˜ԥd LTa>%ž¸)Õ§ªÆìçÝx>—ò ‡.Ê!å¡»~ÿ¤@8 g·+´,±rù>¥'ûÐý¥H¶ŸÆÍûŸ
Ä^ËÌø @ƒàJ)×à[Ö
œ1~%î7oc¡ ·»´t‡ƒ-½±ñ¯œ-ýôÄæÏ£µT˜Z8eJ9›ÓìD-'‘‚kÌÍžÞF€ÐÅ$œÃ8"?yh‹Šóÿ€¬lш"Œæþn}·+D]‹·ùчƔdøaá1„7Ù]ŠÉ¶Â¶„?Q¥–bÔLÊz!nYÝ¿ºI…áê^üßd@ts“¿Œæìh}z”±ˆ° ñ€®7Ênu¸F÷+ž¡d!ØÜDôË=Ÿ”‘1fpþç|
xf}þ•×cz$J{6ŒÓÛ„¸zcµ>w0isqsfÅDcSL©ïóZÏ™.
H '1«ã²º
$Ý_ºˆ¨œbG¹uJ ™gY½Ø2~?ïÙ 4~Ô~ñ-è“Dš;z÷Š\ÌÜê‰5¾ƒcé(A«åOR¯µÜ¢iG+;Uñ#Gaâ¡-É\DiŸó=TÏŽ*…ó:„¾ó$+×ɽbÓ½(ìëð‹ÿ"XnÃy(ó°$Èg‚š°åP«µMÔo˜û¼m©ø9Ýåß·¥Žs9ä>"ʀ솙rÝgw¢]ÀšçöвRpuwÂ#·uµÏ«D!Yi’rX#¿áúUh”ÉBÓd‹J/,÷úc;Øn»N¸æäÓ Eèu£ î,F’–m}d7HÞëvG7»ÛBwwõdfQ‡âõ£š[ÄÕ´&Ñüº–XÄB|‹*ÂíÉÎoròˆB*/U>³v Ú©ûV•$¡˜ŸzÃÆêD.ž=¬‘Õ—5êj²%†²•½"å˜kûÄ%Нõšè[É€XÑ#ƪ–YdÀµªöu‰x*:>t…Ó<é¤F¦Ðl<¥›=WÙô¯¢øžê\1qÔ1<)b*fµv×Ô+áíÉá`Úr“óø…QnìïÌg⼟¾ÆV7¼¿|¯Ær=ME{kIòNQ+›o@‹Éc½b§ƒ¸G¹í[º(»›©îÝþW!2|}ÚCk¥4ð‹Å„w3: ‚óÓ–]±2ƒ—Ýj~¾§3Gå Æ€íPO¤à¹Ø/°çûë»Ù~¬ŒîÉi8¿AN-ƒðïÀÇ^´›ì@Y
õî@Ž…Œ’FØEl†—?ا»Q¢ë:þX¸¯#rQø#h´ˆïÀë(՛³¿N&ÛQnŽRऋqÝÅlÉêÒÿ±t<˜
v&ò¡j±ÿœŸŒÃ½÷Õ›äæzú
(·Bà~!/¡È•ÂéÝéJªšæ€L«~r3÷]ñ
"|ˆ¡‰¼?ÓÕ)*/\ÚU¼;›üŸF™\wÇkÓÑt}¾P &oÙ¨ •ïðÂ]U(Ѓ}šËhò‚$Vq JbƒCªö40ÅNaPø½ÖÂ8± }ÊhÍ ƒ¶¥üÆze´õªEëÏ` ´¯ÁѵÙðkß”£bõ}±G”_2%Ë×L `n{ËÈ28PaÝÅýµj«‚;É\°§ÝÓÅzS!ÈÈï
u$›c
}À yãìlHŒ
õýŠñò}íÒÑâ5×}¨|OFFÈ6:¥sOëI9½ô6ÚC^xà xÈQÎpf6Ù>HQç@Ò““¬s^ÃUŽ»â÷ÖLÏt“8L–Ú®Q—h\!„1dúì}ûÊ‹üƒï\ºâÃ%+/EwS;Ègß&|Š)n•#‘qŸü[ØhH¬²åˆ®´$vPƒ H ŽV¬XìñK@ƒ\ô¯é;X¬õw®æ˜õ£q aAK€u\B¯fû#¯Ñ7N†:¤ÁˆÃæ$nï"BHÿÇÇbò²0YäpQçÐè—ʧ®w?''þbõ$9_:³a^d'Ïœ„Å87 ü-íþV.q¡¢?³øÞÕOÏïê"œ8PÐ¥ À‹üLß.¡ƒV2;hÒqWâ„àm¸ÚÄhNÖÄsou4äçžm"åôìÇü ^ÁðqP¡e,oÙÒÑɦ+@¾Aké"<({ù§zâìªúÂßOÎRKé¤nßè·q!NœÓöÌŠP@Ô¥˜ŒŒ‘Ë¿ÇÌ:D H’ØuJÿ0 $®ŸH!¢¿¯
‰Vi…4Ô“
€1õöV•€÷¨½?@w}[S±q±ù¹½ç¾O[÷ÅFcÄ9yÄaG}°jLõ/›!ˆËªAV
Ö}ßt•Â<…ËèÅüÔìîR_6~ä2‹ÎÕ·F-Úc›ßRîæX”øêo¬A³ÎÞÑ_HùWç¹'CÙwåì;Óüã?¦ŽÑæiú:yt‘ŸE+½dýÅö E=XìLû÷òÅœ:€=u]†7Ôw(fêë5ùËæÝÎ/«³
ç+·îC¥¾@Õ¨¾¤äŽù¶MPV¢b$Ø”ŒaÝ®·Ÿí]=)ø.q·½Ni-ÏÓ™Œ¦Ö¥Q/#Ryò| ›C)"@ÔüÿÄú·eÚ¸udÚò1ô×T^‹“¶™çQfÛÉ"óZ·&w¬hŽQ¯Òʹ±’jé£~Tsú˜æËBRƒÇj»ÉS90jiþžŠ´ä©Žð);ÿ få'çZÅËÒ?û$§ŽOÿqÝ%ûþN/‡g¿ûTÅïëk½N¬,ªÈwú]ýí3♓ª“oŒ×¡çÒt
5M¥‚|éèÞ
ŽÇº%
·´þ½ZŠê|GÛ9›8tcž;F.€iÁiÓH%täñ—Ißöxº›~ýõt+¾»…—jzÒmh¿Ï% Äg¤±ªp íõ úŽV¥-ÈóÍÔ
Î27E\:a1u.ãHÕ €,ƒ"“«pÜ_€™¾ùµðC€Àöæ£v²fºƒ<_&" &üÙÍŠQFÌ=ù¨€Žä`¬_£/û1,Gó™OO6û õå>}‘aÛO~LìaÒeýÏd°ï‹¡Ñ©Î¾ítý’x0”õðT¸í·ó{Àù{»QšÄ±Ðp¾Ô6âC=ÎÙÃï.ô>㺒½\^<ÁcD4Ë}ÖÃù½#9ê8û½Ì´9¯•x%&Úìª6uS[ƒç‹i [»‚
{†°LtüzaØàB3°ÔW3Sì>FX2¯ZoôJó6ÒWÆ^±^Ósó•#0h%²ŽÊI ÞŠ%âð, p„B•ãû%¾dVa¬³Üd¼Ò/Û‹î‡7'FçÃp{ù;ôy’Ž0ÀK¤oNq–×EògÔ¿3|TÒò¾Št 7f˜˜n+™ÊÑ7uÆ„_Æâ[hEj0à:-Ž›“1LdbëdíKnlŽÛÅÊã¹Ó¡®íØ•3¹®MÍ7¼c;Ñ"ˉٷ}è×îÞE&2ûjͯ…NÔË&úª”ÿ|š¹Ï˜hHš%ÙÃzŠ¢g‹iHk5¯dÀŠ¨Ù€ zâðIăõJWy‚œ½[‚à|¬bPÔ¥$™´“½å®ŠJØç'vØf£÷òÓ§ò
ÖÀõ̤ù=ïÞ½>+5u÷¤l?]:¤g°O†>FÂö¯›-‰Ì¯UPÓp>‘p‚Œ|„›‹0–OÇC|3´|B0’L`™Õí½Åwcf“KéBIƒhÀ„•ÐëôO(7¥à\šWTGIkUÿãŒÂæƒo•JKiF_uhF-¢z.áõ½Æôa4Ö‘n1íDlyy›²†f}™ N $¬L|…ãH
ˆ†ÔtžÍç´å`ˆ`"û
|¡äÖGÉ
<=E¯ÁŽRqM¤tÏË)6¸žëÁ[{Éu#zñ Ýz¬XcçžÆSœXHý³Íþ_ñF3ë Bð´>»:à¨o•˜NÍ‘TòpŠŸØ‡²ˆJ¢;.þƒÙíßšÜx0G¢½œ[‹¹Ë5!í]pJm2·´áT±£ê… O47¦V÷çuœ»IßݤÙöu2hƒÒgTk~—…ñ¤ßóc½ÔÝ+¾Z†³Ì˜GØ,8v5ºü wÈØÁ¶6lm5¡$3>b©ìEl[¨-f;U_³ê£–Btü5#@áõŒßŠö§åÚ{›¿ªÚ*ÞA¢÷¹Ûf}EH*…;pŒ!Vl ¹pßJâVh°pE¸-µþµ?ê‹c~“¦©Ú¬ût—Ã(u }žÝ}0ÈF(Â÷ÍþB/²…÷û[ :5ÔcÈh~¯½N$ºv6Ì
¥žŠïÅ%Aç((=6'‹N2h¦ÓZ;;½
³IÉtd³þû|cÅ¿fŽ
)¯åé~ïÇÁAëÊý…(’$î¬k5“-Æîf{»oñx
AÓS—ÛÞ¹$ Ô#o´È~= ®¸õæXb¸‹^žá\jRs4b™Éô+í@Ú@°;õüÉçù’†yª££¬ZŒyߎÁÊ-àËß·ï÷`PõUÔ¡°Ô™å÷댶gßyÒÅW×ï/WöÉž½E¸¦ç@éº#ö;ÍöWÁO10çq˜T\AšÖô¢ölH“ˆÄ*h};—]ƒY3ŸWàd÷MZjÃ3nBL±$WÝ60ªwŵ?¿óŽ| Ã),UB’4%«š,»ÿhÁqÈ?]†ÆQV>÷Žž~Áò5؃¯’LŒå)à‹Åh
^*pе¸¶°ëepvÕ‹;²SòÖHKÆà8îóχ6d i»^Òtµ£‰%÷ì]¤É?FÓcH&¥5º-’÷mÆ`¤àî¯á"wI@}ò¹}Å—Èg³ææ£›:£l¶3RH'[Â,ãëKõe‚/DõÚãÅ’«ì“_;Wë9÷¶åuµÉ)æ«õy5þâwœ”¸‘s¿àÍì$5J'ƒyÔ,*§Zt4ØhÆÆ¯YfÂ\&çèHÛÓ0]€¶@§üIœÑ×+Íùò¿ £ÒI€!HK”u"'˜š»p˜™‚âhmVÊc®€zPsØ+iëg®$žr
ÏÍÃ.òV’;Íçãûcã’d&ì$Æ•ÜÏÆô¿3\˜<ûÔ¯EÄ%PqÛæ×1.ÒµÇÃu
Eñþ¶H¡Ë*Vë’ºòìˆãÊÒϺ‡ùáØÑÈÞ.`kþ€á@g55W8A;d&LÉVåõìèÃK'~Uc&id}ò>yµWBw|’ pªO°E`?.è2µ<*©2¦ãÚoaÆ¡ó¡_Š‚Œ,ØÚ•0?ÇÄ1— ROiKÅtr¿ßæ[ÿÅWj¯1Ÿž™Áó ‘6ŽËkY§.<î¾TÍõÉÉÅÝ"m·-è³
|