Skip to content

Commit

Permalink
Rewrite publication of wrapper packages
Browse files Browse the repository at this point in the history
Previously we relied on hacks and implementation details to get our wrapper
packages into the user's namespace. This did not work all that well anymore
after module loading became lexical in rakudo. This rewrite replaces those
hacks with an implementation that uses the same mechanism that handles symbols
from native Perl 6 modules.
  • Loading branch information
niner committed Jan 28, 2017
1 parent 12d2cb0 commit c125bfc
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 14 deletions.
67 changes: 54 additions & 13 deletions lib/Inline/Perl5.pm6
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,7 @@ method import (Str $module, *@args) {
}

my %loaded_modules;
method require(Str $module, Num $version?) {
method require(Str $module, Num $version?, Bool :$handle) {
# wrap the load_module call so exceptions can be translated to Perl 6
if $version {
self.call('v6::load_module', $module, $version);
Expand All @@ -1267,6 +1267,11 @@ method require(Str $module, Num $version?) {

return unless self eq $default_perl5; # Only create Perl 6 packages for the primary interpreter to avoid confusion

if try ::($module) ~~ Perl5Extension {
# Wrapper package already created. Nothing left for us to do.
return CompUnit::Handle.from-unit(Stash.new);
}

my $class;
my $first-time = True;
my $symbols = self.subs_in_module($module);
Expand Down Expand Up @@ -1296,7 +1301,8 @@ method require(Str $module, Num $version?) {
# register the new class by its name
my @parts = $module.split('::');
my $inner = @parts.pop;
my $ns := ::GLOBAL.WHO;
my $stash := $handle ?? Stash.new !! ::GLOBAL.WHO;
my $ns := $stash;
for @parts {
$ns{$_} := Metamodel::PackageHOW.new_type(name => $_) unless $ns{$_}:exists;
$ns := $ns{$_}.WHO;
Expand All @@ -1310,22 +1316,57 @@ method require(Str $module, Num $version?) {
if $first-time {
# install subs like Test::More::ok
for @$symbols -> $name {
::($module).WHO{"&$name"} := sub (*@args) {
$class.WHO{"&$name"} := sub (*@args) {
self.call("{$module}::$name", @args.list);
}
}
}

::($module).WHO<EXPORT> := Metamodel::PackageHOW.new();
::($module).WHO<&EXPORT> := sub EXPORT(*@args) {
$*W.do_pragma(Any, 'precompilation', False, []);
return Map.new(self.import($module, @args.list).map({
my $name = $_;
'&' ~ $name => sub (|args) {
self.call-args("main::$name", args); # main:: because the sub got exported to main
}
}));
};
my &export := sub EXPORT(*@args) {
$*W.do_pragma(Any, 'precompilation', False, []);
my @symbols = self.import($module, @args.list).map({
my $name = $_;
'&' ~ $name => sub (|args) {
self.call-args("main::$name", args); # main:: because the sub got exported to main
}
});
# Hack needed for rakudo versions post-lexical_module_load but before support for
# getting a CompUnit::Handle from require was implemented.
@symbols.unshift: $module => $class unless $handle;
return Map.new(@symbols);
};

unless $handle {
::($module).WHO<EXPORT> := Metamodel::PackageHOW.new();
::($module).WHO<&EXPORT> := &export;
}
my $compunit-handle = class :: is CompUnit::Handle {
has &!EXPORT;
use nqp;
submethod fill(Stash $unit, &EXPORT) {
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(
nqp::create($?CLASS),
CompUnit::Handle,
'$!unit',
nqp::decont($unit),
),
$?CLASS,
'&!EXPORT',
&EXPORT,
)
}
method export-package() returns Stash {
Stash.new
}
method export-sub() returns Callable {
&!EXPORT
}
}.fill(
$stash,
&export,
);
return $compunit-handle;
}

method use(Str $module, *@args) {
Expand Down
5 changes: 4 additions & 1 deletion t/use.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ BEGIN {
$p5.call('Test::More::ok', 1, 'use loaded the module');
}

use Test::More:from<Perl5>;

BEGIN {
Test::More::ok(1, 'package functions work');
$p5.use('Data::Dumper');
}

use Data::Dumper:from<Perl5>;

my $dumper = Data::Dumper.new([1, 2].item);
Test::More::is($dumper.Dump.Str, "\$VAR1 = 1;\n \$VAR2 = 2;\n", 'constructor works');
Test::More::is(Data::Dumper.Dump([1, 2].item).Str, "\$VAR1 = 1;\n \$VAR2 = 2;\n", 'package methods work');
Expand Down

0 comments on commit c125bfc

Please sign in to comment.