3 # See POD at end for documentation
8 # Set the version for CPAN
9 use vars qw{$VERSION $XS_COMPATIBLE @XS_EXCLUDE};
12 $XS_COMPATIBLE = '0.845';
18 use PPI::Exception ();
21 use PPI::Statement ();
22 use PPI::Structure ();
24 use PPI::Document::File ();
25 use PPI::Document::Fragment ();
26 use PPI::Document::Normalized ();
28 use PPI::Tokenizer ();
31 # If it is installed, load in PPI::XS
32 unless ( $PPI::XS_DISABLE ) {
33 eval { require PPI::XS };
34 # Only ignore the failure to load PPI::XS if not installed
35 die if $@ && $@ !~ /^Can't locate .*? at /;
46 PPI - Parse, Analyze and Manipulate Perl (without perl)
52 # Create a new empty document
53 my $Document = PPI::Document->new;
55 # Create a document from source
56 $Document = PPI::Document->new(\'print "Hello World!\n"');
58 # Load a Document from a file
59 $Document = PPI::Document->new('Module.pm');
61 # Does it contain any POD?
62 if ( $Document->find_any('PPI::Token::Pod') ) {
63 print "Module contains POD\n";
66 # Get the name of the main package
67 $pkg = $Document->find_first('PPI::Statement::Package')->namespace;
69 # Remove all that nasty documentation
70 $Document->prune('PPI::Token::Pod');
71 $Document->prune('PPI::Token::Comment');
74 $Document->save('Module.pm.stripped');
78 =head2 About this Document
80 This is the PPI manual. It describes its reason for existing, its general
81 structure, its use, an overview of the API, and provides a few
82 implementation samples.
86 The ability to read, and manipulate Perl (the language) programmatically
87 other than with perl (the application) was one that caused difficulty
90 The cause of this problem was Perl's complex and dynamic grammar.
91 Although there is typically not a huge diversity in the grammar of most
92 Perl code, certain issues cause large problems when it comes to parsing.
94 Indeed, quite early in Perl's history Tom Christenson introduced the Perl
95 community to the quote I<"Nothing but perl can parse Perl">, or as it is
96 more often stated now as a truism:
98 B<"Only perl can parse Perl">
100 One example of the sorts of things the prevent Perl being easily parsed are
101 function signatures, as demonstrated by the following.
103 @result = (dothis $foo, $bar);
105 # Which of the following is it equivalent to?
106 @result = (dothis($foo), $bar);
107 @result = dothis($foo, $bar);
109 The first line above can be interpreted in two different ways, depending
110 on whether the C<&dothis> function is expecting one argument, or two,
113 A "code parser" (something that parses for the purpose of execution) such
114 as perl needs information that is not found in the immediate vicinity of
115 the statement being parsed.
117 The information might not just be elsewhere in the file, it might not even be
118 in the same file at all. It might also not be able to determine this
119 information without the prior execution of a C<BEGIN {}> block, or the
120 loading and execution of one or more external modules. Or worse the &dothis
121 function may not even have been written yet.
123 B<When parsing Perl as code, you must also execute it>
125 Even perl itself never really fully understands the structure of the source
126 code after and indeed B<as> it processes it, and in that sense doesn't
127 "parse" Perl source into anything remotely like a structured document.
128 This makes it of no real use for any task that needs to treat the source
129 code as a document, and do so reliably and robustly.
131 For more information on why it is impossible to parse perl, see Randal
132 Schwartz's seminal response to the question of "Why can't you parse Perl".
134 L<http://www.perlmonks.org/index.pl?node_id=44722>
136 The purpose of PPI is B<not> to parse Perl I<Code>, but to parse Perl
137 I<Documents>. By treating the problem this way, we are able to parse a
138 single file containing Perl source code "isolated" from any other
139 resources, such as libraries upon which the code may depend, and
140 without needing to run an instance of perl alongside or inside the parser.
142 Historically, using an embedded perl parser was widely considered to be
143 the most likely avenue for finding a solution to C<Parse::Perl>. It was
144 investigated from time to time and attempts have generally failed or
145 suffered from sufficiently bad corner cases that they were abandoned.
147 =head2 What Does PPI Stand For?
149 C<PPI> is an acronym for the longer original module name
150 C<Parse::Perl::Isolated>. And in the spirit or the silly acronym games
151 played by certain unnamed Open Source projects you may have I<hurd> of,
152 it also a reverse backronym of "I Parse Perl".
154 Of course, I could just be lying and have just made that second bit up
155 10 minutes before the release of PPI 1.000. Besides, B<all> the cool
156 Perl packages have TLAs (Three Letter Acronyms). It's a rule or something.
158 Why don't you just think of it as the B<Perl Parsing Interface> for simplicity.
160 The original name was shortened to prevent the author (and you the users)
161 from contracting RSI by having to type crazy things like
162 C<Parse::Perl::Isolated::Token::QuoteLike::Backtick> 100 times a day.
164 In acknowledgment that someone may some day come up with a valid solution
165 for the grammar problem it was decided at the commencement of the project
166 to leave the C<Parse::Perl> namespace free for any such effort.
168 Since that time I've been able to prove to my own satisfaction that it
169 B<is> truly impossible to accurately parse Perl as both code and document
170 at once. For the academics, parsing Perl suffers from the "Halting Problem".
172 With this in mind C<Parse::Perl> has now been co-opted as the title for
173 the SourceForge project that publishes PPI and a large collection of other
174 applications and modules related to the (document) parsing of Perl source
177 You can find this project at L<http://sf.net/projects/parseperl>,
178 however we no longer use the SourceForge CVS server. Instead, the
179 current development version of PPI is available via SVN at
180 L<http://svn.ali.as/cpan/trunk/PPI/>.
182 =head2 Why Parse Perl?
184 Once you can accept that we will never be able to parse Perl well enough
185 to meet the standards of things that treat Perl as code, it is worth
186 re-examining C<why> we want to "parse" Perl at all.
188 What are the things that people might want a "Perl parser" for.
194 Analyzing the contents of a Perl document to automatically generate
195 documentation, in parallel to, or as a replacement for, POD documentation.
197 Allow an indexer to to locate and process all the comments and
198 documentation from code for "full text search" applications.
200 =item Structural and Quality Analysis
202 Determine quality or other metrics across a body of code, and identify
203 situations relating to particular phrases, techniques or locations.
205 Index functions, variables and packages within Perl code, and doing search
206 and graph (in the node/edge sense) analysis of large code bases.
210 Make structural, syntax, or other changes to code in an automated manner,
211 either independently or in assistance to an editor. This sort of task list
212 includes backporting, forward porting, partial evaluation, "improving" code,
213 or whatever. All the sort of things you'd want from a L<Perl::Editor>.
217 Change the layout of code without changing its meaning. This includes
218 techniques such as tidying (like L<perltidy>), obfuscation, compressing and
219 "squishing", or to implement formatting preferences or policies.
223 This includes methods of improving the presentation of code, without changing
224 the content of the code. Modify, improve, syntax colour etc the presentation
225 of a Perl document. Generating "IntelliText"-like functions.
229 If we treat this as a baseline for the sort of things we are going to have
230 to build on top of Perl, then it becomes possible to identify a standard
231 for how good a Perl parser needs to be.
233 =head2 How good is Good Enough(TM)
235 PPI seeks to be good enough to achieve all of the above tasks, or to provide
236 a sufficiently good API on which to allow others to implement modules in
237 these and related areas.
239 However, there are going to be limits to this process. Because PPI cannot
240 adapt to changing grammars, any code written using source filters should not
241 be assumed to be parsable.
243 At one extreme, this includes anything munged by L<Acme::Bleach>, as well
244 as (arguably) more common cases like L<Switch>. We do not pretend to be
245 able to always parse code using these modules, although as long as it still
246 follows a format that looks like Perl syntax, it may be possible to extend
247 the lexer to handle them.
249 The ability to extend PPI to handle lexical additions to the language is on
250 the drawing board to be done some time post-1.0
252 The goal for success was originally to be able to successfully parse 99% of
253 all Perl documents contained in CPAN. This means the entire file in each
256 PPI has succeeded in this goal far beyond the expectations of even the
257 author. At time of writing there are only 28 non-Acme Perl modules in CPAN
258 that PPI is incapable of parsing. Most of these are so badly broken they
259 do not compile as Perl code anyway.
261 So unless you are actively going out of your way to break PPI, you should
262 expect that it will handle your code just fine.
264 =head2 Internationalisation
266 PPI provides partial support for internationalisation and localisation.
268 Specifically, it allows the use characters from the Latin-1 character
269 set to be used in quotes, comments, and POD. Primarily, this covers
270 languages from Europe and South America.
272 PPI does B<not> currently provide support for Unicode, although there
273 is an initial implementation available in a development branch from
276 If you need Unicode support, and would like to help stress test the
277 Unicode support so we can move it to the main branch and enable it
278 in the main release should contact the author. (contact details below)
280 =head2 Round Trip Safe
282 When PPI parses a file it builds B<everything> into the model, including
283 whitespace. This is needed in order to make the Document fully "Round Trip"
286 The general concept behind a "Round Trip" parser is that it knows what it
287 is parsing is somewhat uncertain, and so B<expects> to get things wrong
288 from time to time. In the cases where it parses code wrongly the tree
289 will serialize back out to the same string of code that was read in,
290 repairing the parser's mistake as it heads back out to the file.
292 The end result is that if you parse in a file and serialize it back out
293 without changing the tree, you are guaranteed to get the same file you
294 started with. PPI does this correctly and reliably for 100% of all known
297 B<What goes in, will come out. Every time.>
299 The one minor exception at this time is that if the newlines for your file
300 are wrong (meaning not matching the platform newline format), PPI will
301 localise them for you. (It isn't to be convenient, supporting
302 arbitrary newlines would make some of the code more complicated)
304 Better control of the newline type is on the wish list though, and
305 anyone wanting to help out is encouraged to contact the author.
307 =head1 IMPLEMENTATION
309 =head2 General Layout
311 PPI is built upon two primary "parsing" components, L<PPI::Tokenizer>
312 and L<PPI::Lexer>, and a large tree of about 50 classes which implement
313 the various the I<Perl Document Object Model> (PDOM).
315 The PDOM is conceptually similar in style and intent to the regular DOM or
316 other code Abstract Syntax Trees (ASTs), but contains some differences
317 to handle perl-specific cases, and to assist in treating the code as a
318 document. Please note that it is B<not> an implementation of the official
319 Document Object Model specification, only somewhat similar to it.
321 On top of the Tokenizer, Lexer and the classes of the PDOM, sit a number
322 of classes intended to make life a little easier when dealing with PDOM
325 Both the major parsing components were hand-coded from scratch with only
326 plain Perl code and a few small utility modules. There are no grammar or
327 patterns mini-languages, no YACC or LEX style tools and only a small number
328 of regular expressions.
330 This is primarily because of the sheer volume of accumulated cruft that
331 exists in Perl. Not even perl itself is capable of parsing Perl documents
332 (remember, it just parses and executes it as code).
334 As a result, PPI needed to be cruftier than perl itself. Feel free to
335 shudder at this point, and hope you never have to understand the Tokenizer
336 codebase. Speaking of which...
340 The Tokenizer takes source code and converts it into a series of tokens. It
341 does this using a slow but thorough character by character manual process,
342 rather than using a pattern system or complex regexes.
344 Or at least it does so conceptually. If you were to actually trace the code
345 you would find it's not truly character by character due to a number of
346 regexps and optimisations throughout the code. This lets the Tokenizer
347 "skip ahead" when it can find shortcuts, so it tends to jump around a line
348 a bit wildly at times.
350 In practice, the number of times the Tokenizer will B<actually> move the
351 character cursor itself is only about 5% - 10% higher than the number of
352 tokens contained in the file. This makes it about as optimal as it can be
353 made without implementing it in something other than Perl.
355 In 2001 when PPI was started, this structure made PPI quite slow, and not
356 really suitable for interactive tasks. This situation has improved greatly
357 with multi-gigahertz processors, but can still be painful when working with
360 The target parsing rate for PPI is about 5000 lines per gigacycle. It is
361 currently believed to be at about 1500, and main avenue for making it to
362 the target speed has now become L<PPI::XS>, a drop-in XS accelerator for
365 Since L<PPI::XS> has only just gotten off the ground and is currently only
366 at proof-of-concept stage, this may take a little while. Anyone interested
367 in helping out with L<PPI::XS> is B<highly> encouraged to contact the
368 author. In fact, the design of L<PPI::XS> means it's possible to port
369 one function at a time safely and reliably. So every little bit will help.
373 The Lexer takes a token stream, and converts it to a lexical tree. Because
374 we are parsing Perl B<documents> this includes whitespace, comments, and
375 all number of weird things that have no relevance when code is actually
378 An instantiated L<PPI::Lexer> consumes L<PPI::Tokenizer> objects and
379 produces L<PPI::Document> objects. However you should probably never be
380 working with the Lexer directly. You should just be able to create
381 L<PPI::Document> objects and work with them directly.
383 =head2 The Perl Document Object Model
385 The PDOM is a structured collection of data classes that together provide
386 a correct and scalable model for documents that follow the standard Perl
389 =head2 The PDOM Class Tree
391 The following lists all of the 67 current PDOM classes, listing with indentation
392 based on inheritance.
397 PPI::Document::Fragment
399 PPI::Statement::Package
400 PPI::Statement::Include
402 PPI::Statement::Scheduled
403 PPI::Statement::Compound
404 PPI::Statement::Break
405 PPI::Statement::Given
409 PPI::Statement::Expression
410 PPI::Statement::Variable
412 PPI::Statement::UnmatchedBrace
413 PPI::Statement::Unknown
415 PPI::Structure::Block
416 PPI::Structure::Subscript
417 PPI::Structure::Constructor
418 PPI::Structure::Condition
421 PPI::Structure::Given
423 PPI::Structure::Unknown
425 PPI::Token::Whitespace
429 PPI::Token::Number::Binary
430 PPI::Token::Number::Octal
431 PPI::Token::Number::Hex
432 PPI::Token::Number::Float
433 PPI::Token::Number::Exp
434 PPI::Token::Number::Version
436 PPI::Token::DashedWord
439 PPI::Token::ArrayIndex
442 PPI::Token::Quote::Single
443 PPI::Token::Quote::Double
444 PPI::Token::Quote::Literal
445 PPI::Token::Quote::Interpolate
446 PPI::Token::QuoteLike
447 PPI::Token::QuoteLike::Backtick
448 PPI::Token::QuoteLike::Command
449 PPI::Token::QuoteLike::Regexp
450 PPI::Token::QuoteLike::Words
451 PPI::Token::QuoteLike::Readline
453 PPI::Token::Regexp::Match
454 PPI::Token::Regexp::Substitute
455 PPI::Token::Regexp::Transliterate
458 PPI::Token::Structure
460 PPI::Token::Separator
463 PPI::Token::Prototype
464 PPI::Token::Attribute
467 To summarize the above layout, all PDOM objects inherit from the
468 L<PPI::Element> class.
470 Under this are L<PPI::Token>, strings of content with a known type,
471 and L<PPI::Node>, syntactically significant containers that hold other
474 The three most important of these are the L<PPI::Document>, the
475 L<PPI::Statement> and the L<PPI::Structure> classes.
477 =head2 The Document, Statement and Structure
479 At the top of all complete PDOM trees is a L<PPI::Document> object. It
480 represents a complete file of Perl source code as you might find it on
483 There are some specialised types of document, such as L<PPI::Document::File>
484 and L<PPI::Document::Normalized> but for the purposes of the PDOM they are
485 all just considered to be the same thing.
487 Each Document will contain a number of B<Statements>, B<Structures> and
490 A L<PPI::Statement> is any series of Tokens and Structures that are treated
491 as a single contiguous statement by perl itself. You should note that a
492 Statement is as close as PPI can get to "parsing" the code in the sense that
493 perl-itself parses Perl code when it is building the op-tree.
495 Because of the isolation and Perl's syntax, it is provably impossible for
496 PPI to accurately determine precedence of operators or which tokens are
497 implicit arguments to a sub call.
499 So rather than lead you on with a bad guess that has a strong chance of
500 being wrong, PPI does not attempt to determine precedence or sub parameters
503 At a fundamental level, it only knows that this series of elements
504 represents a single Statement as perl sees it, but it can do so with
505 enough certainty that it can be trusted.
507 However, for specific Statement types the PDOM is able to derive additional
508 useful information about their meaning. For the best, most useful, and most
509 heavily used example, see L<PPI::Statement::Include>.
511 A L<PPI::Structure> is any series of tokens contained within matching braces.
512 This includes code blocks, conditions, function argument braces, anonymous
513 array and hash constructors, lists, scoping braces and all other syntactic
514 structures represented by a matching pair of braces, including (although it
515 may not seem obvious at first) C<E<lt>READLINEE<gt>> braces.
517 Each Structure contains none, one, or many Tokens and Structures (the rules
518 for which vary for the different Structure subclasses)
520 Under the PDOM structure rules, a Statement can B<never> directly contain
521 another child Statement, a Structure can B<never> directly contain another
522 child Structure, and a Document can B<never> contain another Document
523 anywhere in the tree.
525 Aside from these three rules, the PDOM tree is extremely flexible.
527 =head2 The PDOM at Work
529 To demonstrate the PDOM in use lets start with an example showing how the
530 tree might look for the following chunk of simple Perl code.
534 print( "Hello World!" );
538 Translated into a PDOM tree it would have the following structure (as shown
539 via the included L<PPI::Dumper>).
542 PPI::Token::Comment '#!/usr/bin/perl\n'
543 PPI::Token::Whitespace '\n'
544 PPI::Statement::Expression
545 PPI::Token::Bareword 'print'
546 PPI::Structure::List ( ... )
547 PPI::Token::Whitespace ' '
548 PPI::Statement::Expression
549 PPI::Token::Quote::Double '"Hello World!"'
550 PPI::Token::Whitespace ' '
551 PPI::Token::Structure ';'
552 PPI::Token::Whitespace '\n'
553 PPI::Token::Whitespace '\n'
554 PPI::Statement::Expression
555 PPI::Token::Bareword 'exit'
556 PPI::Structure::List ( ... )
557 PPI::Token::Structure ';'
558 PPI::Token::Whitespace '\n'
560 Please note that in this this example, strings are only listed for the
561 B<actual> L<PPI::Token> that contains that string. Structures are listed
562 with the type of brace characters it represents noted.
564 The L<PPI::Dumper> module can be used to generate similar trees yourself.
566 We can make that PDOM dump a little easier to read if we strip out all the
567 whitespace. Here it is again, sans the distracting whitespace tokens.
570 PPI::Token::Comment '#!/usr/bin/perl\n'
571 PPI::Statement::Expression
572 PPI::Token::Bareword 'print'
573 PPI::Structure::List ( ... )
574 PPI::Statement::Expression
575 PPI::Token::Quote::Double '"Hello World!"'
576 PPI::Token::Structure ';'
577 PPI::Statement::Expression
578 PPI::Token::Bareword 'exit'
579 PPI::Structure::List ( ... )
580 PPI::Token::Structure ';'
582 As you can see, the tree can get fairly deep at time, especially when every
583 isolated token in a bracket becomes its own statement. This is needed to
584 allow anything inside the tree the ability to grow. It also makes the
585 search and analysis algorithms much more flexible.
587 Because of the depth and complexity of PDOM trees, a vast number of very easy
588 to use methods have been added wherever possible to help people working with
589 PDOM trees do normal tasks relatively quickly and efficiently.
591 =head2 Overview of the Primary Classes
593 The main PPI classes, and links to their own documentation, are listed
594 here in alphabetical order.
598 =item L<PPI::Document>
600 The Document object, the root of the PDOM.
602 =item L<PPI::Document::Fragment>
604 A cohesive fragment of a larger Document. Although not of any real current
605 use, it is needed for use in certain internal tree manipulation
608 For example, doing things like cut/copy/paste etc. Very similar to a
609 L<PPI::Document>, but has some additional methods and does not represent
610 a lexical scope boundary.
612 A document fragment is also non-serializable, and so cannot be written out
617 A simple class for dumping readable debugging versions of PDOM structures,
618 such as in the demonstration above.
620 =item L<PPI::Element>
622 The Element class is the abstract base class for all objects within the PDOM
626 Implements an instantiable object form of a PDOM tree search.
630 The PPI Lexer. Converts Token streams into PDOM trees.
634 The Node object, the abstract base class for all PDOM objects that can
635 contain other Elements, such as the Document, Statement and Structure
638 =item L<PPI::Statement>
640 The base class for all Perl statements. Generic "evaluate for side-effects"
641 statements are of this actual type. Other more interesting statement types
642 belong to one of its children.
644 See it's own documentation for a longer description and list of all of the
645 different statement types and sub-classes.
647 =item L<PPI::Structure>
649 The abstract base class for all structures. A Structure is a language
650 construct consisting of matching braces containing a set of other elements.
652 See the L<PPI::Structure> documentation for a description and
653 list of all of the different structure types and sub-classes.
657 A token is the basic unit of content. At its most basic, a Token is just
658 a string tagged with metadata (its class, and some additional flags in
661 =item L<PPI::Token::_QuoteEngine>
663 The L<PPI::Token::Quote> and L<PPI::Token::QuoteLike> classes provide
664 abstract base classes for the many and varied types of quote and
665 quote-like things in Perl. However, much of the actual quote login is
666 implemented in a separate quote engine, based at
667 L<PPI::Token::_QuoteEngine>.
669 Classes that inherit from L<PPI::Token::Quote>, L<PPI::Token::QuoteLike>
670 and L<PPI::Token::Regexp> are generally parsed only by the Quote Engine.
672 =item L<PPI::Tokenizer>
674 The PPI Tokenizer. One Tokenizer consumes a chunk of text and provides
675 access to a stream of L<PPI::Token> objects.
677 The Tokenizer is very very complicated, to the point where even the author
678 treads carefully when working with it.
680 Most of the complication is the result of optimizations which have tripled
681 the tokenization speed, at the expense of maintainability. We cope with the
682 spaghetti by heavily commenting everything.
684 =item L<PPI::Transform>
686 The Perl Document Transformation API. Provides a standard interface and
687 abstract base class for objects and classes that manipulate Documents.
693 The core PPI distribution is pure Perl and has been kept as tight as
694 possible and with as few dependencies as possible.
696 It should download and install normally on any platform from within
697 the CPAN and CPANPLUS applications, or directly using the distribution
698 tarball. If installing by hand, you may need to install a few small
699 utility modules first. The exact ones will depend on your version of
702 There are no special install instructions for PPI, and the normal
703 C<Perl Makefile.PL>, C<make>, C<make test>, C<make install> instructions
708 The PPI namespace itself is reserved for the sole use of the modules under
709 the umbrella of the C<Parse::Perl> SourceForge project.
711 L<http://sf.net/projects/parseperl>
713 You are recommended to use the PPIx:: namespace for PPI-specific
714 modifications or prototypes thereof, or Perl:: for modules which provide
715 a general Perl language-related functions.
717 If what you wish to implement looks like it fits into PPIx:: namespace,
718 you should consider contacting the C<Parse::Perl> mailing list (detailed on
719 the SourceForge site) first, as what you want may already be in progress,
720 or you may wish to consider joining the team and doing it within the
721 C<Parse::Perl> project itself.
725 - Many more analysis and utility methods for PDOM classes
727 - Creation of a PPI::Tutorial document
729 - Add many more key functions to PPI::XS
731 - We can B<always> write more and better unit tests
733 - Complete the full implementation of -E<gt>literal (1.200)
735 - Full understanding of scoping (due 1.300)
739 This module is stored in an Open Repository at the following address.
741 L<http://svn.ali.as/cpan/trunk/PPI>
743 Write access to the repository is made available automatically to any
744 published CPAN author, and to most other volunteers on request.
746 If you are able to submit your bug report in the form of new (failing)
747 unit tests, or can apply your fix directly instead of submitting a patch,
748 you are B<strongly> encouraged to do so, as the author currently maintains
749 over 100 modules and it can take some time to deal with non-"Critical" bug
752 This will also guarentee that your issue will be addressed in the next
753 release of the module.
755 For large changes though, please consider creating a branch so that they
756 can be properly reviewed and trialed before being applied to the trunk.
758 If you cannot provide a direct test or fix, or don't have time to do so,
759 then regular bug reports are still accepted and appreciated via the CPAN
762 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=PPI>
764 For other issues or questions, contact the C<Parse::Perl> project mailing
767 For commercial or media-related enquiries, or to have your SVN commit bit
768 enabled, contact the author.
772 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
774 =head1 ACKNOWLEDGMENTS
776 A huge thank you to Phase N Australia (L<http://phase-n.com/>) for
777 permitting the original open sourcing and release of this distribution
778 from what was originally several thousand hours of commercial work.
780 Another big thank you to The Perl Foundation
781 (L<http://www.perlfoundation.org/>) for funding for the final big
782 refactoring and completion run.
784 Also, to the various co-maintainers that have contributed both large and
785 small with tests and patches and especially to those rare few who have
786 deep-dived into the guts to (gasp) add a feature.
788 - Dan Brook : PPIx::XPath, Acme::PerlML
789 - Audrey Tang : "Line Noise" Testing
790 - Arjen Laarhoven : Three-element ->location support
791 - Elliot Shank : Perl 5.10 support, five-element ->location
793 And finally, thanks to those brave ( and foolish :) ) souls willing to dive
794 in and use, test drive and provide feedback on PPI before version 1.000,
795 in some cases before it made it to beta quality, and still did extremely
796 distasteful things (like eating 50 meg of RAM a second).
798 I owe you all a beer. Corner me somewhere and collect at your convenience.
799 If I missed someone who wasn't in my email history, thank you too :)
801 # In approximate order of appearance
805 - CPAN Author "CHOCOLATEBOY"
807 - CPAN Author "PODMASTER"
809 - Nadim ibn Hamouda el Khemir
820 - CPAN Author "CHROMATIC"
827 And to single one person out, thanks go to Randal Schwartz who
828 spent a great number of hours in IRC over a critical 6 month period
829 explaining why Perl is impossibly unparsable and constantly shoving evil
830 and ugly corner cases in my face. He remained a tireless devil's advocate,
831 and without his support this project genuinely could never have been
834 So for my schooling in the Deep Magiks, you have my deepest gratitude Randal.
838 Copyright 2001 - 2009 Adam Kennedy.
840 This program is free software; you can redistribute
841 it and/or modify it under the same terms as Perl itself.
843 The full text of the license can be found in the
844 LICENSE file included with this module.