HP-Handy

 view release on metacpan or  search on metacpan

lib/HP/Handy.pm  view on Meta::CPAN


    # is / is not test
    if ($expr =~ /^(.+?)\s+is\s+not\b\s+(\w+)(?:\s+(.+))?$/) {
        my ($lhs, $test, $arg) = ($1, $2, $3);
        my $val = $self->_eval_expr($lhs, $vars);
        my $targ = defined $arg ? $self->_eval_expr($arg, $vars) : undef;
        my $fn = $self->{_tests}{$test};
        return $fn ? ($fn->($val, $targ) ? 0 : 1) : 1;
    }
    if ($expr =~ /^(.+?)\s+is\s+(\w+)(?:\s+(.+))?$/) {
        my ($lhs, $test, $arg) = ($1, $2, $3);
        my $val = $self->_eval_expr($lhs, $vars);
        my $targ = defined $arg ? $self->_eval_expr($arg, $vars) : undef;
        my $fn = $self->{_tests}{$test};
        return $fn ? ($fn->($val, $targ) ? 1 : 0) : 0;
    }

    # Attribute access: obj.attr or obj["key"] or obj['key']
    if ($expr =~ /^(.+?)\.(\w+)(?:\(([^)]*)\))?$/) {
        my ($obj_expr, $attr, $call_args) = ($1, $2, $3);
        my $obj = $self->_eval_expr($obj_expr, $vars);
        if (defined $call_args) {
            # Method call (filters on object)
            my $fn = $self->{_filters}{$attr};
            my @args = map { $self->_eval_expr($_, $vars) } _split_args($call_args);
            return $fn ? $fn->($obj, @args) : undef;
        }
        return _get_attr($obj, $attr);
    }

    if ($expr =~ /^(.+?)\[["'](\w+)["']\]$/) {
        my ($obj_expr, $key) = ($1, $2);
        my $obj = $self->_eval_expr($obj_expr, $vars);
        return _get_attr($obj, $key);
    }

    if ($expr =~ /^(.+?)\[(-?\d+)\]$/) {
        my ($obj_expr, $idx) = ($1, $2);
        my $obj = $self->_eval_expr($obj_expr, $vars);
        return ref($obj) eq 'ARRAY' ? $obj->[$idx] : undef;
    }

    # Slice: list[start:end]
    if ($expr =~ /^(.+?)\[(-?\d*):(-?\d*)\]$/) {
        my ($obj_expr, $s, $e) = ($1, $2, $3);
        my $obj = $self->_eval_expr($obj_expr, $vars);
        return undef unless ref($obj) eq 'ARRAY';
        my $len  = scalar @$obj;
        my $si   = ($s ne '') ? int($s) : 0;
        my $ei   = ($e ne '') ? int($e) : $len;
        $si += $len if $si < 0;
        $ei += $len if $ei < 0;
        $si = 0    if $si < 0;
        $ei = $len if $ei > $len;
        return [ @{$obj}[$si .. $ei - 1] ];
    }

    # Function/macro call: name(args)
    if ($expr =~ /^(\w+)\s*\(([^)]*)\)$/) {
        my ($fname, $argstr) = ($1, $2);
        # Macro call
        if (exists $self->{_macros}{$fname}) {
            return $self->_call_macro($fname, $argstr, $vars, '<expr>');
        }
        # Built-in functions
        if ($fname eq 'range') {
            return $self->_eval_range($argstr, $vars);
        }
    }

    # Variable lookup
    if ($expr =~ /^(\w+)$/) {
        return exists $vars->{$expr} ? $vars->{$expr} : undef;
    }

    return undef;
}

###############################################################################
# _eval_dict - Parse and evaluate a dict literal { key: val, ... }
###############################################################################
sub _eval_dict {
    my ($self, $inner, $vars) = @_;
    my %h;
    # Simple k:v split (no nested dicts)
    for my $pair (_split_args($inner)) {
        if ($pair =~ /^(.+?)\s*:\s*(.+)$/) {
            my $k = $self->_eval_expr($1, $vars);
            my $v = $self->_eval_expr($2, $vars);
            $h{$k} = $v if defined $k;
        }
    }
    return { %h };
}

###############################################################################
# _eval_range - Evaluate range(stop) / range(start, stop[, step])
###############################################################################
sub _eval_range {
    my ($self, $args_str, $vars) = @_;
    my @args = map { $self->_eval_expr($_, $vars) } _split_args($args_str);
    my ($start, $stop, $step);
    if (@args == 1) { ($start, $stop, $step) = (0, int($args[0]), 1) }
    elsif (@args == 2) { ($start, $stop, $step) = (int($args[0]), int($args[1]), 1) }
    else { ($start, $stop, $step) = (int($args[0]), int($args[1]), int($args[2] || 1)) }
    $step = 1 if $step == 0;
    my @result;
    if ($step > 0) { for (my $n = $start; $n < $stop; $n += $step) { push @result, $n } }
    else           { for (my $n = $start; $n > $stop; $n += $step) { push @result, $n } }
    return [ @result ];
}

###############################################################################
# _get_attr - Get attribute from hash or array
###############################################################################
sub _get_attr {
    my ($obj, $attr) = @_;
    return undef unless defined $obj;
    if (ref($obj) eq 'HASH') {
        return exists $obj->{$attr} ? $obj->{$attr} : undef;
    }



( run in 0.496 second using v1.01-cache-2.11-cpan-40ba7b3775d )