# Pastebin r9yB0p52 sunit module Devel::Trace; use nqp; my %sources; sub eval_in_ctx($ctx, $code) { ENTER $*DEBUG_HOOKS.suspend(); LEAVE $*DEBUG_HOOKS.unsuspend(); my $compiler := nqp::getcomp('perl6'); my $vm_ctx := nqp::getattr(nqp::decont($ctx), PseudoStash, '$!ctx'); my $comp'd := nqp::findmethod($compiler, 'compile')($compiler, $code, :outer_ctx($vm_ctx), :global(GLOBAL)); nqp::forceouterctx($comp'd, $vm_ctx); $comp'd(); } my class SourceFile { has $.filename; has $.source; has @!lines; method BUILD(:$!filename, :$!source) { # Ensure source ends with a newline. unless $!source ~~ /\n$/ { $!source ~= "\n"; } # Store (abbreviated if needed) lines. @!lines = lines($!source).map(-> $l { $l.chars > 77 ?? $l.substr(0, 74) ~ '...' !! $l }); my $i = 0; } method say_line($from, $to, $ctx) { my $line-number = $!source.substr(0, $to).lines.elems; my $line-text = $.source.substr($from, $to - $from); say "./$.filename:$line-number: " ~ $line-text; for $line-text.comb(/\$\w\S*/) -> $t { my $k = $t.subst(/<[./)+,]>.*/, ''); my $v = '(?)'; try { $v = eval_in_ctx($ctx, $k); } say $k ~ ': ' ~ $v; } } } $*DEBUG_HOOKS.set_hook('new_file', -> $filename, $source { %sources{$filename} = SourceFile.new(:$filename, :$source); }); $*DEBUG_HOOKS.set_hook('statement_simple', -> $filename, $ctx, $from, $to { %sources{$filename}.say_line($from, $to, $ctx); }); $*DEBUG_HOOKS.set_hook('statement_cond', -> $filename, $ctx, $type, $from, $to { %sources{$filename}.say_line($from, $to, $ctx); });