Skip to content

Commit

Permalink
- Added the map-operator (»op») from Perl6
Browse files Browse the repository at this point in the history
Example:
	[1,2,3] »+» 1;	# same as: [1,2,3].map{ _ + 1};

- Simplified the parser with regard of parsing composed operators.
- The unroll-operator (>op<) is now available only as >>op<< in ASCII form.
- The reduce-operator (<op> and [op]) is now available only as <<op>> in ASCII form.
  • Loading branch information
trizen committed Aug 21, 2015
1 parent 852c857 commit 2023e2e
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 29 deletions.
70 changes: 45 additions & 25 deletions lib/Sidef/Parser.pm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ package Sidef::Parser {
'...' => 1,
'!' => 1,
},
special_ops => {
mop => [1, 'map_operator'],
uop => [1, 'unroll_operator'],
rop => [0, 'reduce_operator'],
},
binpost_ops => { # infix + postfix operators
'...' => 1,
},
Expand Down Expand Up @@ -278,16 +283,22 @@ package Sidef::Parser {
);

qr{
»(?<uop>[_\pL][_\pL\pN]*|(?&op))« # unroll method + op (e.g.: »add« or »+«)
| >(?<uop>[_\pL][_\pL\pN]*|(?&op))< # unroll method + op (e.g.: >add< or >+<)
| \[(?<rop>(?&op))\] # reduce operator (e.g.: [+])
| <(?<rop>[_\pL][_\pL\pN]*)> # reduce method (e.g.: <add>)
| «(?<rop>[_\pL][_\pL\pN]*|(?&op))» # reduce method + op (e.g.: «add» or «+»)
| \h*\^(?<mop>[_\pL][_\pL\pN]*[!:?]?)\^\h* # method-like operator
| (?<op>@operators
| \p{Block: Mathematical_Operators}
| \p{Block: Supplemental_Mathematical_Operators}
)
(?(DEFINE)
(?<ops>
@operators
| \p{Block: Mathematical_Operators}
| \p{Block: Supplemental_Mathematical_Operators}
)
)
»(?<uop>[_\pL][_\pL\pN]*|(?&ops))« # unroll method + op (e.g.: »add« or »+«)
| >>(?<uop>[_\pL][_\pL\pN]*|(?&ops))<< # unroll method + op (e.g.: >>add<< or >>+<<)
| »(?<mop>[_\pL][_\pL\pN]*|(?&ops))» # mapping operator (e.g.: »add» or »+»)
| >>(?<mop>[_\pL][_\pL\pN]*|(?&ops))>> # mapping operator (e.g.: >>add>> or >>+>>)
| <<(?<rop>[_\pL][_\pL\pN]*|(?&ops))>> # reduce method (e.g.: <<add>> or <<+>>)
| «(?<rop>[_\pL][_\pL\pN]*|(?&ops))» # reduce method + op (e.g.: «add» or «+»)
| \h*\^(?<op>[_\pL][_\pL\pN]*[!:?]?)\^\h* # method-like operator (e.g.: ^add^)
| (?<op>(?&ops)) # primitive operator (e.g.: +, -, *, /)
}x;
},

Expand Down Expand Up @@ -500,7 +511,6 @@ package Sidef::Parser {
# 1st: method/operator (or undef)
# 2nd: does operator require and argument (0 or 1)
# 3rd: type of operator (e.g.: »+« is "uop", [+] is "rop")
# 4th: the position after match
sub get_method_name {
my ($self, %opt) = @_;

Expand All @@ -510,21 +520,27 @@ package Sidef::Parser {
($self->parse_whitespace(code => $opt{code}))[1] && return;

# Alpha-numeric method name
if (/\G($self->{method_name_re})/gxoc) {
return ($1, 0, '');
if (/\G($self->{method_name_re})/goc) {
return ($1, 0, 'op');
}

# Operator-like method name
if (m{\G$self->{operators_re}}goc) {
my $uop = exists($+{uop});
my $rop = exists($+{rop});
return ($+, ($uop ? 1 : $rop ? 0 : not exists $self->{postfix_ops}{$+}), ($uop ? 'uop' : $rop ? 'rop' : ''));
my ($key) = keys(%+);
return (
$+,
(
exists($self->{special_ops}{$key})
? $self->{special_ops}{$key}[0]
: not(exists $self->{postfix_ops}{$+})
),
$key
);
}

# Method name as expression
my ($obj) = $self->parse_expr(code => $opt{code});
$obj // return;
return ({self => $obj}, 0, '');
return ({self => $obj // return}, 0, 'op');
}

sub _parse_delim {
Expand Down Expand Up @@ -1903,19 +1919,23 @@ package Sidef::Parser {
sub append_method {
my ($self, %opt) = @_;

if ($opt{op_type} eq '') {
# Standard operator
if ($opt{op_type} eq 'op') {
push @{$opt{array}}, {method => $opt{method}};
}
elsif ($opt{op_type} eq 'uop') {
push @{$opt{array}}, {method => 'unroll_operator', arg => [Sidef::Types::String::String->new($opt{method})]};
}
elsif ($opt{op_type} eq 'rop') {
push @{$opt{array}}, {method => 'reduce_operator', arg => [Sidef::Types::String::String->new($opt{method})]};

# Special operator
elsif (exists $self->{special_ops}{$opt{op_type}}) {
push @{$opt{array}},
{method => $self->{special_ops}{$opt{op_type}}[1], arg => [Sidef::Types::String::String->new($opt{method})]};
}

# Unknown operator
else {
die "[PARSER ERROR] Invalid operator of type '$opt{op_type}'...";
die "[PARSER ERROR] Invalid operator of type '$opt{op_type}'";
}

# Append the argument
if (exists($opt{arg}) and (%{$opt{arg}} || ($opt{method} =~ /^$self->{operators_re}\z/))) {
push @{$opt{array}[-1]{arg}}, $opt{arg};
}
Expand Down
24 changes: 21 additions & 3 deletions lib/Sidef/Types/Array/Array.pm
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,41 @@ package Sidef::Types::Array::Array {
my ($self, $operator, $arg) = @_;

my @array;
my $method = $operator->get_value;

if (ref $operator) {
$operator = $operator->get_value;
}

if (defined $arg) {

foreach my $i (0 .. $#{$self}) {
push @array, $self->[$i]->get_value->$method($arg->[$i]->get_value);
push @array, $self->[$i]->get_value->$operator($arg->[$i]->get_value);
}
}
else {
foreach my $i (0 .. $#{$self}) {
push @array, $self->[$i]->get_value->$method;
push @array, $self->[$i]->get_value->$operator;
}
}

$self->new(@array);
}

sub map_operator {
my ($self, $operator, $arg) = @_;

if (ref $operator) {
$operator = $operator->get_value;
}

my @array;
foreach my $i (0 .. $#{$self}) {
push @array, $self->[$i]->get_value->$operator($arg);
}

$self->new(@array);
}

sub reduce_operator {
my ($self, $operator) = @_;

Expand Down
2 changes: 1 addition & 1 deletion scripts/Rosettacode/Vector_products.sf
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class Vector(x, y, z) {
method (vec) {
self[:x..:z] »*« vec[:x..:z] [+];
self[:x..:z] »*« vec[:x..:z] «+»;
}
 
method (vec) {
Expand Down

0 comments on commit 2023e2e

Please sign in to comment.