Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Get deferal stuff back in place, to the degree we had it in alpha.
  • Loading branch information
jnthn committed Feb 25, 2010
1 parent 5d38786 commit 1cdb0d8
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 9 deletions.
3 changes: 3 additions & 0 deletions src/Perl6/Actions.pm
Expand Up @@ -205,6 +205,9 @@ method newpad($/) {
my $new_block := PAST::Block.new( PAST::Stmts.new(
PAST::Op.new(
:inline(" .local pmc true\n true = get_hll_global 'True'")
),
PAST::Var.new(
:name('__CANDIDATE_LIST__'), :scope('lexical'), :isdecl(1)
)
));
@BLOCK.unshift($new_block);
Expand Down
134 changes: 134 additions & 0 deletions src/builtins/control.pir
Expand Up @@ -209,6 +209,140 @@ src/builtins/control.pir - control flow related functions
.return ($N0)
.end


=item callwith

=cut

.sub '&callwith'
.param pmc pos_args :slurpy
.param pmc named_args :slurpy :named

# For callwith, it's easy - just want to get the next candidate, call
# it and hand back it's return values. A tailcall does fine.
.local pmc clist, lexpad, self, next
get_next_candidate_info clist, $P0, lexpad
next = clone clist
next.'set_failure_mode'()
$P0 = deref next
$I0 = isa $P0, 'Method'
unless $I0 goto not_method
self = lexpad['self']
.tailcall next(self, pos_args :flat, named_args :flat :named)
not_method:
.tailcall next(pos_args :flat, named_args :flat :named)
.end


=item nextwith

=cut

.sub '&nextwith'
.param pmc pos_args :slurpy
.param pmc named_args :slurpy :named

# Find next candiate, invoke it and get its return value, then use
# return to return it as if it was from our original call.
.local pmc clist, lexpad, self, next, result
get_next_candidate_info clist, $P0, lexpad
next = clone clist
next.'set_failure_mode'()
$P0 = deref next
$I0 = isa $P0, 'Method'
unless $I0 goto not_method
self = lexpad['self']
(result) = next(self, pos_args :flat, named_args :flat :named)
goto process_result
not_method:
(result) = next(pos_args :flat, named_args :flat :named)

process_result:
$I0 = isa result, ['Failure']
unless $I0 goto did_defer
$P0 = result.'exception'()
if null $P0 goto did_defer
$S0 = $P0.'Str'()
if $S0 != 'No method to defer to' goto did_defer
.return (result)

did_defer:
$P0 = root_new ['parrot';'Exception']
$P0['type'] = .CONTROL_RETURN
setattribute $P0, 'payload', result
throw $P0
.end


=item callsame

=cut

.sub '&callsame'
# Find next candidate as well as caller and lexpad.
.local pmc clist, routine, lexpad, next
get_next_candidate_info clist, routine, lexpad
next = clone clist

# Build arguments based upon what the caller was originall invoked with,
# and tailcall the next candidate.
.local pmc pos_args, named_args
$P1 = lexpad['call_sig']
(pos_args, named_args) = '!deconstruct_call_sig'($P1)
next.'set_failure_mode'()
.tailcall next(pos_args :flat, named_args :flat :named)
.end


=item nextsame

=cut

.sub '&nextsame'
# Find next candidate as well as caller and lexpad.
.local pmc clist, routine, lexpad, next
get_next_candidate_info clist, routine, lexpad
next = clone clist

# Build arguments based upon what the caller was originall invoked with,
# get the result of the next candidate and use return to retrun from
# the caller, provided the defer did not fail.
.local pmc pos_args, named_args, result
$P1 = lexpad['call_sig']
(pos_args, named_args) = '!deconstruct_call_sig'($P1)
next.'set_failure_mode'()
(result) = next(pos_args :flat, named_args :flat :named)

$I0 = isa result, ['Failure']
unless $I0 goto did_defer
$P0 = result.'exception'()
if null $P0 goto did_defer
$S0 = $P0.'Str'()
if $S0 != 'No method to defer to' goto did_defer
.return (result)

did_defer:
$P0 = root_new ['parrot';'Exception']
$P0['type'] = .CONTROL_RETURN
setattribute $P0, 'payload', result
throw $P0
.end


=item lastcall

Trims the candidate list so that nextsame/nextwith/callsame/callwith will
find nothing more to call.

=cut

.sub '&lastcall'
# Find candidate list and trim it.
.local pmc clist
get_next_candidate_info clist, $P0, $P1
clist.'trim_candidate_list'()
.end

=back

=cut
15 changes: 15 additions & 0 deletions src/glue/dispatch.pir
Expand Up @@ -253,3 +253,18 @@ there are none.
concat $S0, "'"
'&die'($S0)
.end
=item !deferal_fail
Used by P6invocation to help us get soft-failure semantics when no deferal
is possible.
=cut
.sub '!deferal_fail'
.param pmc pos_args :slurpy
.param pmc named_args :slurpy :named
.lex '__CANDIDATE_LIST__', $P0
.tailcall '!FAIL'('No method to defer to')
.end
12 changes: 3 additions & 9 deletions src/ops/perl6.ops
Expand Up @@ -306,7 +306,7 @@ nextsame need.
inline op get_next_candidate_info(out PMC, out PMC, out PMC) :base_core {
PMC *ctx = Parrot_pcc_get_caller_ctx(interp, CURRENT_CONTEXT(interp));
STRING *name = string_from_literal(interp, "__CANDIDATE_LIST__");
STRING *wrapper = string_from_literal(interp, "$!wrapper_block");
STRING *wrapper = string_from_literal(interp, "$!p6type");
PMC *last_lexpad = PMCNULL;
PMC *last_sub = PMCNULL;

Expand All @@ -317,14 +317,8 @@ inline op get_next_candidate_info(out PMC, out PMC, out PMC) :base_core {
if (!PMC_IS_NULL(clist)) {
/* Found. Set results and we're done. */
$1 = clist;
if (PMC_IS_NULL(VTABLE_getprop(interp, Parrot_pcc_get_sub(interp, ctx), wrapper))) {
$2 = Parrot_pcc_get_sub(interp, ctx);
$3 = lexpad;
}
else {
$2 = last_sub;
$3 = last_lexpad;
}
$2 = Parrot_pcc_get_sub(interp, ctx);
$3 = lexpad;
break;
}
else {
Expand Down

0 comments on commit 1cdb0d8

Please sign in to comment.