1PPI(3) User Contributed Perl Documentation PPI(3)
2
3
4
6 PPI - Parse, Analyze and Manipulate Perl (without perl)
7
9 use PPI;
10
11 # Create a new empty document
12 my $Document = PPI::Document->new;
13
14 # Create a document from source
15 $Document = PPI::Document->new(\'print "Hello World!\n"');
16
17 # Load a Document from a file
18 $Document = PPI::Document->new('Module.pm');
19
20 # Does it contain any POD?
21 if ( $Document->find_any('PPI::Token::Pod') ) {
22 print "Module contains POD\n";
23 }
24
25 # Get the name of the main package
26 $pkg = $Document->find_first('PPI::Statement::Package')->namespace;
27
28 # Remove all that nasty documentation
29 $Document->prune('PPI::Token::Pod');
30 $Document->prune('PPI::Token::Comment');
31
32 # Save the file
33 $Document->save('Module.pm.stripped');
34
36 About this Document
37 This is the PPI manual. It describes its reason for existing, its
38 general structure, its use, an overview of the API, and provides a few
39 implementation samples.
40
41 Background
42 The ability to read, and manipulate Perl (the language)
43 programmatically other than with perl (the application) was one that
44 caused difficulty for a long time.
45
46 The cause of this problem was Perl's complex and dynamic grammar.
47 Although there is typically not a huge diversity in the grammar of most
48 Perl code, certain issues cause large problems when it comes to
49 parsing.
50
51 Indeed, quite early in Perl's history Tom Christiansen introduced the
52 Perl community to the quote "Nothing but perl can parse Perl", or as it
53 is more often stated now as a truism:
54
55 "Only perl can parse Perl"
56
57 One example of the sorts of things the prevent Perl being easily parsed
58 are function signatures, as demonstrated by the following.
59
60 @result = (dothis $foo, $bar);
61
62 # Which of the following is it equivalent to?
63 @result = (dothis($foo), $bar);
64 @result = dothis($foo, $bar);
65
66 The first line above can be interpreted in two different ways,
67 depending on whether the &dothis function is expecting one argument, or
68 two, or several.
69
70 A "code parser" (something that parses for the purpose of execution)
71 such as perl needs information that is not found in the immediate
72 vicinity of the statement being parsed.
73
74 The information might not just be elsewhere in the file, it might not
75 even be in the same file at all. It might also not be able to determine
76 this information without the prior execution of a "BEGIN {}" block, or
77 the loading and execution of one or more external modules. Or worse the
78 &dothis function may not even have been written yet.
79
80 When parsing Perl as code, you must also execute it
81
82 Even perl itself never really fully understands the structure of the
83 source code after and indeed as it processes it, and in that sense
84 doesn't "parse" Perl source into anything remotely like a structured
85 document. This makes it of no real use for any task that needs to
86 treat the source code as a document, and do so reliably and robustly.
87
88 For more information on why it is impossible to parse perl, see Randal
89 Schwartz's seminal response to the question of "Why can't you parse
90 Perl".
91
92 <http://www.perlmonks.org/index.pl?node_id=44722>
93
94 The purpose of PPI is not to parse Perl Code, but to parse Perl
95 Documents. By treating the problem this way, we are able to parse a
96 single file containing Perl source code "isolated" from any other
97 resources, such as libraries upon which the code may depend, and
98 without needing to run an instance of perl alongside or inside the
99 parser.
100
101 Historically, using an embedded perl parser was widely considered to be
102 the most likely avenue for finding a solution to parsing Perl. It has
103 been investigated from time to time, but attempts have generally failed
104 or suffered from sufficiently bad corner cases that they were
105 abandoned.
106
107 What Does PPI Stand For?
108 "PPI" is an acronym for the longer original module name
109 "Parse::Perl::Isolated". And in the spirit of the silly acronym games
110 played by certain unnamed Open Source projects you may have hurd of, it
111 is also a reverse backronym of "I Parse Perl".
112
113 Of course, I could just be lying and have just made that second bit up
114 10 minutes before the release of PPI 1.000. Besides, all the cool Perl
115 packages have TLAs (Three Letter Acronyms). It's a rule or something.
116
117 Why don't you just think of it as the Perl Parsing Interface for
118 simplicity.
119
120 The original name was shortened to prevent the author (and you the
121 users) from contracting RSI by having to type crazy things like
122 "Parse::Perl::Isolated::Token::QuoteLike::Backtick" 100 times a day.
123
124 In acknowledgment that someone may some day come up with a valid
125 solution for the grammar problem it was decided at the commencement of
126 the project to leave the "Parse::Perl" namespace free for any such
127 effort.
128
129 Since that time I've been able to prove to my own satisfaction that it
130 is truly impossible to accurately parse Perl as both code and document
131 at once. For the academics, parsing Perl suffers from the "Halting
132 Problem".
133
134 Why Parse Perl?
135 Once you can accept that we will never be able to parse Perl well
136 enough to meet the standards of things that treat Perl as code, it is
137 worth re-examining why we want to "parse" Perl at all.
138
139 What are the things that people might want a "Perl parser" for?
140
141 Documentation
142 Analyzing the contents of a Perl document to automatically generate
143 documentation, in parallel to, or as a replacement for, POD
144 documentation.
145
146 Allow an indexer to locate and process all the comments and
147 documentation from code for "full text search" applications.
148
149 Structural and Quality Analysis
150 Determine quality or other metrics across a body of code, and
151 identify situations relating to particular phrases, techniques or
152 locations.
153
154 Index functions, variables and packages within Perl code, and doing
155 search and graph (in the node/edge sense) analysis of large code
156 bases.
157
158 Perl::Critic, based on PPI, is a large, thriving tool for bug
159 detection and style analysis of Perl code.
160
161 Refactoring
162 Make structural, syntax, or other changes to code in an automated
163 manner, either independently or in assistance to an editor. This
164 sort of task list includes backporting, forward porting, partial
165 evaluation, "improving" code, or whatever. All the sort of things
166 you'd want from a Perl::Editor.
167
168 Layout
169 Change the layout of code without changing its meaning. This
170 includes techniques such as tidying (like perltidy), obfuscation,
171 compressing and "squishing", or to implement formatting preferences
172 or policies.
173
174 Presentation
175 This includes methods of improving the presentation of code,
176 without changing the content of the code. Modify, improve, syntax
177 colour etc the presentation of a Perl document. Generating
178 "IntelliText"-like functions.
179
180 If we treat this as a baseline for the sort of things we are going to
181 have to build on top of Perl, then it becomes possible to identify a
182 standard for how good a Perl parser needs to be.
183
184 How good is Good Enough(TM)
185 PPI seeks to be good enough to achieve all of the above tasks, or to
186 provide a sufficiently good API on which to allow others to implement
187 modules in these and related areas.
188
189 However, there are going to be limits to this process. Because PPI
190 cannot adapt to changing grammars, any code written using source
191 filters should not be assumed to be parsable.
192
193 At one extreme, this includes anything munged by Acme::Bleach, as well
194 as (arguably) more common cases like Switch. We do not pretend to be
195 able to always parse code using these modules, although as long as it
196 still follows a format that looks like Perl syntax, it may be possible
197 to extend the lexer to handle them.
198
199 The ability to extend PPI to handle lexical additions to the language
200 is on the drawing board to be done some time post-1.0
201
202 The goal for success was originally to be able to successfully parse
203 99% of all Perl documents contained in CPAN. This means the entire file
204 in each case.
205
206 PPI has succeeded in this goal far beyond the expectations of even the
207 author. At time of writing there are only 28 non-Acme Perl modules in
208 CPAN that PPI is incapable of parsing. Most of these are so badly
209 broken they do not compile as Perl code anyway.
210
211 So unless you are actively going out of your way to break PPI, you
212 should expect that it will handle your code just fine.
213
214 Internationalisation
215 PPI provides partial support for internationalisation and localisation.
216
217 Specifically, it allows the use of characters from the Latin-1
218 character set to be used in quotes, comments, and POD. Primarily, this
219 covers languages from Europe and South America.
220
221 PPI does not currently provide support for Unicode. If you need
222 Unicode support and would like to help, contact the author. (contact
223 details below)
224
225 Round Trip Safe
226 When PPI parses a file it builds everything into the model, including
227 whitespace. This is needed in order to make the Document fully "Round
228 Trip" safe.
229
230 The general concept behind a "Round Trip" parser is that it knows what
231 it is parsing is somewhat uncertain, and so expects to get things wrong
232 from time to time. In the cases where it parses code wrongly the tree
233 will serialize back out to the same string of code that was read in,
234 repairing the parser's mistake as it heads back out to the file.
235
236 The end result is that if you parse in a file and serialize it back out
237 without changing the tree, you are guaranteed to get the same file you
238 started with. PPI does this correctly and reliably for 100% of all
239 known cases.
240
241 What goes in, will come out. Every time.
242
243 The one minor exception at this time is that if the newlines for your
244 file are wrong (meaning not matching the platform newline format), PPI
245 will localise them for you. (It isn't to be convenient, supporting
246 arbitrary newlines would make some of the code more complicated)
247
248 Better control of the newline type is on the wish list though, and
249 anyone wanting to help out is encouraged to contact the author.
250
252 General Layout
253 PPI is built upon two primary "parsing" components, PPI::Tokenizer and
254 PPI::Lexer, and a large tree of about 70 classes which implement the
255 various the Perl Document Object Model (PDOM).
256
257 The PDOM is conceptually similar in style and intent to the regular DOM
258 or other code Abstract Syntax Trees (ASTs), but contains some
259 differences to handle perl-specific cases, and to assist in treating
260 the code as a document. Please note that it is not an implementation of
261 the official Document Object Model specification, only somewhat similar
262 to it.
263
264 On top of the Tokenizer, Lexer and the classes of the PDOM, sit a
265 number of classes intended to make life a little easier when dealing
266 with PDOM trees.
267
268 Both the major parsing components were hand-coded from scratch with
269 only plain Perl code and a few small utility modules. There are no
270 grammar or patterns mini-languages, no YACC or LEX style tools and only
271 a small number of regular expressions.
272
273 This is primarily because of the sheer volume of accumulated cruft that
274 exists in Perl. Not even perl itself is capable of parsing Perl
275 documents (remember, it just parses and executes it as code).
276
277 As a result, PPI needed to be cruftier than perl itself. Feel free to
278 shudder at this point, and hope you never have to understand the
279 Tokenizer codebase. Speaking of which...
280
281 The Tokenizer
282 The Tokenizer takes source code and converts it into a series of
283 tokens. It does this using a slow but thorough character by character
284 manual process, rather than using a pattern system or complex regexes.
285
286 Or at least it does so conceptually. If you were to actually trace the
287 code you would find it's not truly character by character due to a
288 number of regexps and optimisations throughout the code. This lets the
289 Tokenizer "skip ahead" when it can find shortcuts, so it tends to jump
290 around a line a bit wildly at times.
291
292 In practice, the number of times the Tokenizer will actually move the
293 character cursor itself is only about 5% - 10% higher than the number
294 of tokens contained in the file. This makes it about as optimal as it
295 can be made without implementing it in something other than Perl.
296
297 In 2001 when PPI was started, this structure made PPI quite slow, and
298 not really suitable for interactive tasks. This situation has improved
299 greatly with multi-gigahertz processors, but can still be painful when
300 working with very large files.
301
302 The target parsing rate for PPI is about 5000 lines per gigacycle. It
303 is currently believed to be at about 1500, and the main avenue for
304 making it to the target speed has now become PPI::XS, a drop-in XS
305 accelerator for PPI.
306
307 Since PPI::XS has only just gotten off the ground and is currently only
308 at proof-of-concept stage, this may take a little while. Anyone
309 interested in helping out with PPI::XS is highly encouraged to contact
310 the author. In fact, the design of PPI::XS means it's possible to port
311 one function at a time safely and reliably. So every little bit will
312 help.
313
314 The Lexer
315 The Lexer takes a token stream, and converts it to a lexical tree.
316 Because we are parsing Perl documents this includes whitespace,
317 comments, and all number of weird things that have no relevance when
318 code is actually executed.
319
320 An instantiated PPI::Lexer consumes PPI::Tokenizer objects and produces
321 PPI::Document objects. However you should probably never be working
322 with the Lexer directly. You should just be able to create
323 PPI::Document objects and work with them directly.
324
325 The Perl Document Object Model
326 The PDOM is a structured collection of data classes that together
327 provide a correct and scalable model for documents that follow the
328 standard Perl syntax.
329
330 The PDOM Class Tree
331 The following lists all of the 72 current PDOM classes, listing with
332 indentation based on inheritance.
333
334 PPI::Element
335 PPI::Node
336 PPI::Document
337 PPI::Document::Fragment
338 PPI::Statement
339 PPI::Statement::Package
340 PPI::Statement::Include
341 PPI::Statement::Sub
342 PPI::Statement::Scheduled
343 PPI::Statement::Compound
344 PPI::Statement::Break
345 PPI::Statement::Given
346 PPI::Statement::When
347 PPI::Statement::Data
348 PPI::Statement::End
349 PPI::Statement::Expression
350 PPI::Statement::Variable
351 PPI::Statement::Null
352 PPI::Statement::UnmatchedBrace
353 PPI::Statement::Unknown
354 PPI::Structure
355 PPI::Structure::Block
356 PPI::Structure::Subscript
357 PPI::Structure::Constructor
358 PPI::Structure::Condition
359 PPI::Structure::List
360 PPI::Structure::For
361 PPI::Structure::Given
362 PPI::Structure::When
363 PPI::Structure::Unknown
364 PPI::Token
365 PPI::Token::Whitespace
366 PPI::Token::Comment
367 PPI::Token::Pod
368 PPI::Token::Number
369 PPI::Token::Number::Binary
370 PPI::Token::Number::Octal
371 PPI::Token::Number::Hex
372 PPI::Token::Number::Float
373 PPI::Token::Number::Exp
374 PPI::Token::Number::Version
375 PPI::Token::Word
376 PPI::Token::DashedWord
377 PPI::Token::Symbol
378 PPI::Token::Magic
379 PPI::Token::ArrayIndex
380 PPI::Token::Operator
381 PPI::Token::Quote
382 PPI::Token::Quote::Single
383 PPI::Token::Quote::Double
384 PPI::Token::Quote::Literal
385 PPI::Token::Quote::Interpolate
386 PPI::Token::QuoteLike
387 PPI::Token::QuoteLike::Backtick
388 PPI::Token::QuoteLike::Command
389 PPI::Token::QuoteLike::Regexp
390 PPI::Token::QuoteLike::Words
391 PPI::Token::QuoteLike::Readline
392 PPI::Token::Regexp
393 PPI::Token::Regexp::Match
394 PPI::Token::Regexp::Substitute
395 PPI::Token::Regexp::Transliterate
396 PPI::Token::HereDoc
397 PPI::Token::Cast
398 PPI::Token::Structure
399 PPI::Token::Label
400 PPI::Token::Separator
401 PPI::Token::Data
402 PPI::Token::End
403 PPI::Token::Prototype
404 PPI::Token::Attribute
405 PPI::Token::Unknown
406
407 To summarize the above layout, all PDOM objects inherit from the
408 PPI::Element class.
409
410 Under this are PPI::Token, strings of content with a known type, and
411 PPI::Node, syntactically significant containers that hold other
412 Elements.
413
414 The three most important of these are the PPI::Document, the
415 PPI::Statement and the PPI::Structure classes.
416
417 The Document, Statement and Structure
418 At the top of all complete PDOM trees is a PPI::Document object. It
419 represents a complete file of Perl source code as you might find it on
420 disk.
421
422 There are some specialised types of document, such as
423 PPI::Document::File and PPI::Document::Normalized but for the purposes
424 of the PDOM they are all just considered to be the same thing.
425
426 Each Document will contain a number of Statements, Structures and
427 Tokens.
428
429 A PPI::Statement is any series of Tokens and Structures that are
430 treated as a single contiguous statement by perl itself. You should
431 note that a Statement is as close as PPI can get to "parsing" the code
432 in the sense that perl-itself parses Perl code when it is building the
433 op-tree.
434
435 Because of the isolation and Perl's syntax, it is provably impossible
436 for PPI to accurately determine precedence of operators or which tokens
437 are implicit arguments to a sub call.
438
439 So rather than lead you on with a bad guess that has a strong chance of
440 being wrong, PPI does not attempt to determine precedence or sub
441 parameters at all.
442
443 At a fundamental level, it only knows that this series of elements
444 represents a single Statement as perl sees it, but it can do so with
445 enough certainty that it can be trusted.
446
447 However, for specific Statement types the PDOM is able to derive
448 additional useful information about their meaning. For the best, most
449 useful, and most heavily used example, see PPI::Statement::Include.
450
451 A PPI::Structure is any series of tokens contained within matching
452 braces. This includes code blocks, conditions, function argument
453 braces, anonymous array and hash constructors, lists, scoping braces
454 and all other syntactic structures represented by a matching pair of
455 braces, including (although it may not seem obvious at first)
456 "<READLINE>" braces.
457
458 Each Structure contains none, one, or many Tokens and Structures (the
459 rules for which vary for the different Structure subclasses)
460
461 Under the PDOM structure rules, a Statement can never directly contain
462 another child Statement, a Structure can never directly contain another
463 child Structure, and a Document can never contain another Document
464 anywhere in the tree.
465
466 Aside from these three rules, the PDOM tree is extremely flexible.
467
468 The PDOM at Work
469 To demonstrate the PDOM in use lets start with an example showing how
470 the tree might look for the following chunk of simple Perl code.
471
472 #!/usr/bin/perl
473
474 print( "Hello World!" );
475
476 exit();
477
478 Translated into a PDOM tree it would have the following structure (as
479 shown via the included PPI::Dumper).
480
481 PPI::Document
482 PPI::Token::Comment '#!/usr/bin/perl\n'
483 PPI::Token::Whitespace '\n'
484 PPI::Statement
485 PPI::Token::Word 'print'
486 PPI::Structure::List ( ... )
487 PPI::Token::Whitespace ' '
488 PPI::Statement::Expression
489 PPI::Token::Quote::Double '"Hello World!"'
490 PPI::Token::Whitespace ' '
491 PPI::Token::Structure ';'
492 PPI::Token::Whitespace '\n'
493 PPI::Token::Whitespace '\n'
494 PPI::Statement
495 PPI::Token::Word 'exit'
496 PPI::Structure::List ( ... )
497 PPI::Token::Structure ';'
498 PPI::Token::Whitespace '\n'
499
500 Please note that in this example, strings are only listed for the
501 actual PPI::Token that contains that string. Structures are listed with
502 the type of brace characters they represent noted.
503
504 The PPI::Dumper module can be used to generate similar trees yourself.
505
506 We can make that PDOM dump a little easier to read if we strip out all
507 the whitespace. Here it is again, sans the distracting whitespace
508 tokens.
509
510 PPI::Document
511 PPI::Token::Comment '#!/usr/bin/perl\n'
512 PPI::Statement
513 PPI::Token::Word 'print'
514 PPI::Structure::List ( ... )
515 PPI::Statement::Expression
516 PPI::Token::Quote::Double '"Hello World!"'
517 PPI::Token::Structure ';'
518 PPI::Statement
519 PPI::Token::Word 'exit'
520 PPI::Structure::List ( ... )
521 PPI::Token::Structure ';'
522
523 As you can see, the tree can get fairly deep at time, especially when
524 every isolated token in a bracket becomes its own statement. This is
525 needed to allow anything inside the tree the ability to grow. It also
526 makes the search and analysis algorithms much more flexible.
527
528 Because of the depth and complexity of PDOM trees, a vast number of
529 very easy to use methods have been added wherever possible to help
530 people working with PDOM trees do normal tasks relatively quickly and
531 efficiently.
532
533 Overview of the Primary Classes
534 The main PPI classes, and links to their own documentation, are listed
535 here in alphabetical order.
536
537 PPI::Document
538 The Document object, the root of the PDOM.
539
540 PPI::Document::Fragment
541 A cohesive fragment of a larger Document. Although not of any real
542 current use, it is needed for use in certain internal tree
543 manipulation algorithms.
544
545 For example, doing things like cut/copy/paste etc. Very similar to
546 a PPI::Document, but has some additional methods and does not
547 represent a lexical scope boundary.
548
549 A document fragment is also non-serializable, and so cannot be
550 written out to a file.
551
552 PPI::Dumper
553 A simple class for dumping readable debugging versions of PDOM
554 structures, such as in the demonstration above.
555
556 PPI::Element
557 The Element class is the abstract base class for all objects within
558 the PDOM
559
560 PPI::Find
561 Implements an instantiable object form of a PDOM tree search.
562
563 PPI::Lexer
564 The PPI Lexer. Converts Token streams into PDOM trees.
565
566 PPI::Node
567 The Node object, the abstract base class for all PDOM objects that
568 can contain other Elements, such as the Document, Statement and
569 Structure objects.
570
571 PPI::Statement
572 The base class for all Perl statements. Generic "evaluate for side-
573 effects" statements are of this actual type. Other more interesting
574 statement types belong to one of its children.
575
576 See its own documentation for a longer description and list of all
577 of the different statement types and sub-classes.
578
579 PPI::Structure
580 The abstract base class for all structures. A Structure is a
581 language construct consisting of matching braces containing a set
582 of other elements.
583
584 See the PPI::Structure documentation for a description and list of
585 all of the different structure types and sub-classes.
586
587 PPI::Token
588 A token is the basic unit of content. At its most basic, a Token is
589 just a string tagged with metadata (its class, and some additional
590 flags in some cases).
591
592 PPI::Token::_QuoteEngine
593 The PPI::Token::Quote and PPI::Token::QuoteLike classes provide
594 abstract base classes for the many and varied types of quote and
595 quote-like things in Perl. However, much of the actual quote logic
596 is implemented in a separate quote engine, based at
597 PPI::Token::_QuoteEngine.
598
599 Classes that inherit from PPI::Token::Quote, PPI::Token::QuoteLike
600 and PPI::Token::Regexp are generally parsed only by the Quote
601 Engine.
602
603 PPI::Tokenizer
604 The PPI Tokenizer. One Tokenizer consumes a chunk of text and
605 provides access to a stream of PPI::Token objects.
606
607 The Tokenizer is very very complicated, to the point where even the
608 author treads carefully when working with it.
609
610 Most of the complication is the result of optimizations which have
611 tripled the tokenization speed, at the expense of maintainability.
612 We cope with the spaghetti by heavily commenting everything.
613
614 PPI::Transform
615 The Perl Document Transformation API. Provides a standard interface
616 and abstract base class for objects and classes that manipulate
617 Documents.
618
620 The core PPI distribution is pure Perl and has been kept as tight as
621 possible and with as few dependencies as possible.
622
623 It should download and install normally on any platform from within the
624 CPAN and CPANPLUS applications, or directly using the distribution
625 tarball. If installing by hand, you may need to install a few small
626 utility modules first. The exact ones will depend on your version of
627 perl.
628
629 There are no special install instructions for PPI, and the normal "Perl
630 Makefile.PL", "make", "make test", "make install" instructions apply.
631
633 The PPI namespace itself is reserved for use by PPI itself. You are
634 recommended to use the PPIx:: namespace for PPI-specific modifications
635 or prototypes thereof, or Perl:: for modules which provide a general
636 Perl language-related functions.
637
638 If what you wish to implement looks like it fits into the PPIx::
639 namespace, you should consider contacting the PPI maintainers on GitHub
640 first, as what you want may already be in progress, or you may wish to
641 consider contributing to PPI itself.
642
644 - Many more analysis and utility methods for PDOM classes
645
646 - Creation of a PPI::Tutorial document
647
648 - Add many more key functions to PPI::XS
649
650 - We can always write more and better unit tests
651
652 - Complete the full implementation of ->literal (1.200)
653
654 - Full understanding of scoping (due 1.300)
655
657 The most recent version of PPI is available at the following address.
658
659 <http://search.cpan.org/~mithaldu/PPI/>
660
661 PPI source is maintained in a GitHub repository at the following
662 address.
663
664 <https://github.com/adamkennedy/PPI>
665
666 Contributions via GitHub pull request are welcome.
667
668 Bug fixes in the form of pull requests or bug reports with new
669 (failing) unit tests have the best chance of being addressed by busy
670 maintainers, and are strongly encouraged.
671
672 If you cannot provide a test or fix, or don't have time to do so, then
673 regular bug reports are still accepted and appreciated via the GitHub
674 bug tracker.
675
676 <https://github.com/adamkennedy/PPI/issues>
677
678 The "ppidump" utility that is part of the Perl::Critic distribution is
679 a useful tool for demonstrating how PPI is parsing (or misparsing)
680 small code snippets, and for providing information for bug reports.
681
682 For other issues, questions, or commercial or media-related enquiries,
683 contact the author.
684
686 Adam Kennedy <adamk@cpan.org>
687
689 A huge thank you to Phase N Australia (<http://phase-n.com/>) for
690 permitting the original open sourcing and release of this distribution
691 from what was originally several thousand hours of commercial work.
692
693 Another big thank you to The Perl Foundation
694 (<http://www.perlfoundation.org/>) for funding for the final big
695 refactoring and completion run.
696
697 Also, to the various co-maintainers that have contributed both large
698 and small with tests and patches and especially to those rare few who
699 have deep-dived into the guts to (gasp) add a feature.
700
701 - Dan Brook : PPIx::XPath, Acme::PerlML
702 - Audrey Tang : "Line Noise" Testing
703 - Arjen Laarhoven : Three-element ->location support
704 - Elliot Shank : Perl 5.10 support, five-element ->location
705
706 And finally, thanks to those brave ( and foolish :) ) souls willing to
707 dive in and use, test drive and provide feedback on PPI before version
708 1.000, in some cases before it made it to beta quality, and still did
709 extremely distasteful things (like eating 50 meg of RAM a second).
710
711 I owe you all a beer. Corner me somewhere and collect at your
712 convenience. If I missed someone who wasn't in my email history, thank
713 you too :)
714
715 # In approximate order of appearance
716 - Claes Jacobsson
717 - Michael Schwern
718 - Jeff T. Parsons
719 - CPAN Author "CHOCOLATEBOY"
720 - Robert Rotherberg
721 - CPAN Author "PODMASTER"
722 - Richard Soderberg
723 - Nadim ibn Hamouda el Khemir
724 - Graciliano M. P.
725 - Leon Brocard
726 - Jody Belka
727 - Curtis Ovid
728 - Yuval Kogman
729 - Michael Schilli
730 - Slaven Rezic
731 - Lars Thegler
732 - Tony Stubblebine
733 - Tatsuhiko Miyagawa
734 - CPAN Author "CHROMATIC"
735 - Matisse Enzer
736 - Roy Fulbright
737 - Dan Brook
738 - Johnny Lee
739 - Johan Lindstrom
740
741 And to single one person out, thanks go to Randal Schwartz who spent a
742 great number of hours in IRC over a critical 6 month period explaining
743 why Perl is impossibly unparsable and constantly shoving evil and ugly
744 corner cases in my face. He remained a tireless devil's advocate, and
745 without his support this project genuinely could never have been
746 completed.
747
748 So for my schooling in the Deep Magiks, you have my deepest gratitude
749 Randal.
750
752 Copyright 2001 - 2011 Adam Kennedy.
753
754 This program is free software; you can redistribute it and/or modify it
755 under the same terms as Perl itself.
756
757 The full text of the license can be found in the LICENSE file included
758 with this module.
759
760
761
762perl v5.32.0 2020-07-28 PPI(3)