At yesterday online meeting of Germany PM we had a discussion about Destructuring Assignment aka unpacking aka Type Patterns which is available in languages like JS (ES6) and Haskell.
I claimed it shouldn't be to difficult to do this in pure Perl, this is what I got so far.
NB: This is a proof of concept !
Neither syntactic sugar nor performance are at it's limits.
(you know "release often ... yadda yadda" ;-)
Grabbing of (almost greedy) lists @arr and %hsh not implemented yet.
Comments welcome.
use strict;
use warnings;
use Data::Dump qw/pp dd/;
use Scalar::Util qw/reftype/;
use autovivification;
use Test::More;
use constant DBG => 0;
my @rules;
sub parse_arr (\@$) {
my ( $arr, $path ) = @_;
for ( my $i=0; $i <= @$arr; $i++ ) {
my $item = $arr->[$i];
parse( $item, "${path}[$i]");
}
}
sub parse_hsh (\%$) {
my ( $hsh, $path ) = @_;
while ( my ($key,$val) = each %$hsh ) {
parse( $val, "${path}{$key}");
}
}
sub parse {
my ( $item, $path ) = @_;
$path //= '';
my $type = ref $item;
return
unless $type;
if ( $type eq "GRAB") {
push @rules, [ $item->{ref} , $path ];
} elsif ( $type eq "ARRAY" ) {
parse_arr( @$item, $path )
} elsif ( $type eq "HASH" ) {
parse_hsh( %$item, $path )
} else {
warn "Unknown $type";
}
}
sub assign (++){
my ($pattern,$in) =@_;
@rules = ();
parse($pattern);
warn pp @rules if DBG;
no autovivification;
for my $rule (@rules) {
my ($ref,$path) = @$rule;
my $code = "\$in->$path";
$$ref = eval($code);
}
}
sub set (\[@$%]) {
bless {ref => $_[0]}, "GRAB";
}
my @pattern = ( 1,2,3, set my $y , [ 5,6, set my $z ] );
my $src = [ 1,2,3, 42 , [5,6, 666] ];
assign
@pattern
=>
$src;
is_deeply
(
[$z,$y],
[666, 42],
"AoA grabbing different levels"
);
assign
{ u => [undef, set( my $u )], v => set my $v }
=>
{ u => [1,123] , v => "VVV"}
;
is_deeply
(
[$u,$v],
[123,"VVV"],
"HoA grabbing different levels"
);
done_testing;
C:/Perl_524/bin\perl.exe d:/exp/grab_assign.pl
ok 1 - AoA grabbing different levels
ok 2 - HoA grabbing different levels
1..2