1 package PPI::Token::Unknown;
7 PPI::Token::Unknown - Token of unknown or as-yet undetermined type
17 Object of the type C<PPI::Token::Unknown> exist primarily inside the
18 tokenizer, where they are temporarily brought into existing for a very
19 short time to represent a token that could be one of a number of types.
21 Generally, they only exist for a character or two, after which they are
22 resolved and converted into the correct type. For an object of this type
23 to survive the parsing process is considered a major bug.
25 Please report any C<PPI::Token::Unknown> you encounter in a L<PPI::Document>
32 use PPI::Exception ();
34 use vars qw{$VERSION @ISA};
44 #####################################################################
47 sub __TOKENIZER__on_char {
48 my $t = $_[1]; # Tokenizer object
49 my $c = $t->{token}->{content}; # Current token
50 my $char = substr( $t->{line}, $t->{line_cursor}, 1 ); # Current character
52 # Now, we split on the different values of the current content
54 if ( $char =~ /(?:(?!\d)\w|\:)/ ) {
55 # Symbol (unless the thing before it is a number
56 my $tokens = $t->_previous_significant_tokens(1);
57 my $p0 = $tokens->[0];
58 if ( $p0 and ! $p0->isa('PPI::Token::Number') ) {
59 $t->{class} = $t->{token}->set_class( 'Symbol' );
66 $t->{class} = $t->{token}->set_class( 'Cast' );
67 return $t->_finalize_token->__TOKENIZER__on_char( $t );
71 # Operator/operand-sensitive, multiple or GLOB cast
73 my $tokens = $t->_previous_significant_tokens(1);
74 my $p0 = $tokens->[0];
76 # Is it a token or a number
77 if ( $p0->isa('PPI::Token::Symbol') ) {
79 } elsif ( $p0->isa('PPI::Token::Number') ) {
82 $p0->isa('PPI::Token::Structure')
84 $p0->content =~ /^(?:\)|\])$/
88 ### This is pretty weak, there's
89 ### room for a dozen more tests
90 ### before going with a default.
91 ### Or even better, a proper
92 ### operator/operand method :(
96 # Nothing before it, must be glob cast
100 # Set class and rerun
101 $t->{class} = $t->{token}->set_class( $_class );
102 return $t->_finalize_token->__TOKENIZER__on_char( $t );
105 if ( $char eq '*' || $char eq '=' ) {
106 # Power operator '**' or mult-assign '*='
107 $t->{class} = $t->{token}->set_class( 'Operator' );
111 $t->{class} = $t->{token}->set_class( 'Operator' );
112 return $t->_finalize_token->__TOKENIZER__on_char( $t );
116 } elsif ( $c eq '$' ) {
117 if ( $char =~ /[a-z_]/i ) {
119 $t->{class} = $t->{token}->set_class( 'Symbol' );
123 if ( $PPI::Token::Magic::magic{ $c . $char } ) {
125 $t->{class} = $t->{token}->set_class( 'Magic' );
130 $t->{class} = $t->{token}->set_class( 'Cast' );
131 return $t->_finalize_token->__TOKENIZER__on_char( $t );
135 } elsif ( $c eq '@' ) {
136 if ( $char =~ /[\w:]/ ) {
138 $t->{class} = $t->{token}->set_class( 'Symbol' );
142 if ( $char =~ /[\-\+\*]/ ) {
144 $t->{class} = $t->{token}->set_class( 'Magic' );
149 $t->{class} = $t->{token}->set_class( 'Cast' );
150 return $t->_finalize_token->__TOKENIZER__on_char( $t );
154 } elsif ( $c eq '%' ) {
156 if ( $char =~ /\d/ ) {
157 # This is %2 (modulus number)
158 $t->{class} = $t->{token}->set_class( 'Operator' );
159 return $t->_finalize_token->__TOKENIZER__on_char( $t );
162 # Is it a magic variable?
163 if ( $char =~ /[!^]/ ) {
164 $t->{class} = $t->{token}->set_class( 'Magic' );
169 if ( $char =~ /[\w:]/ ) {
170 $t->{class} = $t->{token}->set_class( 'Symbol' );
174 if ( $char =~ /[\$@%*{]/ ) {
176 $t->{class} = $t->{token}->set_class( 'Cast' );
177 return $t->_finalize_token->__TOKENIZER__on_char( $t );
181 # Probably the mod operator
182 $t->{class} = $t->{token}->set_class( 'Operator' );
183 return $t->{class}->__TOKENIZER__on_char( $t );
187 } elsif ( $c eq '&' ) {
189 if ( $char =~ /\d/ ) {
190 # This is &2 (bitwise-and number)
191 $t->{class} = $t->{token}->set_class( 'Operator' );
192 return $t->_finalize_token->__TOKENIZER__on_char( $t );
196 if ( $char =~ /[\w:]/ ) {
197 $t->{class} = $t->{token}->set_class( 'Symbol' );
201 if ( $char =~ /[\$@%{]/ ) {
202 # The ampersand is a cast
203 $t->{class} = $t->{token}->set_class( 'Cast' );
204 return $t->_finalize_token->__TOKENIZER__on_char( $t );
207 # Probably the binary and operator
208 $t->{class} = $t->{token}->set_class( 'Operator' );
209 return $t->{class}->__TOKENIZER__on_char( $t );
213 } elsif ( $c eq '-' ) {
214 if ( $char =~ /\d/o ) {
216 $t->{class} = $t->{token}->set_class( 'Number' );
220 if ( $char eq '.' ) {
222 $t->{class} = $t->{token}->set_class( 'Number::Float' );
226 if ( $char =~ /[a-zA-Z]/ ) {
227 $t->{class} = $t->{token}->set_class( 'DashedWord' );
231 # The numeric negative operator
232 $t->{class} = $t->{token}->set_class( 'Operator' );
233 return $t->{class}->__TOKENIZER__on_char( $t );
237 } elsif ( $c eq ':' ) {
238 if ( $char eq ':' ) {
239 # ::foo style bareword
240 $t->{class} = $t->{token}->set_class( 'Word' );
244 # Now, : acts very very differently in different contexts.
245 # Mainly, we need to find out if this is a subroutine attribute.
246 # We'll leave a hint in the token to indicate that, if it is.
247 if ( $_[0]->__TOKENIZER__is_an_attribute( $t ) ) {
248 # This : is an attribute indicator
249 $t->{class} = $t->{token}->set_class( 'Operator' );
250 $t->{token}->{_attribute} = 1;
251 return $t->_finalize_token->__TOKENIZER__on_char( $t );
254 # It MIGHT be a label, but its probably the ?: trinary operator
255 $t->{class} = $t->{token}->set_class( 'Operator' );
256 return $t->{class}->__TOKENIZER__on_char( $t );
260 PPI::Exception->throw('Unknown value in PPI::Token::Unknown token');
263 # Are we at a location where a ':' would indicate a subroutine attribute
264 sub __TOKENIZER__is_an_attribute {
265 my $t = $_[1]; # Tokenizer object
266 my $tokens = $t->_previous_significant_tokens(3);
267 my $p0 = $tokens->[0];
269 # If we just had another attribute, we are also an attribute
270 return 1 if $p0->isa('PPI::Token::Attribute');
272 # If we just had a prototype, then we are an attribute
273 return 1 if $p0->isa('PPI::Token::Prototype');
275 # Other than that, we would need to have had a bareword
276 return '' unless $p0->isa('PPI::Token::Word');
278 # We could be an anonymous subroutine
279 if ( $p0->isa('PPI::Token::Word') and $p0->content eq 'sub' ) {
283 # Or, we could be a named subroutine
284 my $p1 = $tokens->[1];
285 my $p2 = $tokens->[2];
287 $p1->isa('PPI::Token::Word')
289 $p1->content eq 'sub'
291 $p2->isa('PPI::Token::Structure')
293 $p2->isa('PPI::Token::Whitespace')
302 # We arn't an attribute
312 See the L<support section|PPI/SUPPORT> in the main module.
316 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
320 Copyright 2001 - 2009 Adam Kennedy.
322 This program is free software; you can redistribute
323 it and/or modify it under the same terms as Perl itself.
325 The full text of the license can be found in the
326 LICENSE file included with this module.