my class X::ControlFlow::Return { ... } my class X::Eval::NoSuchLang { ... } my class X::Multi::NoMatch { ... } my class X::NYI { ... } my class PseudoStash { ... } my class Label { ... } class CompUnit::DependencySpecification { ... } sub THROW(int $type, Mu \arg) is raw { # is implementation-detail my Mu $ex := nqp::newexception(); nqp::setpayload($ex, arg); nqp::setextype($ex, $type); nqp::throw($ex); arg; } sub THROW-NIL(int $type --> Nil) { # is implementation-detail my Mu $ex := nqp::newexception(); # nqp::setpayload($ex, Nil); nqp::setextype($ex, $type); nqp::throw($ex); } sub RETURN-LIST(Mu \list) is raw { # is implementation-detail my \reified := nqp::getattr(list, List, '$!reified'); nqp::isgt_i(nqp::elems(reified),1) ?? list !! nqp::elems(reified) ?? nqp::shift(reified) !! Nil } proto sub return-rw(|) {*} multi sub return-rw(--> Nil) { nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, Nil); } multi sub return-rw(Mu \x --> Nil) { nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, x); } multi sub return-rw(**@x is raw --> Nil) { nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, @x); } proto sub return(|) {*} multi sub return(--> Nil) { nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, Nil); } multi sub return(Mu \x --> Nil) { nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, nqp::p6recont_ro(x)); } multi sub return(**@x is raw --> Nil) { nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, @x); } proto sub take-rw(|) {*} multi sub take-rw() { die "take-rw without parameters doesn't make sense" } multi sub take-rw(\value) { my Mu $ex := nqp::newexception(); nqp::setpayload($ex,value); nqp::setextype($ex,nqp::const::CONTROL_TAKE); nqp::throw($ex); value } multi sub take-rw(|) { nqp::setpayload( (my Mu $ex := nqp::newexception), (my \out := nqp::isgt_i(nqp::elems(my $positionals := nqp::p6argvmarray),1) ?? nqp::p6bindattrinvres( nqp::create(List),List,'$!reified',$positionals) !! nqp::elems($positionals) ?? nqp::shift($positionals) !! Nil ) ); nqp::setextype($ex,nqp::const::CONTROL_TAKE); nqp::throw($ex); out } proto sub take(|) {*} multi sub take() { die "take without parameters doesn't make sense" } multi sub take(\value) { my Mu $ex := nqp::newexception(); nqp::setpayload($ex,my \out := nqp::p6recont_ro(value)); nqp::setextype($ex,nqp::const::CONTROL_TAKE); nqp::throw($ex); out } multi sub take(|) { nqp::setpayload( (my Mu $ex := nqp::newexception), (my \out := nqp::p6recont_ro( nqp::isgt_i(nqp::elems(my $positionals := nqp::p6argvmarray),1) ?? nqp::p6bindattrinvres( nqp::create(List),List,'$!reified',$positionals) !! nqp::elems($positionals) ?? nqp::shift($positionals) !! Nil )) ); nqp::setextype($ex,nqp::const::CONTROL_TAKE); nqp::throw($ex); out } proto sub goto($, *%) {*} multi sub goto(Label:D $x --> Nil) { $x.goto } proto sub last($?, *%) {*} multi sub last(--> Nil) { nqp::throwextype(nqp::const::CONTROL_LAST); Nil } multi sub last(Label:D $x --> Nil) { $x.last } proto sub next($?, *%) {*} multi sub next(--> Nil) { nqp::throwextype(nqp::const::CONTROL_NEXT); Nil } multi sub next(Label:D $x --> Nil) { $x.next } proto sub redo($?, *%) {*} multi sub redo(--> Nil) { nqp::throwextype(nqp::const::CONTROL_REDO); Nil } multi sub redo(Label:D $x --> Nil) { $x.redo } proto sub succeed(|) {*} multi sub succeed(--> Nil) { THROW-NIL(nqp::const::CONTROL_SUCCEED) } multi sub succeed(\x --> Nil) { THROW(nqp::const::CONTROL_SUCCEED, x) } multi sub succeed(| --> Nil) { THROW(nqp::const::CONTROL_SUCCEED,RETURN-LIST(nqp::p6argvmarray)) } sub proceed(--> Nil) { THROW-NIL(nqp::const::CONTROL_PROCEED) } sub callwith(|c) is raw { $/ := nqp::getlexcaller('$/'); #?if moar # TODO Future mechanism to avoid having to flatten here nqp::dispatch('boot-resume-caller', nqp::const::DISP_CALLWITH, |c) #?endif #?if !moar nqp::stmts((my Mu $dispatcher := nqp::p6finddispatcher('callwith')), $dispatcher.exhausted ?? Nil !! $dispatcher.call_with_args(|c)) #?endif } sub nextwith(|c) is raw { $/ := nqp::getlexcaller('$/'); #?if moar # TODO Future mechanism to avoid having to flatten here nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, nqp::dispatch('boot-resume-caller', nqp::const::DISP_CALLWITH, |c)) #?endif #?if !moar nqp::stmts((my Mu $dispatcher := nqp::p6finddispatcher('nextwith')), nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $dispatcher.exhausted ?? Nil !! $dispatcher.call_with_args(|c))) #?endif } sub callsame() is raw { $/ := nqp::getlexcaller('$/'); #?if moar nqp::dispatch('boot-resume-caller', nqp::const::DISP_CALLSAME) #?endif #?if !moar nqp::stmts((my Mu $dispatcher := nqp::p6finddispatcher('callsame')), $dispatcher.exhausted ?? Nil !! $dispatcher.call_with_capture( nqp::p6argsfordispatcher($dispatcher))) #?endif } sub nextsame() is raw { $/ := nqp::getlexcaller('$/'); #?if moar nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, nqp::dispatch('boot-resume-caller', nqp::const::DISP_CALLSAME)) #?endif #?if !moar nqp::stmts((my Mu $dispatcher := nqp::p6finddispatcher('nextsame')), nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $dispatcher.exhausted ?? Nil !! $dispatcher.call_with_capture(nqp::p6argsfordispatcher($dispatcher)))) #?endif } sub lastcall(--> True) { #?if moar nqp::dispatch('boot-resume-caller', nqp::const::DISP_LASTCALL) #?endif #?if !moar nqp::p6finddispatcher('lastcall').last(); #?endif } sub nextcallee() { #?if moar nqp::dispatch('boot-resume-caller', nqp::const::DISP_NEXTCALLEE) #?endif #?if !moar nqp::stmts((my Mu $dispatcher := nqp::p6finddispatcher('nextcallee')), $dispatcher.exhausted ?? Nil !! $dispatcher.shift_callee()) #?endif } sub samewith(|c) { $/ := nqp::getlexcaller('$/'); my Mu $ctx := nqp::ctxcaller(nqp::ctx()); until nqp::isnull($ctx) { my $caller := nqp::getcodeobj(nqp::ctxcode($ctx)); if nqp::istype($caller, Routine) { if $caller.multi { die "Could not find dispatcher" unless my $dispatcher := nqp::can($caller,"dispatcher") && $caller.dispatcher; return nqp::istype($caller, Method) ?? $dispatcher(nqp::atkey($ctx, 'self') // $caller.package,|c) !! $dispatcher(|c); } else { return $caller(|c); } } $ctx := nqp::ctxouter($ctx); } die "Cannot use samewith outside of a routine"; } sub leave(|) { NYI('leave').throw; } sub emit(Mu \value --> Nil) { my Mu $ex := nqp::newexception(); nqp::setpayload($ex,nqp::p6recont_ro(value)); nqp::setextype($ex,nqp::const::CONTROL_EMIT); nqp::throw($ex); } proto sub done(|) {*} multi sub done(--> Nil) { THROW-NIL(nqp::const::CONTROL_DONE); } multi sub done(Mu \value --> Nil) { emit value; done; } proto sub die(|) {*}; multi sub die(--> Nil) { my $stash := CALLER::LEXICAL::; my $payload = $stash<$!>.DEFINITE ?? $stash<$!> !! "Died"; $payload ~~ Exception ?? $payload.throw !! X::AdHoc.new(:$payload).throw } multi sub die(Exception:U $e --> Nil) { X::AdHoc.new(:payload("Died with undefined " ~ $e.^name)).throw; } multi sub die($payload --> Nil) { $payload ~~ Exception ?? $payload.throw !! X::AdHoc.new(:$payload).throw } multi sub die(|cap ( *@msg ) --> Nil) { X::AdHoc.from-slurpy(|cap).throw } proto sub warn(|) {*} multi sub warn(*@msg) { my $msg := @msg.join || "Warning: something's wrong"; my $ex := nqp::newexception(); nqp::setmessage($ex, nqp::unbox_s($msg)); nqp::setextype($ex, nqp::const::CONTROL_WARN); nqp::throw($ex); 0; } multi sub warn(Junction:D $j) { $j.THREAD: &warn } constant Inf = nqp::p6box_n(nqp::inf()); constant NaN = nqp::p6box_n(nqp::nan()); # For some reason, we cannot move this to Rakudo::Internals as a class # method, because then the return value is always HLLized :-( sub CLONE-HASH-DECONTAINERIZED(\hash) { # is implementation-detail my \clone := nqp::hash; my \iter := nqp::iterator(nqp::getattr(hash,Map,'$!storage')); nqp::while( iter, nqp::bindkey(clone, nqp::iterkey_s(nqp::shift(iter)), nqp::if( nqp::defined(nqp::iterval(iter)), nqp::decont(nqp::iterval(iter)).Str, '' ) ) ); clone } sub CLONE-LIST-DECONTAINERIZED(*@list) { # is implementation-detail my Mu \list-without := nqp::list(); nqp::push(list-without, nqp::decont(~$_)) for @list.eager; list-without; } # vim: expandtab shiftwidth=4