File Coverage

blib/lib/Dios.pm
Criterion Covered Total %
statement 512 635 80.6
branch 249 352 70.7
condition 95 146 65.0
subroutine 57 58 98.2
pod n/a
total 913 1191 76.6


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