From c72370155fa28470c7567f5c35dd1a64242ebfcb Mon Sep 17 00:00:00 2001 From: trizen Date: Thu, 10 Dec 2015 23:11:54 +0200 Subject: [PATCH] - Topic variables (_) are better localized now. They are no longer declared in every single block of the program, but only in places where it makes sense. For example, no topic variable will be generated inside the blocks of a if/else construct. A side effect of this change is reflected in the calling of blocks as functions: it will fail when called without arguments, because every real-block has a topic variable. Example: var block = { say "hi" }; block.run; # perfect block.call(nil); # ok block(); # error --- MANIFEST | 8 ++-- lib/Sidef/Deparse/Perl.pm | 40 ++++++------------ lib/Sidef/Deparse/Sidef.pm | 6 +-- lib/Sidef/Parser.pm | 42 +++++++++---------- lib/Sidef/Types/Block/Block.pm | 2 +- .../0080-square_root_digital_expansion.sf | 25 +++++++++++ scripts/Tests/amb.sf | 6 +-- scripts/Tests/classes_and_objects.sf | 2 +- scripts/Tests/man_or_boy.sf | 4 +- scripts/Tests/man_or_boy_2.sf | 2 +- scripts/Tests/man_or_boy_3.sf | 2 +- scripts/Tests/man_or_boy_cached.sf | 2 +- scripts/Tests/power_numbers.sf | 8 ++-- scripts/Tests/run_length_encoding.sf | 6 +-- scripts/Tests/run_length_encoding_2.sf | 4 +- scripts/continued_fraction.sf | 2 +- scripts/langton_s_ant_2.sf | 2 +- scripts/stern-brocot_sequence.sf | 2 +- 18 files changed, 85 insertions(+), 80 deletions(-) create mode 100644 scripts/Project Euler/0080-square_root_digital_expansion.sf diff --git a/MANIFEST b/MANIFEST index 3dcd1b971..316eba5d5 100644 --- a/MANIFEST +++ b/MANIFEST @@ -260,6 +260,7 @@ scripts/permutations_rec.sf 'scripts/Project Euler/0071-ordered_fractions.sf' 'scripts/Project Euler/0076-counting_summations.sf' 'scripts/Project Euler/0077-prime_summations.sf' +'scripts/Project Euler/0080-square_root_digital_expansion.sf' 'scripts/Project Euler/0097-large_non-mersenne_prime.sf' 'scripts/Project Euler/0120-square_remainders.sf' 'scripts/Project Euler/0137-fibonacci_golden_nuggets.sf' @@ -506,9 +507,12 @@ scripts/RosettaCode/word_wrap.sf scripts/RosettaCode/zeckendorf_number_representation.sf scripts/RosettaCode/zig-zag_matrix.sf scripts/sets.sf +scripts/sierpinski_carpet.sf scripts/sierpinski_triangle.sf scripts/simple_moving_average.sf scripts/simple_moving_average_oo.sf +scripts/smart_word_wrap.sf +scripts/smart_word_wrap_simple.sf scripts/space_collisions.sf scripts/stack.sf scripts/stern-brocot_sequence.sf @@ -695,16 +699,12 @@ scripts/Tests/sidef_executor.sf scripts/Tests/sidef_keywords.sf scripts/Tests/sidef_to_json.sf scripts/Tests/sierpinski_alphabet.sf -scripts/Tests/sierpinski_carpet.sf scripts/Tests/sierpinski_diamond.sf scripts/Tests/sierpinski_penta.sf scripts/Tests/sierpinski_sidef.sf -scripts/Tests/sierpinski_triangle.sf scripts/Tests/sierpinski_triangle_90.sf scripts/Tests/sierpinski_x.sf scripts/Tests/smart_match_operator.sf -scripts/Tests/smart_word_wrap.sf -scripts/Tests/smart_word_wrap_simple.sf scripts/Tests/sort_disjoint_sublist.sf scripts/Tests/sort_with_custom_cmp.sf scripts/Tests/soundex.sf diff --git a/lib/Sidef/Deparse/Perl.pm b/lib/Sidef/Deparse/Perl.pm index 86f9b7368..673626cef 100644 --- a/lib/Sidef/Deparse/Perl.pm +++ b/lib/Sidef/Deparse/Perl.pm @@ -661,14 +661,7 @@ HEADER $code = 'Sidef::Types::Block::Block->new(code => __SUB__'; if (exists($obj->{init_vars}) and @{$obj->{init_vars}{vars}}) { - my @vars = @{$obj->{init_vars}{vars}}; - - # Remove the underscore (_) variable - if (@vars > 1 or (@vars == 1 and $vars[0]{name} eq '_')) { - pop @vars; - } - - $code .= ', ' . $self->_dump_var_attr(@vars); + $code .= ', ' . $self->_dump_var_attr(@{$obj->{init_vars}{vars}}); } $code .= ')'; @@ -750,18 +743,11 @@ HEADER $code .= "\n" . (" " x ($Sidef::SPACES - $Sidef::SPACES_INCR)) . "code => sub {\n"; if (exists($obj->{init_vars}) and @{$obj->{init_vars}{vars}}) { - my @vars = @{$obj->{init_vars}{vars}}; - - # Remove the underscore (_) variable - if (@vars > 1) { - pop @vars; - } - - $code .= $self->_dump_sub_init_vars(@vars); + $code .= $self->_dump_sub_init_vars(@{$obj->{init_vars}{vars}}); + } - if ($is_function) { - $code .= (' ' x $Sidef::SPACES) . 'my @return;' . "\n"; - } + if ($is_function) { + $code .= (' ' x $Sidef::SPACES) . 'my @return;' . "\n"; } } @@ -822,14 +808,7 @@ HEADER } if (exists($obj->{init_vars}) and @{$obj->{init_vars}{vars}}) { - my @vars = @{$obj->{init_vars}{vars}}; - - # Remove the underscore (_) variable - if (@vars > 1 or (@vars == 1 and $vars[0]{name} eq '_')) { - pop @vars; - } - - $code .= ', ' . $self->_dump_var_attr(@vars); + $code .= ', ' . $self->_dump_var_attr(@{$obj->{init_vars}{vars}}); } $code .= ')'; } @@ -949,7 +928,12 @@ HEADER } elsif ($ref eq 'Sidef::Types::Block::Given') { $self->top_add(qq{use experimental 'smartmatch';\n}); - $code = 'do{given ' . $self->deparse_args($obj->{expr}) . $self->deparse_bare_block($obj->{block}{code}) . '}'; + my $dvar = $self->_dump_var($obj->{block}{init_vars}->{vars}[0]); + $code = + 'do{given (my ' + . $dvar . '=' + . $self->deparse_args($obj->{expr}) . ')' + . $self->deparse_bare_block($obj->{block}{code}) . '}'; } elsif ($ref eq 'Sidef::Types::Block::When') { $code = 'when($_ ~~ ' . $self->deparse_args($obj->{expr}) . ')' . $self->deparse_bare_block($obj->{block}{code}); diff --git a/lib/Sidef/Deparse/Sidef.pm b/lib/Sidef/Deparse/Sidef.pm index 0151b135f..caed03bb6 100644 --- a/lib/Sidef/Deparse/Sidef.pm +++ b/lib/Sidef/Deparse/Sidef.pm @@ -166,7 +166,7 @@ package Sidef::Deparse::Sidef { my $var_obj = delete $block->{init_vars}; $code .= '(' - . $self->_dump_vars(@{$var_obj->{vars}}[($obj->{type} eq 'method' ? 1 : 0) .. $#{$var_obj->{vars}} - 1]) + . $self->_dump_vars(@{$var_obj->{vars}}[($obj->{type} eq 'method' ? 1 : 0) .. $#{$var_obj->{vars}}]) . ') '; if (exists $obj->{cached}) { @@ -264,8 +264,7 @@ package Sidef::Deparse::Sidef { local $self->{class} = $obj->{class}; $code .= "class " . $self->_dump_class_name($obj->{name}); - my $vars = $obj->{vars}; - $code .= '(' . $self->_dump_vars(@{$vars}) . ')'; + $code .= '(' . $self->_dump_vars(@{$obj->{vars}}) . ')'; if (exists $obj->{inherit}) { $code .= ' << ' . join(', ', map { $_->{name} } @{$obj->{inherit}}) . ' '; } @@ -286,7 +285,6 @@ package Sidef::Deparse::Sidef { $code = '{'; if (exists($obj->{init_vars}) and @{$obj->{init_vars}{vars}}) { my @vars = @{$obj->{init_vars}{vars}}; - pop @vars; if (@vars) { $code .= '| ' . $self->_dump_vars(@vars) . ' |'; } diff --git a/lib/Sidef/Parser.pm b/lib/Sidef/Parser.pm index 8f7984d39..def532a1c 100644 --- a/lib/Sidef/Parser.pm +++ b/lib/Sidef/Parser.pm @@ -636,7 +636,7 @@ package Sidef::Parser { if (/\G(?=\{)/) { my $code = substr($_, pos); - $self->parse_block(code => \$code); + $self->parse_block(code => \$code, topic_var => 1); $vars[-1] .= substr($_, pos($_), pos($code)); pos($_) += pos($code); } @@ -733,7 +733,7 @@ package Sidef::Parser { if (defined($end_delim)) { if (/\G\h*(?=\{)/gc) { - $where_block = $self->parse_block(code => $opt{code}); + $where_block = $self->parse_block(code => $opt{code}, topic_var => 1); } elsif (/\G\h*(?=\()/gc) { $where_expr = $self->parse_arguments(code => $opt{code}); @@ -978,7 +978,7 @@ package Sidef::Parser { # Block as object if (/\G(?=\{)/) { - my $obj = $self->parse_block(code => $opt{code}); + my $obj = $self->parse_block(code => $opt{code}, topic_var => 1); return $obj; } @@ -1593,7 +1593,7 @@ package Sidef::Parser { local $self->{current_given} = $given_obj; my $block = ( /\G\h*(?=\{)/gc - ? $self->parse_block(code => $opt{code}) + ? $self->parse_block(code => $opt{code}, topic_var => 1) : $self->fatal_error( error => "expected a block after `given(expr)`", code => $_, @@ -2093,7 +2093,7 @@ package Sidef::Parser { /\G\h*/gc; # remove any horizontal whitespace my $arg = ( /\G(?=\()/ ? $self->parse_arguments(code => $opt{code}) - : /\G(?=\{)/ ? $self->parse_block(code => $opt{code}) + : /\G(?=\{)/ ? $self->parse_block(code => $opt{code}, topic_var => 1) : $self->parse_obj(code => $opt{code}) ); @@ -2264,21 +2264,19 @@ package Sidef::Parser { type => 'var'); } - { # special '_' variable + # Special '_' variable + if ($opt{topic_var} and not @{$var_objs}) { my $var_obj = bless({name => '_', type => 'var', class => $self->{class}}, 'Sidef::Variable::Variable'); - push @{$var_objs}, $var_obj; - my (undef, $code) = $self->find_var('_', $self->{class}); - if (not defined($code) or $code == 0) { - unshift @{$self->{vars}{$self->{class}}}, - { - obj => $var_obj, - name => '_', - count => 0, - type => 'var', - line => $self->{line}, - }; - } + push @{$var_objs}, $var_obj; + unshift @{$self->{vars}{$self->{class}}}, + { + obj => $var_obj, + name => '_', + count => 0, + type => 'var', + line => $self->{line}, + }; } my $obj = $self->parse_script(code => $opt{code}); @@ -2347,7 +2345,7 @@ package Sidef::Parser { my $arg = ( /\G(?=\()/ ? $self->parse_arguments(code => \$code) : ($req_arg || exists($self->{binpost_ops}{$method})) ? $self->parse_obj(code => \$code) - : /\G(?=\{)/ ? $self->parse_block(code => \$code) + : /\G(?=\{)/ ? $self->parse_block(code => \$code, topic_var => 1) : die "[PARSING ERROR] Something is wrong in the if condition" ); @@ -2594,19 +2592,21 @@ package Sidef::Parser { and exists $self->{special_constructs}{ref($obj)} and /\G\h*(?=\{)/gc) { - my $arg = $self->parse_block(code => $opt{code}); - if (ref($obj) eq 'Sidef::Types::Block::For') { if ($#{$struct{$self->{class}}[-1]{call}[-1]{arg}} == 0) { + my $arg = $self->parse_block(code => $opt{code}, topic_var => 1); $struct{$self->{class}}[-1]{self} = shift @{delete $struct{$self->{class}}[-1]{call}[-1]{arg}}; push @{$struct{$self->{class}}[-1]{call}[-1]{arg}}, $arg; } else { + my $arg = $self->parse_block(code => $opt{code}); push @{$struct{$self->{class}}[-1]{call}[-1]{block}}, $arg->{code}; } } else { + my $arg = $self->parse_block(code => $opt{code}); + push @{$struct{$self->{class}}[-1]{call}[-1]{block}}, $arg->{code}; if (ref($obj) eq 'Sidef::Types::Block::If') { diff --git a/lib/Sidef/Types/Block/Block.pm b/lib/Sidef/Types/Block/Block.pm index f18e6cf75..27f793a27 100644 --- a/lib/Sidef/Types/Block/Block.pm +++ b/lib/Sidef/Types/Block/Block.pm @@ -26,7 +26,7 @@ package Sidef::Types::Block::Block { my %seen; my @left_args; - my @vars = @{$method->{vars}}; + my @vars = exists($method->{vars}) ? @{$method->{vars}} : (); foreach my $arg (@args) { if (ref($arg) eq 'Sidef::Variable::NamedParam') { diff --git a/scripts/Project Euler/0080-square_root_digital_expansion.sf b/scripts/Project Euler/0080-square_root_digital_expansion.sf new file mode 100644 index 000000000..5c9410958 --- /dev/null +++ b/scripts/Project Euler/0080-square_root_digital_expansion.sf @@ -0,0 +1,25 @@ +#!/usr/bin/ruby + +# For the first one hundred natural numbers, find the total of the digital sums of the first one hundred decimal digits for all the irrational square roots. + +# https://projecteuler.net/problem=80 + +# Answer: 40886 + +var sum = 0; +Math.accuracy(102); + +for (1 ..^ 100) { |i| + + var sr = i.sqrt; + next if sr.is_int; + + var x = sr.to_s; + x -= /\./; + x.substr!(0, 100); + + sum += x.to_i.digits.sum; +} + +say sum.int; +Math.accuracy(0); diff --git a/scripts/Tests/amb.sf b/scripts/Tests/amb.sf index e435cb204..5c58e70ac 100644 --- a/scripts/Tests/amb.sf +++ b/scripts/Tests/amb.sf @@ -9,7 +9,7 @@ var w = [ "slowly|,quickly|", ]; -for (w.map{'{'+_+'}'}->join.glob) { - _.gsub!('|', ' ') ~~ - /\w+?(\w) \1\w+?(\w) \2\w+?(\w) \3\w+/ && (_.say); +for (w.map{'{'+_+'}'}->join.glob) { |i| + i.gsub!('|', ' ') ~~ + /\w+?(\w) \1\w+?(\w) \2\w+?(\w) \3\w+/ && (i.say); } diff --git a/scripts/Tests/classes_and_objects.sf b/scripts/Tests/classes_and_objects.sf index 43e93f096..a38e7e1a9 100644 --- a/scripts/Tests/classes_and_objects.sf +++ b/scripts/Tests/classes_and_objects.sf @@ -5,7 +5,7 @@ class Task(callback, dependencies=[]) { method perform { dependencies.each { .perform }; - callback(); + callback.run; } } diff --git a/scripts/Tests/man_or_boy.sf b/scripts/Tests/man_or_boy.sf index 405cb2726..b750aa43e 100644 --- a/scripts/Tests/man_or_boy.sf +++ b/scripts/Tests/man_or_boy.sf @@ -3,8 +3,8 @@ func a(k, x1, x2, x3, x4, x5) { func b { a(--k, b, x1, x2, x3, x4) }; k <= 0 ? (x4() + x5()) : b(); -}; +} -assert_eq(a(10, {1}, {-1}, {-1}, {1}, {0}), -67); +assert_eq(a(10, ->{1}, ->{-1}, ->{-1}, ->{1}, ->{0}), -67); say "** Test passed!"; diff --git a/scripts/Tests/man_or_boy_2.sf b/scripts/Tests/man_or_boy_2.sf index 0c5a6eb69..b86c653b7 100644 --- a/scripts/Tests/man_or_boy_2.sf +++ b/scripts/Tests/man_or_boy_2.sf @@ -1,7 +1,7 @@ #!/usr/bin/ruby func a(k, x1, x2, x3, x4, x5) { - k <= 0 ? (x4() + x5()) + k <= 0 ? (x4.run + x5.run) : func b { a(--k, b, x1, x2, x3, x4) }(); }; diff --git a/scripts/Tests/man_or_boy_3.sf b/scripts/Tests/man_or_boy_3.sf index 6cdd86f7f..679f51375 100644 --- a/scripts/Tests/man_or_boy_3.sf +++ b/scripts/Tests/man_or_boy_3.sf @@ -3,7 +3,7 @@ class Test { method a(k, x1, x2, x3, x4, x5) { func b { self.a(--k, b, x1, x2, x3, x4) }; - k <= 0 ? (x4() + x5()) : b(); + k <= 0 ? (x4.run + x5.run) : b(); } } diff --git a/scripts/Tests/man_or_boy_cached.sf b/scripts/Tests/man_or_boy_cached.sf index b49d93d9b..bd05d6546 100644 --- a/scripts/Tests/man_or_boy_cached.sf +++ b/scripts/Tests/man_or_boy_cached.sf @@ -2,7 +2,7 @@ func a(k, x1, x2, x3, x4, x5) is cached -> Number { func b() -> Number { a(--k, b, x1, x2, x3, x4) }; - k <= 0 ? (x4() + x5()) : b(); + k <= 0 ? (x4.run + x5.run) : b(); } assert_eq(a(10, {1}, {-1}, {-1}, {1}, {0}), -67); diff --git a/scripts/Tests/power_numbers.sf b/scripts/Tests/power_numbers.sf index a83b6a774..e751edf1b 100644 --- a/scripts/Tests/power_numbers.sf +++ b/scripts/Tests/power_numbers.sf @@ -1,10 +1,10 @@ #!/usr/bin/ruby -for (1..15) { - var pow = (1 << (_-1) / _); +for (1..15) { |i| + var pow = (1 << (i-1) / i); - var num = (_**_); - {num=(num.sqrt)} * (_-1); + var num = (i**i); + {num=(num.sqrt)} * (i-1); "%3.0f\t%s\n".printf(num**pow, pow); } diff --git a/scripts/Tests/run_length_encoding.sf b/scripts/Tests/run_length_encoding.sf index 214e9d8e6..9561ec89e 100644 --- a/scripts/Tests/run_length_encoding.sf +++ b/scripts/Tests/run_length_encoding.sf @@ -10,8 +10,7 @@ func encode (str) { var output = Chars.new; - for (chars.range) { - var index = _; + chars.range.each { |index| if (i > 0 && (chars[index] != lc)) { output.append(i.to_s + (lc.to_s)); i = 0; @@ -33,9 +32,8 @@ func decode (str) { var acc = ''; var output = ''; - for (chars.range) { + chars.range.each { |index| - var index = _; var sc = chars[index].to_s; if (sc != ' '){ diff --git a/scripts/Tests/run_length_encoding_2.sf b/scripts/Tests/run_length_encoding_2.sf index e6ad02634..639926a1c 100644 --- a/scripts/Tests/run_length_encoding_2.sf +++ b/scripts/Tests/run_length_encoding_2.sf @@ -30,8 +30,8 @@ func decode (encoded) { var output = ''; - for (encoded) { - output += (_[1].to_s * _[0]); + for i in (encoded) { + output += (i[1].to_s * i[0]); } return(output); diff --git a/scripts/continued_fraction.sf b/scripts/continued_fraction.sf index b250af923..d529de927 100644 --- a/scripts/continued_fraction.sf +++ b/scripts/continued_fraction.sf @@ -1,7 +1,7 @@ #!/usr/bin/ruby func continued_fraction(a, b, n=100) { - a() + (n > 0 && (b() / continued_fraction(a, b, n-1))); + a.run + (n > 0 && (b.run / continued_fraction(a, b, n-1))); } var f = Hash.new( diff --git a/scripts/langton_s_ant_2.sf b/scripts/langton_s_ant_2.sf index 1348d1fbd..53a43e442 100644 --- a/scripts/langton_s_ant_2.sf +++ b/scripts/langton_s_ant_2.sf @@ -11,7 +11,7 @@ var size = 15; # we treat any false as white and true as black, so undef is fine for initial all-white grid var plane = []; -for (0 .. size-1) { plane[_] = [] }; +for (0 .. size-1) {|i| plane[i] = [] }; # start out in approximate middle var (x, y) = (size/2, size/2); diff --git a/scripts/stern-brocot_sequence.sf b/scripts/stern-brocot_sequence.sf index 85981b594..fe0316b79 100644 --- a/scripts/stern-brocot_sequence.sf +++ b/scripts/stern-brocot_sequence.sf @@ -3,7 +3,7 @@ # Declare a function to generate the Stern-Brocot sequence func stern_brocot { var list = [1, 1]; - { + func { list.append(list[0]+list[1], list[1]); list.shift; }