Skip to content

Instantly share code, notes, and snippets.

@mlschroe
Created September 21, 2011 17:27
Show Gist options
  • Save mlschroe/1232725 to your computer and use it in GitHub Desktop.
Save mlschroe/1232725 to your computer and use it in GitHub Desktop.
diff --git a/src/Perl6/Actions.pm b/src/Perl6/Actions.pm
index e5e6caf..2228b2c 100644
--- a/src/Perl6/Actions.pm
+++ b/src/Perl6/Actions.pm
@@ -3728,26 +3728,34 @@ class Perl6::Actions is HLL::Actions {
unless $block.handlers() {
$block.handlers([]);
}
- $handler := PAST::Block.new(
- :blocktype('declaration'),
- PAST::Var.new( :scope('parameter'), :name('$_') ),
- PAST::Op.new( :pasttype('bind_6model'),
- PAST::Var.new( :scope('lexical_6model'), :name('$_') ),
- PAST::Op.new(
- :name('&EXCEPTION'),
- PAST::Var.new( :scope('lexical_6model'), :name('$_') ),
- ),
+
+ my $handler_start := PAST::Stmts.new(
+ PAST::Op.new( :pasttype('bind'),
+ PAST::Var.new( :scope('register'), :name('exception'), :isdecl(1) ),
+ PAST::Var.new( :scope('parameter') ),
),
- PAST::Var.new( :scope('lexical_6model'), :name('$/'), :isdecl(1) ),
PAST::Op.new( :pasttype('bind_6model'),
- PAST::Var.new( :scope('lexical_6model'), :name('$!'), :isdecl(1) ),
+ PAST::Var.new( :scope('lexical_6model'), :name('$_'), :isdecl(1) ),
+ PAST::Op.new( :name('&EXCEPTION'), PAST::Var.new( :scope('register'), :name('exception') ) ),
+ ),
+ PAST::Op.new( :pirop('perl6_container_store__0PP'),
+ PAST::Op.new( :pirop('find_lex_skip_current Ps'), '$!'),
PAST::Var.new( :scope('lexical_6model'), :name('$_') ),
),
- PAST::Op.new( :pasttype('call'),
- $handler,
- ));
- $handler.symbol('$_', :scope('lexical_6model'));
- $handler.symbol('$!', :scope('lexical_6model'));
+ PAST::Var.new( :scope('lexical_6model'), :name('$!'), :isdecl(1) ),
+ PAST::Var.new( :scope('lexical_6model'), :name('$/'), :isdecl(1) ),
+ );
+ $handler<past_block>[1].unshift($handler_start);
+ $handler<past_block>[1].push(PAST::Op.new( :inline(" rethrow_skipnextctx exception")));
+
+ unless $handler<past_block>.handlers() {
+ $handler<past_block>.handlers([]);
+ }
+ $handler<past_block>.handlers.unshift(
+ PAST::Control.new( PAST::Op.new( :inline(" rethrow_skipnextctx exception")) )
+ );
+
+
$handler := PAST::Stmts.new(
PAST::Op.new( :pasttype('call'),
$handler,
diff --git a/src/ops/perl6.ops b/src/ops/perl6.ops
index a5d04f1..58a7881 100644
--- a/src/ops/perl6.ops
+++ b/src/ops/perl6.ops
@@ -1100,6 +1100,51 @@ inline op encodelocaltime(out INT, in PMC) :base_core {
$1 = mktime(&tm);
}
+
+/*
+
+=item rethrow_skipnextctx(in PMC)
+
+Rethrow an exception, but skip the remaining handlers of the current
+context plus all handlers of the next context. We use this to bypass
+the original handler when en exception occures in an CATCH/CONTROL
+block.
+
+=cut
+
+*/
+inline op rethrow_skipnextctx(in PMC) :base_core {
+ PMC *except = $1;
+ opcode_t *dest;
+ STRING *handler_iter_str = Parrot_str_new_constant(interp, "handler_iter");
+ PMC *next_ctx = Parrot_pcc_get_caller_ctx(interp, CURRENT_CONTEXT(interp));
+ VTABLE_set_attr_str(interp, except, handler_iter_str, PMCNULL);
+ VTABLE_set_pointer(interp, except, next_ctx);
+ dest = Parrot_ex_rethrow_from_op(interp, except);
+ goto ADDRESS(dest);
+}
+
+inline op die_with_payload(in PMC, in PMC) :flow {
+ opcode_t *dest;
+ opcode_t * const ret = expr NEXT();
+ PMC * const resume = pmc_new(interp, enum_class_Continuation);
+ STRING * const msg = PMC_IS_NULL($1) ? NULL : VTABLE_get_string(interp, $1);
+ PMC * const exception =
+ Parrot_ex_build_exception(interp, EXCEPT_error, CONTROL_ERROR, msg);
+
+ if (!PMC_IS_NULL($2)) {
+ VTABLE_set_attr_str(interp, exception, Parrot_str_new_constant(interp, "payload"), $2);
+ }
+
+ VTABLE_set_pointer(interp, resume, ret);
+
+ VTABLE_set_attr_str(interp, exception,
+ Parrot_str_new_constant(interp, "resume"), resume);
+ dest = Parrot_ex_throw_from_op(interp, exception, ret);
+ goto ADDRESS(dest);
+}
+
+
/*
* Local variables:
* c-file-style: "parrot"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment