App-RoboBot
view release on metacpan or search on metacpan
lib/App/RoboBot/Type.pm view on Meta::CPAN
$App::RoboBot::Type::VERSION = '4.004';
use v5.20;
use namespace::autoclean;
use Moose;
use Scalar::Util qw( blessed );
has 'bot' => (
is => 'ro',
isa => 'App::RoboBot',
required => 1,
);
has 'type' => (
is => 'ro',
isa => 'Str',
default => 'nil',
);
has 'value' => (
is => 'rw',
predicate => 'has_value',
);
has 'quoted' => (
is => 'rw',
isa => 'Bool',
default => 0,
);
has 'log' => (
is => 'rw',
predicate => 'has_logger',
);
sub BUILD {
my ($self) = @_;
my $logger_name = 'core.type.' . lc($self->type);
$self->log($self->bot->logger($logger_name)) unless $self->has_logger;
}
sub ast {
my ($self) = @_;
$self->log->debug(sprintf('Generating AST for type %s.', $self->type));
return $self->type;
}
sub build_from_val {
my ($class, $bot, $val, $quoted) = @_;
$quoted //= 0;
return unless defined $bot && defined $val;
# If we're building a List or Expression, we need to downgrade to Strings
# any operands that follow which are marked as Macros, since a macro must
# always be the operator.
if (ref($val) eq 'ARRAY') {
foreach my $el (@{$val}[1..$#$val]) {
next unless blessed($el) && $el->type eq 'Macro';
$el = App::RoboBot::Type::String->new(
bot => $bot,
value => $el->value,
quoted => $el->quoted,
);
}
}
return $class->new(
bot => $bot,
value => $val,
quoted => $quoted,
);
}
# TODO: Need better name, since we don't follow the return value conventions of
# C/Perl style cmp functions.
sub cmp {
shift if $_[0] eq __PACKAGE__;
my ($obj_a, $obj_b) = @_;
return 0 unless defined $obj_a && defined $obj_b;
# Basic checks that these are actually Type objects and not something else.
return 0 unless ref($obj_a) =~ m{^App::RoboBot::Type} && ref($obj_b) =~ m{^RoboBot::Type};
# Objects of different types cannot be the same as each other. We aren't
# testing whether two things evaluate to the same state, but whether they
# are *currently* the same.
return 0 if $obj_a->type ne $obj_b->type;
# If they don't both have values, there's no comparison that will succeed.
return 0 if $obj_a->is_nil || $obj_b->is_nil;
# Delegate to Type's _cmp method to handle the specifics, if supported.
return $obj_a->_cmp($obj_b) if $obj_a->can('_cmp');
# Otherwise just do a naive stringy comparison of ->value returns;
return 1 if $obj_a->value eq $obj_b->value;
return 0;
}
sub evaluate {
my ($self, $message, $rpl) = @_;
$self->log->debug(sprintf('Testing for value before evaluating %s type contents.', $self->type));
return unless $self->has_value;
$self->log->debug(sprintf('Value exists, proceeding with %s type evaluation.', $self->type));
if (defined $rpl && ref($rpl) eq 'HASH' && exists $rpl->{$self->value}) {
$self->log->debug(sprintf('Stack contains variable by the same name (%s). Evaluating stack variable.', $self->value));
my $r = $rpl->{$self->value};
if (defined $r && blessed($r) && $r->can('evaluate')) {
return $r->evaluate($message, $rpl);
} else {
return $r;
( run in 0.516 second using v1.01-cache-2.11-cpan-39bf76dae61 )