File Coverage

blib/lib/Dios.pm
Criterion Covered Total %
statement 635 869 73.0
branch 254 362 70.1
condition 100 156 64.1
subroutine 57 58 98.2
pod n/a
total 1046 1445 72.3


line stmt bran cond sub pod time code
1             package Dios;
2             our $VERSION = '0.002012';
3              
4 56     56   2507695 use 5.014; use warnings;
  56     56   547  
  56         277  
  56         81  
  56         1577  
5 56     56   32359 use Dios::Types;
  56         365  
  56         399  
6 56     56   3082 use Keyword::Declare;
  56         94  
  56         348  
7              
8             my $PARAMETER_SYNTAX = qr{
9             (?&WS)?+
10             (?
11             (?
12             (? (?&PerlNumber) )
13             |
14             (? (?&PerlQuotelikeQ) )
15             |
16             (? (?&PerlMatch) )
17             )
18             |
19             # TYPE...
20             (? (?&TYPE_SPEC) )?+
21              
22             # NAME...
23             (?&WS)?+
24             (?
25             : (? (?&IDENT) ) \( (?&WS)?+
26             (? (? [\$\@%]) (?&IDENT) ) (?&WS)?+
27             \)
28             |
29             : (? (? [\$\@%]) (? (?&IDENT) ) )
30             |
31             \* (?)
32             (?:
33             (? (? [\@%]) (?&IDENT) )
34             |
35             : (? (?&IDENT) ) \( (?&WS)?
36             (? (? \@) (?&IDENT) ) (?&WS)?
37             \)
38             |
39             : (? (? \@) (? (?&IDENT) ) )
40             |
41             (? (? [\@%]) )
42             )
43             |
44             (? (? [\$\@%]) (?&IDENT) )
45             |
46             (? (? [\$\@%]?+) )
47             )
48              
49             # OPTIONAL OR REQUIRED...
50             (?: (? \? ) (? )
51             | (? \! )
52             )?+
53              
54             # CONSTRAINT...
55             (?&WS)?+
56             (?: where (?&WS)?+ (? (?&PerlBlock) ) )?+
57              
58             # READONLY OR ALIAS...
59             (?: (?&WS)?+ is (?&WS)?+ (? ro | alias ) )?+
60              
61             # DEFAULT VALUE...
62             (?: (?&WS)?+ (? (?> // | \|\| )?+ = )
63             (?&WS)?+ (? (?&PerlConditionalExpression) ))?+
64              
65             (?&WS)?+
66             )
67             (? , | : | (?= --> ) | \z )
68              
69             (?(DEFINE)
70             (? (?&TYPE_NAME) (?: [&|] (?&TYPE_NAME) )*+ )
71             (? (?&QUAL_IDENT) (?&TYPE_PARAM)?+ )
72             (? \[ (?: [^][]*+ | (?&TYPE_PARAM) )*+ \] )
73             (? (?&IDENT) (?: :: (?&IDENT) )*+ )
74             (? [^\W\d] \w*+ )
75             (? (\s++ | \# [^\n]*+ \n )++ )
76             $PPR::GRAMMAR
77             )
78             }xms;
79              
80             my $EMPTY_PARAM_LIST = qr{
81             \A
82             (?&OWS)
83             (?:
84             \( (?&OWS) (\*\@_)?+ (?&OWS) \)
85             )?+
86             (?&OWS)
87             \z
88              
89             (?(DEFINE)
90             (? \s*+ (?: \# .* \n \s*+ )*+ )
91             )
92             }xm;
93              
94             sub _translate_parameters {
95 230     230   2123 my $params = shift;
96 230         496 my $kind = shift;
97 230         450 my $sub_name = shift;
98 230         458 my $sub_name_tidy = $sub_name;
99 230         1058 $sub_name_tidy =~ s{\A \s*+ (?: \# .*+ \n \s*+ )*+ }{}x;
100              
101 230         522 my @param_names;
102 230 100       1056 my $sub_desc = $sub_name ? "$kind $sub_name_tidy" : "anonymous $kind";
103 230   50     1294 my $invocant_name = $^H{'Dios invocant_name'} // '$self';
104              
105             # Empty and "standard" parameter lists are easy...
106 230 100 66     3412 if (!defined $params || $params =~ $EMPTY_PARAM_LIST) {
107 52         505 my $std_slurpy = defined $1;
108 52 100       513 my $code
    100          
109             = ($kind eq 'method'
110             ? _generate_invocant("method $sub_name_tidy", {var=>$invocant_name, sigil=>'$'})
111             : q{}
112             )
113             . ($std_slurpy ? q{} : qq{Dios::_error(ucfirst(q{$sub_desc takes no arguments})) if \@_;});
114              
115 52 100       303 my $spec = ( $kind eq 'method' ? q{ {type=>'Any', where=[]}, } : q{} )
    100          
116             . ( $std_slurpy ? q{ {optional => 1, type=>'Slurpy', where=>[]} } : q{} );
117              
118 52         409 return { code => $code, spec => $spec, names=>\@param_names };
119             }
120              
121 178         865 $params =~ s{\A \s*+ \(}{}x;
122 178         850 $params =~ s{\) \s*+ \z}{}x;
123              
124 178         451 my $return_type = undef;
125 178         326 my $return_constraint = undef;
126 178 100       602 my $invocant = $kind eq 'method' ? $invocant_name : undef;
127 178         440 my $first_param = 1;
128 178         321 my @params;
129              
130 178   66     3973600 while (length($params) && $params =~ s{\A \s*+ $PARAMETER_SYNTAX }{}x) {
131 286         80208 my %param = %+;
132 286 100       4792 last if $param{raw_param} !~ /\S/;
133              
134             # Special case of literal numeric constant as parameter (e.g. multi func fib(0) { 0 } )...
135 253 100       2642 if (defined $param{is_num_constant}) {
    100          
    100          
136 3         9 $param{type} = 'Num';
137 3         14 $param{constraint} = "{ \$_ == $param{is_num_constant} }";
138             }
139              
140             # Special case of literal string constant as parameter (e.g. multi func handle_event('add') {...} )...
141             elsif (defined $param{is_str_constant}) {
142 7         22 $param{type} = 'Str';
143 7         29 $param{constraint} = "{ \$_ eq $param{is_str_constant} }";
144             }
145              
146             # Special case of literal regex match as parameter (e.g. multi func # handle_event(/a|b/) {...} )...
147             elsif (defined $param{is_regex_constant}) {
148 2         8 $param{type} = 'Str';
149 2         9 $param{constraint} = "{ \$_ =~ $param{is_regex_constant} }";
150             }
151              
152 253         2477071 push @params, \%param;
153              
154             }
155              
156             # Make an implicit invocant explicit...
157 178 100 100     1196 if (!@params && $kind eq 'method') {
158 1         22852 "$invocant:" =~ m{\A \s*+ $PARAMETER_SYNTAX }x;
159 1         249 push @params, {%+};
160             }
161              
162             # Extract trailing return type specification...
163 178 100       1038 if ($params =~ s{ (?&WS) --> (?&WS) (.*+) (?(DEFINE) (? \s*+ (\# [^\n]*+ \n \s*+ )*+)) }{}xms ) {
164 33         235 ($return_type, $return_constraint) = split /\bwhere\b/, $1, 2;
165             }
166              
167             # Anything else in the parameter list is a mistake...
168 178 50       667 _error( qq{Invalid parameter specification: $params\n in $kind declaration} )
169             if $params =~ /\S/;
170              
171             # Convert the parameters into checking code...
172 178         413 my $code = q{};
173 178         394 my $spec = q{};
174 178         389 my $nameless_pos = 0;
175 178         426 my (%param_named, @positional, @named, $slurpy);
176              
177 178         576 for my $param (@params) {
178 254         392 $nameless_pos++;
179              
180             # Constraints imply an Any type...
181 254 100 66     1012 if (defined $param->{constraint} && (!defined $param->{type} || $param->{type} !~ /\S/)) {
      100        
182 1         3 $param->{type} = 'Any';
183             }
184              
185             # Rectify nameless params...
186 254 100       677 if (exists $param->{nameless}) {
187 19   100     80 $param->{sigil} ||= '$';
188 19 100       107 my $nth = $nameless_pos
    100          
    100          
189             . ( $nameless_pos =~ /(?
190             : $nameless_pos =~ /(?
191             : $nameless_pos =~ /(?
192             : 'th'
193             );
194 19         85 $param->{var} = $param->{sigil} . '__nameless_'.$nth.'_parameter__';
195 19         55 $param->{namedvar} = $param->{sigil} . ' (unnamed $nth parameter)';
196             }
197              
198             # "There ken be onla one!" (...parameter of any given name)...
199             _error( qq{Can't declare two parameters named $param->{var}\n in specification of $sub_desc})
200 254 50       864 if exists $param_named{ $param->{var} };
201 254         812 $param_named{ $param->{var} }++;
202 254 100       759 push @param_names, $param->{name} if $param->{name};
203              
204             # Parameters are lexical, so can't be named @_ or $_ or %_...
205             _error(
206             qq{Can't declare a },
207             (exists $param->{name} ? 'named' : exists $param->{slurpy} ? 'slurpy' : 'positional'),
208             qq{ parameter named $param->{var}\nin specification of $sub_desc},
209 254 0 66     1061 ) if substr($param->{var},1) eq '_' && $param->{namedvar} ne '*@_';
    0          
    50          
210              
211             # Handle implicit invocant specially...
212 254 100 100     1526 if ($first_param && $kind eq 'method' && $param->{terminator} ne ':') {
      100        
213 91         950 $code .= _generate_invocant( "$sub_desc", {var=>$invocant_name, sigil=>'$'} );
214 91         310 $first_param = 0;
215             }
216              
217             # Handle explicit invocant...
218 254 100 100     1580 if ($first_param && $param->{terminator} && $param->{terminator} eq ':') {
    100 100        
219 18 50       54 _error( qq{Can't specify invocant ($param->{raw_param}:) for $sub_desc} ) if $kind ne 'method';
220 18         106 $code .= _generate_invocant( "$sub_desc", $param );
221 18   50     109 my $type = $param->{type} // 'Any';
222 18 50       66 my $constraint = $param->{constraint} ? "where => sub $param->{constraint}" : q{};
223 18         60 $spec .= qq{{type => '$type', $constraint },};
224 18         47 $first_param = 0;
225             }
226              
227             # Save a scalar (named or positional) paramater...
228             elsif (!exists $param->{slurpy}) {
229 216 100       519 if (exists $param->{name}) { push @named, $param }
  60         156  
230 156         354 else { push @positional, $param }
231             }
232              
233             # Save the final slurpy array or hash...
234             else {
235 20 50       77 _error( qq{Can't specify more than one slurpy parameter },
236             qq{($slurpy->{namedvar}, $param->{namedvar})\n},
237             qq{ in specification of $sub_desc}
238             ) if defined $slurpy;
239              
240 20 100       80 if (exists $param->{name}) {
241             _error( qq{Can't specify non-array named slurpy parameter ($param->{namedvar})\n},
242             qq{ in specification of $sub_desc}
243 2 50 33     10 ) if exists $param->{name} && $param->{sigil} ne '@';
244              
245 2         5 push @named, $param;
246             }
247             else {
248 18         45 $slurpy = $param;
249             }
250             }
251             }
252              
253 178 100       551 if (@positional) {
254 104         548 $code .= _generate_positionals( "$sub_desc", @positional );
255 104         298 for my $param (@positional) {
256 156   100     532 my $type = $param->{type} // 'Any';
257              
258 156 100       598 if ($param->{sigil} eq '@') { $type = "Array[$type]"; }
  6 100       19  
259 2         5 elsif ($param->{sigil} eq '%') { $type = "Hash[$type]"; }
260              
261 156 100       414 my $constraint = $param->{constraint} ? "where => sub $param->{constraint}" : q{};
262              
263 156 100       372 my $is_optional = exists $param->{default_type} ? 1 : 0;
264              
265 156         630 $spec .= qq{{optional => $is_optional, type => '$type', $constraint},};
266             }
267             }
268 178 100       552 if (@named) {
269 42         224 $code .= _generate_nameds( "$sub_desc", @named );
270 42         110 for my $param (@named) {
271 62   100     214 my $type = $param->{type} // 'Any';
272              
273 62 100       240 if ($param->{sigil} eq '@') { $type = "Array[$type]"; }
  5 100       13  
274 1         3 elsif ($param->{sigil} eq '%') { $type = "Hash[$type]"; }
275              
276 62 100       151 my $constraint = $param->{constraint} ? "where => sub $param->{constraint}" : q{};
277              
278 62 100       146 my $is_optional = exists $param->{default_type} ? 1 : 0;
279              
280 62         293 $spec .= qq{{named => '$param->{name}', optional => $is_optional, type => '$type', $constraint},};
281             }
282             }
283              
284 178 100       511 if (defined $slurpy) {
285 18 100       98 if ($slurpy->{var} ne '@_') {
286 17 50       128 my $constraint = $slurpy->{constraint} ? "where => sub $slurpy->{constraint}" : q{};
287 17         92 $code .= _generate_slurpies( "$sub_desc", $slurpy );
288 17         61 $spec .= qq{ {optional => 1, type=>'Slurpy', $constraint} };
289             }
290             }
291             else {
292 160         819 $code .= qq[Dios::_error q{Unexpected extra argument}.(\@_==1?q{}:q{s}).' ('.join(', ', map { Dios::_perl \$_ } \@_).q{) in call to $sub_desc} if \@_;];
293             }
294              
295 178 100       554 $return_type = defined $return_type ? qq{q{$return_type}} : "";
296 178 50       463 if (defined $return_constraint) {
297 0         0 $return_type .= qq{, sub $return_constraint };
298             }
299 178         2382 return { code => $code, return_type => $return_type, spec => $spec, names => \@param_names };
300             }
301              
302             sub _verify_required_named {
303 42     42   126 my ($context, @params) = @_;
304 42         99 my $code = q{};
305 42         107 for my $param (@params) {
306 62 100       196 next if !$param->{required};
307 1         3 my $vardesc = quotemeta $param->{namedvar};
308 1   50     5 my $argdesc = qq{'$param->{name}' => <} . lc($param->{type}//'value'). q{>};
309 1         6 $code .= qq[Dios::_error(qq{No argument ($argdesc) found for required named parameter $vardesc\\n]
310             . qq[in call to $context}) if !\$seen{$param->{name}}; ];
311             }
312 42         98 return $code;
313             }
314              
315             sub _generate_invocant {
316 157     157   513 my ($context, $param) = @_;
317 157         282 my $code;
318 157         535 my $vardesc = qq{invocant $param->{var}};
319              
320             # Create and unpack corresponding argument...
321 157         580 $code .= qq{my $param->{var}; };
322 157         384 $code .= _unpack_code( @{$param}{'sigil','var','name','default','special'}, $vardesc, $context );
  157         1209  
323              
324             # Install a type check, if necessary...
325 157 50       586 if (exists $param->{type}) {
326 0         0 $code .= _typecheck_code(@{$param}{'sigil','var','type','constraint'}, $vardesc, $context);
  0         0  
327             }
328              
329 157         577 return $code;
330             }
331              
332             sub _generate_positionals {
333 104     104   375 my ($context, @positionals) = @_;
334 104         180 my $code;
335              
336 104         254 for my $param (@positionals) {
337             # Create and unpack corresponding argument...
338 156         328 my $var = $param->{var};
339 156 100       658 my $vardesc = $var =~ /^(.)__nameless_(\d++[^\W_]++)_parameter__$/
340             ? "unnamed $2 positional parameter"
341             : "positional parameter $var";
342 156         429 $code .= qq{my $var; };
343             $code .= _unpack_code(
344 156         317 @{$param}{'sigil','var','name','default','special'},
  156         722  
345             $vardesc,
346             $context
347             );
348 156 100 66     753 if (exists $param->{name} && exists $param->{default_type}) {
349 36 100 100     237 if ($param->{default_type} eq '//=' && $param->{sigil} eq '$') {
    100          
350 9         16 my $assign_code = _assign_value_code( @{$param}{'sigil','var','special','default'}, q{});
  9         24  
351 9         29 $code .= qq{ do {$assign_code} if !defined $var; };
352             }
353             elsif ($param->{default_type} eq '||=') {
354 10         21 my $assign_code = _assign_value_code( @{$param}{'sigil','var','special','default'}, q{});
  10         25  
355 10         30 $code .= qq{ do {$assign_code} if !$var; };
356             }
357             }
358              
359             # Install a type check, if necessary...
360 156 100       476 next if !exists $param->{type};
361 55         118 $code .= _typecheck_code(@{$param}{'sigil','var','type','constraint'}, $vardesc, $context);
  55         205  
362             }
363              
364 104         541 return $code;
365             }
366              
367             sub _generate_nameds {
368 42     42   377 my ($context, @nameds) = @_;
369 42         224 my $code;
370              
371             # Declare all named args...
372 42         149 $code .= 'my (' . join(',', map { $_->{var} } @nameds) . '); ';
  62         327  
373              
374             # Walk the arg list, unpacking them...
375 42         118 $code .= qq[{ my %seen; while (\@_) { my \$next_key = shift;];
376              
377 42         89 my $defaults = q{};
378 42         114 for my $param (@nameds) {
379 62         192 $code .= qq[ if (\$next_key eq q{$param->{name}}) {];
380             my $unpack_code =
381             exists $param->{slurpy} ? _unpack_named_slurpy_code(
382 2         13 @{$param}{qw< var sigil name special >},
383             "slurpy named parameter $param->{namedvar}", $context
384             )
385             : _unpack_code(
386 60         362 @{$param}{'sigil','var','name'}, undef, $param->{special},
387 62 100       193 "named parameter $param->{namedvar}", $context
388             );
389 62         200 $code .= qq[$unpack_code next}];
390              
391 62 100 66     394 if (exists $param->{name} && exists $param->{default}) {
392 2         7 my $assign_code = _assign_value_code( @{$param}{'sigil','var','special','default'}, q{});
  2         9  
393             $defaults .= qq{ do {$assign_code} if }
394             . ( $param->{default_type} eq '//=' ? qq{!defined $param->{var}; }
395 2 50       19 : $param->{default_type} eq '||=' ? qq{!$param->{var}; }
    100          
396             : qq{!\$seen{$param->{'name'}}; }
397             );
398             }
399             }
400              
401 42         174 my $requireds = _verify_required_named($context, @nameds);
402              
403 42         168 $code .= qq[unshift \@_, \$next_key; last} $defaults $requireds}];
404              
405 42         99 for my $param (@nameds) {
406 62 100       169 next if !exists $param->{type};
407              
408 40 100       113 my $slurpy = exists $param->{slurpy} ? q{slurpy } : q{};
409             $code .= _typecheck_code(
410 40         71 @{$param}{'sigil','var','type','constraint'}, "${slurpy}named parameter $param->{namedvar}", $context
  40         207  
411             );
412             }
413              
414 42         206 return $code;
415             }
416              
417             my $REFALIASING = q{use experimental 'refaliasing'};
418              
419             sub _generate_slurpies {
420 17     17   48 my ($context, $param) = @_;
421              
422             # No slurpy by default...
423 17 50       77 return q{} if !defined $param;
424 17         44 my $special = $param->{special};
425 17         44 my $code = q{};
426              
427 17 100       84 my $vardesc = $param->{var} =~ /^(.)__nameless_.*_parameter__$/
428             ? "nameless slurpy parameter (*$1)"
429             : "slurpy parameter *$param->{var}";
430              
431             # Check named slurpies...
432 17 100       67 if ($param->{sigil} eq '%') {
433 2         10 $code .= qq{Dios::_error('Final key ('.Dios::dump(\$_[-1]).qq{) for $vardesc is missing its value\\nin call to $context}) if \@_ % 2;}
434             }
435              
436             # Create and unpack corresponding argument...
437 17 50 33     92 $code .= !$special ? qq{ my $param->{var} = }
    50          
    50          
    100          
438             : $special eq 'ro' ? qq{ Const::Fast::const my $param->{var} => }
439             : $special eq 'alias' && $] < 5.022 ? qq{ Data::Alias::alias my $param->{var} = }
440             : $special eq 'alias' ? qq{ $REFALIASING; \\my $param->{var} =\\ }
441             : die "Internal error: unknown special trait: is $special";
442              
443 17 100       59 $code .= exists $param->{default} ? qq{ (\@_ ? \@_ : $param->{default}); }
444             : qq{ \@_; };
445              
446             # Install a type check, if necessary...
447 17 100       56 if (exists $param->{type}) {
448 1         2 $code .= _typecheck_code(@{$param}{'sigil','var','type','constraint'}, $vardesc, $context, 'slurpy');
  1         4  
449             }
450              
451             # Install existence check, if necessary...
452 17 100       51 if (exists $param->{required}) {
453 1         3 my $vardesc = quotemeta $vardesc;
454 1         3 $code .= qq[Dios::_error qq{Missing argument for required $vardesc\\nin $context} if !\@_;];
455             }
456              
457 17         48 return $code;
458             }
459              
460             sub _assign_value_code {
461 394     394   920 my ($sigil, $var, $special, $value_source, $check_type) = @_;
462 394   100     1540 $special //= q{};
463              
464 394 100       1000 if ($sigil eq '$') {
465 381 100 66     3104 return $special eq 'ro' ? qq[ Const::Fast::const($var => $value_source); ]
    50          
    100          
466             : $special eq 'alias' && $] < 5.022 ? qq[ Data::Alias::alias $var = $value_source ; ]
467             : $special eq 'alias' ? qq[ $REFALIASING; \\$var = \\($value_source); ]
468             : qq[ $var = $value_source ; ]
469             }
470              
471             # Arrays and hashes, need more type-checking...
472 13 100       39 if ($sigil eq '@') {
473 10 50 33     122 return qq[ { my \$next_value = $value_source; ]
    50          
    50          
474             . $check_type
475             . ( $special eq 'ro' ? qq[ Const::Fast::const($var => \@{\$next_value}); ]
476             : $special eq 'alias' && $] < 5.022 ? qq[ Data::Alias::alias $var = \@{\$next_value} ; ]
477             : $special eq 'alias' ? qq[ $REFALIASING; \\$var = \@{\$next_value} ; ]
478             : qq[ $var = \@{\$next_value} ; ]
479             )
480             . qq[} ];
481             }
482 3 50       19 if ($sigil eq '%') {
483 3 50 33     45 return qq[ { my \$next_value = $value_source; ]
    50          
    50          
484             . $check_type
485             . ( $special eq 'ro' ? qq[ Const::Fast::const($var => \%{\$next_value}); ]
486             : $special eq 'alias' && $] < 5.022 ? qq[ Data::Alias::alias $var = \%{\$next_value} ; ]
487             : $special eq 'alias' ? qq[ $REFALIASING; \\$var = \%{\$next_value} ; ]
488             : qq[ $var = \%{\$next_value} ; ]
489             )
490             . qq[} ];
491             }
492             }
493              
494             sub _unpack_code {
495 373     373   1171 my ($sigil, $var, $name, $default, $special, $vardesc, $context) = @_;
496 373         819 state $type_of = { '$' => q{}, '@' => 'ARRAY', '%' => 'HASH' };
497              
498             # Set up for readonly or aliasing, if specified...
499 373 100       847 if ($special) {
500 4 100 33     26 if ($special eq 'ro') {
    50          
501             _error(q{'is ro' requires the Const::Fast module (which could not be loaded)})
502 2 50       6 if !eval { require Const::Fast; 1 };
  2         551  
  2         775  
503             }
504             elsif ($special eq 'alias' && $] < 5.022) {
505             _error(q{'is alias' requires the Data::Alias module (which could not be loaded)})
506 0 0       0 if !eval { require Data::Alias; 1 };
  0         0  
  0         0  
507             }
508             }
509              
510             # Set up for default handling, if specified...
511 373         1021 my $value_source = qq{ ( !\@_ ? Dios::_error(q{No argument found for $vardesc in call to $context}) : shift) };
512 373         1885 my $type_check = qq[ Dios::_error q{Argument for $vardesc is not \L$type_of->{$sigil}\E ref in call to $context} ]
513             . qq[ if ref(\$next_value) ne '$type_of->{$sigil}';];
514              
515 373 100       867 if (defined($default)) {
516 36 50 66     141 $default ||= $sigil eq '$' ? 'undef'
    100          
517             : $sigil eq '@' ? '[]'
518             : '{}';
519 36 100       120 my $and_type_test = $sigil eq '$' ? '' : "&& ref(\$_[0]) eq '$type_of->{$sigil}'";
520 36         102 $value_source = qq{ \@_ $and_type_test ? shift() : $default };
521 36         81 $type_check = q{};
522             }
523              
524             # Named params have to be tracked, if they have defaults...
525 373 100       990 my $note_seen
526             = $name ? qq{ Dios::_error(q{Unexpected second value (}.Dios::_perl($var).q{) for named '$name' parameter in call to $context}) if \$seen{$name}; \$seen{$name} = 1; }
527             : q{};
528              
529             # Return the code...
530 373         1023 return _assign_value_code($sigil, $var, $special, $value_source, $type_check)
531             . $note_seen;
532             }
533              
534             sub _unpack_named_slurpy_code {
535 2     2   5 my ($var, $sigil, $name, $special, $vardesc, $context) = @_;
536 2   50     9 $special //= q{};
537              
538             # Must be able to use the module, if it's required
539 2 50 33     6 if ($special eq 'alias' && $] < 5.022) {
540             _error(q{'is alias' requires the Data::Alias module (which could not be loaded)})
541 0 0       0 if !eval { require Data::Alias; 1 };
  0         0  
  0         0  
542             }
543              
544             # Work out how at unpack the arg
545 2 50 33     10 my $unpack_code
    50          
546             = $special eq 'alias' && $] >= 5.022 ? qq{use experimental 'refaliasing';\\\$${name}[\@$name]=\\shift;}
547             : $special eq 'alias' ? qq{ Data::Alias::alias( \$${name}[\@$name] = shift); }
548             : qq{ push $var, shift; };
549              
550 2         9 return qq{ Dios::_error q{No argument found for $vardesc in call to $context} if !\@_; }
551             . $unpack_code;
552             }
553              
554             sub _typecheck_code {
555 96     96   290 my ($sigil, $var, $type, $constraint, $vardesc, $context, $is_slurpy) = @_;
556 96 100       247 $constraint = $constraint ? "sub $constraint" : q{};
557              
558             # Provide a human-readble description for any error message...
559 96         197 $vardesc = qq{q{Value (%s) for $vardesc}};
560              
561 96 100       218 if ($sigil eq '$') {
562 94         513 return qq[{package Dios::Types; validate(q{$type}, $var,$vardesc,$constraint)}];
563             }
564 2 50       3 if ($sigil eq '@') {
565 2 100       7 return qq[{package Dios::Types; validate(q{List[$type]}, \\$var,$vardesc,$constraint)}] if $is_slurpy;
566 1         5 return qq[{package Dios::Types; validate(q{Array[$type]},\\$var,$vardesc,$constraint)}];
567             }
568 0 0       0 if ($sigil eq '%') {
569 0         0 return qq[{package Dios::Types; validate(q{Hash[$type]}, \\$var,$vardesc,$constraint)}];
570             }
571 0         0 die 'Internal error: unable to generate type checking code';
572             }
573              
574             sub _perl {
575 56     56   184784 use Data::Dump 'dump';
  56         138  
  56         5069  
576 7     7   7733 return dump(@_);
577             }
578              
579             our @CARP_NOT = 'Keyword::Declare';
580             sub _error {
581 56     56   365 use Carp;
  56         90  
  56         4240  
582 20     20   17574 croak @_;
583             }
584              
585 56     56   340 use re 'eval';
  56         105  
  56         120531  
586             my $FIELD_DEFN = qr{
587             (?
588             (?&TYPE_SPEC)
589             )? \s*+
590             (?
591             [\$\@%]
592             )
593             (?
594             [.!]?
595             )
596             (?
597             [^\W\d] \w* # Simple identifier
598             )
599             (?
600             \s+ is \s+ req(?:uired)?
601             )?
602             (?:
603             \s+ is \s+
604             (? r[wo] )
605             )?
606             (? # repeat to allow 'is' options in either order
607             \s+ is \s+ req(?:uired)?
608             )?
609             (?
610             \s*+ : \s*+ (?&ATTR)
611             (?:
612             (?: \s*+ : \s*+ | \s++) (?&ATTR)
613             )*+
614             )?
615             (?
616             .*+
617             )
618              
619             (?(DEFINE)
620             (? (?&TYPE_NAME) (?: [&|] (?&TYPE_NAME) )*+ )
621             (? (?&QUAL_IDENT) (?&TYPE_PARAM)?+ )
622             (? \[ (?: [^][]*+ | (?&TYPE_PARAM) )*+ \] )
623             (? (?&IDENT) (?: :: (?&IDENT) )*+ )
624             (? [^\W\d] \w*+ )
625             (? [^\W\d]\w*+ (?! [(] ) )
626             )
627              
628             }xms;
629              
630             my $SHARED_DEFN = qr{
631             (?
632             (?&TYPE_SPEC)
633             )?
634             \s*+
635             (?
636             \$ | \@ | \%
637             )
638             (?
639             [.!]?
640             )
641             (?
642             [^\W\d] \w* # Simple identifier
643             )
644             (?:
645             \s+ is \s+
646             (? r[wo] )
647             )?
648             (?
649             .*
650             )
651              
652             (?(DEFINE)
653             (? (?&TYPE_NAME) (?: [&|] (?&TYPE_NAME) )*+ )
654             (? (?&QUAL_IDENT) (?&TYPE_PARAM)?+ )
655             (? \[ (?: [^][]*+ | (?&TYPE_PARAM) )*+ \] )
656             (? (?&IDENT) (?: :: (?&IDENT) )*+ )
657             (? [^\W\d] \w*+ )
658             )
659              
660             }xms;
661              
662             my $LEXICAL_DEFN = qr{
663             (?
664             (?&TYPE_SPEC)
665             )?
666             \s*+
667             (?
668             \$ | \@ | \%
669             )
670             (?
671             [^\W\d] \w* # Simple identifier
672             )
673             (?
674             .*
675             )
676              
677             (?(DEFINE)
678             (? (?&TYPE_NAME) (?: (?: [&|] | => ) (?&TYPE_NAME) )*+ )
679             (? (?&QUAL_IDENT) (?&TYPE_PARAM)?+ )
680             (? \[ (?: [^][]*+ | (?&TYPE_PARAM) )*+ \] )
681             (? (?&IDENT) (?: :: (?&IDENT) )*+ )
682             (? [^\W\d] \w*+ )
683             )
684              
685             }xms;
686              
687              
688             # These options can be passed in when importing, to change how accessors are generated...
689             my %OIO_accessor_keyword = (
690             'standard' => { rw => 'Std', ro => 'StdRO' },
691             'unified' => { rw => 'Acc', ro => 'Get' },
692             'lvalue' => { rw => 'Lvalue', ro => 'Get' },
693             );
694             @OIO_accessor_keyword{qw< std uni lval >}
695             = @OIO_accessor_keyword{qw< standard unified lvalue >};
696              
697             my %OIO_accessor_generate = (
698             'standard' => {
699             rw => sub { my ($name, $sigil) = @_;
700             my $var = $sigil.$name;
701             my $unpack = $sigil eq '$' ? 'shift' : '@_';
702             return qq{ sub get_$name { shift; $var }
703             sub set_$name { local \$Carp::CarpLevel = 1;
704             shift;
705             $var = $unpack;
706             };
707             };
708             },
709             ro => sub { my ($name, $sigil) = @_; my $var = $sigil.$name;
710             return qq{ sub get_$name { shift; $var } };
711             },
712             },
713              
714             'unified' => {
715             rw => sub { my ($name, $sigil) = @_;
716             my $var = $sigil.$name;
717             my $unpack = $sigil eq '$' ? 'shift' : '@_';
718             return qq{ sub $name { local \$Carp::CarpLevel = 1;
719             shift;
720             if (\@_) {
721             $var = $unpack;
722             }
723             $var
724             }; };
725             },
726             ro => sub { my ($name, $sigil) = @_; my $var = $sigil.$name;
727             return qq{ sub $name { shift; $var } };
728             },
729             },
730              
731             'lvalue' => {
732             rw => sub { my ($name, $sigil) = @_;
733             my $var = $sigil.$name;
734             return qq{ sub $name :lvalue {
735             local \$Carp::CarpLevel = 1;
736             $var
737             }
738             };
739             },
740             ro => sub { my ($name, $sigil) = @_; my $var = $sigil.$name;
741             return qq{ sub $name { $var } };
742             },
743             },
744             );
745             @OIO_accessor_generate{qw< std uni lval >}
746             = @OIO_accessor_generate{qw< standard unified lvalue >};
747              
748             # Convert a 'has' to an OIO variable declaration with attributes...
749             sub _compose_field {
750 34     34   111 my ($type, $var, $traits, $handles, $initializer, $constraint) = @_;
751              
752             # Normalize constraint...
753 34 100       170 $constraint = $constraint ? 'sub ' . substr($constraint, 5) : q{};
754 34 50 66     410 if ($constraint && !defined $type) {
755 0         0 $type = 'Any';
756             }
757              
758             # Read-only or readwrite???
759 34 100       87 my $rw = $traits =~ /\brw\b/ ? 'rw' : 'ro';
760 34         287 my $required = $traits =~ /\breq(?:uired)?\b/;
761              
762             # Did the user specify a particular kind of accessor generation???
763 34         281 my $accessor_type = $^H{'Dios accessor_type'};
764              
765             # Unpack the parsed components of the field declaration...
766 34         81 my ($sigil, $twigil, $name) = $var =~ m{\A ([\$\@%]) ([.!]?+) (\S*+) }xms;
767              
768             # Adapt type to sigil...
769 34 100 50     394 my $container_type = ($sigil eq '@') ? "Array[".($type//'Any')."]"
    100 50        
770             : ($sigil eq '%') ? "Hash[".($type//'Any')."]"
771             : $type;
772              
773             # Is it type-checked???
774 34         80 my $TYPE_SETUP = q{};
775 34         66 my $TYPE_VALIDATOR = q{};
776 34 100       101 if ($type) {
777 28         60 state $validator_num = 0; $validator_num++;
  28         60  
778 28         146 $TYPE_VALIDATOR = qq[ { no warnings; \$Dios::_internal::attr_validator_$validator_num = Dios::Types::validator_for(q{$container_type}, 'Value (%s) for $sigil$name attribute', $constraint ); } ];
779 28         81 $TYPE_SETUP = qq[ :Type( sub{ \$Dios::_internal::attr_validator_$validator_num->(shift) }) ];
780             }
781              
782             # Define accessors...
783 34 100       259 my $access = $twigil ne '.' ? q{} : $OIO_accessor_keyword{$accessor_type}{$rw}."(Name=>q{$name}) $TYPE_SETUP";
784              
785             # Is it a delegated handler???
786 34         71 my $delegators = '';
787 34         101 for my $delegation (split /(?&WS) handles (?&WS) (?(DEFINE) (? \s*+ (?: \# [^\n]*+ \n \s*+ )*+ ))/x, $handles) {
788 0 0       0 next unless $delegation;
789 0 0       0 if ($delegation =~ m{^:(.*)<(.*)>$}xms) {
790 0         0 $delegators .= " :Handles($1-->$2)";
791             }
792             else {
793 0         0 $delegators .= " :Handles($delegation)";
794             }
795             }
796              
797             # Is it initialized???
798 34 100       302 my $init = qq{:Arg(Name=>q{$name} } . ($required ? q{, Mandatory=>1)} : q{)} );
799 34         65 my $INIT_FUNC = q{};
800              
801             # Ensure array and hash attrs are initialized...
802 34 50 33     186 if ($sigil =~ /[\@%]/ && (!$initializer || $initializer =~ m{\A \s*+ \z}xms)) {
      66        
803 15         100 $initializer = '//=()';
804             }
805              
806             # Install the initialization code...
807 34 100       141 if ($initializer =~ m{\A \s*+ (? // \s*+ )? = (? .*+ ) }xms) {
808 20         240 my %init_field = %+;
809 20         72 my $init_val = $init_field{INIT_VAL};
810              
811             # Adapt initializer value to sigil...
812 20 100       92 if ($sigil eq '@') { $init_val = "[$init_val]"; }
  7 100       23  
813 8         26 elsif ($sigil eq '%') { $init_val = "+{$init_val}"; }
814              
815 20 100       90 $init = qq{:DEFAULT(___i_n_i_t__${name}___(\$self)) } . ($init_field{DEFAULT_INIT} ? $init : q{});
816 20         79 $INIT_FUNC = qq{sub ___i_n_i_t__${name}___ { my (\$self) = \@_; $init_val }};
817             }
818             else {
819 14         78 $init .= $initializer;
820             }
821              
822             # Update the attribute setting code...
823 34         232 $^H{'Dios attrnames'} .= "$name,";
824 34 100       109 if ($sigil eq '$') {
825 19 50       204 $^H{'Dios attrs'} .= $] < 5.022 ? qq{alias my \$$name = \$_Dios__attr_${name}[\${\$_[0]}];}
826             : qq{ \\ my \$$name = \\ \$_Dios__attr_${name}[\${\$_[0]}];};
827             }
828             else {
829 15 50       124 $^H{'Dios attrs'}
830             .= $] < 5.022 ? qq{alias my $sigil$name = $sigil}.qq{{\$_Dios__attr_${name}[\${\$_[0]}]};}
831             : qq{ \\ my $sigil$name = \$_Dios__attr_${name}[\${\$_[0]}]; };
832             }
833             # Add type-checking code to alias...
834 34 100       105 if ($type) {
835 28         156 $^H{'Dios attrs'} .= qq{ Dios::Types::_set_var_type(q{$type}, \\$sigil$name, 'Value (%s) for $sigil$name attribute', $constraint ); };
836             }
837              
838             # Return the converted syntax...
839 34         426 return qq{ $TYPE_VALIDATOR my \@_Dios__attr_$name : Field $access $delegators $init $TYPE_SETUP; $INIT_FUNC; };
840             }
841              
842             # Convert a typed lexical variable...
843             sub _compose_lexical {
844 3     3   10 my ($type, $variable, $constraint) = @_;
845              
846             # Normalize constraint...
847 3 100       42 $constraint = $constraint ? 'sub ' . substr($constraint, 5) : q{};
848 3 50 66     57 if ($constraint && !defined $type) {
849 0         0 $type = 'Any';
850             }
851              
852             # Is it type-checked???
853 3         6 my $TYPE_SETUP = q{};
854 3 50       10 if (defined $type) {
855 3         14 $TYPE_SETUP = qq[ Dios::Types::_set_var_type(q{$type}, \\$variable, 'Value (%s) assigned to $variable', $constraint ); ];
856             }
857              
858             # Return the converted syntax...
859 3         26 return qq{my $variable; $TYPE_SETUP; $variable = $variable};
860             }
861              
862              
863             # Convert a 'shared' to a class attribute...
864             sub _compose_shared {
865 5     5   15 my ($type, $var, $traits, $initializer, $constraint) = @_;
866              
867             # Normalize constraint...
868 5 100       25 $constraint = $constraint ? 'sub ' . substr($constraint, 5) : q{};
869 5 50 66     62 if ($constraint && !defined $type) {
870 0         0 $type = 'Any';
871             }
872              
873             # Did the user specify a particular kind of accessor generation???
874 5         17 my $accessor_type = $^H{'Dios accessor_type'};
875              
876             # Unpack the parsed components of the shared declaration...
877 5         14 my ($sigil, $twigil, $name) = $var =~ m{\A ([\$\@%]) ([.!]?+) (\S*+) }xms;
878 5 100       37 my $rw = $traits =~ /\brw\b/ ? 'rw' : 'ro';
879              
880             # Generate accessor subs...
881             my $accessors = $twigil ne '.' ? q{}
882 5 50       59 : $OIO_accessor_generate{$accessor_type}{$rw}->($name, $sigil);
883              
884             # Build type checking sub...
885 5         12 my $type_func = q{};
886 5 100       10 if ($type) {
887 1         6 $type_func = qq[ sub ___t_y_p_e__${name}___ { state \$check = Dios::Types::validator_for(q{$type}, 'Value (%s) for \$$name attribute' ); \$check->($_[0]) } ___t_y_p_e__${name}___($sigil$name); ];
888             }
889             else {
890 4         22 $type_func = q{};
891             }
892             # Is it type-checked???
893 5         10 my $TYPE_SETUP = q{};
894 5 100       9 if ($type) {
895 1         5 $TYPE_SETUP = qq[ Dios::Types::_set_var_type(q{$type}, \\$sigil$name, 'Value (%s) for shared $sigil$name attribute', '$sigil', $constraint ); ];
896             }
897              
898             # Return the converted syntax...
899 5         31 return qq{my $sigil$name $initializer; $TYPE_SETUP; $accessors};
900             }
901              
902              
903              
904             sub _multi_dispatch {
905 56     56   483 use Data::Dump 'dump';
  56         103  
  56         33190  
906              
907 58     58   75998 my $subname = shift;
908 58         109 my $kind = shift;
909 58         158 my @arg_list = @_;
910              
911             # Find all possible variants for this call...
912 58         102 our %multis;
913 58   50     114 my @variants = @{ $Dios::multis{$subname} //= [] };
  58         331  
914              
915             # But only those in the right hierarchy, if it's a method call
916 58 100       182 if ($kind eq 'method') {
917 28         57 @variants = grep { $arg_list[0]->isa($_->{class}) } @variants;
  196         1850  
918             }
919              
920             # And only those in the right namespace, if it's a function call...
921             else {
922 30         100 my $caller = caller;
923 30         581 @variants = grep { $_->{class} eq $caller } @variants;
  122         301  
924             }
925              
926             # Eliminate variants that doen't match the argument list...
927 58         348 for my $variant (@variants) {
928 290         374 my $match = eval{ $variant->{validator}(@arg_list) };
  290         1042  
929 290 100       53857 if (defined $match) {
930 103         128 @{$variant}{ keys %{$match} } = values %{$match};
  103         486  
  103         191  
  103         262  
931             }
932             else {
933 187         387 $variant = undef;
934             }
935             }
936 58         126 @variants = grep { defined } @variants;
  290         442  
937              
938             # If there's only one left, we're done...
939 58 100       227 return $variants[0] if @variants == 1;
940              
941             # If there isn't one left, we're also done (but not in a good way)...
942             return {
943 6     6   74 impl => sub { my $args = dump(@arg_list);
944 6 50       1407 croak "No suitable '$subname' variant found for call to multi $subname",
945             (($args =~ m{\A \( .* \) \Z}xms) ? $args : qq{($args)});
946             },
947 33 100       163 } if @variants == 0;
948              
949             # There were 2+ left, so pick the one with the most specific signature...
950 27         98 @variants = Dios::Types::_resolve_signatures($kind, @variants);
951              
952             # If there isn't one left, we're also done (but in an even worse way than before)...
953             return {
954 0     0   0 impl => sub { my $args = dump(@arg_list);
955 0 0       0 croak "Dios: Internal error in dispatch resolution of multi $subname",
956             (($args =~ m{\A \( .* \) \Z}xms) ? $args : qq{($args)});
957             },
958 27 50       76 } if @variants == 0;
959              
960             # Otherwise, return the most specific/earliest...
961 27         89 return $variants[0];
962              
963             #====[ NOTE: I still prefer an ambiguity warning, but Perl 6 no longer does that :-( ]=====
964             #
965             # # Otherwise, the call is ambiguous, so report that...
966             # return {
967             # impl => sub {
968             # croak "Ambiguous call to multi '$subname'. Could invoke any of:\n",
969             # map({ my $sig = $_->{sig}; "\t$subname(". join(',',map({$_->{type}} @$sig)) .")\n" } @variants),
970             # "to handle:\n\t$subname(", dump(@arg_list)=~s/^\(|\)$//gr, ")\ncalled";
971             # },
972             # };
973             }
974              
975 56     56   1415109 keytype ParamList is m{
976             \(
977             (?:
978             (?&Parameter)
979             (?:
980             (?: (?&PerlOWS) [:,]
981             (?: (?&Parameter) (?&PerlOWS) , )*+
982             (?&Parameter)?+
983             )?+
984             )?+
985             )?+
986             (?: (?&PerlOWS) --> [^)]*+ )?+
987             (?&PerlOWS)
988             \)
989              
990             (?(DEFINE)
991             (?
992             (?&PerlOWS)
993             (?:
994             # Nameless literal constraint
995             (?&PerlNumber) | (?&PerlQuotelikeQ) | (?&PerlMatch)
996             |
997             (?! , | --> | \) ) # Every component is optional, but there must be at least one
998              
999             # TYPE...
1000             (?: (?&TYPE_SPEC) (?&PerlOWS) )?+
1001              
1002             # NAME...
1003             (?>
1004             : (?&IDENT) \( (?&PerlOWS) [\$\@%] (?&IDENT) (?&PerlOWS) \)
1005             |
1006             : [\$\@%] (?&IDENT)
1007             |
1008             \*
1009             (?:
1010             [\@%] (?&IDENT)?+
1011             |
1012             : (?&IDENT) \( (?&PerlOWS) \@ (?&IDENT) (?&PerlOWS) \)
1013             |
1014             : \@ (?&IDENT)
1015             )
1016             |
1017             [\$\@%] (?&IDENT)?+
1018             )?+
1019              
1020             # OPTIONAL OR REQUIRED...
1021             [?!]?+
1022              
1023             # CONSTRAINT...
1024             (?: (?&PerlOWS) where (?&PerlOWS) (?&PerlBlock) )?+
1025              
1026             # READONLY OR ALIAS...
1027             (?: (?&PerlOWS) is (?&PerlOWS) (?: ro | alias ) )?+
1028              
1029             # DEFAULT VALUE...
1030             (?: (?&PerlOWS) (?://|\|\|)? = (?&PerlOWS) (?&PerlConditionalExpression) )?+
1031             )
1032             )
1033              
1034             (? (?&TYPE_NAME) (?: [&|] (?&TYPE_NAME) )*+ )
1035             (? (?&QUAL_IDENT) (?&TYPE_PARAM)?+ )
1036             (? \[ (?: [^][]*+ | (?&TYPE_PARAM) )*+ \] )
1037             (? (?&IDENT) (?: :: (?&IDENT) )*+ )
1038             (? [^\W\d] \w*+ )
1039             )
1040             }xms;
1041              
1042 0           sub import {
1043 66     66   6638 my (undef, $opt) = @_;
1044              
1045             # What kind of accessors were requested in this scope???
1046             $^H{'Dios accessor_type'}
1047 66   66     1159 = $opt->{accessor} // $opt->{accessors} // $opt->{acc} // q{standard};
      100        
      100        
1048              
1049             # How should the invocants be named in this scope???
1050 66   100     603 my $invocant_name = $opt->{invocant} // $opt->{inv} // q{$self};
      100        
1051 66 50       751 if ($invocant_name =~ m{\A (\$?+) ([^\W\d]\w*+) \Z}xms) {
1052 66   100     663 $^H{'Dios invocant_name'} = ($1||'$').$2;
1053             }
1054             else {
1055 0         0 _error "Invalid invocant specification: '$invocant_name'\nin 'use Dios' statement";
1056             }
1057              
1058 66         137 # Class definitions are translated to encapsulated packages using OIO...
1059 56     56   1267702 keytype Bases is /is (?&PerlNWS) (?&PerlQualifiedIdentifier)/x;
  66         117  
1060 0 50 50 52   0 keyword class (
  0         0  
  0         0  
  66         459  
  52         3623566  
  52         136  
  52         148  
1061 0         0 QualIdent $class_name,
  66         2497  
  52         183  
1062 0         0 Bases* @bases,
  52         1154  
1063             Block $block
1064 0         0 )
  0         0  
  52         1881  
  52         108  
1065 0         0 {{{ { package <{$class_name}>; use Object::InsideOut <{ s{^ is (?&WS) (?(DEFINE) (? \s*+ (?: \# .*+ \n \s*+ )*+ ))}{}x for @bases; (@bases ? qq{qw{@bases}} : q{}) }>; do <{ $block }> } }}}
  52         113  
1066 0   0     0  
  52   100     281324  
1067 0         0 # Function definitions are translated to subroutines with extra argument-unpacking code...
  21         176631  
  66         1456  
1068 0 50 50 53   0 keyword func (
  0         0  
  0         0  
  66         249  
  53         2785265  
  53         95  
  53         113  
1069 0         0 QualIdent $sub_name = '',
  66         1450  
  53         108  
1070 0         0 ParamList $parameter_list = '',
  0         0  
  52         284826  
  53         1147  
1071             Attributes $attrs = '',
1072 0         0 Block $block
  0         0  
  0         0  
  0         0  
  52         115  
  52         133  
  53         1588  
  53         109  
1073 0         0 )
  0         0  
  52         5579  
  53         1090530  
1074 0         0 {
  52         1118  
1075             # Generate code that unpacks and tests arguments...
1076 56 0       409 $parameter_list = _translate_parameters($parameter_list, func => "$sub_name");
  0 100       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  66         662  
  52         859  
  52         150  
  52         118  
  52         261  
  52         286  
  52         782  
1077 66         3459  
1078 56     56   1477156 # Assemble and return the sub definition...
1079             if (my $return_type = $parameter_list->{return_type}) {
1080             qq{sub $sub_name $attrs { $parameter_list->{code} Dios::Types::_validate_return_type [q{$sub_name}, $return_type], \@_, sub $block } };
1081             }
1082             else {
1083             ($sub_name ? "sub $sub_name;" : q{} )
1084             . qq{sub $sub_name $attrs { $parameter_list->{code} do $block } };
1085             }
1086             }
1087              
1088 66         1354 # Multi definitions are translated to subroutines with extra argument-unpacking code...
1089 0 50 50 34   0 keyword multi (
  0         0  
  0         0  
  66         211  
  34         2174356  
  34         73  
  34         91  
1090 0         0 /method|func/ $type = 'func',
  66         1360  
  34         98  
1091 0         0 QualIdent $sub_name = '',
  34         1055  
1092             ParamList $parameter_list = '',
1093 0         0 Attributes $attrs = '',
  0         0  
  34         1267  
  34         92  
1094 0         0 Block $block
  34         95  
1095 0         0 )
  34         677  
1096             {
1097 0         0 # Generate code that unpacks and tests arguments...
  0         0  
  34         719  
  34         77  
1098 0         0 $parameter_list = _translate_parameters($parameter_list, $type => "$sub_name");
  34         795269  
1099             my $parameter_types = $parameter_list->{spec};
1100              
1101             # Assemble and return the method definition...
1102             my $code = qq{ BEGIN { *$sub_name = sub { my \$best_variant = Dios::_multi_dispatch('$sub_name', '$type', \@_); \@_ = \@{\$best_variant->{args}//[]}; goto &{\$best_variant->{impl}}; } if ! *${sub_name}{CODE}; } };
1103              
1104             my $multiname = sprintf 'DIOS_multi_%010d', ++$Dios::multinum;
1105              
1106             # Assemble and return the sub definition...
1107             if (my $return_type = $parameter_list->{return_type}) {
1108             $code .= qq{sub $multiname; sub $multiname $attrs { local *$multiname = '$sub_name'; $parameter_list->{code}; return { args => \\\@_, impl => sub { local *__ANON__ = '$sub_name'; Dios::Types::_validate_return_type [q{$sub_name}, $return_type], \@_, sub $block } } } };
1109             }
1110             else {
1111             $block = substr($block,1,-1);
1112             $code .= qq{sub $multiname; sub $multiname $attrs { local *$multiname = '$sub_name'; $parameter_list->{code}; return { args => \\\@_, impl => sub { local *__ANON__ = '$sub_name'; $block } } } };
1113             }
1114             $code .= qq{BEGIN{ push \@{ \$Dios::multis{q{$sub_name}} }, { sig => [$parameter_types], class => __PACKAGE__, validator => \\&$multiname }; }};
1115              
1116             return $code;
1117             }
1118              
1119 66         1370 # Method definitions are translated to subroutines with extra invocant-and-argument-unpacking code...
1120 0 50 50 131   0 keyword method (
  0         0  
  0         0  
  66         244  
  131         8290578  
  131         358  
  131         341  
1121 0         0 QualIdent $sub_name = '',
  66         1479  
  131         357  
1122 0         0 ParamList $parameter_list = '',
  131         3486  
1123             Attributes $attrs = '',
1124 0         0 Block $block
  0         0  
  131         4558  
  131         293  
1125 0         0 )
  131         2977497  
1126             {
1127             # Which kind of aliasing do we need (to create local vars bound to the object's fields)???
1128             my $use_aliasing = $] < 5.022 ? q{use Data::Alias} : q{use experimental 'refaliasing'};
1129             my $attr_binding = $^H{'Dios attrs'} ? "$use_aliasing; $^H{'Dios attrs'}" : q{};
1130              
1131             # Generate code that unpacks and tests arguments...
1132             $parameter_list = _translate_parameters($parameter_list, method => "$sub_name");
1133              
1134             # Assemble and return the method definition...
1135             ($sub_name ? "sub $sub_name;" : q{} )
1136             . qq{sub $sub_name $attrs { $attr_binding { $parameter_list->{code}; do $block } } };
1137             }
1138              
1139 0         0 # Submethod definitions are translated like methods, but with special re-routing...
  53         12380  
  66         1260  
1140 0 50 50 12   0 keyword submethod (
  0         0  
  0         0  
  66         203  
  12         742302  
  12         38  
  12         35  
1141 0         0 QualIdent $sub_name = '',
  0         0  
  0         0  
  53         3338  
  53         134  
  66         1362  
  12         30  
1142 0         0 ParamList $parameter_list = '',
  0         0  
  53         117  
  12         284  
1143 0         0 Attributes $attrs = '',
  53         1897  
1144 0         0 Block $block
  0         0  
  12         406  
  12         36  
1145 0         0 )
  0         0  
  0         0  
  53         1317  
  53         121  
  12         272463  
1146 0         0 {
  53         21166  
1147 0         0 # Which kind of aliasing do we need (to create local vars bound to the object's fields)???
  53         11081  
1148             my $use_aliasing = $] < 5.022 ? q{use Data::Alias} : q{use experimental 'refaliasing'};
1149 0         0 my $attr_binding = $^H{'Dios attrs'} ? "$use_aliasing; $^H{'Dios attrs'}" : q{};
  53         1068  
1150              
1151 0         0 # Extract attribute names...
  53         479  
1152             my %attr_name = map { $_ => 1 } split ',', ($^H{'Dios attrnames'}//q{});
1153              
1154 0 0       0 # Generate the code to unpack and test arguments...
  53 100       225  
1155 0         0 my $parameter_spec = _translate_parameters($parameter_list, method => "$sub_name");
  30         241  
1156              
1157             # Handle any special submethod names...
1158 0 0       0 my $init_args = q{};
  23 100       148  
1159             if ($sub_name eq 'BUILD') {
1160             # Extract named args for :InitArgs hash (TODO: this should pull out type/required info too)...
1161 56         408  
  66         495  
1162 66         2414 my $invalid_names
1163 56     56   1872854 = join ', ', map { $attr_name{$_} ? ":$_" : () } @{$parameter_spec->{names}};
1164 0         0 if (my $invalid_names = join ', ', map { $attr_name{$_} ? ":$_" : () } @{$parameter_spec->{names}} ) {
  34         8502  
1165             _error("Can't use an attribute name as a parameter name ($invalid_names)\nin submethod BUILD()");
1166 0         0 }
  0         0  
  34         2455  
  34         110  
1167 0         0  
  34         91  
1168 0         0 # Tell OIO about this constructor args...
  34         1595  
1169             $init_args = qq{ BEGIN{ my %$sub_name :InitArgs = map { \$_ => {} } qw{@{$parameter_spec->{names}}}; } };
1170 0         0  
  0         0  
  34         1019  
  34         77  
1171 0         0 # Mark the sub as an initializer
  34         16673  
1172 0         0 $attrs .= ' :Private :Init';
  34         5971  
1173              
1174 0         0 # Repack the arguments from ($self, {attr=>val, et=>cetera}) to ($self, attr=>val, et=>cetera)...
  34         835  
1175             $attr_binding = q{@_ = ($_[0], %{$_[1]});} . $attr_binding;
1176 0         0 }
  34         390  
1177 0         0 elsif ($sub_name eq 'DESTROY') {
  34         123  
1178             # Parameter list will never be satisfied (which breaks cleanup), so don't allow it at all...
1179             return q{die 'submethod DESTROY cannot have a parameter list';}
1180 0         0 if $parameter_list && $parameter_list !~ /^\(\s*+\)$/;
  34         157  
1181              
1182 0         0 # Mark it as a destructor...
  34         599  
1183             $attrs .= ' :Private :Destroy';
1184              
1185 0 0       0 # Rename it so as not to clash with OIO's DESTROY...
  34 50       124  
1186 0         0 $sub_name = '___DESTROY___';
  0         0  
1187             }
1188             else {
1189 0         0 $attr_binding = qq{ if ((ref(\$_[0])||\$_[0]) ne __PACKAGE__) { return \$_[0]->SUPER::$sub_name(\@_[1..\$#_]); } } . $attr_binding;
  34         103  
1190 0         0 }
  34         376  
1191 0         0  
  131         33275  
1192 0         0 # Assemble and return the method definition...
  34         452  
1193 0         0 ($sub_name ? "sub $sub_name;" : q{} )
  0         0  
  131         9156  
  131         408  
1194 0         0 . qq{$init_args sub $sub_name $attrs { $attr_binding { $parameter_spec->{code}; do $block } } };
  0         0  
  34         938  
  131         435  
1195 56         487 }
  0         0  
  66         1663  
  131         5008  
1196 66         3592  
1197 56     56   2067559 # Components of variable declaration...
  0         0  
  0         0  
  131         3565  
  131         315  
  66         1240  
1198 0     56   0 keytype TypeSpec is m{ (?&TypeSpec)
  56         1301170  
  131         24739  
1199 0         0 (?(DEFINE)
  131         111458  
1200             (?
1201 0         0 (?&TypeName) (?: (?: [&|] | => ) (?&TypeName) )*+
  131         3122  
1202             )
1203 0 0       0 (?
  131 50       742  
1204 0 0       0 \s* (?&TypeName) (?: \s* (?: [&|] | => ) \s* (?&TypeName) )*+ \s*
  131 100       682  
1205             )
1206             (?
1207 0         0 Match \[ [^]]*+ \]
  131         1268  
1208             |
1209             (?&PerlIdentifier) \[ (?&TypeSpecSpacey) \]
1210 0 0       0 |
  131 100       937  
1211 0         0 (?&PerlQualifiedIdentifier)
  12         2646  
1212 56         400 )
  66         452  
1213 0         0 )
  0         0  
  66         2321  
  12         1141  
  12         59  
1214 56     56   1991536 }x;
  0         0  
  12         34  
  66         108  
1215 0     56   0 keytype Var is / [\$\@%] [.!]?+ (?&PerlIdentifier) /x;
  56         1284751  
  12         394  
  66         92  
1216 56     56   1273686 keytype Traits is / (?: (?&PerlOWS) is (?&PerlOWS) (?: ro | rw | req(?:uired)? ) )++ /x;
  66         89  
1217 0     56   0 keytype Handles is / (?: (?&PerlOWS) handles (?&PerlOWS)
  0         0  
  56         1282894  
  12         311  
  12         26  
1218 0         0 (?: (?&PerlIdentifier) | :(?&PerlIdentifier)<(?&PerlIdentifier)> )
  12         1424  
1219 0         0 )++ /x;
  12         7074  
  66         96  
1220 56     56   1283818 keytype Init is m{ (?: // )?+ = (?&PerlOWS) (?&PerlExpression) }x;
  66         89  
1221 0     56   0 keytype Constraint is m{ where (?&PerlOWS) (?&PerlBlock) }x;
  56         1281900  
  12         273  
1222              
1223 0 0       0 # An attribute definition is translated into an array with a :Field attribute...
  12 50       75  
  66         102  
1224 0 0 50 34   0 keyword has (
  0 100       0  
  0 50       0  
  0         0  
  12         85  
  66         189  
  34         2130748  
  34         87  
  34         108  
1225 0         0 TypeSpec $type = '',
  66         1391  
  34         753124  
1226             Var $variable,
1227 0   0     0 Constraint $constraint = '',
  0   100     0  
  12         102  
  7         35  
1228             Traits $traits = '',
1229             Handles $handles = '',
1230 0         0 Init $init = '',
  12         69  
1231             ) {
1232             _compose_field($type, $variable, $traits, $handles, $init, $constraint)
1233 0         0 }
  12         35  
1234 0 0       0  
  12 0       64  
  66 100       1312  
    100          
1235 56     56   1284076 keytype ReadTraits is / (?&PerlOWS) is (?&PerlOWS) (?: ro | rw ) /x;
1236              
1237 66         110 # An attribute definition is translated into an my var with extra code for accessors...
1238 0 0 50 5   0 keyword shared (
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  0         0  
  8         101  
  5         62  
  8         45  
  66         186  
  5         356953  
  5         12  
  5         10  
1239 0 0       0 TypeSpec $type = '',
  0 0       0  
  0 50       0  
  0 50       0  
  8         17  
  5         43  
  8         23  
  66         1322  
  5         101489  
1240 0         0 Var $variable,
  0         0  
1241             Constraint $constraint = '',
1242 0         0 ReadTraits $traits = '',
  34         7979  
1243             Init $init = '',
1244 0         0 ) {
  0         0  
  0         0  
  0         0  
  8         40  
  8         53  
  34         2387  
  34         110  
1245 0         0 _compose_shared($type, $variable, $traits, $init, $constraint)
  34         2908  
1246 0         0 }
  34         1468  
1247 0         0  
  8         18  
1248 0         0 # An lexical variable definition is translated into a typed lexical...
  0         0  
  34         1195  
  34         79  
  66         1328  
1249 0 50 50 3   0 keyword lex (TypeSpec? $type, Var $variable, Constraint? $constraint) {
  0         0  
  0         0  
  0         0  
  34         109  
  66         215  
  3         218499  
  3         7  
  3         8  
1250 0         0 _compose_lexical($type, $variable, $constraint)
  0         0  
  0         0  
  8         60  
  34         696  
  66         1391  
  3         66962  
1251             }
1252 0         0  
  0         0  
  34         735  
  34         74  
1253 0         0  
  34         948  
1254 0 0 0     0 # Subtypes are handled by Dios::Types...
  0 50 66     0  
  3         49  
  34         572  
  66         1354  
1255 56 50 50 2   387 keyword subtype {{{ use Dios::Types; subtype }}}
  0         0  
  0         0  
  66         203  
  66         329  
  2         132091  
  2         9  
1256 0         0  
  0         0  
  0         0  
  34         615  
  34         67  
  5         1027  
  66         1360  
  66         1748  
1257 0     56   0 # Tail recursion is handled as in Perl 6...
  56         1670028  
  34         65  
  66         1355  
1258 0 50 50 1   0 keyword callwith () {{{ goto &{+do{no strict 'refs'; \&{(caller 0)[3]} }} for 1, @_ = grep 1, }}}
  0         0  
  0         0  
  0         0  
  56         383  
  0         0  
  0         0  
  3         17  
  34         432  
  5         309  
  5         14  
  66         207  
  66         332  
  1         52586  
  1         7  
  66         1296  
1259 0 50 50 1   0 keyword callsame () {{{ goto &{+do{no strict 'refs'; \&{(caller 0)[3]} }} }}}
  56         386  
  0         0  
  0         0  
  5         328  
  66         1293  
  66         1750  
  66         227  
  66         320  
  1         54122  
  1         6  
1260 0     56   0  
  0         0  
  0         0  
  56         1689550  
  34         558  
  34         79  
  5         113  
  66         1263  
  66         1703  
1261 0     56   0 }
  0         0  
  56         1712106  
  3         19  
  34         176  
1262 0         0  
  0         0  
  0         0  
  34         392  
  5         112  
  5         10  
1263 0         0 1; # Magic true value required at end of module
  5         44  
1264 0         0  
  0         0  
  0         0  
  1         9  
  34         535  
  5         75  
1265 0         0 __END__