Version 0.006004
[p5sagit/Devel-Declare.git] / lib / Devel / Declare / Context / Simple.pm
CommitLineData
e7be1784 1package Devel::Declare::Context::Simple;
2
e7be1784 3use strict;
4use warnings;
616311ae 5use Devel::Declare ();
6use B::Hooks::EndOfScope;
7use Carp qw/confess/;
e7be1784 8
9sub new {
5b27c9b2 10 my $class = shift;
11 bless {@_}, $class;
e7be1784 12}
13
14sub init {
5b27c9b2 15 my $self = shift;
16 @{$self}{ qw(Declarator Offset) } = @_;
ab449c2e 17 return $self;
e7be1784 18}
19
ab449c2e 20sub offset {
21 my $self = shift;
22 return $self->{Offset}
23}
24
25sub inc_offset {
26 my $self = shift;
27 $self->{Offset} += shift;
28}
29
30sub declarator {
31 my $self = shift;
32 return $self->{Declarator}
33}
e7be1784 34
35sub skip_declarator {
5b27c9b2 36 my $self = shift;
616311ae 37 my $decl = $self->declarator;
38 my $len = Devel::Declare::toke_scan_word($self->offset, 0);
39 confess "Couldn't find declarator '$decl'"
40 unless $len;
41
42 my $linestr = $self->get_linestr;
43 my $name = substr($linestr, $self->offset, $len);
44 confess "Expected declarator '$decl', got '${name}'"
45 unless $name eq $decl;
46
47 $self->inc_offset($len);
e7be1784 48}
49
50sub skipspace {
5b27c9b2 51 my $self = shift;
ab449c2e 52 $self->inc_offset(Devel::Declare::toke_skipspace($self->offset));
e7be1784 53}
54
7a3f5539 55sub get_linestr {
56 my $self = shift;
57 my $line = Devel::Declare::get_linestr();
58 return $line;
59}
60
61sub set_linestr {
62 my $self = shift;
63 my ($line) = @_;
64 Devel::Declare::set_linestr($line);
65}
66
e7be1784 67sub strip_name {
5b27c9b2 68 my $self = shift;
69 $self->skipspace;
70 if (my $len = Devel::Declare::toke_scan_word( $self->offset, 1 )) {
7a3f5539 71 my $linestr = $self->get_linestr();
5b27c9b2 72 my $name = substr( $linestr, $self->offset, $len );
73 substr( $linestr, $self->offset, $len ) = '';
7a3f5539 74 $self->set_linestr($linestr);
5b27c9b2 75 return $name;
76 }
b0a89632 77
78 $self->skipspace;
5b27c9b2 79 return;
e7be1784 80}
81
c0f4fa58 82sub strip_ident {
83 my $self = shift;
84 $self->skipspace;
85 if (my $len = Devel::Declare::toke_scan_ident( $self->offset )) {
86 my $linestr = $self->get_linestr();
87 my $ident = substr( $linestr, $self->offset, $len );
88 substr( $linestr, $self->offset, $len ) = '';
89 $self->set_linestr($linestr);
90 return $ident;
91 }
92
93 $self->skipspace;
94 return;
95}
96
e7be1784 97sub strip_proto {
5b27c9b2 98 my $self = shift;
99 $self->skipspace;
100
7a3f5539 101 my $linestr = $self->get_linestr();
b0a89632 102 if (substr($linestr, $self->offset, 1) eq '(') {
103 my $length = Devel::Declare::toke_scan_str($self->offset);
7a3f5539 104 my $proto = Devel::Declare::get_lex_stuff();
5b27c9b2 105 Devel::Declare::clear_lex_stuff();
86964fb3 106 $linestr = $self->get_linestr();
7a3f5539 107
b0a89632 108 substr($linestr, $self->offset, $length) = '';
7a3f5539 109 $self->set_linestr($linestr);
110
5b27c9b2 111 return $proto;
112 }
113 return;
e7be1784 114}
115
01fadf71 116sub strip_names_and_args {
117 my $self = shift;
118 $self->skipspace;
119
120 my @args;
121
122 my $linestr = $self->get_linestr;
123 if (substr($linestr, $self->offset, 1) eq '(') {
124 # We had a leading paren, so we will now expect comma separated
125 # arguments
126 substr($linestr, $self->offset, 1) = '';
127 $self->set_linestr($linestr);
128 $self->skipspace;
129
130 # At this point we expect to have a comma-separated list of
131 # barewords with optional protos afterward, so loop until we
132 # run out of comma-separated values
133 while (1) {
134 # Get the bareword
135 my $thing = $self->strip_name;
79f9fba8 136 # If there's no bareword here, bail
137 confess "failed to parse bareword. found ${linestr}"
138 unless defined $thing;
01fadf71 139
140 $linestr = $self->get_linestr;
141 if (substr($linestr, $self->offset, 1) eq '(') {
142 # This one had a proto, pull it out
143 push(@args, [ $thing, $self->strip_proto ]);
144 } else {
145 # This had no proto, so store it with an undef
146 push(@args, [ $thing, undef ]);
147 }
148 $self->skipspace;
149 $linestr = $self->get_linestr;
150
151 if (substr($linestr, $self->offset, 1) eq ',') {
152 # We found a comma, strip it out and set things up for
153 # another iteration
154 substr($linestr, $self->offset, 1) = '';
155 $self->set_linestr($linestr);
156 $self->skipspace;
157 } else {
158 # No comma, get outta here
159 last;
160 }
161 }
162
163 # look for the final closing paren of the list
164 if (substr($linestr, $self->offset, 1) eq ')') {
165 substr($linestr, $self->offset, 1) = '';
166 $self->set_linestr($linestr);
167 $self->skipspace;
168 }
169 else {
170 # fail if it isn't there
79f9fba8 171 confess "couldn't find closing paren for argument. found ${linestr}"
01fadf71 172 }
173 } else {
174 # No parens, so expect a single arg
175 my $thing = $self->strip_name;
79f9fba8 176 # If there's no bareword here, bail
177 confess "failed to parse bareword. found ${linestr}"
178 unless defined $thing;
01fadf71 179 $linestr = $self->get_linestr;
180 if (substr($linestr, $self->offset, 1) eq '(') {
181 # This one had a proto, pull it out
182 push(@args, [ $thing, $self->strip_proto ]);
183 } else {
184 # This had no proto, so store it with an undef
185 push(@args, [ $thing, undef ]);
186 }
187 }
188
189 return \@args;
190}
191
9de3c057 192sub strip_attrs {
193 my $self = shift;
194 $self->skipspace;
195
196 my $linestr = Devel::Declare::get_linestr;
197 my $attrs = '';
198
199 if (substr($linestr, $self->offset, 1) eq ':') {
200 while (substr($linestr, $self->offset, 1) ne '{') {
201 if (substr($linestr, $self->offset, 1) eq ':') {
202 substr($linestr, $self->offset, 1) = '';
203 Devel::Declare::set_linestr($linestr);
204
205 $attrs .= ':';
206 }
207
208 $self->skipspace;
209 $linestr = Devel::Declare::get_linestr();
210
211 if (my $len = Devel::Declare::toke_scan_word($self->offset, 0)) {
212 my $name = substr($linestr, $self->offset, $len);
213 substr($linestr, $self->offset, $len) = '';
214 Devel::Declare::set_linestr($linestr);
215
216 $attrs .= " ${name}";
217
218 if (substr($linestr, $self->offset, 1) eq '(') {
219 my $length = Devel::Declare::toke_scan_str($self->offset);
220 my $arg = Devel::Declare::get_lex_stuff();
221 Devel::Declare::clear_lex_stuff();
222 $linestr = Devel::Declare::get_linestr();
223 substr($linestr, $self->offset, $length) = '';
224 Devel::Declare::set_linestr($linestr);
225
226 $attrs .= "(${arg})";
227 }
228 }
229 }
230
231 $linestr = Devel::Declare::get_linestr();
232 }
233
234 return $attrs;
235}
236
237
e7be1784 238sub get_curstash_name {
5b27c9b2 239 return Devel::Declare::get_curstash_name;
e7be1784 240}
241
242sub shadow {
ab449c2e 243 my $self = shift;
5b27c9b2 244 my $pack = $self->get_curstash_name;
245 Devel::Declare::shadow_sub( $pack . '::' . $self->declarator, $_[0] );
e7be1784 246}
247
248sub inject_if_block {
b0a89632 249 my $self = shift;
5b27c9b2 250 my $inject = shift;
b0a89632 251 my $before = shift || '';
252
5b27c9b2 253 $self->skipspace;
b0a89632 254
7a3f5539 255 my $linestr = $self->get_linestr;
b0a89632 256 if (substr($linestr, $self->offset, 1) eq '{') {
257 substr($linestr, $self->offset + 1, 0) = $inject;
258 substr($linestr, $self->offset, 0) = $before;
7a3f5539 259 $self->set_linestr($linestr);
712c5dd1 260 return 1;
5b27c9b2 261 }
712c5dd1 262 return 0;
e7be1784 263}
264
265sub scope_injector_call {
b0a89632 266 my $self = shift;
267 my $inject = shift || '';
268 return ' BEGIN { ' . ref($self) . "->inject_scope('${inject}') }; ";
e7be1784 269}
270
271sub inject_scope {
b0a89632 272 my $class = shift;
273 my $inject = shift;
274 on_scope_end {
5b27c9b2 275 my $linestr = Devel::Declare::get_linestr;
b0a89632 276 return unless defined $linestr;
5b27c9b2 277 my $offset = Devel::Declare::get_linestr_offset;
b0a89632 278 substr( $linestr, $offset, 0 ) = ';' . $inject;
5b27c9b2 279 Devel::Declare::set_linestr($linestr);
b0a89632 280 };
e7be1784 281}
282
2831;
b0a89632 284# vi:sw=2 ts=2