File Coverage

blib/lib/Devel/TypeCheck/Type/Chi.pm
Criterion Covered Total %
statement 15 125 12.0
branch 0 40 0.0
condition 0 3 0.0
subroutine 5 22 22.7
pod 10 17 58.8
total 30 207 14.4


line stmt bran cond sub pod time code
1             package Devel::TypeCheck::Type::Chi;
2              
3             =head1 NAME
4              
5             Devel::TypeCheck::Type::Chi - Represents hashes.
6              
7             =head1 SYNOPSIS
8              
9             use Devel::TypeCheck::Type::Chi;
10              
11             =head1 DESCRIPTION
12              
13             This class represents the Chi (capital 'X') terminal in the type
14             language. As such, it maintains type information for hashes. This
15             class is similar to Omicron. This class inherits from the
16             Devel::TypeCheck::Type and Devel::TypeCheck::TSub classes.
17              
18             =cut
19              
20 1     1   9492 use strict;
  1         4  
  1         46  
21 1     1   7 use Carp;
  1         3  
  1         124  
22              
23 1     1   7 use Devel::TypeCheck::Type;
  1         3  
  1         41  
24 1     1   7 use Devel::TypeCheck::Util;
  1         3  
  1         219  
25              
26             our @ISA = qw(Devel::TypeCheck::Type Devel::TypeCheck::Type::TSub);
27              
28             # **** CLASS ****
29              
30             our @SUBTYPES;
31             our @subtypes;
32              
33             BEGIN {
34 1     1   11 @SUBTYPES = (Devel::TypeCheck::Type::K());
35              
36 1         5 for my $i (@SUBTYPES) {
37 1         1677 $subtypes[$i] = 1;
38             }
39             }
40              
41             sub hasSubtype {
42 0     0 1   my ($this, $index) = @_;
43 0           return ($subtypes[$index]);
44             }
45              
46             # **** INSTANCE ****
47              
48             sub new {
49 0     0 1   my ($name, $type) = @_;
50              
51 0           my $this = {};
52              
53 0           $this->{'ref'} = newRef($type);
54              
55 0           return bless($this, $name);
56             }
57              
58             sub newRef {
59 0     0 0   my ($type) = @_;
60              
61 0           my $ref = {};
62              
63 0 0         if (defined($type)) {
64 0           $ref->{'hsh'} = undef;
65 0           $ref->{'homogeneous'} = TRUE;
66 0           $ref->{'subtype'} = $type;
67             } else {
68 0           $ref->{'hsh'} = {};
69 0           $ref->{'homogeneous'} = FALSE;
70 0           $ref->{'subtype'} = undef;
71             }
72              
73 0           return $ref;
74             }
75              
76             sub derefIndex {
77 0     0 1   my ($this, $index, $env) = @_;
78              
79 0 0         if ($this->homogeneous) {
80 0           return $this->derefHomogeneous;
81             } else {
82 0 0         if (!exists($this->hsh->{$index})) {
83 0           $this->hsh->{$index} = $env->freshKappa();
84             }
85              
86 0           return $this->hsh->{$index};
87             }
88             }
89              
90             sub hsh {
91 0     0 0   my ($this) = @_;
92 0           return $this->{'ref'}->{'hsh'};
93             }
94              
95             sub subtype {
96 0     0 1   return undef;
97             }
98              
99             sub derefHomogeneous {
100 0     0 1   my ($this) = @_;
101 0           return $this->{'ref'}->{'subtype'};
102             }
103              
104             sub homogeneous {
105 0     0 1   my ($this) = @_;
106 0           return $this->{'ref'}->{'homogeneous'};
107             }
108              
109             sub str {
110 0     0 1   my ($this, $env) = @_;
111              
112 0 0         if ($this->homogeneous) {
113 0           return "{* => " . $this->derefHomogeneous->str($env) . "}";
114             } else {
115 0           my $str = "{";
116              
117 0           my @str = ();
118 0           foreach my $i (keys %{$this->hsh}) {
  0            
119 0           push(@str, "\"" . $i . "\" => " . $this->derefIndex($i, $env)->str($env));
120             }
121            
122 0           $str .= join(",", @str);
123              
124 0           return $str . "}";
125             }
126             }
127              
128             sub pretty {
129 0     0 1   my ($this, $env) = @_;
130              
131 0 0         if ($this->homogeneous) {
132 0           return "ASSOCIATIVE ARRAY of {" . $this->derefHomogeneous->pretty($env) . "}";
133             } else {
134 0           my $str = "RECORD of {";
135              
136 0           my @str = ();
137 0           foreach my $i (keys %{$this->hsh}) {
  0            
138 0           push(@str, "\"" . $i . "\" => " . $this->derefIndex($i, $env)->pretty($env));
139             }
140            
141 0           $str .= join(", ", @str);
142              
143 0           return $str . "}";
144             }
145             }
146              
147             sub copyFrom {
148 0     0 0   my ($this, $that) = @_;
149              
150 0           $this->{'ref'} = $that->{'ref'};
151             }
152              
153             sub bindUp {
154 0     0 0   my ($this, $that, $env) = @_;
155              
156 0 0         if (! $this->homogeneous) {
157 0           confess("Can not bind up against non-homogeneous hash");
158             }
159              
160 0 0         if ($that->homogeneous) {
161 0           confess("Can not bind up homogeneous hash to homogeneous hash, unify instead");
162             }
163              
164 0           foreach my $i (keys(%{$that->hsh})) {
  0            
165 0 0         if (!defined($env->unify($this->derefIndex($i, $env), $this->derefHomogeneous))) {
166 0           return undef;
167             }
168             }
169            
170 0           $that->copyFrom($this);
171              
172 0           return $this;
173             }
174              
175             sub recordUnify {
176 0     0 0   my ($this, $that, $env) = @_;
177            
178 0 0 0       if ($this->homogeneous || $that->homogeneous) {
179 0           confess("Both inputs must not be homogeneous for recordUnify");
180             }
181              
182 0           my %keys;
183              
184 0           foreach my $i (keys(%{$this->hsh})) {
  0            
185 0           $keys{$i} = TRUE;
186             }
187              
188 0           foreach my $i (keys(%{$that->hsh})) {
  0            
189 0           $keys{$i} = TRUE;
190             }
191            
192 0           foreach my $i (keys(%keys)) {
193 0 0         if (!defined($env->unify($this->derefIndex($i, $env), ($that->derefIndex($i, $env))))) {
194 0           return undef;
195             }
196             }
197              
198 0           $that->copyFrom($this);
199            
200 0           return $this;
201             }
202            
203             sub unify {
204 0     0 0   my ($this, $that, $env) = @_;
205              
206 0           $this = $env->find($this);
207 0           $that = $env->find($that);
208              
209 0 0         if ($this->type == $that->type) {
210 0 0         if ($this->homogeneous) {
211 0 0         if ($that->homogeneous) {
212 0           return $env->unify($this->derefHomogeneous, $that->derefHomogeneous);
213             } else {
214 0           return $this->bindUp($that, $env);
215             }
216             } else {
217 0 0         if ($that->homogeneous) {
218 0           return $that->bindUp($this, $env);
219             } else {
220 0           return $this->recordUnify($that, $env);
221             }
222             }
223             } else {
224 0           return undef;
225             }
226             }
227              
228             sub type {
229 0     0 1   return Devel::TypeCheck::Type::X();
230             }
231              
232             # Do the occurs check against $that with the given environment $env.
233             sub occurs {
234 0     0 0   my ($this, $that, $env) = @_;
235            
236 0 0         if ($that->type != Devel::TypeCheck::Type::VAR()) {
237 0           die("Invalid type ", $that->str, " for occurs check");
238             }
239              
240 0 0         if ($this->homogeneous) {
241 0           return $this->derefHomogeneous->occurs($that, $env);
242             } else {
243 0           foreach my $i (keys %{$this->hsh}) {
  0            
244 0           my $occurs = $this->derefIndex($i, $env)->occurs($that, $env);
245 0 0         return $occurs if ($occurs);
246             }
247              
248 0           return FALSE();
249             }
250             }
251              
252             sub listCoerce {
253 0     0 1   my ($this, $env) = @_;
254              
255 0           my $t;
256 0 0         if (!$this->homogeneous) {
257 0           my $t0 = $env->genChi($env->freshKappa);
258 0           $t = $t0->subtype->bindUp($this, $env);
259              
260 0 0         return undef if (!$t);
261             } else {
262 0           $t = $this;
263             }
264              
265 0           my $type = $env->unify($t->derefHomogeneous, $env->freshUpsilon);
266 0 0         return undef if (!$type);
267            
268 0           return $env->genOmicron($type);
269             }
270              
271             TRUE;
272              
273             =head1 AUTHOR
274              
275             Gary Jackson, C<< >>
276              
277             =head1 BUGS
278              
279             This version is specific to Perl 5.8.1. It may work with other
280             versions that have the same opcode list and structure, but this is
281             entirely untested. It definitely will not work if those parameters
282             change.
283              
284             Please report any bugs or feature requests to
285             C, or through the web interface at
286             L.
287             I will be notified, and then you'll automatically be notified of progress on
288             your bug as I make changes.
289              
290             =head1 COPYRIGHT & LICENSE
291              
292             Copyright 2005 Gary Jackson, all rights reserved.
293              
294             This program is free software; you can redistribute it and/or modify it
295             under the same terms as Perl itself.
296              
297             =cut