File Coverage

blib/lib/App/optex/rpn.pm
Criterion Covered Total %
statement 23 49 46.9
branch 0 10 0.0
condition 0 8 0.0
subroutine 8 14 57.1
pod 0 5 0.0
total 31 86 36.0


line stmt bran cond sub pod time code
1             package App::optex::rpn;
2              
3             our $VERSION = "1.01";
4              
5             =encoding utf-8
6              
7             =head1 NAME
8              
9             rpn - Reverse Polish Notation calculation
10              
11             =head1 SYNOPSIS
12              
13             optex -Mrpn command ...
14              
15             =head1 VERSION
16              
17             Version 1.01
18              
19             =head1 DESCRIPTION
20              
21             B is a filter module for B command to detect arguments
22             which look like Reverse Polish Notation (RPN), and replace them by the
23             result of calculation.
24              
25             See L for Reverse Polish Noatation detail.
26              
27             Since RPN part requires two terms at least,
28              
29             optex -Mrpn echo RAND
30              
31             print just "RAND". Use something like C to get random
32             number.
33              
34             =head1 EXAMPLE
35              
36             Prevent macOS to suspend for 5 hours.
37              
38             $ optex -Mrpn caffeinate -d -t 3600,5*
39              
40             =head1 INSTALL
41              
42             cpanm https://github.com/kaz-utashiro/optex-rpn.git
43              
44             =head1 SEE ALSO
45              
46             L, L
47              
48             L, L
49              
50             L
51              
52             L
53              
54             =head1 AUTHOR
55              
56             Kazumasa Utashiro
57              
58             =head1 LICENSE
59              
60             Copyright 2021 Kazumasa Utashiro.
61              
62             This library is free software; you can redistribute it and/or modify
63             it under the same terms as Perl itself.
64              
65             =cut
66              
67 1     1   1119 use v5.14;
  1         5  
68 1     1   7 use warnings;
  1         2  
  1         52  
69 1     1   6 use Carp;
  1         4  
  1         70  
70 1     1   967 use utf8;
  1         15  
  1         5  
71 1     1   1510 use open IO => 'utf8', ':std';
  1         1863  
  1         8  
72 1     1   1010 use Data::Dumper;
  1         7292  
  1         242  
73              
74             our %option = (
75             debug => 0,
76             verbose => 0,
77             );
78              
79             my($mod, $argv);
80 0     0 0   sub initialize { ($mod, $argv) = @_ }
81              
82             sub argv (&) {
83 0     0 0   my $sub = shift;
84 0           @$argv = $sub->(@$argv);
85             }
86              
87             my @operator = sort { length $b <=> length $a } split /[,\s]+/, <<'END';
88             +,ADD ++,INCR -,SUB --,DECR *,MUL /,DIV %,MOD POW SQRT
89             SIN COS TAN
90             LOG EXP
91             ABS INT
92             &,AND |,OR !,NOT XOR ~
93             <,LT <=,LE =,==,EQ >,GT >=,GE !=,NE
94             IF
95             DUP EXCH POP
96             MIN MAX
97             TIME
98             RAND LRAND
99             END
100              
101             my $operator_re = join '|', map "\Q$_", @operator;
102 1     1   7 my $term_re = qr/(?:\d*\.)?\d+|$operator_re/i;
  1         2  
  1         11  
103             my $rpn_re = qr/(?: $term_re ,* ){2,}/xi;
104              
105             sub rpn_calc {
106 1     1   538 use Math::RPN ();
  1         2789  
  1         393  
107 0     0 0   my @terms = map { /$term_re/g } @_;
  0            
108 0           my @ans = do { local $_; Math::RPN::rpn @terms };
  0            
  0            
109 0 0 0       if (@ans == 1 && defined $ans[0] && $ans[0] !~ /[^\.\d]/) {
      0        
110 0           $ans[0];
111             } else {
112 0           return undef;
113             }
114             }
115              
116              
117             sub rpn {
118             argv {
119 0     0     my($cmd, @arg) = @_;
120 0           my $count;
121 0           for (@arg) {
122 0 0         /^$rpn_re$/ or next;
123 0   0       my $calc = rpn_calc($_) // next;
124 0 0         if ($calc ne $_) {
125 0           $count++;
126 0           $_ = $calc;
127             }
128             }
129 0 0         warn "exec: $cmd @arg\n" if $option{verbose};
130 0           ($cmd, @arg);
131 0     0 0   };
132             }
133              
134             sub option {
135 0     0 0   while (my($k, $v) = splice @_, 0, 2) {
136 0 0         if ($k =~ s/^no-?//) {
137 0           $option{$k} = 0;
138             } else {
139 0           $option{$k} = $v;
140             }
141             }
142             }
143              
144             1;
145              
146             __DATA__