From a353469efbf26207c65bbee9210850ae60e0a4f4 Mon Sep 17 00:00:00 2001 From: trizen Date: Fri, 30 Oct 2015 20:23:15 +0200 Subject: [PATCH] - Added support for structures. Example: struct Person { String name, Number age, }; var p1 = Person(name: "Brad Pitt", age: 42); var p2 = Person("Angelina Jolie", 35); say p1.name; # prints: "Brad Pitt" say p2.name; # prints: "Angelina Jolie" --- MANIFEST | 3 ++ lib/Sidef/Deparse/Perl.pm | 42 ++++++++++++++++---- lib/Sidef/Deparse/Sidef.pm | 13 ++----- lib/Sidef/Optimizer.pm | 2 +- lib/Sidef/Parser.pm | 29 +++++++------- lib/Sidef/Types/Glob/Backtick.pod | 8 ++++ lib/Sidef/Types/Hash/Hash.pm | 8 ---- lib/Sidef/Types/Hash/Hash.pod | 8 ---- lib/Sidef/Variable/ClassInit.pm | 18 ++++----- lib/Sidef/Variable/ClassInit.pod | 64 +++++++++++++++++++++++++++++++ lib/Sidef/Variable/Struct.pm | 26 ++----------- lib/Sidef/Variable/Struct.pod | 25 ++++++++++++ scripts/Tests/structures.sf | 49 +++++++++++++++++++++++ 13 files changed, 214 insertions(+), 81 deletions(-) create mode 100644 lib/Sidef/Variable/ClassInit.pod create mode 100644 lib/Sidef/Variable/Struct.pod create mode 100644 scripts/Tests/structures.sf diff --git a/MANIFEST b/MANIFEST index 975693038..88a5e501f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -124,6 +124,7 @@ lib/Sidef/Types/Regex/Regex.pod lib/Sidef/Types/String/String.pm lib/Sidef/Types/String/String.pod lib/Sidef/Variable/ClassInit.pm +lib/Sidef/Variable/ClassInit.pod lib/Sidef/Variable/Const.pm lib/Sidef/Variable/Const.pod lib/Sidef/Variable/ConstInit.pm @@ -149,6 +150,7 @@ lib/Sidef/Variable/Ref.pm lib/Sidef/Variable/Static.pm lib/Sidef/Variable/Static.pod lib/Sidef/Variable/Struct.pm +lib/Sidef/Variable/Struct.pod lib/Sidef/Variable/Variable.pm LICENSE Makefile.PL @@ -731,6 +733,7 @@ scripts/Tests/string_escapes.sf scripts/Tests/string_to_number.sf scripts/Tests/strip_chars_from_str.sf scripts/Tests/strip_non_ascii_chars.sf +scripts/Tests/structures.sf scripts/Tests/subtractive_generator.sf scripts/Tests/swap.sf scripts/Tests/sylvesters_sequence.sf diff --git a/lib/Sidef/Deparse/Perl.pm b/lib/Sidef/Deparse/Perl.pm index 08409504c..8bc7a680a 100644 --- a/lib/Sidef/Deparse/Perl.pm +++ b/lib/Sidef/Deparse/Perl.pm @@ -567,16 +567,42 @@ HEADER } } elsif ($ref eq 'Sidef::Variable::Struct') { + my $name = $self->_dump_class_name($obj); if ($addr{$refaddr}++) { - $code = $obj->{__NAME__}; + $code = $name; } else { - my @vars; - foreach my $key (sort keys %{$obj}) { - next if $key eq '__NAME__'; - push @vars, $obj->{$key}; + local $self->{parent_name} = ['struct initialization', $obj->{name}]; + + # Mark the variables all in use + foreach my $var (@{$obj->{vars}}) { + $var->{in_use} = 1; } - $code = "struct $obj->{__NAME__} {" . $self->_dump_vars(@vars) . '}'; + + $Sidef::SPACES += $Sidef::SPACES_INCR; + $code = + "package $name {\n" + . (' ' x $Sidef::SPACES) + . "sub new {\n" + . (' ' x $Sidef::SPACES) + . $self->_dump_sub_init_vars('undef', @{$obj->{vars}}) + + . (' ' x ($Sidef::SPACES * 2)) + . "bless {" + . join(", ", map { $self->_dump_string($_->{name}) . " => " . $self->_dump_var($_) } @{$obj->{vars}}) + . "}, __PACKAGE__" . "\n" + . (' ' x $Sidef::SPACES) . "}\n" + . + + (' ' x $Sidef::SPACES) . "*call = \\&new;\n" . + + (' ' x $Sidef::SPACES) + . join("\n" . (' ' x $Sidef::SPACES), + map { "sub $_->{name} : lvalue { \$_[0]->{$_->{name}} }" } @{$obj->{vars}}) + + . "\n" . (' ' x ($Sidef::SPACES - $Sidef::SPACES_INCR)) . "}"; + + $Sidef::SPACES -= $Sidef::SPACES_INCR; } } elsif ($ref eq 'Sidef::Variable::LocalInit') { @@ -649,7 +675,7 @@ HEADER $code = q{'} . $self->_dump_class_name($obj) . q{'}; } else { - my $block = $obj->{__BLOCK__}; + my $block = $obj->{block}; $code = "do {package "; @@ -671,7 +697,7 @@ HEADER $code .= ($package_name = $self->_dump_class_name($obj)); } - my $vars = $obj->{__VARS__}; + my $vars = $obj->{vars}; local $self->{class} = refaddr($block); local $self->{class_name} = $obj->{name}; local $self->{parent_name} = ['class initialization', $obj->{name}]; diff --git a/lib/Sidef/Deparse/Sidef.pm b/lib/Sidef/Deparse/Sidef.pm index ef53d3277..e61a81202 100644 --- a/lib/Sidef/Deparse/Sidef.pm +++ b/lib/Sidef/Deparse/Sidef.pm @@ -200,15 +200,10 @@ package Sidef::Deparse::Sidef { } elsif ($ref eq 'Sidef::Variable::Struct') { if ($addr{refaddr($obj)}++) { - $code = $obj->{__NAME__}; + $code = $obj->{name}; } else { - my @vars; - foreach my $key (sort keys %{$obj}) { - next if $key eq '__NAME__'; - push @vars, $obj->{$key}; - } - $code = "struct $obj->{__NAME__} {" . $self->_dump_vars(@vars) . '}'; + $code = "struct $obj->{name} {" . $self->_dump_vars(@{$obj->{vars}}) . '}'; } } elsif ($ref eq 'Sidef::Variable::LocalInit') { @@ -275,7 +270,7 @@ package Sidef::Deparse::Sidef { ); } else { - my $block = $obj->{__BLOCK__}; + my $block = $obj->{block}; my $in_module = $obj->{class} ne $self->{class}; if ($in_module) { @@ -286,7 +281,7 @@ package Sidef::Deparse::Sidef { local $self->{class} = $obj->{class}; $code .= "class " . $self->_dump_class_name($obj->{name}); - my $vars = $obj->{__VARS__}; + my $vars = $obj->{vars}; $code .= '(' . $self->_dump_vars(@{$vars}) . ')'; if (exists $obj->{inherit}) { $code .= ' << ' . join(', ', map { $_->{name} } @{$obj->{inherit}}) . ' '; diff --git a/lib/Sidef/Optimizer.pm b/lib/Sidef/Optimizer.pm index f84090796..664caea87 100644 --- a/lib/Sidef/Optimizer.pm +++ b/lib/Sidef/Optimizer.pm @@ -505,7 +505,7 @@ package Sidef::Optimizer { ## ok } else { - $obj->{__BLOCK__} = $self->optimize_expr({self => $obj->{__BLOCK__}}); + $obj->{block} = $self->optimize_expr({self => $obj->{block}}); } } elsif ($ref eq 'Sidef::Variable::Init') { diff --git a/lib/Sidef/Parser.pm b/lib/Sidef/Parser.pm index 73c51ecd1..b0e77d157 100644 --- a/lib/Sidef/Parser.pm +++ b/lib/Sidef/Parser.pm @@ -1084,9 +1084,9 @@ package Sidef::Parser { # Struct declaration if (/\Gstruct\b\h*/gc) { - my $name; + my ($name, $class_name); if (/\G($self->{var_name_re})\h*/goc) { - $name = $1; + ($name, $class_name) = $self->get_name_and_class($1); } if (defined($name) and (exists($self->{keywords}{$name}) or exists($self->{built_in_classes}{$name}))) { @@ -1105,10 +1105,14 @@ package Sidef::Parser { type => 'var', ); - my $struct = Sidef::Variable::Struct->__new__($name, $vars); + my $struct = Sidef::Variable::Struct->new( + name => $name, + class => $class_name, + vars => $vars, + ); if (defined $name) { - unshift @{$self->{vars}{$self->{class}}}, + unshift @{$self->{vars}{$class_name}}, { obj => $struct, name => $name, @@ -1283,8 +1287,7 @@ package Sidef::Parser { : $type eq 'global' ? Sidef::Variable::Global->new(name => $name, class => $class_name) : $type eq 'func' ? Sidef::Variable::Variable->new(name => $name, type => $type, class => $class_name) : $type eq 'method' ? Sidef::Variable::Variable->new(name => $name, type => $type, class => $class_name) - : $type eq 'class' - ? Sidef::Variable::ClassInit->__new__(name => ($built_in_obj // $name), class => $class_name) + : $type eq 'class' ? Sidef::Variable::ClassInit->new(name => ($built_in_obj // $name), class => $class_name) : $self->fatal_error( error => "invalid type", expected => "expected a magic thing to happen", @@ -1345,7 +1348,7 @@ package Sidef::Parser { }, ); - $obj->__set_params__($var_names); + $obj->set_params($var_names); # Class inheritance (class Name(...) << Name1, Name2) if (/\G\h*<find_var($name, $class_name))) { if ($class->{type} eq 'class') { - push @{$obj->{inherit}}, $class->{obj}; #$class_name . '::' . $name; - - #while (my ($name, $method) = each %{$class->{obj}{__METHODS__}}) { - # ($built_in_obj // $obj)->__add_method__($name, $method); - #} + push @{$obj->{inherit}}, $class->{obj}; } else { $self->fatal_error( @@ -1403,7 +1402,7 @@ package Sidef::Parser { local $self->{current_class} = $built_in_obj // $obj; my $block = $self->parse_block(code => $opt{code}); - $obj->__set_block__($block); + $obj->set_block($block); } if ($type eq 'func' or $type eq 'method') { @@ -1506,7 +1505,7 @@ package Sidef::Parser { $obj->{value} = $block; #if (not $private) { - # $self->{current_class}->__add_method__($name, $block) if $type eq 'method'; + # $self->{current_class}->add_method($name, $block) if $type eq 'method'; #} } @@ -1781,7 +1780,7 @@ package Sidef::Parser { and defined( my $var = List::Util::first( sub { $_->{name} eq $name }, - @{$self->{current_class}{__VARS__}}, + @{$self->{current_class}{vars}}, #@{$self->{current_class}{__DEF_VARS__}} ) diff --git a/lib/Sidef/Types/Glob/Backtick.pod b/lib/Sidef/Types/Glob/Backtick.pod index e4de924ed..6e05aad23 100644 --- a/lib/Sidef/Types/Glob/Backtick.pod +++ b/lib/Sidef/Types/Glob/Backtick.pod @@ -33,6 +33,14 @@ Aliases: I, I, I =cut +=head2 call + +Backtick.call() -> I + +Return the + +=cut + =head2 dump Backtick.dump() -> I diff --git a/lib/Sidef/Types/Hash/Hash.pm b/lib/Sidef/Types/Hash/Hash.pm index b492b8aa7..37ab1cabd 100644 --- a/lib/Sidef/Types/Hash/Hash.pm +++ b/lib/Sidef/Types/Hash/Hash.pm @@ -34,14 +34,6 @@ package Sidef::Types::Hash::Hash { \%hash; } - sub default { - my ($self, $value) = @_; - if (@_ > 1) { - $self->{__DEFAULT_VALUE__} = $value; - } - $self->{__DEFAULT_VALUE__}; - } - sub items { my ($self, @keys) = @_; Sidef::Types::Array::Array->new(map { exists($self->{$_}) ? $self->{$_} : undef } @keys); diff --git a/lib/Sidef/Types/Hash/Hash.pod b/lib/Sidef/Types/Hash/Hash.pod index 4ec689230..cd2246008 100644 --- a/lib/Sidef/Types/Hash/Hash.pod +++ b/lib/Sidef/Types/Hash/Hash.pod @@ -82,14 +82,6 @@ Return the =cut -=head2 default - -Hash.default() -> I - -Return the - -=cut - =head2 delete Hash.delete() -> I diff --git a/lib/Sidef/Variable/ClassInit.pm b/lib/Sidef/Variable/ClassInit.pm index 5a60088b4..8b8c11e8f 100644 --- a/lib/Sidef/Variable/ClassInit.pm +++ b/lib/Sidef/Variable/ClassInit.pm @@ -6,31 +6,31 @@ package Sidef::Variable::ClassInit { Sidef::Object::Object ); - sub __new__ { + sub new { my (undef, %opt) = @_; bless \%opt, __PACKAGE__; } - sub __set_params__ { + sub set_params { my ($self, $names) = @_; - $self->{__VARS__} = $names; + $self->{vars} = $names; } - sub __set_block__ { + sub set_block { my ($self, $block) = @_; - $self->{__BLOCK__} = $block; + $self->{block} = $block; $self; } - sub __add_method__ { + sub add_method { my ($self, $name, $method) = @_; - $self->{__METHODS__}{$name} = $method; + $self->{methods}{$name} = $method; $self; } - sub __add_vars__ { + sub add_vars { my ($self, $vars) = @_; - push @{$self->{__DEF_VARS__}}, @{$vars}; + push @{$self->{def_vars}}, @{$vars}; $self; } }; diff --git a/lib/Sidef/Variable/ClassInit.pod b/lib/Sidef/Variable/ClassInit.pod new file mode 100644 index 000000000..2654ca619 --- /dev/null +++ b/lib/Sidef/Variable/ClassInit.pod @@ -0,0 +1,64 @@ + +=encoding utf8 + +=head1 NAME + +Sidef::Variable::ClassInit + +=head1 DESCRIPTION + +This object is ... + +=head1 SYNOPSIS + +var obj = ClassInit.new(...); + + +=head1 INHERITS + +Inherits methods from: + + * Sidef::Object::Object + +=head1 METHODS + + +=head2 add_method + +ClassInit.add_method() -> I + +Return the + +=cut + +=head2 add_vars + +ClassInit.add_vars() -> I + +Return the + +=cut + +=head2 new + +ClassInit.new() -> I + +Return the + +=cut + +=head2 set_block + +ClassInit.set_block() -> I + +Return the + +=cut + +=head2 set_params + +ClassInit.set_params() -> I + +Return the + +=cut diff --git a/lib/Sidef/Variable/Struct.pm b/lib/Sidef/Variable/Struct.pm index 987512208..9c234a07e 100644 --- a/lib/Sidef/Variable/Struct.pm +++ b/lib/Sidef/Variable/Struct.pm @@ -1,30 +1,10 @@ package Sidef::Variable::Struct { use 5.014; - our $AUTOLOAD; - sub __new__ { - my (undef, $name, $vars) = @_; - bless { - __NAME__ => $name, - map { $_->{name} => $_ } @{$vars} - }, - __PACKAGE__; - } - - sub DESTROY { } - - sub AUTOLOAD { - my ($self, $arg) = @_; - - my ($name) = ($AUTOLOAD =~ /^.*[^:]::(.*)$/); - - # Variable autovification - if (not exists $self->{$name}) { - return $self->{$name} = Sidef::Variable::Variable->new(name => '', type => 'var', value => $arg); - } - - $self->{$name}; + sub new { + my (undef, %opt) = @_; + bless \%opt, __PACKAGE__; } } diff --git a/lib/Sidef/Variable/Struct.pod b/lib/Sidef/Variable/Struct.pod new file mode 100644 index 000000000..3fb816f6f --- /dev/null +++ b/lib/Sidef/Variable/Struct.pod @@ -0,0 +1,25 @@ + +=encoding utf8 + +=head1 NAME + +Sidef::Variable::Struct + +=head1 DESCRIPTION + +This object is ... + +=head1 SYNOPSIS + +var obj = Struct.new(...); + +=head1 METHODS + + +=head2 new + +Struct.new() -> I + +Return the + +=cut diff --git a/scripts/Tests/structures.sf b/scripts/Tests/structures.sf new file mode 100644 index 000000000..9ae75f2b5 --- /dev/null +++ b/scripts/Tests/structures.sf @@ -0,0 +1,49 @@ +#!/usr/bin/ruby + +# +## Struct 1 +# + +struct Person { + name, + age, +} + +var man = Person(name: "John Smith", age: 30); + +assert_eq(man.name, "John Smith"); +assert_eq(man.age, 30); + +man.age += 1; +assert_eq(man.age, 31); + +var woman = Person("Chris Miller", 24); + +assert_eq(woman.name, "Chris Miller"); +assert_eq(woman.age, 24); + +# +## Struct 2 +# + +struct Job { + String title, + Number salary = 1000, # default salary +} + +var job1 = Job(title: "Programmer", salary: 3000); +var job2 = Job("Writer", 2400); +var job3 = Job("Worker"); + +assert_eq(job1.salary, 3000); +assert_eq(job2.salary, 2400); +assert_eq(job3.salary, 1000); + +job3.salary = 800; +assert_eq(job3.salary, 800); +assert_eq(job2.salary, 2400); + +assert_eq(woman.age, 24); +assert_eq(man.age, 31); + +say "** Test passed!";