242 lines
5.2 KiB
Perl
242 lines
5.2 KiB
Perl
package PPI::Token::Symbol;
|
|
|
|
=pod
|
|
|
|
=head1 NAME
|
|
|
|
PPI::Token::Symbol - A token class for variables and other symbols
|
|
|
|
=head1 INHERITANCE
|
|
|
|
PPI::Token::Symbol
|
|
isa PPI::Token
|
|
isa PPI::Element
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
The C<PPI::Token::Symbol> class is used to cover all tokens that represent
|
|
variables and other things that start with a sigil.
|
|
|
|
=head1 METHODS
|
|
|
|
This class has several methods beyond what is provided by its
|
|
L<PPI::Token> and L<PPI::Element> parent classes.
|
|
|
|
Most methods are provided to help work out what the object is actually
|
|
pointing at, rather than what it might appear to be pointing at.
|
|
|
|
=cut
|
|
|
|
use strict;
|
|
use Params::Util qw{_INSTANCE};
|
|
use PPI::Token ();
|
|
|
|
our $VERSION = '1.270'; # VERSION
|
|
|
|
our @ISA = "PPI::Token";
|
|
|
|
|
|
|
|
|
|
|
|
#####################################################################
|
|
# PPI::Token::Symbol Methods
|
|
|
|
=pod
|
|
|
|
=head2 canonical
|
|
|
|
The C<canonical> method returns a normalized, canonical version of the
|
|
symbol.
|
|
|
|
For example, it converts C<$ ::foo'bar::baz> to C<$main::foo::bar::baz>.
|
|
|
|
This does not fully resolve the symbol, but merely removes syntax
|
|
variations.
|
|
|
|
=cut
|
|
|
|
sub canonical {
|
|
my $symbol = shift->content;
|
|
$symbol =~ s/\s+//;
|
|
$symbol =~ s/\'/::/g;
|
|
$symbol =~ s/(?<=[\$\@\%\&\*])::/main::/;
|
|
$symbol;
|
|
}
|
|
|
|
=pod
|
|
|
|
=head2 symbol
|
|
|
|
The C<symbol> method returns the ACTUAL symbol this token refers to.
|
|
|
|
A token of C<$foo> might actually be referring to C<@foo>, if it is found
|
|
in the form C<$foo[1]>.
|
|
|
|
This method attempts to resolve these issues to determine the actual
|
|
symbol.
|
|
|
|
Returns the symbol as a string.
|
|
|
|
=cut
|
|
|
|
my %cast_which_trumps_braces = map { $_ => 1 } qw{ $ @ % };
|
|
|
|
sub symbol {
|
|
my $self = shift;
|
|
my $symbol = $self->canonical;
|
|
|
|
# Immediately return the cases where it can't be anything else
|
|
my $type = substr( $symbol, 0, 1 );
|
|
return $symbol if $type eq '&';
|
|
|
|
# Unless the next significant Element is a structure, it's correct.
|
|
my $after = $self->snext_sibling;
|
|
return $symbol unless _INSTANCE($after, 'PPI::Structure');
|
|
|
|
# Process the rest for cases where it might actually be something else
|
|
my $braces = $after->braces;
|
|
return $symbol unless defined $braces;
|
|
if ( $type eq '$' ) {
|
|
|
|
# If it is cast to '$' or '@', that trumps any braces
|
|
my $before = $self->sprevious_sibling;
|
|
return $symbol if $before &&
|
|
$before->isa( 'PPI::Token::Cast' ) &&
|
|
$cast_which_trumps_braces{ $before->content };
|
|
|
|
# Otherwise the braces rule
|
|
substr( $symbol, 0, 1, '@' ) if $braces eq '[]';
|
|
substr( $symbol, 0, 1, '%' ) if $braces eq '{}';
|
|
|
|
} elsif ( $type eq '@' ) {
|
|
substr( $symbol, 0, 1, '%' ) if $braces eq '{}';
|
|
|
|
} elsif ( $type eq '%' ) {
|
|
substr( $symbol, 0, 1, '@' ) if $braces eq '[]';
|
|
|
|
}
|
|
|
|
$symbol;
|
|
}
|
|
|
|
=pod
|
|
|
|
=head2 raw_type
|
|
|
|
The C<raw_type> method returns the B<apparent> type of the symbol in the
|
|
form of its sigil.
|
|
|
|
Returns the sigil as a string.
|
|
|
|
=cut
|
|
|
|
sub raw_type {
|
|
substr( $_[0]->content, 0, 1 );
|
|
}
|
|
|
|
=pod
|
|
|
|
=head2 symbol_type
|
|
|
|
The C<symbol_type> method returns the B<actual> type of the symbol in the
|
|
form of its sigil.
|
|
|
|
Returns the sigil as a string.
|
|
|
|
=cut
|
|
|
|
sub symbol_type {
|
|
substr( $_[0]->symbol, 0, 1 );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#####################################################################
|
|
# Tokenizer Methods
|
|
|
|
sub __TOKENIZER__on_char {
|
|
my $t = $_[1];
|
|
|
|
# Suck in till the end of the symbol
|
|
pos $t->{line} = $t->{line_cursor};
|
|
if ( $t->{line} =~ m/\G([\w:\']+)/gc ) {
|
|
$t->{token}->{content} .= $1;
|
|
$t->{line_cursor} += length $1;
|
|
}
|
|
|
|
# Handle magic things
|
|
my $content = $t->{token}->{content};
|
|
if ( $content eq '@_' or $content eq '$_' ) {
|
|
$t->{class} = $t->{token}->set_class( 'Magic' );
|
|
return $t->_finalize_token->__TOKENIZER__on_char( $t );
|
|
}
|
|
|
|
# Shortcut for most of the X:: symbols
|
|
if ( $content eq '$::' ) {
|
|
# May well be an alternate form of a Magic
|
|
my $nextchar = substr( $t->{line}, $t->{line_cursor}, 1 );
|
|
if ( $nextchar eq '|' ) {
|
|
$t->{token}->{content} .= $nextchar;
|
|
$t->{line_cursor}++;
|
|
$t->{class} = $t->{token}->set_class( 'Magic' );
|
|
}
|
|
return $t->_finalize_token->__TOKENIZER__on_char( $t );
|
|
}
|
|
if ( $content =~ /^[\$%*@&]::(?:[^\w]|$)/ ) {
|
|
my $current = substr( $content, 0, 3, '' );
|
|
$t->{token}->{content} = $current;
|
|
$t->{line_cursor} -= length( $content );
|
|
return $t->_finalize_token->__TOKENIZER__on_char( $t );
|
|
}
|
|
if ( $content =~ /^(?:\$|\@)\d+/ ) {
|
|
$t->{class} = $t->{token}->set_class( 'Magic' );
|
|
return $t->_finalize_token->__TOKENIZER__on_char( $t );
|
|
}
|
|
|
|
# Trim off anything we oversucked...
|
|
$content =~ /^(
|
|
[\$@%&*]
|
|
(?: : (?!:) | # Allow single-colon non-magic variables
|
|
(?: \w+ | \' (?!\d) \w+ | \:: \w+ )
|
|
(?:
|
|
# Allow both :: and ' in namespace separators
|
|
(?: \' (?!\d) \w+ | \:: \w+ )
|
|
)*
|
|
(?: :: )? # Technically a compiler-magic hash, but keep it here
|
|
)
|
|
)/x or return undef;
|
|
unless ( length $1 eq length $content ) {
|
|
$t->{line_cursor} += length($1) - length($content);
|
|
$t->{token}->{content} = $1;
|
|
}
|
|
|
|
$t->_finalize_token->__TOKENIZER__on_char( $t );
|
|
}
|
|
|
|
1;
|
|
|
|
=pod
|
|
|
|
=head1 SUPPORT
|
|
|
|
See the L<support section|PPI/SUPPORT> in the main module.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
Copyright 2001 - 2011 Adam Kennedy.
|
|
|
|
This program is free software; you can redistribute
|
|
it and/or modify it under the same terms as Perl itself.
|
|
|
|
The full text of the license can be found in the
|
|
LICENSE file included with this module.
|
|
|
|
=cut
|