Home > Raku > Exceptionally colourful

Exceptionally colourful

STDERR is often (ab)used for printing debug or status information. This can create clutter which in turn hides the important stuff. I want to print the essential stuff in exceptions in red unless a dynvar or environment variable is set.

class Explode is Exception {
    method message {
        put "$*dynvar is bad‼";
    }
}

sub e() {
    await start {
        Explode.new.throw;
    }
    CATCH { default { put .message } }
}

my $*dynvar = 'foo';
e();

# OUTPUT: foo is bad‼

We can access a dynvar inside the method of an exception from within an exception handler. In Shell::Piping error handling is a bit more involved. The biggest issue is fail because the enclosed exception is thrown by some routine in CORE about two steps down the call tree seen from the implicit or explicit MAIN sub. The dynvar is simply not there at this point in time. Luckily instances of Exception tend not to be long lived so we can get away with capturing the state of a dynvar at object creation. A good place to do so is TWEAK.

sub infix:<///>(\a, \b) is raw {
    my $dyn-name = a.VAR.name;
    my $has-outer-dynvar = CALLER::CALLERS::{$dyn-name}:exists;
    CALLER::{$dyn-name} = $has-outer-dynvar ?? CALLER::CALLERS::{$dyn-name} !! b
}

role Exception::Colored is Exception is export {
    has $.color;
    submethod TWEAK {
        my $*colored-exceptions /// on;
        $!color = $*colored-exceptions ~~ on && $env-color ?? 31 !! 0;
    }
    method RED($str) {
        $*ERR.t ?? ("\e[" ~ $.color ~ 'm' ~ $str ~ "\e[0m") !! $str
    }
}

Now I can use $.RED in .message of any exception that is Exception::Colored.

To have a look at the full stack was very helpful to figure out why the dynvar wasn’t there in some cases. For such cases I have a context sensitive binding in my .vimrc.

nmap <F1> :w<CR>:!raku -I ./lib %<CR>
imap <F1> <esc>:w<CR>:!raku --ll-exception -I ./lib %<CR>

In insert mode F1 will write the file and run Rakudo with an additional parameter. This results in a full stack trace.

foo failed
   at SETTING::src/core.c/Exception.pm6:62  (/usr/local/src/rakudo/install/share/perl6/runtime/CORE.c.setting.moarvm:throw)
 from SETTING::src/core.c/Failure.pm6:56  (/usr/local/src/rakudo/install/share/perl6/runtime/CORE.c.setting.moarvm:throw)
 from SETTING::src/core.c/Failure.pm6:111  (/usr/local/src/rakudo/install/share/perl6/runtime/CORE.c.setting.moarvm:sink)
 from /home/dex/tmp/tmp-2.raku:56  (<ephemeral file>:<unit>)
 from /home/dex/tmp/tmp-2.raku:1  (<ephemeral file>:<unit-outer>)
 from gen/moar/stage2/NQPHLL.nqp:1948  (/usr/local/src/rakudo/install/share/nqp/lib/NQPHLL.moarvm:eval)
 from gen/moar/stage2/NQPHLL.nqp:2153  (/usr/local/src/rakudo/install/share/nqp/lib/NQPHLL.moarvm:evalfiles)
 from gen/moar/stage2/NQPHLL.nqp:2113  (/usr/local/src/rakudo/install/share/nqp/lib/NQPHLL.moarvm:command_eval)
 from gen/moar/Compiler.nqp:60  (/usr/local/src/rakudo/install/share/perl6/lib/Perl6/Compiler.moarvm:command_eval)
 from gen/moar/stage2/NQPHLL.nqp:2038  (/usr/local/src/rakudo/install/share/nqp/lib/NQPHLL.moarvm:command_line)
 from gen/moar/rakudo.nqp:116  (/usr/local/src/rakudo/install/share/perl6/runtime/perl6.moarvm:MAIN)
 from gen/moar/rakudo.nqp:1  (/usr/local/src/rakudo/install/share/perl6/runtime/perl6.moarvm:<mainline>)
 from <unknown>:1  (/usr/local/src/rakudo/install/share/perl6/runtime/perl6.moarvm:<main>)
 from <unknown>:1  (/usr/local/src/rakudo/install/share/perl6/runtime/perl6.moarvm:<entry>)

As you can see there are quite a few things called before your script will be executed. Luckily Rakudo is implementing Raku in Raku so we have a chance to see what is going on.

Categories: Raku
  1. August 25, 2020 at 01:39

    The TWEAK in role will work until another TWEAK is declared by an exception class. This is fixed in Raku 6.e.PREVIEW.

  1. August 24, 2020 at 20:20
  2. August 31, 2020 at 22:50
  3. September 7, 2020 at 23:13

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: