1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
|
NAME
Devel::Declare::Parser - Higher level interface to Devel-Declare
DESCRIPTION
Devel-Declare-Parser is a higher-level API sitting on top of
Devel::Declare. It is used by Devel::Declare::Exporter to simplify
exporting of Devel::Declare magic. Writing custom parsers usually only
requires subclassing this module and overriding a couple methods.
DOCUMENTATION
Devel::Declare::Interface
This is the primary interface for those who want to use
Devel-Declare-Parser magic, and don't wantto use Exporter-Declare.
Devel::Declare::Parser
This Document covers the API for Devel::Declare::Parser. This API is
a useful reference when writing or modifying a custom parser.
SYNOPSIS
package Devel::Declare::Parser::MyParser;
use strict;
use warnings;
use base 'Devel::Declare::Parser';
use Devel::Declare::Interface;
# Create an accessor (See INTERNALS WARNING below)
__PACKAGE__->add_accessor( 'my_accessor' );
# Register the parser for use.
Devel::Declare::Interface::register_parser( 'myparser' );
# Override the rewrite() method to take the parsed bits (parts) and put the
# ones you want into new_parts.
sub rewrite {
my $self = shift;
my $parts = $self->parts;
$new_parts = $self->process_parts( $parts );
$self->new_parts( $new_parts );
1;
}
1;
OVERVIEW
This is a brief overview of how a parser is used.
WORKFLOW
Parser is constructed
Name, Declarator, and Offset are provided by Devel::Declare.
The process() method is called
The process method calls all of the following in sequence, if any
returns false, process() will return.
pre_parse()
Check if we want to process the line at all.
parse() Turn the line into 'parts' (see below).
post_parse()
Hook, currently does nothing.
rewrite()
Hook, currently takes all the arguments between the
declarator and the codeblock/semicolon (which have been
turned into 'parts' structures in the parts() attribute) and
puts them into the new_parts() attribute.
This is usually the method you want to override.
write_line()
Opens, fills in, and closes the line as a string, then
rewrites the actual line using Devel::Declare.
edit_line()
Hook, currently does nothing.
"PARTS"
'Parts' are datastructures created by the parse() method. Every argument
on the line (space separated) up until an opening curly brace ({) or a
semicolon (;) will be turned into a part. Here are the parts to expect:
Parts will either be a plain string, or an arrayref containing a string
and the quote character used to define the string. "String" or [
"String", '"' ]. Variables and operators (excluding those containing
only string characters) are typically the only parts left in a plain
string form.
See the format_parts() method for an easy way to get what you need from
a 'part' datastructure.
Bareword or Package Name
A barword name is anythign that starts with [a-zA-z] and contains
only alpha-numerics plus underscore. It is also not quoted. Examples
include my_name, something5, etc.
The structure will be an arrayref, the first element will be the
string form of the bareword name, the second element will be undef.
Example:
# my_keyword My::Package;
$part = [
'My::Package',
undef,
];
# my_keyword some_name;
$part = [
"some_name",
undef,
];
Quoted or Enclosed Element
A quoted or enclosed element includes strings quoted with single or
double quotes, and text contained within opening and closing
brackets, braces or parens (excluding the curly brace '{').
Example Structures:
# my_keyword "double quoted string";
$part = [
'double quoted string',
'"',
];
# my_keyword 'single quoted string';
$part = [
'double quoted string',
'"',
];
# my_keyword ... ( a => 'b', c => 'd' );
$part = [
" a => 'b', c => 'd' ",
"(",
];
Variable or Operator
Anything starting with a non-alphanumeric, non-quoting character
will be placed as-is (not interpolated) into a string. This catches
most variables and operators, the exception are alpha-numeric
operators such as 'eq', 'gt', 'cmp', etc. Eventually I plan to add
logic to catch all oeprators, but it appears I will have to
hard-code them.
# my_keyword $variable
$part = '$variable';
# my_keyword <=>
$part = '<=>';
EVENTUAL OUTPUT
Parser is designed such that it will transform any and all uses of your
keyword into proper function calls.
That is this:
function x { ... }
Will become this:
function( 'x', sub { ... });
Note Parser does not read in the entire codeblock, rather it injects a
statement into the start of the block that uses a callback to attach the
');' to the end of the statement. This is per the documentation of
Devel::Declare. Reading in the entire sub is not a desirable scenario.
DEVEL-DECLARE-PARSER API
INTERNALS WARNING
Parser objects are blessed arrays, not hashrefs.
If you want to create a new accessor use the add_accessor() class
method. It will take care of assigning an unused array element to the
attribute, and will create a read/write accessor sub for you.
__PACKAGE__->add_accessor( 'my_accessor' );
There are many public and private methods on the parser base class. Only
the public methods are fully documented. Be sure to refer often to the
list of private methods at the end of this document, accidently
overriding a private method could have devestating consequences.
CLASS METHODS
$class->new( $name, $declarator, $offset )
The constructor, "DO NOT OVERRIDE THIS!"
$class->DEBUG($bool)
Turn debugging on/off. This will output the line after it has been
modified, as well as some context information.
NOTE: This has a global effect, all parsers will start debugging.
UTILITY METHODS
bail( @messages )
Like croak, dies providing you context information. Since any death
occurs inside the parser, carp provides useless information.
diag( @message )
Like carp, warns providing you context information. Since the warn
occurs inside the parser carp provides useless information.
end_quote($start_char)
Find the end-character for the provide starting quote character. As
in '{' returns '}' and '(' returns ')'. If there is no counter-part
the start character is returned: "'" returns "'".
filename()
Filename the rewrite is occuring against.
linenum()
Linenum the rewrite is occuring on.
format_part()
Returns the stringified form of a part datastructure. For variables
and operators that is just the item itself as a string. For
barewords or package names it is the item itself with single quotes
wrapped around it. For quoted items it is the string wrapped in its
proper quoting characters. If a second parameter is provided (and
true) no single quotes will be added to barewords.
ACCESSORS
These are the read/write accessors used by Parser. Not all of these act
on an array element, some will directly alter the current line.
line()
This will retrieve the current line from Devel-Declare. If given a
value, that value will be set as the current line using
Devel-Declare.
name()
Name of the declarator as provided via the parser.
declarator()
Name of the declarator as provided via the Devel-Declare.
original_offset()
Offset on the line when the parsing was started.
offset()
Current line offset.
parts()
Arrayref of parts (may be undef)
new_parts()
Arrayref of new parts (may be undef)
end_char()
Will be set to the character just after the completely parsed line
(usually '{' or ';')
prototype()
Used internally for prototype tracking.
contained()
True if the parser determined this was a contained call. This means
your keyword was followed by an opening paren, and the statement
ended with a closing paren and semicolon. By default Parser will not
modify such lines.
OVERRIDABLE METHODS
These are methods you can, should, or may override in your baseclass.
quote_chars()
Specify the starting characters for quoted strings. (returns a list)
end_chars()
Characters to recognise as end of statement characters (';' and '{')
(returns a list)
inject()
Code to inject into functions enhanced by this parser.
pre_parse()
Check if we want to process the line at all.
parse()
Turn the line into 'parts'.
post_parse()
Hook, currently does nothing.
rewrite()
Hook, currently takes all the arguments between the declarator and
the codeblock/semicolon (which have been turned into 'parts'
structures in the parts() attribute) and puts them into the
new_parts() attribute.
This is usually the method you want to override.
write_line()
Opens, fills in, and closes the line as a string, then rewrites the
actual line using Devel::Declare.
edit_line()
Hook, currently does nothing.
open_line()
Usually returns '('. This is how to start a line following your
keyword
close_line()
End the line, this means either re-inserting the opening '{' on the
codeblock, along with any injections, or returning ');'
POSITION TRACKING
advance( $num_chars )
Advances the offset by $num_chars.
skip_declarator()
Skips the declarator at the start of the line.
skipspace()
Advances the offset past any whitespace.
LINE EXAMINATION (NON-MODIFYING)
These are used by pre_parse() to examine the line prior to any
modification.
is_contained()
True if the line is of the format:
keyword( ... );
is_arrow_contained()
True if the line is of the format:
keyword word_or_string => ( ... );
is_defenition()
True if the line matches the regex m/sub[\s\n]+$name/sm
PART EXAMINATION
These are methods that let you investigate the parts already parsed and
placed in the parts() attribute.
has_non_string_or_quote_parts()
Returns a list of parts that are not strings, quotes, or barewords.
has_string_or_quote_parts()
Returns a list of parts that are strings, quotes, or barewords.
has_keyword( $word )
Check for a keyword in the parts
has_comma()
has_fat_comma()
LINE EXAMINATION (MODIFYING)
This examines the line returning part structures and removing elements
from the line each time they are called.
strip_item()
strip_length()
strip_remaining_items()
LOOKING AHEAD
These methods help the parser determine what comes next in a line. In
most cases these are non-modifying.
peek_is_block()
peek_is_end()
peek_is_other()
peek_is_quote()
peek_is_word()
peek_item()
peek_item_type()
peek_num_chars()
peek_other()
peek_quote()
peek_remaining()
peek_word()
PRIVATE METHODS
Do not use these, and definitely do not override them in a subclass.
_block_end_injection()
_debug()
_edit_block_end()
_item_via_()
_linestr_offset_from_dd()
_move_via_()
_peek_is_package()
_peek_is_word()
_quoted_from_dd()
_scope_end()
_stash()
_unstash()
AUTHORS
Chad Granum exodist7@gmail.com
COPYRIGHT
Copyright (C) 2010 Chad Granum
Devel-Declare-Parser is free software; Standard perl licence.
Devel-Declare-Parser is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for
more details.
|