Skip to content

Commit

Permalink
Apply patch from mls++ that forbids duplicate CATCH and CONTROL block…
Browse files Browse the repository at this point in the history
…s, and saves adding a handler to a try block if it already has a CATCH.
  • Loading branch information
jnthn committed Aug 5, 2011
1 parent 01c7286 commit 2b00770
Showing 1 changed file with 38 additions and 15 deletions.
53 changes: 38 additions & 15 deletions src/Perl6/Actions.pm
Expand Up @@ -694,13 +694,19 @@ class Perl6::Actions is HLL::Actions {
}

method statement_control:sym<CATCH>($/) {
if has_block_handler($*ST.cur_lexpad(), 'CONTROL', :except(1)) {
$/.CURSOR.panic("only one CATCH block allowed");
}
my $block := $<block>.ast;
push_block_handler($/, $*ST.cur_lexpad(), $block);
$*ST.cur_lexpad().handlers()[0].handle_types_except('CONTROL');
make PAST::Var.new( :name('Nil'), :scope('lexical') );
}

method statement_control:sym<CONTROL>($/) {
if has_block_handler($*ST.cur_lexpad(), 'CONTROL') {
$/.CURSOR.panic("only one CONTROL block allowed");
}
my $block := $<block>.ast;
push_block_handler($/, $*ST.cur_lexpad(), $block);
$*ST.cur_lexpad().handlers()[0].handle_types('CONTROL');
Expand Down Expand Up @@ -736,22 +742,28 @@ class Perl6::Actions is HLL::Actions {
}

method statement_prefix:sym<try>($/) {
my $block := PAST::Op.new(:pasttype<call>, block_closure($<blorst>.ast)); # XXX should be immediate
my $past := PAST::Op.new( :pasttype('try'), $block );

# On failure, capture the exception object into $!.
$past.push(
PAST::Op.new(:pasttype<bind_6model>,
PAST::Var.new(:name<$!>, :scope<lexical_6model>),
PAST::Op.new(:name<&EXCEPTION>, :pasttype<call>,
PAST::Op.new(:inline(" .get_results (%r)\n finalize %r")))));

# Otherwise, put Mu into $!.
$past.push(
PAST::Op.new(:pasttype<bind_6model>,
PAST::Var.new( :name<$!>, :scope<lexical_6model> ),
PAST::Var.new( :name<Mu>, :scope<lexical_6model> )));
my $block := $<blorst>.ast;
my $past;
if has_block_handler($block<past_block>, 'CONTROL', :except(1)) {
# we already have a CATCH block, nothing to do here
$past := PAST::Op.new( :pasttype('call'), $block );
} else {
$block := PAST::Op.new(:pasttype<call>, $block); # XXX should be immediate
$past := PAST::Op.new( :pasttype('try'), $block );

# On failure, capture the exception object into $!.
$past.push(
PAST::Op.new(:pasttype<bind_6model>,
PAST::Var.new(:name<$!>, :scope<lexical_6model>),
PAST::Op.new(:name<&EXCEPTION>, :pasttype<call>,
PAST::Op.new(:inline(" .get_results (%r)\n finalize %r")))));

# Otherwise, put Mu into $!.
$past.push(
PAST::Op.new(:pasttype<bind_6model>,
PAST::Var.new( :name<$!>, :scope<lexical_6model> ),
PAST::Var.new( :name<Mu>, :scope<lexical_6model> )));
}
make $past;
}

Expand Down Expand Up @@ -3565,6 +3577,17 @@ class Perl6::Actions is HLL::Actions {
);
}

sub has_block_handler($block, $type, :$except) {
my @handlers := $block.handlers();
for @handlers {
my $ltype := $except ?? $_.handle_types_except() !! $_.handle_types();
if pir::defined($ltype) && $ltype eq $type {
return 1;
}
}
0;
}

# Handles the case where we have a default value closure for an
# attribute.
method install_attr_init($/) {
Expand Down

0 comments on commit 2b00770

Please sign in to comment.