App-EvalServerAdvanced-ConstantCalc

 view release on metacpan or  search on metacpan

lib/App/EvalServerAdvanced/ConstantCalc.pm  view on Meta::CPAN

package App::EvalServerAdvanced::ConstantCalc;

our $VERSION = '0.06';

# ABSTRACT: turns strings and constants into values

use v5.24;
use Moo;
use Function::Parameters;
use Data::Dumper;

has constants => (is => 'ro', default => sub {+{}});
has _parser => (is => 'ro', default => sub {App::EvalServerAdvanced::ConstantCalc::Parser->new(consts => $_[0])});

method get_value($key) {
  die "Missing constant [$key]" unless exists($self->constants->{$key});

  return $self->constants->{$key};
}

method add_constant($key, $value) {
  die "Invalid key [$key]" if ($key =~ /\s/ || $key =~ /^\s*\d/);

  if (exists($self->constants->{$key}) && defined(my $eval = $self->constants->{$key})) {
    die "Cannot redefine a constant [$key].  Existing value [$eval] new value [$value]"
  }

  die "Value undefined for [$key]" unless defined($value);
  die "Value [$value] for [$key] must be an integer" if ($value =~ /[^xob\d\-+_]/i);

  $self->constants->{$key} = App::EvalServerAdvanced::ConstantCalc::Parser::_to_int($value);
}

method calculate($string) {
  return $self->_parser->from_string($string);
}

package
  App::EvalServerAdvanced::ConstantCalc::Parser;

use strict;
use warnings;

# Ensure we can't accidentally turn to strings, or floats, or anything other than an integer
use integer;
no warnings 'experimental::bitwise';
use feature 'bitwise';

use parent qw/Parser::MGC/;
use Function::Parameters;

method new($class: %args) {
  my $consts = delete $args{consts};

  my $self = $class->SUPER::new(%args);

  $self->{_private}{consts} = $consts;

  return $self;
}

method consts() {
  return $self->{_private}{consts};
}

method parse_upper() {
  my $val = $self->parse_term();

  1 while $self->any_of(
    sub {$self->expect("&"); $val &= $self->parse_term(); 1},
    sub {0}
  );

  return $val;
}

method parse() {
  my $val = $self->parse_upper();

  1 while $self->any_of(
      sub {$self->expect("^"); $val ^= $self->parse_upper(); 1 },
      sub {$self->expect("|"); $val |= $self->parse_upper(); 1 },
      sub {0}
  );

  return $val;
}

method parse_term() {
   $self->any_of(
      sub { $self->scope_of( "(", sub { $self->parse }, ")" ) },
      sub { $self->expect('~['); my $bitdepth=$self->token_int; $self->expect(']'); my $val = $self->parse_term; (~ ($val & _get_mask($bitdepth))) & _get_mask($bitdepth)},
      sub { $self->expect('~'); ~$self->parse_term},
      sub { $self->token_constant },
      sub { $self->token_int },
   );
}

method token_int() {
  0+$self->any_of(
     sub {_to_int($self->expect(qr/0x[0-9A-F_]+/i));},
     sub {_to_int($self->expect(qr/0b[0-7_]+/i));},
     sub {_to_int($self->expect(qr/0o?[0-7_]+/i));},
     sub {$self->expect(qr/\d+/)}



( run in 0.916 second using v1.01-cache-2.11-cpan-39bf76dae61 )