view src/core.c/control.pm6 @ 0:c341f82e7ad7 default tip

Rakudo branch in cr.ie.u-ryukyu.ac.jp
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Thu, 26 Dec 2019 16:50:27 +0900
parents
children
line wrap: on
line source

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 {
    my Mu $ex := nqp::newexception();
    nqp::setpayload($ex, arg);
    nqp::setextype($ex, $type);
    nqp::throw($ex);
    arg;
}
sub THROW-NIL(int $type --> Nil) {
    my Mu $ex := nqp::newexception();
#    nqp::setpayload($ex, Nil);
    nqp::setextype($ex, $type);
    nqp::throw($ex);
}

sub RETURN-LIST(Mu \list) is raw {
    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(\x) { THROW(nqp::const::CONTROL_TAKE, x) }
multi sub take-rw(|) {
    THROW(nqp::const::CONTROL_TAKE,RETURN-LIST(nqp::p6argvmarray))
}

proto sub take(|) {*}
multi sub take()   { die "take without parameters doesn't make sense" }
multi sub take(\x) {
    THROW(nqp::const::CONTROL_TAKE, nqp::p6recont_ro(x))
}
multi sub take(|) {
    THROW(
      nqp::const::CONTROL_TAKE,
      nqp::p6recont_ro(RETURN-LIST(nqp::p6argvmarray))
    )
}

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('$/');
    my Mu $dispatcher := nqp::p6finddispatcher('callwith');
    $dispatcher.exhausted ?? Nil !!
        $dispatcher.call_with_args(|c)
}

sub nextwith(|c) is raw {
    $/ := nqp::getlexcaller('$/');
    my Mu $dispatcher := nqp::p6finddispatcher('nextwith');
    nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $dispatcher.exhausted
        ?? Nil
        !! $dispatcher.call_with_args(|c))
}

sub callsame() is raw {
    $/ := nqp::getlexcaller('$/');
    my Mu $dispatcher := nqp::p6finddispatcher('callsame');
    $dispatcher.exhausted ?? Nil !!
        $dispatcher.call_with_capture(
            nqp::p6argsfordispatcher($dispatcher))
}

sub nextsame() is raw {
    $/ := nqp::getlexcaller('$/');
    my Mu $dispatcher := nqp::p6finddispatcher('nextsame');
    nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $dispatcher.exhausted
        ?? Nil
        !! $dispatcher.call_with_capture(nqp::p6argsfordispatcher($dispatcher)))
}

sub lastcall(--> True) {
    nqp::p6finddispatcher('lastcall').last();
}

sub nextcallee() {
    my Mu $dispatcher := nqp::p6finddispatcher('nextsame');
    $dispatcher.exhausted ?? Nil !! $dispatcher.shift_callee()
}

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(|) { X::NYI.new(feature => 'leave').throw }

sub emit(Mu \value --> Nil) {
    THROW(nqp::const::CONTROL_EMIT, nqp::p6recont_ro(value));
}
sub done(--> Nil) {
    THROW-NIL(nqp::const::CONTROL_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) {
    nqp::stmts(
      (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) {
    my Mu \list-without := nqp::list();
    nqp::push(list-without, nqp::decont(~$_)) for @list.eager;
    list-without;
}

# vim: ft=perl6 expandtab sw=4