Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
keep outer block context right in wanted pass
When descending subtrees in the interleaved 'wanted' pass, we can visit
blocks that are done compiling, which means the @!BLOCKS stack in World is
no longer correct.  When entering such a node, we set $*WANTEDOUTERBLOCK
to the correct outer block context, and generate new blocks within
that context.  (This dynvar is a bit of a bandaid that will hopefully no
longer be needed after we switch to following outer chains for everything,
rather than always assuming (as the @!BLOCKS routines assume) that World
routines are only for the single bottom-up pass that happens during parsing.)
  • Loading branch information
TimToady committed Dec 31, 2015
1 parent e651629 commit 37e742f
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 22 deletions.
29 changes: 15 additions & 14 deletions src/Perl6/Actions.nqp
Expand Up @@ -76,6 +76,7 @@ sub wanted($ast,$by) {
}
elsif nqp::istype($ast,QAST::Block) {
my int $i := 1;
my $*WANTEDOUTERBLOCK := $ast;
while $i <= $e {
$ast[$i] := WANTED($ast[$i], $byby);
++$i;
Expand Down Expand Up @@ -115,26 +116,24 @@ sub wanted($ast,$by) {
# we always have a body
my $cond := WANTED($ast[0],$byby);
my $body := WANTED($ast[1],$byby);
my $block := Perl6::Actions::make_thunk_ref($body, $body.node);
my $past := QAST::Op.new(:op<callmethod>, :name<from-loop>, :node($body.node),
QAST::WVal.new( :value($*W.find_symbol(['Seq']))),
block_closure(Perl6::Actions::make_thunk_ref($body, $body.node)) );
block_closure($block) );

# conditional (if not always true (or if repeat))
$past.push( block_closure(
Perl6::Actions::make_thunk_ref(
$while
?? $cond
!! QAST::Op.new( :op<callmethod>, :name<not>, $cond ),
nqp::can($cond,'node')
?? $cond.node
!! $body.node
)
))
if $repeat || !$cond.has_compile_time_value || !$cond.compile_time_value == $while;
if $repeat || !$cond.has_compile_time_value || !$cond.compile_time_value == $while {
$cond := QAST::Op.new( :op<callmethod>, :name<not>, $cond ) unless $while;
$block := Perl6::Actions::make_thunk_ref($cond, nqp::can($cond,'node') ?? $cond.node !! $body.node);
$past.push( block_closure($block) );
}

# 3rd part of loop, if any
$past.push( UNWANTED(block_closure(Perl6::Actions::make_thunk_ref($ast[2], $ast[2].node)),$byby) )
if +@($ast) > 2;
if +@($ast) > 2 {
$block := Perl6::Actions::make_thunk_ref($ast[2], $ast[2].node);
$block.annotate('outer',$*WANTEDOUTERBLOCK) if $*WANTEDOUTERBLOCK;
$past.push( UNWANTED(block_closure($block),$byby) )
}

if $repeat {
my $wval := QAST::WVal.new( :value($*W.find_symbol(['True'])) );
Expand Down Expand Up @@ -228,6 +227,8 @@ sub unwanted($ast, $by) {
}
elsif nqp::istype($ast,QAST::Block) {
my int $i := 1;
my $*WANTEDOUTERBLOCK := $ast;
note('++ ' ~ ($*W.is_lexically_visible('&prefix:<++>',$ast) ?? "yes" !! "no"));
while $i <= $e {
$ast[$i] := UNWANTED($ast[$i], $byby);
++$i;
Expand Down
36 changes: 28 additions & 8 deletions src/Perl6/World.nqp
Expand Up @@ -426,7 +426,10 @@ class Perl6::World is HLL::World {
method push_lexpad($/) {
# Create pad, link to outer, annotate with creating statement, and add to stack.
my $pad := QAST::Block.new( QAST::Stmts.new( :node($/) ) );
if +@!BLOCKS {
if $*WANTEDOUTERBLOCK { # (outside of 1st push/pop pass)
$pad.annotate('outer', $*WANTEDOUTERBLOCK);
}
elsif +@!BLOCKS {
$pad.annotate('outer', @!BLOCKS[+@!BLOCKS - 1]);
}
$pad.annotate('statement_id', $*STATEMENT_ID);
Expand Down Expand Up @@ -1899,7 +1902,12 @@ class Perl6::World is HLL::World {

# Creates a simple code object with an empty signature
method create_simple_code_object($block, $type) {
self.cur_lexpad()[0].push($block);
if $*WANTEDOUTERBLOCK {
$*WANTEDOUTERBLOCK[0].push($block);
}
else {
self.cur_lexpad()[0].push($block);
}
my $sig := self.create_signature(nqp::hash('parameter_objects', []));
return self.create_code_object($block, $type, $sig);
}
Expand Down Expand Up @@ -3453,12 +3461,24 @@ class Perl6::World is HLL::World {
# scopes.
if +@name == 1 {
my $final_name := @name[0];
my int $i := $start_scope;
while $i > 0 {
$i := $i - 1;
my %sym := @!BLOCKS[$i].symbol($final_name);
if +%sym {
return self.force_value(%sym, $final_name, 1);
if $*WANTEDOUTERBLOCK {
my $scope := $*WANTEDOUTERBLOCK;
while $scope {
my %sym := $scope.symbol($final_name);
if +%sym {
return self.force_value(%sym, $final_name, 1);
}
$scope := $scope.ann('outer');
}
}
else {
my int $i := $start_scope;
while $i > 0 {
$i := $i - 1;
my %sym := @!BLOCKS[$i].symbol($final_name);
if +%sym {
return self.force_value(%sym, $final_name, 1);
}
}
}
}
Expand Down

0 comments on commit 37e742f

Please sign in to comment.