File Coverage

blib/lib/Unicode/Overload.pm
Criterion Covered Total %
statement 79 93 84.9
branch 26 40 65.0
condition 4 6 66.6
subroutine 18 18 100.0
pod n/a
total 127 157 80.8


line stmt bran cond sub pod time code
1             package Unicode::Overload;
2              
3 1     1   99460 use utf8;
  1         3  
  1         9  
4 1     1   34 use strict;
  1         2  
  1         39  
5 1     1   6 use warnings; # XXX Version-dependent
  1         7  
  1         38  
6 1     1   1866 use Filter::Simple;
  1         44106  
  1         8  
7 1     1   71 use Carp;
  1         2  
  1         63  
8              
9             #use charnames ':full'; # AHA XXX THIS IS THE MODULE THAT CAUSES $WEIRD_ERROR
10 1     1   5 use vars qw($VERSION);
  1         3  
  1         1240  
11              
12             $VERSION = '0.01';
13              
14             sub _map_params
15             {
16 1     1   10 my %legal_types =
17             (
18             prefix => 1,
19             postfix => 1,
20             infix => 1,
21             outfix => 1,
22             );
23 1         4 my %ops = ();
24 1         7 for(my $i=0;$i<@_;$i+=3)
25             {
26 4         16 my ($name,$type,$sub) = @_[$i..$i+2];
27 4 50       28 croak "Illegal type '$type' for '$name'\n"
28             unless defined $legal_types{$type};
29 4 50       13 croak "Not a subroutine reference for '$name'\n"
30             unless ref $sub eq 'CODE';
31 4 50 66     21 croak "Outfix type requires an array reference of names\n"
32             if $type eq 'outfix' and ref($name) ne 'ARRAY';
33 4 50 66     18 croak "Outfix type only takes two characters\n"
34             if $type eq 'outfix' and @$name != 2;
35              
36 4 100       11 if(ref $name eq 'ARRAY')
37             {
38 1         5 $ops{$name->[0]} = [ 'outfix_l' => $sub ];
39 1         8 $ops{$name->[1]} = [ 'outfix_r' => $sub ];
40             }
41             else
42             {
43 3         19 $ops{$name} = [ $type => $sub ];
44             }
45             }
46 1         7 \%ops;
47             }
48              
49             sub _unicode_subchr
50             {
51 3     3   7 my ($str_ref,$pos,$rep) = @_;
52 3         5 my $len = 1;
53 3 50       13 $len++ if ord(substr($$str_ref,$pos,1)) > 0x7F;
54 3 50       9 $len++ if ord(substr($$str_ref,$pos,1)) > 0xDF;
55 3 50       8 $len++ if ord(substr($$str_ref,$pos,1)) > 0xEF;
56 3         16 substr($$str_ref,$pos,$len) = $rep;
57             }
58              
59             sub _outfix_r
60             {
61 1     1   14 my ($ops,$str_ref) = @_;
62 1         7 for my $char (keys %$ops)
63             {
64 5 100       27 next unless $ops->{$char}[0] eq 'outfix_r';
65 1         2 my $pos;
66 1         7 while(($pos = index($$str_ref,$char)) >= 0)
67             {
68 0         0 _unicode_subchr($str_ref,$pos,')');
69             }
70             }
71             }
72              
73             sub _outfix_l
74             {
75 1     1   5 my ($ops,$str_ref) = @_;
76 1         4 for my $char (keys %$ops)
77             {
78 5 100       19 next unless $ops->{$char}[0] eq 'outfix_l';
79 1         6 while((my $pos = index($$str_ref,$char)) >= 0)
80             {
81 0         0 _unicode_subchr($str_ref,$pos,$ops->{$char}[2].'(');#'_floor(');
82             }
83             }
84             }
85              
86             sub _infix
87             {
88 1     1   3 my ($ops,$str_ref) = @_;
89 1         5 for my $char (keys %$ops)
90             {
91 5 100       16 next unless $ops->{$char}[0] eq 'infix';
92 1         6 while((my $pos = index($$str_ref,$char)) >= 0)
93             {
94 0         0 my $front = _balance_parens($$str_ref,$pos-1,-1);
95 0         0 _unicode_subchr($str_ref,$pos,',');
96 0         0 substr($$str_ref,$front,0) = $ops->{$char}[2];#'_element';
97             }
98             }
99             }
100              
101             sub _prefix
102             {
103 1     1   3 my ($ops,$str_ref) = @_;
104 1         3 for my $char (keys %$ops)
105             {
106 5 100       15 next unless $ops->{$char}[0] eq 'prefix';
107 1         8 while((my $pos = index($$str_ref,$char)) >= 0)
108             {
109 0         0 _unicode_subchr($str_ref,$pos,$ops->{$char}[2]);#'_sigma');
110             }
111             }
112             }
113              
114             sub _postfix
115             {
116 1     1   2 my ($ops,$str_ref) = @_;
117 1         5 for my $char (keys %$ops)
118             {
119 5 100       25 next unless $ops->{$char}[0] eq 'postfix';
120 1         7 while((my $pos = index($$str_ref,$char)) >= 0)
121             {
122 3         11 my $front = _balance_parens($$str_ref,$pos-1,-1);
123 3         10 _unicode_subchr($str_ref,$pos,'');
124 3         23 substr($$str_ref,$front,0) = $ops->{$char}[2];#'_square';
125             }
126             }
127             }
128              
129             sub _balance_parens # Assume it's starting on the appropriate paren
130             {
131 3     3   9 my ($str,$pos,$dir) = @_;
132 3 50       9 if($dir > 0)
133             {
134 0         0 my $balance = 1;
135 0         0 $pos++ while substr($str,$pos,1) =~ /\s/;
136 0         0 while($pos++ < length($str))
137             {
138 0 0       0 $balance++ if substr($str,$pos,1) eq '(';
139 0 0       0 $balance-- if substr($str,$pos,1) eq ')';
140 0 0       0 return $pos if $balance == 0;
141             }
142 0         0 return -1;
143             }
144             else
145             {
146 3         4 my $balance = 1;
147 3         17 $pos-- while substr($str,$pos,1) =~ /\s/;
148 3         9 while(--$pos > 0)
149             {
150 15 100       36 $balance-- if substr($str,$pos,1) eq '(';
151 15 100       38 $balance++ if substr($str,$pos,1) eq ')';
152 15 100       48 return $pos if $balance == 0;
153             }
154 0           return -1;
155             }
156             }
157              
158             my $package;
159 1     1   28 BEGIN { $package = (caller(0))[0]; }; # Filter::Simple gets in the way here
160 1     1   20 use Filter::Simple;
  1         3  
  1         6  
161             FILTER_ONLY code => sub
162             {
163             shift @_;
164             croak "Incorrect number of parameters\n" if @_ % 3;
165             my $ops = _map_params(@_);
166             my @lines = split /\n/;
167             my $sym = 'aaaa';
168             for(keys %$ops)
169             {
170             $ops->{$_}[2]='_'.$sym++;
171             }
172 1     1   197 { no strict 'refs';
  1         2  
  1         34  
173 1     1   4 use POSIX;
  1         2  
  1         10  
174             for(keys %$ops)
175             {
176             *{$package.'::'.$ops->{$_}[2]}=$ops->{$_}[1];
177             }
178             };
179             _outfix_r($ops,\$_);
180             _outfix_l($ops,\$_);
181             _infix($ops,\$_);
182             _prefix($ops,\$_);
183             _postfix($ops,\$_);
184             #die "<$_>\n";
185             };
186              
187             1;
188             __END__