diff --git a/moo/kernel/Except.moo b/moo/kernel/Except.moo index 4016650..3c0a8d6 100644 --- a/moo/kernel/Except.moo +++ b/moo/kernel/Except.moo @@ -221,7 +221,6 @@ pooldic MethodContext.Index // which translates to index 8 ENSURE := 8. - // [ ... ] on: Exception: do: [:ex | ... ] FIRST_ON := 8. } @@ -252,7 +251,8 @@ extend MethodContext * For a single on:do: call, * self class specNumInstVars must return 8.(i.e.MethodContext has 8 instance variables.) * basicAt: 8 must be the on: argument. - * basicAt: 9 must be the do: argument */ + * basicAt: 9 must be the do: argument + */ | size exc i | @@ -261,7 +261,12 @@ extend MethodContext { /* NOTE: the following loop scans all parameters to the on:do: method. * if the on:do: method contains local temporary variables, - * those must be skipped from scanning. */ + * you must change this function to skip scanning local variables. + * the current on:do: method has 1 local variable declared. + * as local variables are placed after method arguments and + * the loop increments 'i' by 2, the last element is naturally + * get excluded from inspection. + */ size := self basicSize. // start scanning from the position of the first parameter @@ -367,7 +372,23 @@ thisContext isExceptionContext dump. exception_active := true. ^self value. } - + + method on: exc1 do: blk1 on: exc2 do: blk2 on: exc3 do: blk3 on: exc4 do: blk4 + { + | exception_active | + + exception_active := true. + ^self value. + } + + method on: exc1 do: blk1 on: exc2 do: blk2 on: exc3 do: blk3 on: exc4 do: blk4 on: exc5 do: blk5 + { + | exception_active | + + exception_active := true. + ^self value. + } + method ensure: aBlock { | retval pending | diff --git a/moo/lib/exec.c b/moo/lib/exec.c index cf81102..c59faad 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -2172,7 +2172,46 @@ static moo_pfrc_t pf_context_goto (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) static moo_pfrc_t pf_context_find_exception_handler (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { - return MOO_PF_FAILURE; + moo_oop_context_t rcv; + moo_ooi_t preamble; + moo_oop_t except_class; + + rcv = (moo_oop_context_t)MOO_STACK_GETRCV(moo, nargs); + MOO_PF_CHECK_RCV (moo, MOO_CLASSOF(moo,rcv) == moo->_method_context); + + preamble = MOO_OOP_TO_SMOOI(((moo_oop_method_t)rcv->method_or_nargs)->preamble); + if (MOO_METHOD_GET_PREAMBLE_CODE(preamble) == MOO_METHOD_PREAMBLE_EXCEPTION) + { + /* context + * on: ... do: ...*/ + moo_oow_t size, i; + + except_class = MOO_STACK_GETARG(moo, nargs, 0); + + size = MOO_OBJ_GET_SIZE(rcv); + for (i = MOO_CONTEXT_NAMED_INSTVARS; i < size; i += 2) + { + /* NOTE: the following loop scans all parameters to the on:do: method. + * if the on:do: method contains local temporary variables, + * you must change this function to skip scanning local variables. + * the current on:do: method has 1 local variable declared. + * as local variables are placed after method arguments and + * the loop increments 'i' by 2, the last element is naturally + * get excluded from inspection. + */ + moo_oop_class_t on_class; + + on_class = (moo_oop_class_t)MOO_OBJ_GET_OOP_VAL(rcv, i); + if (on_class == except_class || (MOO_CLASSOF(moo, on_class) == moo->_class && moo_ischildclassof(moo, except_class, on_class))) + { + MOO_STACK_SETRET (moo, nargs, MOO_OBJ_GET_OOP_VAL(rcv, i + 1)); + return MOO_PF_SUCCESS; + } + } + } + + MOO_STACK_SETRET (moo, nargs, moo->_nil); + return MOO_PF_SUCCESS; } /* ------------------------------------------------------------------ */ diff --git a/moo/lib/moo.c b/moo/lib/moo.c index e66cb3e..a254e55 100644 --- a/moo/lib/moo.c +++ b/moo/lib/moo.c @@ -1066,3 +1066,15 @@ int moo_iskindof (moo_t* moo, moo_oop_t obj, moo_oop_class_t _class) } return 0; } + +int moo_ischildclassof (moo_t* moo, moo_oop_class_t c, moo_oop_class_t k) +{ + c = (moo_oop_class_t)c->superclass; + while ((moo_oop_t)c != moo->_nil) + { + if (c == k) return 1; + c = (moo_oop_class_t)c->superclass; + } + + return 0; +} diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 96ab20d..69eb132 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -2123,6 +2123,13 @@ MOO_EXPORT int moo_iskindof ( moo_oop_class_t _class ); +/* check if c is a child class of k */ +MOO_EXPORT int moo_ischildclassof ( + moo_t* moo, + moo_oop_class_t c, + moo_oop_class_t k +); + /* ========================================================================= * TRAILER MANAGEMENT * ========================================================================= */