Skip to content

Commit

Permalink
- Added support for default values in variable declarations.
Browse files Browse the repository at this point in the history
Example:
	var (x, y=755, z=777) = (666, 655);

	say x;		# prints: 666
	say y;		# prints: 655
	say z;		# prints: 777

Also, this includes the support for slurpy variables:

	var (a, *b) = (1,2,3,4);
	say a;				# prints: 1
	say b;				# prints: [2,3,4]

	var *arr = (1,2,3);
	say arr;		# prints: [1,2,3]

	var :hash = (a => 1, b => 2);
	say hash;			# prints: Hash.new(a => 1, b => 2)

As a side-effect, all variables are now declared at the top of the functions. This improves the performance inside loops, since no reinitialization is done.
  • Loading branch information
trizen committed Oct 22, 2015
1 parent 96fe494 commit 5952210
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 19 deletions.
69 changes: 56 additions & 13 deletions lib/Sidef/Deparse/Perl.pm
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,63 @@ HEADER
}

sub _dump_init_vars {
my ($self, @vars) = @_;
my ($self, $init_obj) = @_;

my @vars = @{$init_obj->{vars}};
@vars || return '';

my @dumped_vars = map { exists($_->{value}) ? $self->deparse_expr({self => $_->{value}}) : ('undef') } @vars;
my @dumped_values = map { exists($_->{value}) ? $self->deparse_expr({self => $_->{value}}) : ('undef') } @vars;

# Ignore "undef" values
if (all { $_ eq 'undef' } @dumped_vars) {
@dumped_vars = ();
if (all { $_ eq 'undef' } @dumped_values) {
@dumped_values = ();
}

'my('
my @code;
push @code,
'('
. join(', ', map { $self->_dump_var($_) } @vars) . ')'
. (@dumped_vars ? ('=(' . join(', ', @dumped_vars) . ')') : '');
. (exists($init_obj->{args}) ? '=' . $self->deparse_args($init_obj->{args}) : '');

foreach my $var (@vars) {

ref($var) || next;
if (exists $var->{array}) {
my $name = $var->{name} . refaddr($var);
push @{$self->{function_declarations}}, [-1, 'my @' . $name . ';'];
push @code, (' ' x $Sidef::SPACES) . "\$$name = Sidef::Types::Array::Array->new(\@$name);\n";
delete $var->{array};
}
elsif (exists $var->{hash}) {
my $name = $var->{name} . refaddr($var);
push @{$self->{function_declarations}}, [-1, 'my %' . $name . ';'];
push @code, (' ' x $Sidef::SPACES) . "\$$name = Sidef::Types::Hash::Hash->new(\%$name);\n";
delete $var->{hash};
}
elsif (exists $var->{value}) {
my $value = $self->deparse_expr({self => $var->{value}});
if ($value ne '') {
push @code, (' ' x $Sidef::SPACES) . "\$$var->{name}" . refaddr($var) . " //= " . $value . ";\n";
}
}
}

# XXX: should we store the declaration in something like 'block_declarations'?
push @{$self->{function_declarations}},
[ -1,
'my('
. join(', ', map { $self->_dump_var($_) } @vars) . ')'
. (@dumped_values ? ('=(' . join(', ', @dumped_values) . ')') : '') . ';'
];

# Return the variables on assignments
if (@code > 1 or exists($init_obj->{args})) {
push @code, '(' . join(', ', map { $self->_dump_var($_) } @vars) . ')';
return ('do { ' . join(';', @code) . '}');
}

# Return one var as a list
'(' . join(',', @code) . ')';
}

sub _dump_sub_init_vars {
Expand Down Expand Up @@ -489,8 +532,7 @@ HEADER
}
}
elsif ($ref eq 'Sidef::Variable::Init') {
my @vars = @{$obj->{vars}};
$code = $self->_dump_init_vars(@vars);
$code = $self->_dump_init_vars($obj);
}
elsif ($ref eq 'Sidef::Variable::ClassInit') {
if ($addr{$refaddr}++) {
Expand Down Expand Up @@ -595,14 +637,15 @@ HEADER
else {
$code .= "\n" . (" " x ($Sidef::SPACES - $Sidef::SPACES_INCR)) . "sub {\n";

if (exists($obj->{init_vars}) and @{$obj->{init_vars}}) {
my $vars = $obj->{init_vars};
if (@{$obj->{init_vars}} > 1) {
if (exists($obj->{init_vars}) and @{$obj->{init_vars}{vars}}) {
my $vars = $obj->{init_vars}{vars};

# Remove the underscore (_) variable
if (@{$vars} > 1) {
--$#{$vars};
}
my @vars = map { @{$_->{vars}} } @{$vars}[0 .. $#{$vars}];

$code .= $self->_dump_sub_init_vars(@vars);
$code .= $self->_dump_sub_init_vars(@{$vars});

if ($is_function) {
$code .= (' ' x $Sidef::SPACES) . 'my @return;' . "\n";
Expand Down
20 changes: 18 additions & 2 deletions lib/Sidef/Parser.pm
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,23 @@ package Sidef::Parser {
error => "expected a variable name after the keyword '$type'!",
);

return Sidef::Variable::Init->new(@{$vars});
my $init_obj = Sidef::Variable::Init->new(vars => $vars);

if (/\G\h*=\h*/gc) {
my $args = (
/\G\s*(?=\()/gc
? $self->parse_arguments(code => $opt{code})
: $self->parse_obj(code => $opt{code})
) // $self->fatal_error(
code => $_,
pos => pos,
error => "expected an expression after variable declaration",
);

$init_obj->{args} = $args;
}

return $init_obj;
}

# Declaration of constants and static variables
Expand Down Expand Up @@ -1992,7 +2008,7 @@ package Sidef::Parser {
grep { ref($_) eq 'HASH' and ref($_->{obj}) eq 'Sidef::Variable::Variable' } @{$self->{vars}{$self->{class}}}
];

$block->{init_vars} = [map { Sidef::Variable::Init->new($_) } @{$var_objs}];
$block->{init_vars} = Sidef::Variable::Init->new(vars => $var_objs);

$block->{code} = $obj;
splice @{$self->{ref_vars_refs}{$self->{class}}}, 0, $count;
Expand Down
7 changes: 3 additions & 4 deletions lib/Sidef/Variable/Init.pm
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package Sidef::Variable::Init {

sub new {
my (undef, @vars) = @_;
bless {vars => \@vars}, __PACKAGE__;
my (undef, %opt) = @_;
bless \%opt, __PACKAGE__;
}

};
}

1;
32 changes: 32 additions & 0 deletions scripts/Tests/default_var_values.sf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/ruby

# Test for declaration of variables with default values

var (x, y=755, z=777) = (666, 655);

assert_eq(x, 666);
assert_eq(y, 655);
assert_eq(z, 777);

var (a, *b) = (1,2,3,4);
assert_eq(a, 1);
assert_eq(b, [2,3,4]);

var *arr = (21,42,84);
assert_eq(arr, [21, 42, 84]);

var :hash = (a => 21, b => 42);
assert_eq(hash, Hash.new(a => 21, b => 42));

assert_eq([var(p, q) = (9,10)], [9, 10]);
assert_eq(p, 9);
assert_eq(q, 10);

assert_eq([var(s=7, t=3)], [7, 3]);
assert_eq(s, 7);
assert_eq(t, 3);

assert_eq([var x = 42], [42]);
assert_eq(x, 42);

say "** Test passed!";

0 comments on commit 5952210

Please sign in to comment.