Skip to content

Commit

Permalink
- Improved the support for autovivification.
Browse files Browse the repository at this point in the history
Example:

	var a = [];
	a[0]{:foo}[1][2]{:bar}{:baz} = 42;
	say a;

In the above example, all required hashes and arrays are automatically created, generating a structure like this:

	Hash("foo" => [nil, [nil, nil, Hash("bar" => Hash("baz" => 42))]])
  • Loading branch information
trizen committed Dec 12, 2015
1 parent 7f6a0eb commit 4455a3f
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 73 deletions.
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ scripts/Tests/array_compare.sf
scripts/Tests/array_unique.sf
scripts/Tests/arrays.sf
scripts/Tests/arrays_intersection.sf
scripts/Tests/autovivification.sf
scripts/Tests/averages_mode.sf
scripts/Tests/avg_mode.sf
scripts/Tests/balanced_brakets.sf
Expand Down
60 changes: 31 additions & 29 deletions lib/Sidef/Deparse/Perl.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1162,46 +1162,48 @@ HEADER
$code = qq{CORE::die "Unimplemented at " . } . $self->_dump_string($obj->{file}) . qq{. " line $obj->{line}\\n"};
}

# Array indices
# Array and hash indices
if (exists $expr->{ind}) {
my $limit = $#{$expr->{ind}};
foreach my $i (0 .. $limit) {

my $ind = $expr->{ind}[$i];
if (exists $ind->{array}) {

if (substr($code, -1) eq '@') {
$code .= $self->_dump_unpacked_indices($ind);
}
elsif ($#{$ind} > 0) {
$code = '@{' . $code . '}' . $self->_dump_indices($ind);
my $pos = $ind->{array};

if (substr($code, -1) eq '@') {
$code .= $self->_dump_unpacked_indices($pos);
}
elsif ($#{$pos} > 0) {
$code = '@{' . $code . '}' . $self->_dump_indices($pos);
}
else {
$code .= '->' . $self->_dump_indices($pos);
}
}
else {
$code .= '->' . $self->_dump_indices($ind);
}

if ($i < $limit and $#{$ind} == 0) {
$code = '(' . $code . ' //= Sidef::Types::Array::Array->new' . ')';
}
}
}
my $key = $ind->{hash};

# Hash lookup
if (exists $expr->{lookup}) {
my $limit = $#{$expr->{lookup}};
foreach my $i (0 .. $limit) {
my $key = $expr->{lookup}[$i];

if (substr($code, -1) eq '@') {
$code .= $self->_dump_unpacked_lookups($key);
}
elsif ($#{$key} > 0) {
$code = '@{' . $code . '}' . $self->_dump_lookups($key);
}
else {
$code .= '->' . $self->_dump_lookups($key);
if (substr($code, -1) eq '@') {
$code .= $self->_dump_unpacked_lookups($key);
}
elsif ($#{$key} > 0) {
$code = '@{' . $code . '}' . $self->_dump_lookups($key);
}
else {
$code .= '->' . $self->_dump_lookups($key);
}
}

if ($i < $limit and $#{$key} == 0) {
$code = '(' . $code . ' //= Sidef::Types::Hash::Hash->new' . ')';
if ($i < $limit) {
if ($expr->{ind}[$i + 1]{array}) {
$code = '(' . $code . ' //= Sidef::Types::Array::Array->new' . ')';
}
else {
$code = '(' . $code . ' //= Sidef::Types::Hash::Hash->new' . ')';
}
}
}
}
Expand Down
23 changes: 11 additions & 12 deletions lib/Sidef/Deparse/Sidef.pm
Original file line number Diff line number Diff line change
Expand Up @@ -577,20 +577,19 @@ package Sidef::Deparse::Sidef {
}
}

# Indices
# Array and hash indices
if (exists $expr->{ind}) {
foreach my $ind (@{$expr->{ind}}) {
$code .= $self->_dump_array($ind);
}
}

if (exists $expr->{lookup}) {
foreach my $lookup (@{$expr->{lookup}}) {
$code .= '{'
. join(',',
map { ref($_) eq 'HASH' ? ($self->deparse_expr($_)) : $self->deparse_generic('', '', '', $_) }
@{$lookup})
. '}';
if (exists $ind->{array}) {
$code .= $self->_dump_array($ind->{array});
}
else {
$code .= '{'
. join(',',
map { ref($_) eq 'HASH' ? ($self->deparse_expr($_)) : $self->deparse_generic('', '', '', $_) }
@{$ind->{hash}})
. '}';
}
}
}

Expand Down
17 changes: 8 additions & 9 deletions lib/Sidef/Optimizer.pm
Original file line number Diff line number Diff line change
Expand Up @@ -731,17 +731,16 @@ package Sidef::Optimizer {
(exists($expr->{call}) ? (call => []) : ()),
};

# Array indices
# Array and hash indices
if (exists $expr->{ind}) {
foreach my $i (0 .. $#{$expr->{ind}}) {
$obj->{ind}[$i] = [map { $self->optimize_expr($_) } @{$expr->{ind}[$i]}];
}
}

# Hash lookup
if (exists $expr->{lookup}) {
foreach my $i (0 .. $#{$expr->{lookup}}) {
$obj->{lookup}[$i] = [map { ref($_) eq 'HASH' ? $self->optimize_expr($_) : $_ } @{$expr->{lookup}[$i]}];
my $ind = $expr->{ind}[$i];
if (exists $ind->{array}) {
$obj->{ind}[$i]{array} = [map { ref($_) eq 'HASH' ? $self->optimize_expr($_) : $_ } @{$ind->{array}}];
}
else {
$obj->{ind}[$i]{hash} = [map { ref($_) eq 'HASH' ? $self->optimize_expr($_) : $_ } @{$ind->{hash}}];
}
}
}

Expand Down
44 changes: 21 additions & 23 deletions lib/Sidef/Parser.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2013,8 +2013,8 @@ package Sidef::Parser {
scalar {
$self->{class} => [
{
self => $var->{obj},
lookup => [[$name]],
self => $var->{obj},
ind => [{hash => [$name]}],
}
]
};
Expand Down Expand Up @@ -2395,33 +2395,44 @@ package Sidef::Parser {

my $parsed = 0;

{
if (/\G(?=\{)/) {
$struct->{$self->{class}}[-1]{self} = {
if (/\G(?=[\{\[])/) {

$struct->{$self->{class}}[-1]{self} = {
$self->{class} => [
{
self => $struct->{$self->{class}}[-1]{self},
exists($struct->{$self->{class}}[-1]{call}) ? (call => delete $struct->{$self->{class}}[-1]{call})
: (),
exists($struct->{$self->{class}}[-1]{ind}) ? (ind => delete $struct->{$self->{class}}[-1]{ind})
: (),
exists($struct->{$self->{class}}[-1]{lookup})
? (lookup => delete $struct->{$self->{class}}[-1]{lookup})
: (),
}
]
};
};
}

{
if (/\G(?=\{)/) {
while (/\G(?=\{)/) {
my $lookup = $self->parse_lookup(code => $opt{code});
push @{$struct->{$self->{class}}[-1]{lookup}}, $lookup->{$self->{class}};
push @{$struct->{$self->{class}}[-1]{ind}}, {hash => $lookup->{$self->{class}}};
}

$parsed ||= 1;
redo;
}

if (/\G(?=\[)/) {
while (/\G(?=\[)/) {
my ($ind) = $self->parse_expr(code => $opt{code});
push @{$struct->{$self->{class}}[-1]{ind}}, {array => $ind};
}

$parsed ||= 1;
redo;
}

if (/\G\h*(?=\()/gc) {

$struct->{$self->{class}}[-1]{self} = {
$self->{class} => [
{
Expand All @@ -2430,23 +2441,10 @@ package Sidef::Parser {
: (),
exists($struct->{$self->{class}}[-1]{ind}) ? (ind => delete $struct->{$self->{class}}[-1]{ind})
: (),
exists($struct->{$self->{class}}[-1]{lookup})
? (lookup => delete $struct->{$self->{class}}[-1]{lookup})
: (),
}
]
};

while (/\G(?=\[)/) {
my ($ind) = $self->parse_expr(code => $opt{code});
push @{$struct->{$self->{class}}[-1]{ind}}, $ind;
}

$parsed ||= 1;
redo;
}

if (/\G\h*(?=\()/gc) {
my $arg = $self->parse_arguments(code => $opt{code});

push @{$struct->{$self->{class}}[-1]{call}},
Expand Down
34 changes: 34 additions & 0 deletions scripts/Tests/autovivification.sf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/ruby

#
## Array
#

var a = [];
a[0]{:foo}[1][2]{:bar}{:baz} = 42;
say a;

var a1 = [Hash("foo" => [nil, [nil, nil, Hash("bar" => Hash("baz" => 42))]])];

assert_eq(a, a1);
assert(a[0].is_a(Hash));
assert_eq(a[0]{:foo}[1][2]{:bar}{:baz}, 42);
assert_eq(a[0]{:foo}[1][2]{:bar}, Hash(baz => 42));
assert_eq(a[0]{:foo}[1][2], Hash(bar => Hash(baz => 42)));

#
## Hash
#

var b = Hash();
b{:foo}[2]{:bar}{:baz}[1][2] = 42;
say b;

var b1 = Hash("foo" => [nil, nil, Hash("bar" => Hash("baz" => [nil, [nil, nil, 42]]))]);

assert_eq(b, b1);
assert(b{:foo}.is_a(Array));
assert_eq(b{:foo}[2]{:bar}{:baz}[1][2], 42);
assert_eq(b{:foo}[2]{:bar}{:baz}[1], [nil, nil, 42]);

say "** Test passed!"

0 comments on commit 4455a3f

Please sign in to comment.