PPI::Token::Symbol - A token class for variables and other symbols


PPI documentation Contained in the PPI distribution.

Index


Code Index:

NAME

Top

PPI::Token::Symbol - A token class for variables and other symbols

INHERITANCE

Top

  PPI::Token::Symbol
  isa PPI::Token
      isa PPI::Element

DESCRIPTION

Top

The PPI::Token::Symbol class is used to cover all tokens that represent variables and other things that start with a sigil.

METHODS

Top

This class has several methods beyond what is provided by its PPI::Token and 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.

canonical

The canonical method returns a normalized, canonical version of the symbol.

For example, it converts $ ::foo'bar::baz to $main::foo::bar::baz.

This does not fully resolve the symbol, but merely removes syntax variations.

symbol

The symbol method returns the ACTUAL symbol this token refers to.

A token of $foo might actually be referring to @foo, if it is found in the form $foo[1].

This method attempts to resolve these issues to determine the actual symbol.

Returns the symbol as a string.

raw_type

The raw_type method returns the apparent type of the symbol in the form of its sigil.

Returns the sigil as a string.

symbol_type

The symbol_type method returns the actual type of the symbol in the form of its sigil.

Returns the sigil as a string.

SUPPORT

Top

See the support section in the main module.

AUTHOR

Top

Adam Kennedy <adamk@cpan.org>

COPYRIGHT

Top


PPI documentation Contained in the PPI distribution.
package PPI::Token::Symbol;

 
use strict;
use Params::Util qw{_INSTANCE};
use PPI::Token   ();

use vars qw{$VERSION @ISA};
BEGIN {
	$VERSION = '1.215';
	@ISA     = 'PPI::Token';
}





#####################################################################
# PPI::Token::Symbol Methods

sub canonical {
	my $symbol = shift->content;
	$symbol =~ s/\s+//;
	$symbol =~ s/(?<=[\$\@\%\&\*])::/main::/;
	$symbol =~ s/\'/::/g;
	$symbol;
}

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 '%';
	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 '{}';

	}

	$symbol;
}

sub raw_type {
	substr( $_[0]->content, 0, 1 );
}

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
	my $line = substr( $t->{line}, $t->{line_cursor} );
	if ( $line =~ /^([\w:\']+)/ ) {
		$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 vars
						(?: \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;