File Coverage

blib/lib/PPI/Token/Structure.pm
Criterion Covered Total %
statement 38 38 100.0
branch 29 32 90.6
condition n/a
subroutine 11 11 100.0
pod 6 6 100.0
total 84 87 96.5


line stmt bran cond sub pod time code
1             package PPI::Token::Structure;
2              
3             =pod
4              
5             =head1 NAME
6              
7             PPI::Token::Structure - Token class for characters that define code structure
8              
9             =head1 INHERITANCE
10              
11             PPI::Token::Structure
12             isa PPI::Token
13             isa PPI::Element
14              
15             =head1 DESCRIPTION
16              
17             The C class is used for tokens that control the
18             general tree structure or code.
19              
20             This consists of seven characters. These are the six brace characters from
21             the "round", "curly" and "square" pairs, plus the semi-colon statement
22             separator C<;>.
23              
24             =head1 METHODS
25              
26             This class has no methods beyond what is provided by its
27             L and L parent classes.
28              
29             =cut
30              
31 65     65   367 use strict;
  65         120  
  65         1442  
32 65     65   261 use PPI::Token ();
  65         117  
  65         36900  
33              
34             our $VERSION = '1.276';
35              
36             our @ISA = "PPI::Token";
37              
38             # Set the matching braces, done as an array
39             # for slightly faster lookups.
40             my %MATCH = (
41             ord '{' => '}',
42             ord '}' => '{',
43             ord '[' => ']',
44             ord ']' => '[',
45             ord '(' => ')',
46             ord ')' => '(',
47             );
48             my %OPENS = (
49             ord '{' => 1,
50             ord '[' => 1,
51             ord '(' => 1,
52             );
53             my %CLOSES = (
54             ord '}' => 1,
55             ord ']' => 1,
56             ord ')' => 1,
57             );
58              
59              
60              
61              
62              
63             #####################################################################
64             # Tokenizer Methods
65              
66             sub __TOKENIZER__on_char {
67             # Structures are one character long, always.
68             # Finalize and process again.
69 8063     8063   14991 $_[1]->_finalize_token->__TOKENIZER__on_char( $_[1] );
70             }
71              
72             sub __TOKENIZER__commit {
73 59078     59078   73091 my $t = $_[1];
74 59078         161872 $t->_new_token( 'Structure', substr( $t->{line}, $t->{line_cursor}, 1 ) );
75 59078         137659 $t->_finalize_token;
76 59078         132581 0;
77             }
78              
79              
80              
81              
82              
83             #####################################################################
84             # Lexer Methods
85              
86             # For a given brace, find its opposing pair
87             sub __LEXER__opposite {
88 20337     20337   59777 $MATCH{ord $_[0]->{content}};
89             }
90              
91              
92              
93              
94              
95             #####################################################################
96             # PPI::Element Methods
97              
98             # There is a unusual situation in regards to "siblings".
99             #
100             # As an Element, braces sit outside the normal tree structure, and in
101             # this context they NEVER have siblings.
102             #
103             # However, as tokens they DO have siblings.
104             #
105             # As such, we need special versions of _all_ of the sibling methods to
106             # handle this.
107             #
108             # Statement terminators do not have these problems, and for them sibling
109             # calls work as normal, and so they can just be passed upwards.
110              
111             sub next_sibling {
112 8 100   8 1 36 return $_[0]->SUPER::next_sibling if $_[0]->{content} eq ';';
113 1         190 return '';
114             }
115              
116             sub snext_sibling {
117 2 100   2 1 740 return $_[0]->SUPER::snext_sibling if $_[0]->{content} eq ';';
118 1         5 return '';
119             }
120              
121             sub previous_sibling {
122 5 100   5 1 20 return $_[0]->SUPER::previous_sibling if $_[0]->{content} eq ';';
123 1         5 return '';
124             }
125              
126             sub sprevious_sibling {
127 2 100   2 1 14 return $_[0]->SUPER::sprevious_sibling if $_[0]->{content} eq ';';
128 1         4 return '';
129             }
130              
131             sub next_token {
132 17     17 1 448 my $self = shift;
133 17 100       45 return $self->SUPER::next_token if $self->{content} eq ';';
134 14 50       34 my $structure = $self->parent or return '';
135              
136             # If this is an opening brace, descend down into our parent
137             # structure, if it has children.
138 14 100       34 if ( $OPENS{ ord $self->{content} } ) {
139 7         26 my $child = $structure->child(0);
140 7 100       19 if ( $child ) {
    100          
141             # Decend deeper, or return if it is a token
142 5 100       20 return $child->isa('PPI::Token') ? $child : $child->first_token;
143             } elsif ( $structure->finish ) {
144             # Empty structure, so next is closing brace
145 1         4 return $structure->finish;
146             }
147              
148             # Anything that slips through to here is a structure
149             # with an opening brace, but no closing brace, so we
150             # just have to go with it, and continue as we would
151             # if we started with a closing brace.
152             }
153              
154             # We can use the default implement, if we call it from the
155             # parent structure of the closing brace.
156 8         32 $structure->next_token;
157             }
158              
159             sub previous_token {
160 16     16 1 45 my $self = shift;
161 16 100       35 return $self->SUPER::previous_token if $self->{content} eq ';';
162 13 50       27 my $structure = $self->parent or return '';
163              
164             # If this is a closing brace, descend down into our parent
165             # structure, if it has children.
166 13 100       30 if ( $CLOSES{ ord $self->{content} } ) {
167 7         16 my $child = $structure->child(-1);
168 7 100       18 if ( $child ) {
    50          
169             # Decend deeper, or return if it is a token
170 6 100       26 return $child->isa('PPI::Token') ? $child : $child->last_token;
171             } elsif ( $structure->start ) {
172             # Empty structure, so next is closing brace
173 1         3 return $structure->start;
174             }
175              
176             # Anything that slips through to here is a structure
177             # with a closing brace, but no opening brace, so we
178             # just have to go with it, and continue as we would
179             # if we started with an opening brace.
180             }
181              
182             # We can use the default implement, if we call it from the
183             # parent structure of the closing brace.
184 6         18 $structure->previous_token;
185             }
186              
187             1;
188              
189             =pod
190              
191             =head1 SUPPORT
192              
193             See the L in the main module.
194              
195             =head1 AUTHOR
196              
197             Adam Kennedy Eadamk@cpan.orgE
198              
199             =head1 COPYRIGHT
200              
201             Copyright 2001 - 2011 Adam Kennedy.
202              
203             This program is free software; you can redistribute
204             it and/or modify it under the same terms as Perl itself.
205              
206             The full text of the license can be found in the
207             LICENSE file included with this module.
208              
209             =cut