File Coverage

blib/lib/Dios/Types.pm
Criterion Covered Total %
statement 545 651 83.7
branch 226 310 72.9
condition 113 196 57.6
subroutine 71 85 83.5
pod 2 2 100.0
total 957 1244 76.9


line stmt bran cond sub pod time code
1             package Dios::Types;
2             our $VERSION = '0.000001';
3              
4 60     60   258785 use 5.014; use warnings;
  60     60   199  
  60         283  
  60         97  
  60         1442  
5 60     60   329 use Carp;
  60         99  
  60         3947  
6 60     60   367 use Scalar::Util qw< reftype blessed looks_like_number openhandle >;
  60         111  
  60         3889  
7 60     60   61371 use overload;
  60         50446  
  60         294  
8 60     60   24963 use Sub::Uplevel;
  60         56099  
  60         318  
9              
10             $Carp::CarpInternal{'Dios::Types'}=1;
11              
12             ### IF KEYWORDS {
13 60     60   46932 use Keyword::Declare;
  60         5492715  
  60         731  
14              
15             ### IF KEYWORDS }
16              
17             my %exportable = ( validate => 1, validator_for => 1 );
18 0         0 sub import {
19              
20             # Throw away the package name...
21 63     63   454 shift @_;
22              
23             # Cycle through each SUB => AS pair...
24 63         403 while (my ($exported, $export_as) = splice(@_, 0, 2)) {
25             # If it's not a rename, don't change the name...
26 4 50 66     43 if ($export_as && $exportable{$export_as}) {
27 0         0 unshift @_, $export_as;
28 0         0 undef $export_as;
29             }
30              
31             # If it's not exported, don't export it...
32 4 50       16 croak "Can't export $exported" if !$exportable{$exported};
33              
34             # Unrenamed exports are exported under their own names...
35 4   66     23 $export_as //= $exported;
36              
37             # Do the export...
38 60     60   17660 no strict 'refs';
  60         110  
  60         14125  
39 4         6 *{caller.'::'.$export_as} = \&{$exported};
  4         22  
  4         12  
40             }
41              
42             ### IF KEYWORDS {
43 63         177  
44 60     60   1398274 keytype TypeSpec is /
45             (?&PerlIdentifier) (?: \[ (?>(?&PPR_balanced_squares)) \])?+
46             (?:
47             (?&PerlOWS) [&|] (?&PerlOWS)
48             (?&PerlIdentifier) (?: \[ (?>(?&PPR_balanced_squares)) \])?+
49             )*+
50             /x;
51 63         90  
52 60     60   1369956 keytype TypeParams is / \[ (?>(?&PPR_balanced_squares)) \] /x;
53              
54 63         84 # Create a new subtype of a known type, adding a constraint...
55 0 50 50 5   0 keyword subtype (
  0         0  
  0         0  
  63         279  
  5         398200  
  5         12  
  5         17  
56 0         0 Ident $new_type,
  63         2279  
  5         10  
57 0         0 TypeParams $new_type_params = q{},
  5         131  
58             'of',
59 0         0 TypeSpec $known_type,
  0         0  
  5         169  
  5         11  
60 0         0 'where',
  5         10  
61 0         0 Block $constraint
  5         77  
62             ) {
63 0         0 my $subtype_defn
  0         0  
  0         0  
  5         92  
  5         10  
  5         9  
64 0         0 = qq{Dios::Types::_define_subtype('$new_type', '$new_type_params', 'Is', '[$known_type]', sub $constraint) };
  5         11  
65 0         0 qq{if (((caller 0)[3]//q{}) =~ /\\b(?:un)?import\\Z/) { $subtype_defn }; BEGIN{ $subtype_defn }};
  5         70  
66             }
67 0         0  
  0         0  
  0         0  
  5         85  
  5         9  
  5         8  
68 0         0  
  5         13  
69 0         0 # Alias a new subtype to a known type...
  5         66  
  63         1453  
70 0 50 50 4   0 keyword subtype (
  0         0  
  0         0  
  63         204  
  4         283739  
  4         10  
  4         10  
71 0         0 Ident $new_type,
  0         0  
  5         85  
  63         1383  
  4         9  
72 0         0 TypeParams $new_type_params = q{},
  0         0  
  5         68  
  4         81  
73             'of',
74 0         0 TypeSpec $known_type,
  0         0  
  0         0  
  5         89  
  4         150  
  4         9  
75 60         431 ) {
  0         0  
  63         538  
  4         6  
76 0         0 my $subtype_defn
  63         2836  
  4         55  
77 60     60   1666035 = qq{Dios::Types::_define_subtype('$new_type', '$new_type_params', 'Is', '[$known_type]') };
78 0         0 qq{if (((caller 0)[3]//q{}) =~ /\\b(?:un)?import\\Z/) { $subtype_defn }; BEGIN{ $subtype_defn }};
  0         0  
  0         0  
  4         68  
  4         5  
  4         8  
79 0         0 }
  4         8  
80 0         0  
  4         45  
81             ### IF KEYWORDS }
82 0         0  
  4         96  
83 0         0 }
  4         47  
84              
85 0         0 my @user_defined_type;
  4         61  
86 60         413  
  63         350  
87 63         1842 ### IF KEYWORDS {
88 60     60   1641015  
89             sub _define_subtype {
90 11     11   2192 my ($new_typename, $new_type_params, $old_typename, $old_type_params, $constraint) = @_;
91 11   100 10   64 $constraint //= sub{1};
  10         21  
92              
93 11   50     49 local $Dios::Types::lexical_hints = (caller 0)[10] // {};
94              
95             # Reassemble the complete base type...
96 11         295 $old_typename .= $old_type_params;
97              
98             # We are building a sub that builds type handlers...
99 11         16 my $new_type_handler_generator;
100              
101             # The simple case (where the new type is not parameterized)...
102 11 100       36 if (!length($new_type_params)) {
103 9         25 my $old_type_handler = _build_handler_for($old_typename);
104              
105             $new_type_handler_generator = sub {
106             return sub {
107 21         47 my $okay = $old_type_handler->($_[0]);
108 21 100       43 return _error_near($_[0], $new_typename, $okay) if !$okay;
109 17 100       45 return _error_near($_[0], $new_typename ) if !$constraint->(local $_ = $_[0]);
110 13         136 return 1;
111             }
112 9     21   40 };
  21         78  
113             }
114              
115             # The more complex case, where the new type has parameters...
116             else {
117             # Extract the new parameter names...
118 2         26 my @new_type_param_names = split /\s*,\s*/, $new_type_params =~ s{\A\[\s*+|\s*+\]\Z}{}grx;
119              
120             $new_type_handler_generator = sub {
121 10     10   24 my ($typename) = @_;
122 10         119 my @params = split /\s*,\s*/, $typename =~ s{\A \w++ \[ \s*+ | \s*+ \] \Z}{}grx;
123 10         27 my $substituted_typename = $old_typename;
124 10         37 for my $n (0..$#params) {
125 12         204 $substituted_typename =~ s{$new_type_param_names[$n]}{$params[$n]}gxms;
126             }
127              
128 10         53 my $old_type_handler
129             = _build_handler_for($substituted_typename,
130             "generated by parameterized subtype: $typename\n");
131              
132             return sub {
133 9         29 my $okay = $old_type_handler->($_[0]);
134 9 100       27 return _error_near($_[0], $typename, $okay) if !$okay;
135 7 100       15 if (! eval{ local $SIG{__WARN__} = sub{}; $constraint->(local $_ = $_[0]) }) {
  7         53  
  7         32  
136 3         35 my $constraint_desc = _describe_constraint($_[0], undef, $constraint, $@);
137 3         28 return _error_near(
138             $_[0], qq{Value ($_[0]) did not satisfy the constraint: $constraint_desc\n }
139             );
140             }
141 4         102 return 1;
142             }
143 2         14 };
  9         64  
144             }
145              
146 11         69 $^H{"Dios::Types subtype=$new_typename"} = @user_defined_type;
147 11         4967 push @user_defined_type, $new_type_handler_generator;
148             }
149              
150             ### IF KEYWORDS }
151              
152             sub _error_near ($$;$) {
153 98     98   303 my ($where, $what, $previous_errors) = @_;
154              
155 0         0 { package Dios::Types::Error;
156 60     60   36574 use overload 'bool' => sub{0}, fallback => 1;
  60     209   129  
  60         580  
  209         597  
157             sub msg {
158 0     0   0 my $self = shift;
159 0 0       0 return $self->[0] ne $self->[-1] ? "$self->[-1]\n(because $self->[0])" : $self->[0];
160             }
161             }
162              
163 98 100 100     130 $previous_errors = bless [], 'Dios::Types::Error' if (reftype($previous_errors)//q{}) ne 'ARRAY';
  98         439  
164 98         123 push @{$previous_errors}, _perl($where) . " isn't of type $what";
  98         382  
165              
166 98         16484 return $previous_errors;
167             }
168              
169             # Standard type checking...
170             my %handler_for = (
171             # Any Perl value or ref...
172             Slurpy => sub { 1 },
173             Any => sub { 1 },
174              
175             # Anything that is true or false (and that's everything in Perl!)
176             Bool => sub { 1 },
177              
178             # Anything defined, or not...
179             Def => sub { defined $_[0] },
180             Undef => sub { !defined $_[0] },
181             Void => sub { !defined $_[0] || ref $_[0] eq 'ARRAY' && !@{$_[0]} },
182              
183             # Values, references, and filehandles...
184             Value => sub { defined($_[0]) && !ref($_[0]) },
185             Ref => sub { ref $_[0] },
186             IO => \&openhandle,
187             Glob => sub { ref($_[0]) eq 'GLOB' },
188              
189             # An integer...
190             Int => sub {
191             # If it's an object, must have a warning-less numeric overloading...
192             if (ref($_[0])) {
193             # Normal references aren't integers...
194             return 0 if !blessed($_[0]);
195              
196             # Is there an overloading???
197             my $converter = overload::Method($_[0],'0+')
198             or return 0;
199              
200             # Does this object convert to a number without complaint???
201             my $warned;
202             local $SIG{__WARN__} = sub { $warned = 1 };
203             my $value = eval{ $converter->($_[0],undef,undef) }
204             // return 0;
205             return 0 if $warned;
206             return $value =~ m{\A \s*+ [+-]?+ (?: \d++ (\.0*+)?+ | inf(?:inity)?+ ) \s*+ \Z}ixms;
207             }
208              
209             # Value must be defined, non-reference, looks like an integer...
210             return defined($_[0])
211             && $_[0] =~ m{\A \s*+ [+-]?+ (?: \d++ (\.0*+)?+ | inf(?:inity)?+ ) \s*+ \Z}ixms;
212             },
213              
214             # A number
215             Num => sub {
216             return 0 if !defined $_[0] || lc($_[0]) eq 'nan';
217             &looks_like_number
218             },
219              
220             # A string, or stringifiable object, or array ref, or hash ref, that is empty...
221             Empty => sub {
222             my $value = shift;
223              
224             # Must be defined...
225             return 0 if !defined($value);
226              
227             # May be an empty array or hash...
228             my $reftype = ref($value);
229             return 1 if $reftype eq 'ARRAY' && !@{$value};
230             return 1 if $reftype eq 'HASH' && !keys %{$value};
231              
232             # May be an object that overloads stringification...
233             my $converter = $reftype && overload::Method($value, q{""});
234             return 1 if $converter && $converter->($value,undef,undef) eq q{};
235              
236             # Otherwise, has to be an empty string...
237             return $value eq q{};
238             },
239              
240             # A string, or stringifiable object...
241             Str => sub { defined($_[0]) && (ref($_[0]) ? defined overload::Method(shift,q{""}) : 1) },
242              
243             # A blessed object...
244             Obj => \&blessed,
245              
246             # Any loaded class (must have @ISA or $VERSION or at least one method defined)...
247             Class => sub {
248             return 0 if ref $_[0] || not $_[0];
249             my $stash = \%main::;
250             for my $partial_name (split /::/, $_[0]) {
251             return 0 if !exists $stash->{$partial_name.'::'};
252             $stash = $stash->{$partial_name.'::'};
253             }
254             return 1 if exists $stash->{'ISA'};
255             return 1 if exists $stash->{'VERSION'};
256             for my $globref (values %$stash) {
257             return 1 if *{$globref}{CODE};
258             }
259             return 0;
260             },
261             );
262              
263             # Built-in type checking...
264             for my $type (qw< SCALAR ARRAY HASH CODE GLOB >) {
265             $handler_for{ ucfirst(lc($type)) } = sub { (reftype($_[0]) // q{}) eq $type };
266             }
267             $handler_for{ Regex } = sub { (reftype($_[0]) // q{}) eq 'REGEXP' };
268             $handler_for{ List } = $handler_for{ Array };
269              
270             # Standard type hierrachy...
271             my %BASIC_NARROWER = (
272             Slurpy => { },
273             Any => { map {$_=>1} qw< Slurpy >},
274             Bool => { map {$_=>1} qw< Slurpy Any >},
275             Undef => { map {$_=>1} qw< Slurpy Any Bool >},
276             Def => { map {$_=>1} qw< Slurpy Any Bool >},
277             Value => { map {$_=>1} qw< Slurpy Any Bool Def >},
278             Num => { map {$_=>1} qw< Slurpy Any Bool Def Value Str >},
279             Int => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Num >},
280             Str => { map {$_=>1} qw< Slurpy Any Bool Def Value >},
281             Class => { map {$_=>1} qw< Slurpy Any Bool Def Value Str >},
282             Empty => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Ref Array List Hash >},
283             Ref => { map {$_=>1} qw< Slurpy Any Bool Def >},
284             Scalar => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
285             Regex => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
286             Code => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
287             Glob => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
288             IO => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
289             Obj => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
290             Array => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
291             List => { map {$_=>1} qw< Slurpy Any Bool Def Ref Array >},
292             Empty => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Ref Array Hash List >},
293             Hash => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
294             Empty => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Ref Array Hash List >},
295             );
296              
297             # This is the full typename syntax...
298             my $BASIC_TYPES = join('|', keys %handler_for);
299              
300             my $TYPED_OR_PURE_ETC = qr{ \s*+ ,? \s*+ \.\.\.}xms;
301             my $TYPED_ETC = qr{ \s*+ \.\.\.}xms;
302             my $PURE_ETC = qr{ \s*+ , \s*+ \.\.\.}xms;
303              
304             my $KEYED_TYPENAME = q{
305             \\s*
306             (?: ' (? [^'\\\\]*+ (?: \\\\. [^'\\\\]*+ )*+ ) '
307             | (? (?&IDENT) )
308             )
309             (? \\s* [?] )?
310             (?: \\s* => \\s* (? (?&CONJ_TYPENAME) ) )?
311             };
312              
313             my $TYPENAME_GRAMMAR = qr{
314              
315             (?
316             (? (?&QUAL_IDENT) )
317             | Is \[ (? \s*+ (?&DISJ_TYPENAME_BAR) \s*+ ) \]
318             | Is \[ (? \s*+ (?&CONJ_TYPENAME) \s*+ ) \]
319             | Not \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
320             | List \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
321             | Array \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
322             | Tuple \[ (? \s*+ (?&TUPLE_FORMAT) \s*+ ) \]
323             | Hash \[ (? \s*+ (?&DISJ_TYPENAME) (?: \s*+ => \s*+ (?&DISJ_TYPENAME) )?+ \s*+ ) \]
324             | Dict \[ (? \s*+ (?&DICT_FORMAT) \s*+ ) \]
325             | Ref \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
326             | Eq \[ (? \s*+ (?&STR_SPEC) \s*+ ) \]
327             | Match \[ (? \s*+ (?®EX_SPEC) \s*+ ) \]
328             | Can \[ (? \s*+ (?&OPT_QUAL_IDENT) \s*+ (?: , \s*+ (?&OPT_QUAL_IDENT) \s*+ )*+ ) \]
329             | Overloads \[ (? [^]]++ ) \]
330             | (? (?&BASIC) )
331             | (? (?!(?&BASIC)) (?&IDENT) (?: \s*+ \[ \s*+ (?&TYPE_LIST) \s*+ \] )?+ )
332             )
333              
334             (?(DEFINE)
335              
336             (? (?&CONJ_TYPENAME) (?: \s* [|] \s* (?&CONJ_TYPENAME) )++ )
337             (? (?&CONJ_TYPENAME) (?: \s* [|] \s* (?&CONJ_TYPENAME) )*+ )
338             (? (?&ATOM_TYPENAME) (?: \s* [&] \s* (?&ATOM_TYPENAME) )*+ )
339              
340             (?
341             (?&CONJ_TYPENAME) (?: \s* [|] \s* (?&CONJ_TYPENAME) )++
342             | (?&ATOM_TYPENAME) (?: \s* [&] \s* (?&ATOM_TYPENAME) )++
343             )
344              
345             (?
346             (?&TYPE_LIST) (?: \s*+ ,? \s*+ \.\.\. )?
347             )
348              
349             (?
350             (?&CONJ_TYPENAME) (?: \s*,\s* (?&CONJ_TYPENAME) )*+
351             )
352              
353             (?
354             (?&KEYED_TYPENAME) (?: \s*,\s* (?&KEYED_TYPENAME) )*+ $PURE_ETC?
355             )
356              
357             (?
358             $KEYED_TYPENAME
359             )
360              
361             (? (?: [^][\\]++ | \\[][\\] )*+ )
362              
363             (? (?: [^][\\]++ | \\\S | \[ \^? \]? [^]]*+ \] )*+ )
364              
365             (? \b (?: $BASIC_TYPES ) \b )
366              
367             (? (?&IDENT) (?: :: (?&IDENT) )++ )
368              
369             (? (?&IDENT) (?: :: (?&IDENT) )*+ )
370              
371             (? [^\W\d] \w*+ )
372             )
373             }xms;
374              
375             my $FROM_TYPENAME_GRAMMAR = qr{ (?(DEFINE) $TYPENAME_GRAMMAR ) }xms;
376              
377             my $IS_REF_TYPE
378             = qr/\A (?: List | Array | Hash | Code | Scalar | Regex | Tuple | Dict | Glob | IO | Obj ) \b/x;
379              
380             # Complex types are built on the fly...
381             sub _build_handler_for {
382 250     250   459 my ($type, $context, $level) = @_;
383              
384             # Reformat conjunctions and disjunctions to avoid left recursion...
385 250 100       18505 if ($type =~ m{\A \s*+ ((?&NON_ATOM_TYPENAME)) \s*+ \Z $FROM_TYPENAME_GRAMMAR }xms) {
386 18         94 $type = "Is[$1]";
387             }
388              
389             # Parse the type specification...
390 250 50       8909 $type =~ m{\A \s*+ $TYPENAME_GRAMMAR \s*+ \Z }xms
    100          
391             or croak "Incomprehensible type name: $type\n",
392             (defined $context ? $context : q{});
393              
394 249         3172 my %type_is = %+;
395              
396             # Conjunction handlers test each component type and fail if any fails...
397 249 100       772 if ( exists $type_is{conj} ) { my @types = grep {defined} $type_is{conj} =~ m{ ((?&ATOM_TYPENAME))
  22         2316  
  972         1112  
398             $FROM_TYPENAME_GRAMMAR
399             }gxms;
400 22         98 my @handlers = map {_build_handler_for($_)} @types;
  27         107  
401             return sub {
402 34     34   61 for (@handlers) {
403 39         81 my $okay = $_->($_[0]);
404 39 100       98 return _error_near($_[0], join(' or ', @types), $okay)
405             if !$okay;
406             }
407 27         41 return 1;
408             }
409 22         139 }
410              
411             # Disjunction handlers test each component type and fail if all of them fail...
412 227 100       465 if ( exists $type_is{disj} ) { my @types = grep {defined} $type_is{disj} =~ m{ ((?&CONJ_TYPENAME))
  14         4332  
  1044         1140  
413             $FROM_TYPENAME_GRAMMAR
414             }gxms;
415 14         108 my @handlers = map {_build_handler_for($_)} @types;
  29         100  
416             return sub {
417 25     25   56 for (@handlers) {
418 43 100       115 return 1 if $_->($_[0]);
419             }
420 3         13 return _error_near($_[0], join(' or ', @types));
421             }
422 14         124 }
423              
424             # Basic types, just use the built-in handler...
425 213 100       381 if ( exists $type_is{basic} ) { return $handler_for{$type_is{basic}}; }
  102         412  
426              
427             # User defined types match an object of that type...
428 111 100       222 if ( exists $type_is{user} ) { my $typename = $type_is{user};
  13         40  
429 13         44 my $root_name = $typename =~ s{\[.*}{}rxms;
430 13         44 my $idx = $Dios::Types::lexical_hints->{"Dios::Types subtype=$root_name"};
431             return sub {
432             # Is it user-defined???
433 33 100   33   67 if (defined $idx) {
434 31         53 for ($_[0]) {
435 31   66     96 return $user_defined_type[$idx]($typename)($_)
436             || _error_near($_[0], $typename);
437             }
438             }
439              
440 2   33     21 return blessed($_[0]) && $_[0]->isa($typename)
441             || _error_near($_[0], $typename);
442             }
443 13         125 }
444              
445             # Array[T] types require an array ref, whose every element is of type T...
446 98 100       191 if ( exists $type_is{array} ) { my $value_handler = _build_handler_for($type_is{array});
  31         244  
447             return sub {
448 76 100 100 76   339 return _error_near($_[0], "Array[$type_is{array}]")
449             if (reftype($_[0]) // q{}) ne 'ARRAY';
450              
451 74         102 for (@{$_[0]}) {
  74         160  
452 161 100       268 next if my $okay = $value_handler->($_);
453 21         56 return _error_near($_, $type_is{array}, $okay);
454             }
455              
456 53         179 return 1;
457             }
458 31         251 }
459              
460             # List[T] types require an array ref, whose every element is of type T...
461 67 100       141 if ( exists $type_is{list} ) { my $value_handler = _build_handler_for($type_is{list});
  3         13  
462             return sub {
463 4 100 100 4   24 return _error_near($_[0], "List[$type_is{list}]")
464             if (reftype($_[0]) // q{}) ne 'ARRAY';
465              
466 3         5 for (@{$_[0]}) {
  3         7  
467 7 50       21 next if my $okay = $value_handler->($_);
468 0         0 return _error_near($_, $type_is{list}, $okay);
469             }
470              
471 3         8 return 1;
472             }
473 3         20 }
474              
475 64 100       117 if ( exists $type_is{tuple} ) { my @types
476 72         72 = grep {defined}
477 1         286 $type_is{tuple} =~ m{ ((?&CONJ_TYPENAME) | $TYPED_OR_PURE_ETC )
478             $FROM_TYPENAME_GRAMMAR
479             }gxms;
480             # Build type handlers for sequence...
481 1         10 my ($final_any, $final_handler);
482 1 50 33     34 if (@types > 1 && $types[-1] =~ /^$TYPED_ETC$/) {
    50 33        
483 0         0 pop @types;
484 0         0 $final_handler = _build_handler_for(pop @types);
485             }
486             elsif (@types > 0 && $types[-1] =~ /^$PURE_ETC$/) {
487 0         0 pop @types;
488 0         0 $final_any = 1;
489 0         0 $final_handler = _build_handler_for('Any');
490             }
491 1         3 my @value_handlers = map {_build_handler_for($_)} @types;
  2         4  
492              
493             return sub {
494 2     2   3 my $array_ref = shift;
495             # Tuples must be array refs the same length as their specifications...
496             return _error_near($array_ref, "Dict[$type_is{tuple}]")
497             if (reftype($array_ref) // q{}) ne 'ARRAY'
498 2 100 50     15 || !$final_handler && @{$array_ref} != @types;
  1   33     4  
      66        
499              
500             # The first N values must match the N types specified...
501 1         3 for my $n (0..$#types) {
502 2         6 my $okay = $value_handlers[$n]($array_ref->[$n]);
503 2 50       10 return _error_near($array_ref, "Dict[$type_is{tuple}]", $okay)
504             if !$okay;
505             }
506              
507             # Succeed at once if no etcetera to test, or it etcetera guaranteed...
508 1 50 33     4 return 1 if $final_any || @{$array_ref} == @types;
  1         4  
509              
510             # Any extra values must match the "et cetera" handler specified...
511 0         0 for my $n ($#types+1..$#{$array_ref}) {
  0         0  
512 0         0 my $okay = $final_handler->($array_ref->[$n]);
513 0 0       0 return _error_near($array_ref, "Dict[$type_is{tuple}]", $okay)
514             if !$okay;
515             }
516              
517 0         0 return 1;
518             }
519 1         8 }
520              
521             # Hash[T] and Hash[T=>T] types require a hash ref, whose every value is of type T...
522 63         213 my $HASH_KV_SPEC = qr{
523             \A
524             ((?&BalancedSquareBrackets))
525             (?: (=>) (.*) )?+
526             \Z
527              
528             (?(DEFINE)
529             (?
530             (?: [^][] | \[ (?&BalancedSquareBrackets) \] )*?
531             )
532             )
533             }xms;
534 63 100       137 if ( exists $type_is{hash} ) { my ($type_k, $arrow, $type_v) = $type_is{hash} =~ $HASH_KV_SPEC;
  21         279  
535             # Only value type specified...
536 21 100       80 if (!$arrow) {
537 12         47 $type_k =~ s/\A\s+|\s+\Z//g;
538 12         76 my $value_handler = _build_handler_for($type_k);
539             return sub {
540 43 100 100 43   219 return _error_near($_[0], "Hash[$type_is{hash}]")
541             if (reftype($_[0]) // q{}) ne 'HASH';
542              
543 39         57 for (values %{$_[0]}) {
  39         104  
544 41         77 my $okay = $value_handler->($_);
545 41 100       118 return _error_near($_, $type_is{hash}, $okay)
546             if !$okay;
547             }
548              
549 35         157 return 1;
550             }
551 12         103 }
552             # Both key and value type specified...
553             else {
554 9         34 $type_k =~ s/\A\s+|\s+\Z//g;
555 9         27 $type_v =~ s/\A\s+|\s+\Z//g;
556 9         26 my $key_handler = _build_handler_for($type_k);
557 9         19 my $value_handler = _build_handler_for($type_v);
558             return sub {
559 18 50 50 18   69 return _error_near($_[0], "Hash[$type_is{hash}]")
560             if (reftype($_[0]) // q{}) ne 'HASH';
561              
562 18         21 for (keys %{$_[0]}) {
  18         44  
563 41         55 my $okay = $key_handler->($_);
564 41 100       86 return _error_near($_, $type_is{hash}, $okay)
565             if !$okay;
566             }
567              
568 11         14 for (values %{$_[0]}) {
  11         20  
569 25         36 my $okay = $value_handler->($_);
570 25 100       49 return _error_near($_, $type_is{hash}, $okay)
571             if !$okay;
572             }
573              
574 9         15 return 1;
575             }
576 9         66 }
577             }
578              
579             # Dict[ k => T, k => T, ... ] requires a hash key, with the specified keys type-matched too...
580 42 100       108 if ( exists $type_is{dict} ) { my (%handler_for, @required_keys, $extra_keys_allowed);
  2         4  
581 2         301 while ($type_is{dict} =~ m{ (? $KEYED_TYPENAME)|(? $PURE_ETC)
582             $FROM_TYPENAME_GRAMMAR}gxms
583             ) {
584             # Create a type checker for each specified key (once!)...
585 6 100       34 if (exists $+{keyed}) {
586 4         25 my ($key, $valtype, $optional) = @+{qw< key valtype optional >};
587             croak qq{Two type specifications for key '$key' },
588             qq{in Dict[$type_is{dict}]}
589 4 50       11 if exists $handler_for{$key};
590 4   50     34 $handler_for{$key}
591             = _build_handler_for($valtype // 'Any');
592 4 50       44 push @required_keys, $key if !$optional;
593             }
594             # And remember whether other keys are allowed...
595             else {
596 2         11 $extra_keys_allowed = 1;
597             }
598             }
599              
600             # Build type handlers for sequence...
601             return sub {
602 4     4   5 my $hash_ref = shift;
603             # It has to be a hash reference...
604 4 100 50     18 return _error_near($hash_ref, "Dict[$type_is{dict}]")
605             if (reftype($hash_ref) // q{}) ne 'HASH';
606              
607             # With all the required keys...
608 3         5 for my $key (@required_keys) {
609             return _error_near($_, "Dict[$type_is{dict}]")
610 5 100       13 if !exists $hash_ref->{$key};
611             }
612              
613             # Each entry has to have a permitted key and the right type of value...
614 2         3 while (my ($key, $value) = each %{$hash_ref}) {
  10         19  
615 8 100       13 if (exists $handler_for{$key}) {
616 4         6 my $okay = $handler_for{$key}($value);
617 4 50       6 return _error_near($_, "Dict[$type_is{dict}]", $okay)
618             if !$okay;
619             }
620             else {
621 4 50       6 return _error_near($_, "Dict[$type_is{dict}]")
622             if !$extra_keys_allowed;
623             }
624             }
625              
626 2         4 return 1;
627             }
628 2         17 }
629              
630             # Ref[T] types require a reference, whose dereferenced value is of type T...
631             # but with special magic if T is already itself a reference type
632 40 100       62 if ( exists $type_is{ref} ) { my $value_handler = _build_handler_for($type_is{ref});
  14         62  
633 14 100       69 return $value_handler if $type_is{ref} =~ $IS_REF_TYPE;
634             return sub {
635 26     26   62 my $reftype = reftype($_[0]);
636 26 50 66     101 return _error_near($_[0], "Ref[$type_is{ref}]")
      33        
637             if !$reftype || $reftype ne 'REF' && $reftype ne 'SCALAR';
638 26         30 my $okay = $value_handler->(${$_[0]});
  26         78  
639 26 100       71 return $okay ? 1 : _error_near($_[0], "Ref[$type_is{ref}]", $okay)
640             }
641 10         73 }
642              
643             # Not[T] negates the usual test...
644 26 100       39 if ( exists $type_is{not} ) { my $negated_handler = _build_handler_for($type_is{not});
  2         7  
645             return sub {
646 11     11   17 my $not_okay = $negated_handler->($_[0]);
647 11 100       21 return _error_near($_[0], "Not[$type_is{not}]", $not_okay)
648             if $not_okay;
649 9         10 return 1;
650             }
651 2         13 }
652              
653             # Eq[S] types require a stringifiable, that matches 'S'...
654 24 50       39 if ( exists $type_is{eq} ) { my $str = eval "q[$type_is{eq}]";
  0         0  
655             return sub {
656             return 1 if defined $_[0]
657             && (!blessed($_[0]) || overload::Method($_[0],q{""}))
658 0 0 0 0   0 && eval{ "$_[0]" eq $str };
  0   0     0  
      0        
659 0         0 return _error_near($_[0], "Eq[$type_is{eq}]");
660             }
661 0         0 }
662              
663             # Match[R] types require a stringifiable, that matches /R/x...
664 24 100       37 if ( exists $type_is{match} ) {
665 6         9 my $regex = eval { qr{$type_is{match}}x };
  6         86  
666 6 50       16 croak "Invalid regex syntax in Match[$type_is{match}]:\n $@" if $@;
667             return sub {
668             return 1 if defined $_[0]
669             && (!blessed($_[0]) || overload::Method($_[0],q{""}))
670 28 100 33 28   108 && eval{ "$_[0]" =~ $regex };
  28   33     137  
      66        
671 4         22 return _error_near($_[0], "Match[$type_is{match}]");
672             }
673 6         42 }
674              
675             # Can[M] types require a class or object with the specified methods...
676 18 100       31 if ( exists $type_is{can} ) { my @method_names = split q{,}, $type_is{can};
  8         21  
677 8         67 s{\s*}{}g for @method_names;
678             return sub {
679 8 50 33 8   29 return 0 if !blessed($_[0]) && !$handler_for{Class}($_[0]);
680 8         11 for my $method_name (@method_names) {
681             return _error_near($_[0], "Can[$type_is{can}]")
682 12 100       14 if !eval{ $_[0]->can($method_name) };
  12         65  
683             }
684 6         11 return 1
685             }
686 8         58 }
687              
688             # Overloads[O] types require a class or object with the specified overloads...
689 10 50       18 if ( exists $type_is{overloads} ) { my @ops = split q{,}, $type_is{overloads};
  10         25  
690 10         77 s{\s*}{}g for @ops;
691             return sub {
692 60     60   199077 use overload;
  60         137  
  60         263  
693 10 50 33 10   35 return 0 if !blessed($_[0]) && !$handler_for{Class}($_[0]);
694 10         15 for my $op (@ops) {
695 24 100       348 return _error_near($_[0], "Can[$type_is{overloads}]")
696             if !overload::Method($_[0], $op);
697             }
698 6         187 return 1
699             }
700 10         69 }
701              
702 0         0 die "Internal error: could not generate a type from '$type'. Please report this as a bug."
703             }
704              
705             sub _complete_desc {
706 558     558   946 my ($desc, $value) = @_;
707 558   100     923 $desc //= q{Value (%s)};
708 558         915 my $value_perl = _perl($value);
709 558         56523 return $desc =~ s{(?
710             }
711              
712             sub validate {
713 757     757 1 179028 my ($typename, $value) = splice(@_,0,2);
714 757         977 my ($value_desc, @constraints);
715 757         1074 for my $arg (@_) {
716             # Subs are undescribed constraints...
717 682 100       1574 if (ref($arg) eq 'CODE') {
    50          
718 60         109 push @constraints, $arg;
719             }
720              
721             # Anything else is part of the value description...
722             elsif (defined $arg) {
723 622         1079 $value_desc .= $arg;
724             }
725             }
726              
727             # What's happening in the caller's lexical scope???
728 757   50     1595 local $Dios::Types::lexical_hints = (caller 0)[10] // {};
729              
730             # All but the basic handlers are built late, as needed...
731 757 100       12978 if (!exists $handler_for{$typename}) {
732 44 50       121 $handler_for{$typename} = _build_handler_for($typename)
733             or die 'Internal error: unable to build type checker. Please report this as a bug.';
734             }
735              
736             # Either the type matches or we die...
737 757 100       1492 if (!$handler_for{$typename}($value)) {
738 314         732 $value_desc = _complete_desc($value_desc, $value);
739 314 50       3622 croak qq{\u$value_desc}
740             . ($value_desc =~ /\s$/ ? q{} : q{ })
741             . qq{is not of type $typename};
742             }
743 442 100       1527 return 1 if !@constraints;
744              
745             # Either every constraint matches or we die...
746 58         92 for my $test (@constraints) {
747 58         62 local $@;
748              
749             # If it fails to match...
750 58 100   0   76 if (! eval{ local $SIG{__WARN__} = sub{}; $test->(local $_ = $value) }) {
  58         276  
  58         158  
751 33         295 $value_desc = _complete_desc($value_desc, $value);
752 33         93 my $constraint_desc = _describe_constraint($value, $value_desc, $test, $@);
753 33 50       551 croak qq{\u$value_desc}
754             . ($value_desc =~ /\s$/ ? q{} : q{ })
755             . qq{did not satisfy the constraint: $constraint_desc\n }
756             }
757             }
758              
759 25         227 return 1;
760             }
761              
762             sub _up_validate {
763 118     118   2717 my ($uplevels, $typename, $value) = splice(@_,0,3);
764 118         145 my ($value_desc, @constraints);
765 118         180 for my $arg (@_) {
766             # Subs are undescribed constraints...
767 166 100       380 if (ref($arg) eq 'CODE') {
    50          
768 50         74 push @constraints, $arg;
769             }
770              
771             # Anything else is part of the value description...
772             elsif (defined $arg) {
773 116         196 $value_desc .= $arg;
774             }
775             }
776              
777             # What's happening in the caller's lexical scope???
778 118   100     246 local $Dios::Types::lexical_hints = (caller $uplevels)[10] // {};
779              
780             # All but the basic handlers are built late, as needed...
781 118 100       2401 if (!exists $handler_for{$typename}) {
782 2 50       7 $handler_for{$typename} = _build_handler_for($typename)
783             or die 'Internal error: unable to build type checker. Please report this as a bug.';
784             }
785              
786             # Either the type matches or we die...
787 118 100       234 if (!$handler_for{$typename}($value)) {
788 13         29 $value_desc = _complete_desc($value_desc, $value);
789 13 100       157 croak qq{\u$value_desc}
790             . ($value_desc =~ /\s$/ ? q{} : q{ })
791             . qq{is not of type $typename};
792             }
793 105 100       360 return 1 if !@constraints;
794              
795             # Either every constraint matches or we die...
796 42         63 for my $test (@constraints) {
797 42         42 local $@;
798              
799             # If it fails to match...
800 42 100   0   54 if (! eval{ local $SIG{__WARN__} = sub{}; $test->(local $_ = $value) }) {
  42         186  
  42         85  
801 4         29 $value_desc = _complete_desc($value_desc, $value);
802 4         15 my $constraint_desc = _describe_constraint($value, $value_desc, $test, $@);
803 4 50       80 croak qq{\u$value_desc}
804             . ($value_desc =~ /\s$/ ? q{} : q{ })
805             . qq{did not satisfy the constraint: $constraint_desc\n }
806             }
807             }
808              
809 38         173 return 1;
810             }
811              
812             sub validator_for {
813 281     281 1 100069 my $typename = shift;
814 281         365 my ($value_desc, @constraints);
815 281         421 for my $arg (@_) {
816             # Subs are undescribed constraints...
817 168 100       416 if (ref($arg) eq 'CODE') {
    50          
818 1         3 push @constraints, $arg;
819             }
820              
821             # Anything else is part of the value description...
822             elsif (defined $arg) {
823 167         311 $value_desc .= $arg;
824             }
825             }
826              
827             # What's happening in the caller's lexical scope???
828 281   50     579 local $Dios::Types::lexical_hints = (caller 0)[10] // {};
829              
830             # All but the basic handlers are built late, as needed...
831 281 100       5305 if (!exists $handler_for{$typename}) {
832 43 50       108 $handler_for{$typename} = _build_handler_for($typename)
833             or die 'Internal error: unable to build type checker. Please report this as a bug.';
834             }
835              
836             # Return the smallest sub that validates the type...
837 281         421 my $handler = $handler_for{$typename};
838              
839 281 50 66     739 return $handler if !$value_desc && !@constraints;
840              
841             return sub {
842 200 100   200   63318 return 1 if $handler->($_[0]);
843              
844 152         318 my $desc = _complete_desc($value_desc, $_[0]);
845 152 50       1551 croak qq{\u$desc}
846             . ($desc =~ /\s$/ ? q{} : q{ })
847             . qq{is not of type $typename};
848 167 100       869 } if !@constraints;
849              
850             return sub {
851             # Either the type matches or we die...
852 10 100   10   30903 if (!$handler_for{$typename}($_[0])) {
853 2         7 my $desc = _complete_desc($value_desc, $_[0]);
854 2 50       34 croak qq{\u$desc}
855             . ($desc =~ /\s$/ ? q{} : q{ })
856             . qq{is not of type $typename};
857             }
858 8 50       25 return 1 if !@constraints;
859              
860             # Either every constraint matches or we die...
861 8         17 for my $test (@constraints) {
862 8         81 local $@;
863              
864             # If it fails to match...
865 8 50       44 if (! eval{ local $SIG{__WARN__} = sub{}; $test->(local $_ = $_[0]) }) {
  8         50  
  8         24  
866 0         0 my $desc = _complete_desc($value_desc, $_[0]);
867 0         0 my $constraint_desc = _describe_constraint($_[0], $desc, $test, $@);
868 0 0       0 croak qq{\u$desc}
869             . ($desc =~ /\s$/ ? q{} : q{ })
870             . qq{did not satisfy the constraint: $constraint_desc\n }
871             }
872             }
873              
874 8         82 return 1;
875             }
876 1         9 }
877              
878             package Dios::Types::TypedArray {
879             our @CARP_NOT = ('Dios::Types');
880 8     8   34 sub TIEARRAY { bless [$_[1]], $_[0] }
881 64     64   15838 sub FETCHSIZE { @{$_[0]} - 1 }
  64         118  
882 0     0   0 sub STORESIZE { $#{$_[0]} = $_[1] + 1 }
  0         0  
883 38     38   1449 sub STORE { my ($type, $desc, @constraint) = @{$_[0][0]};
  38         80  
884 38         92 Dios::Types::_up_validate(1, $type, $_[2], $desc, @constraint);
885 34         125 $_[0]->[$_[1]+1] = $_[2];
886             }
887 53     53   513 sub FETCH { $_[0]->[$_[1]+1] }
888 12     12   3562 sub CLEAR { @{$_[0]} = $_[0][0] }
  12         67  
889 0 0   0   0 sub POP { @{$_[0]} > 1 ? pop(@{$_[0]}) : undef }
  0         0  
  0         0  
890 0     0   0 sub PUSH { my $o = shift; push(@{$o}, @_) }
  0         0  
  0         0  
891 0     0   0 sub SHIFT { splice(@{$_[0]},1,1) }
  0         0  
892 0     0   0 sub UNSHIFT { my $o = shift; splice(@$o,1,0,@_) }
  0         0  
893 0     0   0 sub EXISTS { exists $_[0]->[$_[1]+1] }
894 0     0   0 sub DELETE { delete $_[0]->[$_[1]+1] }
895       12     sub EXTEND { }
896              
897             sub SPLICE
898             {
899 0     0   0 my $ob = shift;
900 0         0 my $sz = @{$ob} - 1;
  0         0  
901 0 0       0 my $off = @_ ? shift : 0;
902 0 0       0 $off += $sz if $off < 0;
903 0 0       0 my $len = @_ ? shift : $sz-$off;
904 0         0 return splice(@$ob,$off+1,$len,@_);
905             }
906             }
907              
908             package Dios::Types::TypedHash {
909             our @CARP_NOT = ('Dios::Types');
910 8     8   44 sub TIEHASH { bless [$_[1], {}], $_[0] }
911 24     24   508 sub STORE { my ($type, $desc, @constraint) = @{$_[0][0]};
  24         68  
912 24         72 Dios::Types::_up_validate(1, $type, $_[2], $desc, @constraint);
913 22         92 $_[0][1]{$_[1]} = $_[2]
914             }
915 35     35   428 sub FETCH { $_[0][1]{$_[1]} }
916 16     16   6318 sub FIRSTKEY { my $a = scalar keys %{$_[0][1]}; each %{$_[0][1]} }
  16         47  
  16         27  
  16         66  
917 32     32   41 sub NEXTKEY { each %{$_[0][1]} }
  32         84  
918 34     34   343 sub EXISTS { exists $_[0][1]{$_[1]} }
919 0     0   0 sub DELETE { delete $_[0][1]{$_[1]} }
920 12     12   6173 sub CLEAR { %{$_[0][1]} = () }
  12         76  
921 0     0   0 sub SCALAR { scalar %{$_[0][1]} }
  0         0  
922             }
923              
924             sub _set_var_type {
925 51     51   37503 my ($type, $varref, $value_desc, @constraint) = @_;
926 51         91 my $vartype = ref $varref;
927              
928 51 100 100     300 if ($vartype ne 'ARRAY' && $vartype ne 'HASH') {
    100          
    50          
929             croak 'Typed attributes require the Variable::Magic module, which could not be loaded'
930 21 50       42 if !eval{ require Variable::Magic };
  21         159  
931              
932 21         199 Variable::Magic::cast( ${$varref}, Variable::Magic::wizard( set => sub {
933             # Code around awkward Object::Insideout behaviour...
934 42 100 100 42   32283 return if ((caller 3)[3]//"") eq 'Object::InsideOut::DESTROY';
935              
936             # Code around more awkward Object::Insideout behaviour...
937 60     60   115745 no warnings 'redefine';
  60         199  
  60         106285  
938 23         404 local *croak = *confess{CODE};
939 23 100       40 return if eval { _up_validate(+2, $type, ${$_[0]}, $value_desc, @constraint) };
  23         38  
  23         85  
940 4         2105 die $@ =~ s{\s+at .*}{}r
941             =~ s{[\h\S]*Dios.*}{}gr
942             =~ s{.*\(eval .*}{}gr
943             =~ s{\s*[\h\S]*called at}{ at}r
944             =~ s{.*called at.*}{}gr;
945 21         43 }));
946             }
947             elsif ($vartype eq 'ARRAY') {
948 15 100       26 return if tied @{$varref};
  15         88  
949 8         19 tie @{$varref}, 'Dios::Types::TypedArray', [$type, $value_desc, @constraint];
  8         80  
950             }
951             elsif ($vartype eq 'HASH') {
952 15 100       27 return if tied %{$varref};
  15         61  
953 8         17 tie %{$varref}, 'Dios::Types::TypedHash', [$type, $value_desc, @constraint];
  8         68  
954             }
955             else {
956 0         0 die 'Internal error: argument to _set_var_type() must be scalar, array ref, or hash ref';
957             }
958             }
959              
960             # Implement return-type checking...
961             sub _validate_return_type {
962              
963             # Type info is first arg (an arrayref), subroutine body is final arg (a sub ref)...
964 33     33   18221 my ($name, $type, $where) = @{shift()};
  33         68  
965 33   50 26   141 $where //= sub{1};
  26         97  
966 33         41 my $function = pop;
967              
968             # List return context...
969 33 100       63 if (wantarray) {
    100          
970             # Tidy up type...
971 1         6 $type =~ s{\A Void \| | \| Void \Z}{}xmsg;
972 1         4 my $void_warning = vec((caller 1)[9], $warnings::Offsets{'void'}, 1);
973 1 50 33     22 warn sprintf "Call to $name() not in void context at %s line %d\n", (caller 1)[1,2]
974             if $void_warning && $type eq 'Void';
975              
976             # Execute the subroutine body in (apparently) the right context...
977 1         3 my @retvals = uplevel 2, $function, @_;
978              
979             # Adapt the constraint to produce a more appropriate error message...
980             my $listwhere = sub {
981 1     1   2 for (@{shift()}) {
  1         3  
982 3 50       4 die _describe_constraint($_,undef,$where) if !$where->($_)
983             }
984 1         6 return 1;
985 1         344 };
986              
987             # Validate the return values...
988             eval {
989 1 50       4 if (@retvals == 1) {
990 0         0 _up_validate(+1,
991             $type, $retvals[0], $where,
992             "Return value (" . (_perl(@retvals)=~s/^\(|\)$//gr) . ") of call to $name()\n"
993             );
994             }
995             else {
996 1         5 undef;
997             }
998             }
999             //
1000 1   33     2 eval {
      50        
1001 1         4 _up_validate(+1,
1002             $type, \@retvals, $listwhere,
1003             "List of return values (" . (_perl(@retvals)=~s/^\(|\)$//gr) . ") of call to $name()\n"
1004             )
1005             }
1006              
1007             # ..or convert the error message to report from the correct line number...
1008 0         0 // die $@ =~ s{\s*+at \S+ line \d++.*+}{sprintf "\nat %s line %d\n", (caller 1)[1,2]}ser;
1009              
1010             # If the return values are valid, return them...
1011 1         8 return @retvals;
1012             }
1013              
1014             # Scalar context...
1015             elsif (defined wantarray) {
1016             # Tidy up type...
1017 30         59 $type =~ s{\A Void \| | \| Void \Z}{}xmsg;
1018 30         73 my $void_warning = vec((caller 1)[9], $warnings::Offsets{'void'}, 1);
1019 30 50 33     631 warn sprintf "Call to $name() not in void context at %s line %d\n", (caller 1)[1,2]
1020             if $void_warning && $type eq 'Void';
1021              
1022             # Execute the subroutine body in (apparently) the right context...
1023 30         70 my $retval = uplevel 2, $function, @_;
1024              
1025             # Validate the return value...
1026 30   100     758 eval {
1027 30         51 _up_validate(+1,
1028             $type, $retval, $where,
1029             "Scalar return value (" . _perl($retval) . ") of call to $name()\n"
1030             )
1031             }
1032             # ...or convert the error message to report from the correct line number...
1033 7         1515 // die $@ =~ s{\s*at \S+ line \d+.*}{sprintf "\nat %s line %d\n", (caller 1)[1,2]}er;
1034              
1035             # If the return value is valid, return it...
1036 23         70 return $retval;
1037             }
1038              
1039             # Void context...
1040             else {
1041             # Execute the subroutine body in (apparently) the right context...
1042 2         7 uplevel 2, $function, @_;
1043              
1044             # Warn about explicit return types in void context, unless return type implies void is okay...
1045 2         347 my $void_warning = vec((caller 1)[9], $warnings::Offsets{'void'}, 1);
1046             warn sprintf
1047             "Useless call to $name() with explicit return type $type\nin void context at %s line %d\n",
1048             (caller 1)[1,2]
1049 2 50 33     42 if $void_warning && !eval{ _up_validate(+1, $type, undef) };
  2         5  
1050              
1051             }
1052             }
1053              
1054              
1055              
1056              
1057             # Compare two types...
1058             sub _is_narrower {
1059 136     136   237 my ($type_a, $type_b, $unnormalized) = @_;
1060              
1061             # Short-circuit on identity...
1062 136 100       242 return 0 if $type_a eq $type_b;
1063              
1064             # Otherwise, normalize and decompose...
1065 110 100 100     3729 if (!$unnormalized && $type_a =~ m{\A (?: Ref ) \Z }xms) {
    50 66        
    100 100        
    50          
1066 24         37 $type_a = "Ref[Any]";
1067             }
1068             elsif (!$unnormalized && $type_a =~ m{\A (?: Array | List ) \Z }xms) {
1069 0         0 $type_a = "Ref[Array[Any]]";
1070             }
1071             elsif (!$unnormalized && $type_a eq 'Hash') {
1072 4         9 $type_a = "Ref[Hash[Any]]";
1073             }
1074             elsif ($type_a =~ m{\A \s*+ ((?&NON_ATOM_TYPENAME)) \s*+ \Z $FROM_TYPENAME_GRAMMAR }xms) {
1075 0         0 $type_a = "Is[$1]";
1076             }
1077 110         2065 $type_a =~ m{\A \s*+ $TYPENAME_GRAMMAR \s*+ \Z }xms; my %type_a_is = %+;
  110         1377  
1078              
1079 110 50 66     3777 if (!$unnormalized && $type_b =~ m{\A (?: Ref ) \Z }xms) {
    50 66        
    100 100        
    50          
1080 0         0 $type_b = "Ref[Any]";
1081             }
1082             elsif (!$unnormalized && $type_b =~ m{\A (?: Array | List ) \Z }xms) {
1083 0         0 $type_b = "Ref[Array[Any]]";
1084             }
1085             elsif (!$unnormalized && $type_b eq 'Hash') {
1086 20         35 $type_b = "Ref[Hash[Any]]";
1087             }
1088             elsif ($type_b =~ m{\A \s*+ ((?&NON_ATOM_TYPENAME)) \s*+ \Z $FROM_TYPENAME_GRAMMAR }xms) {
1089 0         0 $type_b = "Is[$1]";
1090             }
1091 110         2064 $type_b =~ m{\A \s*+ $TYPENAME_GRAMMAR \s*+ \Z }xms; my %type_b_is = %+;
  110         996  
1092              
1093             # If both are basic types, use the standard comparisons...
1094 110 100 100     433 if (exists $type_a_is{basic} && exists $type_b_is{basic}) {
1095 62 100       276 return +1 if $BASIC_NARROWER{$type_b}->{$type_a};
1096 30 50       161 return -1 if $BASIC_NARROWER{$type_a}->{$type_b};
1097             }
1098              
1099             # If both are array or hash or reference types, use the standard comparisons on their element-types...
1100 48         83 for my $elem_type (qw< array hash ref >) {
1101 144 100 100     299 if (exists $type_a_is{$elem_type} && exists $type_b_is{$elem_type}) {
1102 16         51 return _is_narrower($type_a_is{$elem_type}, $type_b_is{$elem_type}, 'unnormalized');
1103             }
1104             }
1105              
1106             # If either type is parameterized, try the generic unparameterized version...
1107 32 50 66     213 if ($type_a =~ s{\A(?:List|Array|Hash|Ref|Match|Eq)\K\[.*}{}xms
1108             || $type_b =~ s{\A(?:List|Array|Hash|Ref|Match|Eq)\K\[.*}{}xms) {
1109 32 0 33     111 return -1 if $type_a =~ m{\A(?:Match|Eq)\Z} && $BASIC_NARROWER{Class}->{$type_b};
1110 32 0 33     86 return +1 if $type_b =~ m{\A(?:Match|Eq)\Z} && $BASIC_NARROWER{Class}->{$type_a};
1111 32         78 return _is_narrower($type_a, $type_b, 'unnormalized');
1112             }
1113              
1114             # If both are user-defined types, try the standard inheritance hierarchy rules...
1115 0 0 0     0 if (exists $type_a_is{user} && exists $type_b_is{user}) {
1116 0 0       0 return +1 if $type_b->isa($type_a);
1117 0 0       0 return -1 if $type_a->isa($type_b);
1118             }
1119              
1120             # Otherwise, unable to compare...
1121 0         0 return 0;
1122             }
1123              
1124             # Compare two type signatures (of equal length)...
1125             sub _cmp_signatures {
1126 46     46   89 my ($sig_a, $sig_b) = @_;
1127              
1128             # Extract named parameters of B...
1129 46         52 state %named_B_for;
1130             my $named_B =
1131 46 100 100     150 $named_B_for{$sig_b} //= { map { $_->{named} ? ($_->{named} => $_) : () } @{$sig_b} };
  34         137  
  18         42  
1132              
1133             # Track relative ordering parameter-by-parameter...
1134 46         64 my $partial_ordering = 0;
1135 46         212 for my $n (0 .. max($#$sig_a, $#$sig_b)) {
1136             # Unpack the next parameter types...
1137 88   50     195 my $sig_a_n = $sig_a->[$n] // {};
1138 88         182 my $sig_a_name = $sig_a_n->{named};
1139 88 100 50     199 my $sig_b_n = ($sig_a_name ? $named_B->{$sig_a_name} : $sig_b->[$n]) // {};
1140 88   50     305 my ($type_a, $type_b) = ($sig_a_n->{type} // 'Any', $sig_b_n->{type} // 'Any');
      50        
1141              
1142             # Find the ordering of the next parameter pair from the two signatures...
1143 88         162 my $is_narrower = _is_narrower($type_a, $type_b);
1144              
1145             # Tie-break in favour of the type with more constraints...
1146 88 100 66     229 if (!$is_narrower && $type_a eq $type_b) {
1147 26   50     80 my $where_a = $sig_a_n->{where} // 0;
1148 26   50     60 my $where_b = $sig_b_n->{where} // 0;
1149 26 50       67 $is_narrower = $where_a > $where_b ? -1
    50          
1150             : $where_a < $where_b ? +1
1151             : 0;
1152             }
1153              
1154             # If this pair's ordering contradicts the ordering so far, there is no ordering...
1155 88 100 100     273 return 0 if $is_narrower && $is_narrower == -$partial_ordering;
1156              
1157             # Otherwise if there's an ordering, it becomes the "ordering so far"...
1158 72   100     223 $partial_ordering ||= $is_narrower;
1159             }
1160              
1161             # If we make it through the entire list, return the resulting ordering...
1162 30         78 return $partial_ordering;
1163             }
1164              
1165             # Resolve ambiguous argument lists using Perl6-ish multiple dispatch rules...
1166 60     60   549 use List::Util qw< max first >;
  60         130  
  60         52717  
1167             sub _resolve_signatures {
1168 27     27   37 state %narrowness_for;
1169 27         71 my ($kind, @sigs) = @_;
1170              
1171             # Track narrownesses...
1172 27         75 my %narrower = map { $_ => [] } 0..$#sigs;
  78         188  
1173              
1174             # Compare all signatures, recording definitive differences in narrowness...
1175 27         90 for my $index_1 (0 .. $#sigs) {
1176 78         184 for my $index_2 ($index_1+1 .. $#sigs) {
1177 91         157 my $sig1 = $sigs[$index_1]{sig};
1178 91         138 my $sig2 = $sigs[$index_2]{sig};
1179             my $narrowness =
1180 91   100     390 $narrowness_for{$sig1,$sig2} //= _cmp_signatures($sig1, $sig2);
1181              
1182 91 100       217 if ($narrowness < 0) { push @{$narrower{$index_1}}, $index_2; }
  35 100       51  
  35         110  
1183 24         32 elsif ($narrowness > 0) { push @{$narrower{$index_2}}, $index_1; }
  24         70  
1184             }
1185             }
1186              
1187             # Find the narrowest signature(s)...
1188 27         77 my $max_narrower = max map { scalar @{$_} } values %narrower;
  78         142  
  78         185  
1189              
1190             # If they're not sufficiently narrow, weed out the non-contenders...
1191 27 100       84 if ($max_narrower < @sigs-1) {
1192 6         21 @sigs = @sigs[ sort grep { @{$narrower{$_}} } keys %narrower ];
  22         23  
  22         62  
1193             }
1194             # Otherwise, locate the narrowest...
1195             else {
1196 21     41   183 @sigs = @sigs[ first { @{$narrower{$_}} >= $max_narrower } keys %narrower ];
  41         52  
  41         114  
1197             }
1198              
1199             # Tie-break methods on the class of the variants...
1200 27 100 100     166 if ($kind eq 'method' && @sigs > 1) {
1201 4         22 @sigs = sort { $a->{class} eq $b->{class} ? 0
1202             : $a->{class}->isa($b->{class}) ? -1
1203 4 50       41 : $b->{class}->isa($a->{class}) ? +1
    50          
    100          
1204             : 0
1205             } @sigs;
1206 4         73 @sigs = grep { $_->{class} eq $sigs[0]{class} } @sigs;
  8         23  
1207             }
1208              
1209 27         119 return @sigs;
1210             }
1211              
1212              
1213             sub _describe_constraint {
1214 40     40   107 my ($value, $value_desc, $constraint, $constraint_desc) = @_;
1215              
1216             # Did the exception provide a constraint description???
1217 40 50       102 if ($constraint_desc) {
1218 0         0 $constraint_desc =~ s{\b at .* line .*+ \s*+}{}gx;
1219             }
1220              
1221             # Describe the value that failed...
1222 40         136 $value_desc = _complete_desc($value_desc, $value);
1223              
1224             # Try to describe the constraint by name, if it was a named sub...
1225 40 50 50     180 if (!length($constraint_desc//q{}) && eval{ require B }) {
  40   33     338  
1226 40         348 my $sub_name = B::svref_2object($constraint)->GV->NAME;
1227 40 50 33     232 if ($sub_name && $sub_name ne '__ANON__') {
1228 0         0 $sub_name =~ s/[:_]++/ /g;
1229 0         0 $constraint_desc = $sub_name;
1230             }
1231             }
1232              
1233             # Deparse the constraint sub (if necessary and possible)...
1234 40 50 50     137 if (!length($constraint_desc//q{}) && eval{ require B::Deparse }) {
  40   33     199  
1235 40         353 state $deparser = B::Deparse->new;
1236 40         126 my ($hint_bits, $warning_bits) = (caller 0)[8,9];
1237 40         1228 $deparser->ambient_pragmas(
1238             hint_bits => $hint_bits, warning_bits => $warning_bits, # '$[' => 0 + $[
1239             );
1240 40         37761 $constraint_desc = $deparser->coderef2text($constraint);
1241 40         1263 $constraint_desc =~ s{\s*+ BEGIN \s*+ \{ (?&CODE) \}
1242             (?(DEFINE) (? [^{}]*+ (\{ (?&CODE) \} [^{}]*+ )*+ ))}{}gxms;
1243 40         444 $constraint_desc =~ s{(?: (?:use|no) \s*+ (?: feature | warnings | strict ) | die \s*+ sprintf ) [^;]* ;}{}gxms;
1244 40         175 $constraint_desc =~ s{package \s*+ \S+ \s*+ ;}{}gxms;
1245 40         196 $constraint_desc =~ s{\s++}{ }g;
1246             }
1247 40   33     173 return $constraint_desc // "$constraint";
1248             }
1249              
1250             sub _perl {
1251 60     60   32208 use Data::Dump 'dump';
  60         268762  
  60         14787  
1252             dump( map {
1253 1471 50   1471   247438 if (my $tiedclass = tied $_) { $tiedclass =~ s/=.*//; "<$tiedclass tie>" }
  1473 100       3777  
  0         0  
  0         0  
1254 2         9 elsif (my $classname = blessed $_) { "<$classname object>" }
1255 1471         4111 else { $_ }
1256             } @_ )
1257             =~ s{" (< \S++ \s (?:object|tie) >) "}{$1}xgmsr;
1258              
1259             }
1260              
1261              
1262              
1263             1; # Magic true value required at end of module
1264             __END__