use Moops; # PODNAME: MarpaX::Languages::M4::Impl::Default::Eval # ABSTRACT: Eval Marpa actions class MarpaX::Languages::M4::Impl::Default::Eval { use Bit::Vector; use Types::Common::Numeric -all; use MarpaX::Languages::M4::Impl::Default::BaseConversion; our $VERSION = '0.003'; # VERSION # # Marpa dislike exceptions throws as objects, because of wanted # backward compatibility with very old versions of Perl. # So we will use Marpa::R2::Context::bail() method # has bits => { is => 'ro', isa => PositiveInt, default => sub {$MarpaX::Languages::M4::Impl::Default::INTEGER_BITS} }; has SELF => { is => 'ro', isa => ConsumerOf ['MarpaX::Languages::M4::Role::Impl'], default => sub {$MarpaX::Languages::M4::Impl::Default::SELF} }; method _eval (ConsumerOf['Bit::Vector'] $expression) { return $expression->to_Dec(); } method _invalidOp (Str $op) { Marpa::R2::Context::bail( 'Invalid operator in ' . $self->SELF->impl_quote('eval') . ': ' . $self->SELF->impl_quote($op) ); } method _noop (Str $op, ConsumerOf['Bit::Vector'] $expression) { return $expression; } method _lneg (Str $op, ConsumerOf['Bit::Vector'] $expression) { return Bit::Vector->new_Dec( $self->bits, $expression->is_empty() ); } method _exp (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { if ( $expression2->to_Dec() < 0 ) { Marpa::R2::Context::bail( 'Negative exponent in ' . $self->SELF->impl_quote('eval') . ': ' . $self->SELF->impl_quote( $expression1->to_Dec ) . ' ' . $self->SELF->impl_quote($op) . ' ' . $self->SELF->impl_quote( $expression2->to_Dec ) ); } if ( $expression1->to_Dec() == 0 && $expression2->to_Dec() == 0 ) { Marpa::R2::Context::bail( 'Divide by zero in ' . $self->SELF->impl_quote('eval') . ': ' . $self->SELF->impl_quote( $expression1->to_Dec ) . ' ' . $self->SELF->impl_quote($op) . ' ' . $self->SELF->impl_quote( $expression2->to_Dec ) ); } my $s = $expression1->Shadow; $s->Power( $expression1, $expression2 ); return $s; } method _neg (Str $op, ConsumerOf['Bit::Vector'] $expression) { my $s = $expression->Shadow; $s->Negate($expression); return $s; } method _bneg (Str $op, ConsumerOf['Bit::Vector'] $expression) { my $s = $expression->Shadow; $s->Complement($expression); return $s; } method _mul (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; $s->Multiply( $expression1, $expression2 ); return $s; } method _div (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; try { $s->Divide( $expression1, $expression2, $expression1->Shadow ); } catch { $s = undef; }; return $s; } method _mod (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; try { $expression1->Shadow->Divide( $expression1, $expression2, $s ); } catch { $s = undef; }; return $s; } method _add (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; $s->add( $expression1, $expression2, 0 ); return $s; } method _sub (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; $s->subtract( $expression1, $expression2, 0 ); return $s; } # From GNU M4 source code: # Minimize undefined C behavior (shifting by a negative number, # shifting by the width or greater, left shift overflow, or # right shift of a negative number). Implement Java 32-bit # wrap-around semantics. This code assumes that the # implementation-defined overflow when casting unsigned to # a signed is a silent twos-complement wrap-around. */ method _left (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { $expression1->Insert( 0, $expression2->to_Dec() % $self->bits ); return $expression1; } method _right (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $u1 = $expression1->Clone; if ( $expression1->Sign < 0 ) { $u1->Complement($u1); } $u1->Delete( 0, $expression2->to_Dec() % $self->bits ); if ( $expression1->Sign < 0 ) { $u1->Complement($u1); } return $u1; } method _gt (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { return Bit::Vector->new_Dec( $self->bits, ( $expression1->Compare($expression2) > 0 ) ? 1 : 0 ); } method _ge (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { return Bit::Vector->new_Dec( $self->bits, ( $expression1->Compare($expression2) >= 0 ) ? 1 : 0 ); } method _lt (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { return Bit::Vector->new_Dec( $self->bits, ( $expression1->Compare($expression2) < 0 ) ? 1 : 0 ); } method _le (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { return Bit::Vector->new_Dec( $self->bits, ( $expression1->Compare($expression2) <= 0 ) ? 1 : 0 ); } method _eq (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { return Bit::Vector->new_Dec( $self->bits, ( $expression1->Compare($expression2) == 0 ) ? 1 : 0 ); } method _eq2 (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { $self->SELF->logger_warn('Warning: recommend == instead of ='); return $self->_eq( $expression1, $op, $expression2 ); } method _ne (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { return Bit::Vector->new_Dec( $self->bits, ( $expression1->Compare($expression2) != 0 ) ? 1 : 0 ); } method _band (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; $s->Intersection( $expression1, $expression2 ); return $s; } method _bxor (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; $s->ExclusiveOr( $expression1, $expression2 ); return $s; } method _bor (ConsumerOf['Bit::Vector'] $expression1, Str $op, ConsumerOf['Bit::Vector'] $expression2) { my $s = $expression1->Shadow; $s->Union( $expression1, $expression2 ); return $s; } # # M4 is short-circuiting valid syntax in case of '||' and '&&', so that things like # 2 || 1 / 0 will not produce a fatal error. To produce such a behaviour # only '||' or '&&' specific actions will be able to handle eventual undef value from # prior actions # method _land (ConsumerOf['Bit::Vector'] $expression1, Str $op, Undef|ConsumerOf['Bit::Vector'] $expression2) { my $rc; if ( !Undef->check($expression2) ) { $rc = Bit::Vector->new_Dec( $self->bits, ( !$expression1->is_empty() && !$expression2->is_empty() ) ? 1 : 0 ); } elsif ( $expression1->is_empty() ) { # # Already zero # $rc = $expression1; } else { Marpa::R2::Context::bail( 'Undefined right-hand expression in ' . $self->SELF->impl_quote('eval') . ': ' . $self->SELF->impl_quote( $expression1->to_Dec ) . ' ' . $self->SELF->impl_quote($op) ); } return $rc; } method _lor (ConsumerOf['Bit::Vector'] $expression1, Str $op, Undef|ConsumerOf['Bit::Vector'] $expression2) { my $rc; if ( !Undef->check($expression2) ) { $rc = Bit::Vector->new_Dec( $self->bits, ( !$expression1->is_empty() || !$expression2->is_empty() ) ? 1 : 0 ); } elsif ( !$expression1->is_empty() ) { $rc = Bit::Vector->new_Dec( $self->bits, 1 ); } else { Marpa::R2::Context::bail( 'Undefined right-hand expression in ' . $self->SELF->impl_quote('eval') . ': ' . $self->SELF->impl_quote( $expression1->to_Dec ) . ' ' . $self->SELF->impl_quote($op) ); } return $rc; } # # Raw inputs are not allowed to fail. Eventual croaks are left alive. # method _decimal (Str $lexeme) { return Bit::Vector->new_Dec( $self->bits, $lexeme + 0 ); } method _octal (Str $lexeme) { return Bit::Vector->new_Dec( $self->bits, oct($lexeme) ); } # oct() supportx 0x notation method _hex (Str $lexeme) { return Bit::Vector->new_Dec( $self->bits, oct($lexeme) ); } # oct() supportx 0b notation method _binary (Str $lexeme) { return Bit::Vector->new_Dec( $self->bits, oct($lexeme) ); } method _radix (Str $lexeme) { # # Per def this is this regexp # $lexeme =~ /0r([\d]+):([\da-zA-Z]+)/; my $radix = substr( $lexeme, $-[1], $+[1] - $-[1] ); my $digits = lc( substr( $lexeme, $-[2], $+[2] - $-[2] ) ) ; # Because max base is 36 if ( $radix == 1 ) { # For radix 1, leading zeros are ignored, # and all remaining digits must be 1 $digits =~ s/^0*//; if ( $digits =~ /[^1]/ ) { Marpa::R2::Context::bail( $self->SELF->impl_quote($lexeme) . ': ' . 'for radix 1, digits must be eventual zeroes followed by 1\'s' ); } } return Bit::Vector->new_Dec( $self->bits, MarpaX::Languages::M4::Impl::Default::BaseConversion->fr_base( $radix, $digits ) ); } } __END__ =pod =encoding UTF-8 =head1 NAME MarpaX::Languages::M4::Impl::Default::Eval - Eval Marpa actions =head1 VERSION version 0.003 =head1 AUTHOR Jean-Damien Durand <jeandamiendurand@free.fr> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2015 by Jean-Damien Durand. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut