File Coverage

blib/lib/PPI/Token/Magic.pm
Criterion Covered Total %
statement 61 64 95.3
branch 31 34 91.1
condition 12 15 80.0
subroutine 6 6 100.0
pod 1 1 100.0
total 111 120 92.5


line stmt bran cond sub pod time code
1             package PPI::Token::Magic;
2              
3             =pod
4              
5             =head1 NAME
6              
7             PPI::Token::Magic - Tokens representing magic variables
8              
9             =head1 INHERITANCE
10              
11             PPI::Token::Magic
12             isa PPI::Token::Symbol
13             isa PPI::Token
14             isa PPI::Element
15              
16             =head1 SYNOPSIS
17              
18             # When we say magic variables, we mean these...
19             $1 $2 $3 $4 $5 $6 $7 $8 $9
20             $_ $& $` $' $+ @+ %+ $* $. $/ $|
21             $\ $" $; $% $= $- @- %- $) $#
22             $~ $^ $: $? $! %! $@ $$ $< $>
23             $( $0 $[ $] @_ @* $} $, $#+ $#-
24             $^L $^A $^E $^C $^D $^F $^H
25             $^I $^M $^N $^O $^P $^R $^S
26             $^T $^V $^W $^X %^H
27              
28             =head1 DESCRIPTION
29              
30             C<PPI::Token::Magic> is a sub-class of L<PPI::Token::Symbol> which
31             identifies the token as "magic variable", one of the strange and
32             unusual variables that are connected to "things" behind the scenes.
33              
34             Some are extremely common, like C<$_>, and others you will quite
35             probably never encounter in your Perl career.
36              
37             =head1 METHODS
38              
39             The class provides no additional methods, beyond those provided by
40             L<PPI::Token::Symbol>, L<PPI::Token> and L<PPI::Element>.
41              
42             =cut
43              
44 67     67   377 use strict;
  67         93  
  67         1984  
45 67     67   248 use PPI::Token::Symbol ();
  67         84  
  67         679  
46 67     67   24733 use PPI::Token::Unknown ();
  67         154  
  67         1770  
47 67     67   394 use PPI::Singletons qw' %MAGIC $CURLY_SYMBOL ';
  67         106  
  67         68987  
48              
49             our $VERSION = '1.284';
50              
51             our @ISA = "PPI::Token::Symbol";
52              
53             sub __TOKENIZER__on_char {
54 1529     1529   2093 my $t = $_[1];
55              
56             # $c is the candidate new content
57 1529         4238 my $c = $t->{token}->{content} . substr( $t->{line}, $t->{line_cursor}, 1 );
58              
59             # Do a quick first test so we don't have to do more than this one.
60             # All of the tests below match this one, so it should provide a
61             # small speed up. This regex should be updated to match the inside
62             # tests if they are changed.
63 1529 100       6939 if ( $c =~ /^ \$ .* [ \w : \$ \{ ] $/x ) {
    100          
64              
65 928 100 100     3930 if ( $c =~ /^(\$(?:\_[\w:]|::))/ or $c =~ /^\$\'[\w]/ ) {
66             # If and only if we have $'\d, it is not a
67             # symbol. (this was apparently a conscious choice)
68             # Note that $::0 on the other hand is legal
69 85 100       213 if ( $c =~ /^\$\'\d$/ ) {
70             # In this case, we have a magic plus a digit.
71             # Save the CURRENT token, and rerun the on_char
72 1         5 return $t->_finalize_token->__TOKENIZER__on_char( $t );
73             }
74              
75             # A symbol in the style $_foo or $::foo or $'foo.
76             # Overwrite the current token
77 84         183 $t->{class} = $t->{token}->set_class('Symbol');
78 84         246 return PPI::Token::Symbol->__TOKENIZER__on_char( $t );
79             }
80              
81 843 100       1913 if ( $c =~ /^\$\$\w/ ) {
82             # This is really a scalar dereference. ( $$foo )
83             # Add the current token as the cast...
84 77         322 $t->{token} = PPI::Token::Cast->new( '$' );
85 77         297 $t->_finalize_token;
86              
87             # ... and create a new token for the symbol
88 77         192 return $t->_new_token( 'Symbol', '$' );
89             }
90              
91 766 100       1446 if ( $c eq '$${' ) {
92             # This _might_ be a dereference of one of the
93             # control-character symbols.
94 1         4 pos $t->{line} = $t->{line_cursor} + 1;
95 1 50       20 if ( $t->{line} =~ m/$CURLY_SYMBOL/gc ) {
96             # This is really a dereference. ( $${^_foo} )
97             # Add the current token as the cast...
98 1         4 $t->{token} = PPI::Token::Cast->new( '$' );
99 1         4 $t->_finalize_token;
100              
101             # ... and create a new token for the symbol
102 1         3 return $t->_new_token( 'Magic', '$' );
103             }
104             }
105              
106 765 100 66     2210 if ( $c eq '$#$' or $c eq '$#{' ) {
107             # This is really an index dereferencing cast, although
108             # it has the same two chars as the magic variable $#.
109 8         63 $t->{class} = $t->{token}->set_class('Cast');
110 8         22 return $t->_finalize_token->__TOKENIZER__on_char( $t );
111             }
112              
113 757 100       1616 if ( $c =~ /^(\$\#)\w/ ) {
114             # This is really an array index thingy ( $#array )
115 94         505 $t->{token} = PPI::Token::ArrayIndex->new( "$1" );
116 94         308 return PPI::Token::ArrayIndex->__TOKENIZER__on_char( $t );
117             }
118              
119 663 100       1596 if ( $c =~ /^\$\^\w+$/o ) {
120             # It's an escaped char magic... maybe ( like $^M )
121 362         553 my $next = substr( $t->{line}, $t->{line_cursor}+1, 1 ); # Peek ahead
122 362 100 66     921 if ($MAGIC{$c} && (!$next || $next !~ /\w/)) {
      100        
123 32         81 $t->{token}->{content} = $c;
124 32         66 $t->{line_cursor}++;
125             } else {
126             # Maybe it's a long magic variable like $^WIDE_SYSTEM_CALLS
127 330         629 return 1;
128             }
129             }
130              
131 333 50       840 if ( $c =~ /^\$\#\{/ ) {
132             # The $# is actually a cast, and { is its block
133             # Add the current token as the cast...
134 0         0 $t->{token} = PPI::Token::Cast->new( '$#' );
135 0         0 $t->_finalize_token;
136              
137             # ... and create a new token for the block
138 0         0 return $t->_new_token( 'Structure', '{' );
139             }
140             } elsif ($c =~ /^%\^/) {
141 20 50       76 return 1 if $c eq '%^';
142             # It's an escaped char magic... maybe ( like %^H )
143 20 100       63 if ($MAGIC{$c}) {
144 8         15 $t->{token}->{content} = $c;
145 8         14 $t->{line_cursor}++;
146             } else {
147             # Back off, treat '%' as an operator
148 12         53 chop $t->{token}->{content};
149 12         27 bless $t->{token}, $t->{class} = 'PPI::Token::Operator';
150 12         18 $t->{line_cursor}--;
151             }
152             }
153              
154 934 100       2453 if ( $MAGIC{$c} ) {
155             # $#+ and $#-
156 42         150 $t->{line_cursor} += length( $c ) - length( $t->{token}->{content} );
157 42         80 $t->{token}->{content} = $c;
158             } else {
159 892         2690 pos $t->{line} = $t->{line_cursor};
160 892 100 66     9573 if ( $t->{line} =~ m/($CURLY_SYMBOL)/gc ) {
    100          
161             # control character symbol (e.g. ${^MATCH})
162 7         19 $t->{token}->{content} .= $1;
163 7         10 $t->{line_cursor} += length $1;
164             } elsif ( $c =~ /^\$\d+$/ and $t->{line} =~ /\G(\d+)/gc ) {
165             # Grab trailing digits of regex capture variables.
166 4         13 $t->{token}{content} .= $1;
167 4         9 $t->{line_cursor} += length $1;
168             }
169             }
170              
171             # End the current magic token, and recheck
172 934         2264 $t->_finalize_token->__TOKENIZER__on_char( $t );
173             }
174              
175             # Our version of canonical is plain simple
176 17     17 1 58 sub canonical { $_[0]->content }
177              
178             1;
179              
180             =pod
181              
182             =head1 SUPPORT
183              
184             See the L<support section|PPI/SUPPORT> in the main module.
185              
186             =head1 AUTHOR
187              
188             Adam Kennedy E<lt>adamk@cpan.orgE<gt>
189              
190             =head1 COPYRIGHT
191              
192             Copyright 2001 - 2011 Adam Kennedy.
193              
194             This program is free software; you can redistribute
195             it and/or modify it under the same terms as Perl itself.
196              
197             The full text of the license can be found in the
198             LICENSE file included with this module.
199              
200             =cut