PPI-1.215/0000755000175100017510000000000011532120507010536 5ustar adamadamPPI-1.215/META.yml0000644000175100017510000000170511532120243012007 0ustar adamadam--- abstract: 'Parse, Analyze and Manipulate Perl (without perl)' author: - 'Adam Kennedy ' build_requires: Class::Inspector: 1.22 ExtUtils::MakeMaker: 6.42 File::Remove: 1.42 Test::More: 0.86 Test::NoWarnings: 0.084 Test::Object: 0.07 Test::SubCalls: 1.07 configure_requires: ExtUtils::MakeMaker: 6.42 distribution_type: module generated_by: 'Module::Install version 1.00' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 module_name: PPI name: PPI no_index: directory: - inc - t - xt requires: Clone: 0.30 Digest::MD5: 2.35 File::Spec: 0.84 IO::String: 1.07 List::MoreUtils: 0.16 List::Util: 1.20 Params::Util: 1.00 Storable: 2.17 Task::Weaken: 0 perl: 5.6.0 resources: ChangeLog: http://fisheye2.atlassian.com/changelog/cpan/trunk/PPI license: http://dev.perl.org/licenses/ repository: http://svn.ali.as/cpan/trunk/PPI version: 1.215 PPI-1.215/README0000644000175100017510000007720311532117301011425 0ustar adamadamNAME PPI - Parse, Analyze and Manipulate Perl (without perl) SYNOPSIS use PPI; # Create a new empty document my $Document = PPI::Document->new; # Create a document from source $Document = PPI::Document->new(\'print "Hello World!\n"'); # Load a Document from a file $Document = PPI::Document->new('Module.pm'); # Does it contain any POD? if ( $Document->find_any('PPI::Token::Pod') ) { print "Module contains POD\n"; } # Get the name of the main package $pkg = $Document->find_first('PPI::Statement::Package')->namespace; # Remove all that nasty documentation $Document->prune('PPI::Token::Pod'); $Document->prune('PPI::Token::Comment'); # Save the file $Document->save('Module.pm.stripped'); DESCRIPTION About this Document This is the PPI manual. It describes its reason for existing, its general structure, its use, an overview of the API, and provides a few implementation samples. Background The ability to read, and manipulate Perl (the language) programmatically other than with perl (the application) was one that caused difficulty for a long time. The cause of this problem was Perl's complex and dynamic grammar. Although there is typically not a huge diversity in the grammar of most Perl code, certain issues cause large problems when it comes to parsing. Indeed, quite early in Perl's history Tom Christenson introduced the Perl community to the quote *"Nothing but perl can parse Perl"*, or as it is more often stated now as a truism: "Only perl can parse Perl" One example of the sorts of things the prevent Perl being easily parsed are function signatures, as demonstrated by the following. @result = (dothis $foo, $bar); # Which of the following is it equivalent to? @result = (dothis($foo), $bar); @result = dothis($foo, $bar); The first line above can be interpreted in two different ways, depending on whether the &dothis function is expecting one argument, or two, or several. A "code parser" (something that parses for the purpose of execution) such as perl needs information that is not found in the immediate vicinity of the statement being parsed. The information might not just be elsewhere in the file, it might not even be in the same file at all. It might also not be able to determine this information without the prior execution of a "BEGIN {}" block, or the loading and execution of one or more external modules. Or worse the &dothis function may not even have been written yet. When parsing Perl as code, you must also execute it Even perl itself never really fully understands the structure of the source code after and indeed as it processes it, and in that sense doesn't "parse" Perl source into anything remotely like a structured document. This makes it of no real use for any task that needs to treat the source code as a document, and do so reliably and robustly. For more information on why it is impossible to parse perl, see Randal Schwartz's seminal response to the question of "Why can't you parse Perl". The purpose of PPI is not to parse Perl *Code*, but to parse Perl *Documents*. By treating the problem this way, we are able to parse a single file containing Perl source code "isolated" from any other resources, such as libraries upon which the code may depend, and without needing to run an instance of perl alongside or inside the parser. Historically, using an embedded perl parser was widely considered to be the most likely avenue for finding a solution to "Parse::Perl". It was investigated from time to time and attempts have generally failed or suffered from sufficiently bad corner cases that they were abandoned. What Does PPI Stand For? "PPI" is an acronym for the longer original module name "Parse::Perl::Isolated". And in the spirit or the silly acronym games played by certain unnamed Open Source projects you may have *hurd* of, it also a reverse backronym of "I Parse Perl". Of course, I could just be lying and have just made that second bit up 10 minutes before the release of PPI 1.000. Besides, all the cool Perl packages have TLAs (Three Letter Acronyms). It's a rule or something. Why don't you just think of it as the Perl Parsing Interface for simplicity. The original name was shortened to prevent the author (and you the users) from contracting RSI by having to type crazy things like "Parse::Perl::Isolated::Token::QuoteLike::Backtick" 100 times a day. In acknowledgment that someone may some day come up with a valid solution for the grammar problem it was decided at the commencement of the project to leave the "Parse::Perl" namespace free for any such effort. Since that time I've been able to prove to my own satisfaction that it is truly impossible to accurately parse Perl as both code and document at once. For the academics, parsing Perl suffers from the "Halting Problem". With this in mind "Parse::Perl" has now been co-opted as the title for the SourceForge project that publishes PPI and a large collection of other applications and modules related to the (document) parsing of Perl source code. You can find this project at , however we no longer use the SourceForge CVS server. Instead, the current development version of PPI is available via SVN at . Why Parse Perl? Once you can accept that we will never be able to parse Perl well enough to meet the standards of things that treat Perl as code, it is worth re-examining "why" we want to "parse" Perl at all. What are the things that people might want a "Perl parser" for. Documentation Analyzing the contents of a Perl document to automatically generate documentation, in parallel to, or as a replacement for, POD documentation. Allow an indexer to to locate and process all the comments and documentation from code for "full text search" applications. Structural and Quality Analysis Determine quality or other metrics across a body of code, and identify situations relating to particular phrases, techniques or locations. Index functions, variables and packages within Perl code, and doing search and graph (in the node/edge sense) analysis of large code bases. Refactoring Make structural, syntax, or other changes to code in an automated manner, either independently or in assistance to an editor. This sort of task list includes backporting, forward porting, partial evaluation, "improving" code, or whatever. All the sort of things you'd want from a Perl::Editor. Layout Change the layout of code without changing its meaning. This includes techniques such as tidying (like perltidy), obfuscation, compressing and "squishing", or to implement formatting preferences or policies. Presentation This includes methods of improving the presentation of code, without changing the content of the code. Modify, improve, syntax colour etc the presentation of a Perl document. Generating "IntelliText"-like functions. If we treat this as a baseline for the sort of things we are going to have to build on top of Perl, then it becomes possible to identify a standard for how good a Perl parser needs to be. How good is Good Enough(TM) PPI seeks to be good enough to achieve all of the above tasks, or to provide a sufficiently good API on which to allow others to implement modules in these and related areas. However, there are going to be limits to this process. Because PPI cannot adapt to changing grammars, any code written using source filters should not be assumed to be parsable. At one extreme, this includes anything munged by Acme::Bleach, as well as (arguably) more common cases like Switch. We do not pretend to be able to always parse code using these modules, although as long as it still follows a format that looks like Perl syntax, it may be possible to extend the lexer to handle them. The ability to extend PPI to handle lexical additions to the language is on the drawing board to be done some time post-1.0 The goal for success was originally to be able to successfully parse 99% of all Perl documents contained in CPAN. This means the entire file in each case. PPI has succeeded in this goal far beyond the expectations of even the author. At time of writing there are only 28 non-Acme Perl modules in CPAN that PPI is incapable of parsing. Most of these are so badly broken they do not compile as Perl code anyway. So unless you are actively going out of your way to break PPI, you should expect that it will handle your code just fine. Internationalisation PPI provides partial support for internationalisation and localisation. Specifically, it allows the use characters from the Latin-1 character set to be used in quotes, comments, and POD. Primarily, this covers languages from Europe and South America. PPI does not currently provide support for Unicode, although there is an initial implementation available in a development branch from CVS. If you need Unicode support, and would like to help stress test the Unicode support so we can move it to the main branch and enable it in the main release should contact the author. (contact details below) Round Trip Safe When PPI parses a file it builds everything into the model, including whitespace. This is needed in order to make the Document fully "Round Trip" safe. The general concept behind a "Round Trip" parser is that it knows what it is parsing is somewhat uncertain, and so expects to get things wrong from time to time. In the cases where it parses code wrongly the tree will serialize back out to the same string of code that was read in, repairing the parser's mistake as it heads back out to the file. The end result is that if you parse in a file and serialize it back out without changing the tree, you are guaranteed to get the same file you started with. PPI does this correctly and reliably for 100% of all known cases. What goes in, will come out. Every time. The one minor exception at this time is that if the newlines for your file are wrong (meaning not matching the platform newline format), PPI will localise them for you. (It isn't to be convenient, supporting arbitrary newlines would make some of the code more complicated) Better control of the newline type is on the wish list though, and anyone wanting to help out is encouraged to contact the author. IMPLEMENTATION General Layout PPI is built upon two primary "parsing" components, PPI::Tokenizer and PPI::Lexer, and a large tree of about 50 classes which implement the various the *Perl Document Object Model* (PDOM). The PDOM is conceptually similar in style and intent to the regular DOM or other code Abstract Syntax Trees (ASTs), but contains some differences to handle perl-specific cases, and to assist in treating the code as a document. Please note that it is not an implementation of the official Document Object Model specification, only somewhat similar to it. On top of the Tokenizer, Lexer and the classes of the PDOM, sit a number of classes intended to make life a little easier when dealing with PDOM trees. Both the major parsing components were hand-coded from scratch with only plain Perl code and a few small utility modules. There are no grammar or patterns mini-languages, no YACC or LEX style tools and only a small number of regular expressions. This is primarily because of the sheer volume of accumulated cruft that exists in Perl. Not even perl itself is capable of parsing Perl documents (remember, it just parses and executes it as code). As a result, PPI needed to be cruftier than perl itself. Feel free to shudder at this point, and hope you never have to understand the Tokenizer codebase. Speaking of which... The Tokenizer The Tokenizer takes source code and converts it into a series of tokens. It does this using a slow but thorough character by character manual process, rather than using a pattern system or complex regexes. Or at least it does so conceptually. If you were to actually trace the code you would find it's not truly character by character due to a number of regexps and optimisations throughout the code. This lets the Tokenizer "skip ahead" when it can find shortcuts, so it tends to jump around a line a bit wildly at times. In practice, the number of times the Tokenizer will actually move the character cursor itself is only about 5% - 10% higher than the number of tokens contained in the file. This makes it about as optimal as it can be made without implementing it in something other than Perl. In 2001 when PPI was started, this structure made PPI quite slow, and not really suitable for interactive tasks. This situation has improved greatly with multi-gigahertz processors, but can still be painful when working with very large files. The target parsing rate for PPI is about 5000 lines per gigacycle. It is currently believed to be at about 1500, and main avenue for making it to the target speed has now become PPI::XS, a drop-in XS accelerator for PPI. Since PPI::XS has only just gotten off the ground and is currently only at proof-of-concept stage, this may take a little while. Anyone interested in helping out with PPI::XS is highly encouraged to contact the author. In fact, the design of PPI::XS means it's possible to port one function at a time safely and reliably. So every little bit will help. The Lexer The Lexer takes a token stream, and converts it to a lexical tree. Because we are parsing Perl documents this includes whitespace, comments, and all number of weird things that have no relevance when code is actually executed. An instantiated PPI::Lexer consumes PPI::Tokenizer objects and produces PPI::Document objects. However you should probably never be working with the Lexer directly. You should just be able to create PPI::Document objects and work with them directly. The Perl Document Object Model The PDOM is a structured collection of data classes that together provide a correct and scalable model for documents that follow the standard Perl syntax. The PDOM Class Tree The following lists all of the 67 current PDOM classes, listing with indentation based on inheritance. PPI::Element PPI::Node PPI::Document PPI::Document::Fragment PPI::Statement PPI::Statement::Package PPI::Statement::Include PPI::Statement::Sub PPI::Statement::Scheduled PPI::Statement::Compound PPI::Statement::Break PPI::Statement::Given PPI::Statement::When PPI::Statement::Data PPI::Statement::End PPI::Statement::Expression PPI::Statement::Variable PPI::Statement::Null PPI::Statement::UnmatchedBrace PPI::Statement::Unknown PPI::Structure PPI::Structure::Block PPI::Structure::Subscript PPI::Structure::Constructor PPI::Structure::Condition PPI::Structure::List PPI::Structure::For PPI::Structure::Given PPI::Structure::When PPI::Structure::Unknown PPI::Token PPI::Token::Whitespace PPI::Token::Comment PPI::Token::Pod PPI::Token::Number PPI::Token::Number::Binary PPI::Token::Number::Octal PPI::Token::Number::Hex PPI::Token::Number::Float PPI::Token::Number::Exp PPI::Token::Number::Version PPI::Token::Word PPI::Token::DashedWord PPI::Token::Symbol PPI::Token::Magic PPI::Token::ArrayIndex PPI::Token::Operator PPI::Token::Quote PPI::Token::Quote::Single PPI::Token::Quote::Double PPI::Token::Quote::Literal PPI::Token::Quote::Interpolate PPI::Token::QuoteLike PPI::Token::QuoteLike::Backtick PPI::Token::QuoteLike::Command PPI::Token::QuoteLike::Regexp PPI::Token::QuoteLike::Words PPI::Token::QuoteLike::Readline PPI::Token::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute PPI::Token::Regexp::Transliterate PPI::Token::HereDoc PPI::Token::Cast PPI::Token::Structure PPI::Token::Label PPI::Token::Separator PPI::Token::Data PPI::Token::End PPI::Token::Prototype PPI::Token::Attribute PPI::Token::Unknown To summarize the above layout, all PDOM objects inherit from the PPI::Element class. Under this are PPI::Token, strings of content with a known type, and PPI::Node, syntactically significant containers that hold other Elements. The three most important of these are the PPI::Document, the PPI::Statement and the PPI::Structure classes. The Document, Statement and Structure At the top of all complete PDOM trees is a PPI::Document object. It represents a complete file of Perl source code as you might find it on disk. There are some specialised types of document, such as PPI::Document::File and PPI::Document::Normalized but for the purposes of the PDOM they are all just considered to be the same thing. Each Document will contain a number of Statements, Structures and Tokens. A PPI::Statement is any series of Tokens and Structures that are treated as a single contiguous statement by perl itself. You should note that a Statement is as close as PPI can get to "parsing" the code in the sense that perl-itself parses Perl code when it is building the op-tree. Because of the isolation and Perl's syntax, it is provably impossible for PPI to accurately determine precedence of operators or which tokens are implicit arguments to a sub call. So rather than lead you on with a bad guess that has a strong chance of being wrong, PPI does not attempt to determine precedence or sub parameters at all. At a fundamental level, it only knows that this series of elements represents a single Statement as perl sees it, but it can do so with enough certainty that it can be trusted. However, for specific Statement types the PDOM is able to derive additional useful information about their meaning. For the best, most useful, and most heavily used example, see PPI::Statement::Include. A PPI::Structure is any series of tokens contained within matching braces. This includes code blocks, conditions, function argument braces, anonymous array and hash constructors, lists, scoping braces and all other syntactic structures represented by a matching pair of braces, including (although it may not seem obvious at first) "" braces. Each Structure contains none, one, or many Tokens and Structures (the rules for which vary for the different Structure subclasses) Under the PDOM structure rules, a Statement can never directly contain another child Statement, a Structure can never directly contain another child Structure, and a Document can never contain another Document anywhere in the tree. Aside from these three rules, the PDOM tree is extremely flexible. The PDOM at Work To demonstrate the PDOM in use lets start with an example showing how the tree might look for the following chunk of simple Perl code. #!/usr/bin/perl print( "Hello World!" ); exit(); Translated into a PDOM tree it would have the following structure (as shown via the included PPI::Dumper). PPI::Document PPI::Token::Comment '#!/usr/bin/perl\n' PPI::Token::Whitespace '\n' PPI::Statement::Expression PPI::Token::Bareword 'print' PPI::Structure::List ( ... ) PPI::Token::Whitespace ' ' PPI::Statement::Expression PPI::Token::Quote::Double '"Hello World!"' PPI::Token::Whitespace ' ' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement::Expression PPI::Token::Bareword 'exit' PPI::Structure::List ( ... ) PPI::Token::Structure ';' PPI::Token::Whitespace '\n' Please note that in this this example, strings are only listed for the actual PPI::Token that contains that string. Structures are listed with the type of brace characters it represents noted. The PPI::Dumper module can be used to generate similar trees yourself. We can make that PDOM dump a little easier to read if we strip out all the whitespace. Here it is again, sans the distracting whitespace tokens. PPI::Document PPI::Token::Comment '#!/usr/bin/perl\n' PPI::Statement::Expression PPI::Token::Bareword 'print' PPI::Structure::List ( ... ) PPI::Statement::Expression PPI::Token::Quote::Double '"Hello World!"' PPI::Token::Structure ';' PPI::Statement::Expression PPI::Token::Bareword 'exit' PPI::Structure::List ( ... ) PPI::Token::Structure ';' As you can see, the tree can get fairly deep at time, especially when every isolated token in a bracket becomes its own statement. This is needed to allow anything inside the tree the ability to grow. It also makes the search and analysis algorithms much more flexible. Because of the depth and complexity of PDOM trees, a vast number of very easy to use methods have been added wherever possible to help people working with PDOM trees do normal tasks relatively quickly and efficiently. Overview of the Primary Classes The main PPI classes, and links to their own documentation, are listed here in alphabetical order. PPI::Document The Document object, the root of the PDOM. PPI::Document::Fragment A cohesive fragment of a larger Document. Although not of any real current use, it is needed for use in certain internal tree manipulation algorithms. For example, doing things like cut/copy/paste etc. Very similar to a PPI::Document, but has some additional methods and does not represent a lexical scope boundary. A document fragment is also non-serializable, and so cannot be written out to a file. PPI::Dumper A simple class for dumping readable debugging versions of PDOM structures, such as in the demonstration above. PPI::Element The Element class is the abstract base class for all objects within the PDOM PPI::Find Implements an instantiable object form of a PDOM tree search. PPI::Lexer The PPI Lexer. Converts Token streams into PDOM trees. PPI::Node The Node object, the abstract base class for all PDOM objects that can contain other Elements, such as the Document, Statement and Structure objects. PPI::Statement The base class for all Perl statements. Generic "evaluate for side-effects" statements are of this actual type. Other more interesting statement types belong to one of its children. See it's own documentation for a longer description and list of all of the different statement types and sub-classes. PPI::Structure The abstract base class for all structures. A Structure is a language construct consisting of matching braces containing a set of other elements. See the PPI::Structure documentation for a description and list of all of the different structure types and sub-classes. PPI::Token A token is the basic unit of content. At its most basic, a Token is just a string tagged with metadata (its class, and some additional flags in some cases). PPI::Token::_QuoteEngine The PPI::Token::Quote and PPI::Token::QuoteLike classes provide abstract base classes for the many and varied types of quote and quote-like things in Perl. However, much of the actual quote login is implemented in a separate quote engine, based at PPI::Token::_QuoteEngine. Classes that inherit from PPI::Token::Quote, PPI::Token::QuoteLike and PPI::Token::Regexp are generally parsed only by the Quote Engine. PPI::Tokenizer The PPI Tokenizer. One Tokenizer consumes a chunk of text and provides access to a stream of PPI::Token objects. The Tokenizer is very very complicated, to the point where even the author treads carefully when working with it. Most of the complication is the result of optimizations which have tripled the tokenization speed, at the expense of maintainability. We cope with the spaghetti by heavily commenting everything. PPI::Transform The Perl Document Transformation API. Provides a standard interface and abstract base class for objects and classes that manipulate Documents. INSTALLING The core PPI distribution is pure Perl and has been kept as tight as possible and with as few dependencies as possible. It should download and install normally on any platform from within the CPAN and CPANPLUS applications, or directly using the distribution tarball. If installing by hand, you may need to install a few small utility modules first. The exact ones will depend on your version of perl. There are no special install instructions for PPI, and the normal "Perl Makefile.PL", "make", "make test", "make install" instructions apply. EXTENDING The PPI namespace itself is reserved for the sole use of the modules under the umbrella of the "Parse::Perl" SourceForge project. You are recommended to use the PPIx:: namespace for PPI-specific modifications or prototypes thereof, or Perl:: for modules which provide a general Perl language-related functions. If what you wish to implement looks like it fits into PPIx:: namespace, you should consider contacting the "Parse::Perl" mailing list (detailed on the SourceForge site) first, as what you want may already be in progress, or you may wish to consider joining the team and doing it within the "Parse::Perl" project itself. TO DO - Many more analysis and utility methods for PDOM classes - Creation of a PPI::Tutorial document - Add many more key functions to PPI::XS - We can always write more and better unit tests - Complete the full implementation of ->literal (1.200) - Full understanding of scoping (due 1.300) SUPPORT This module is stored in an Open Repository at the following address. Write access to the repository is made available automatically to any published CPAN author, and to most other volunteers on request. If you are able to submit your bug report in the form of new (failing) unit tests, or can apply your fix directly instead of submitting a patch, you are strongly encouraged to do so, as the author currently maintains over 100 modules and it can take some time to deal with non-"Critical" bug reports or patches. This will also guarentee that your issue will be addressed in the next release of the module. For large changes though, please consider creating a branch so that they can be properly reviewed and trialed before being applied to the trunk. If you cannot provide a direct test or fix, or don't have time to do so, then regular bug reports are still accepted and appreciated via the CPAN bug tracker. For other issues or questions, contact the "Parse::Perl" project mailing list. For commercial or media-related enquiries, or to have your SVN commit bit enabled, contact the author. AUTHOR Adam Kennedy ACKNOWLEDGMENTS A huge thank you to Phase N Australia () for permitting the original open sourcing and release of this distribution from what was originally several thousand hours of commercial work. Another big thank you to The Perl Foundation () for funding for the final big refactoring and completion run. Also, to the various co-maintainers that have contributed both large and small with tests and patches and especially to those rare few who have deep-dived into the guts to (gasp) add a feature. - Dan Brook : PPIx::XPath, Acme::PerlML - Audrey Tang : "Line Noise" Testing - Arjen Laarhoven : Three-element ->location support - Elliot Shank : Perl 5.10 support, five-element ->location And finally, thanks to those brave ( and foolish :) ) souls willing to dive in and use, test drive and provide feedback on PPI before version 1.000, in some cases before it made it to beta quality, and still did extremely distasteful things (like eating 50 meg of RAM a second). I owe you all a beer. Corner me somewhere and collect at your convenience. If I missed someone who wasn't in my email history, thank you too :) # In approximate order of appearance - Claes Jacobsson - Michael Schwern - Jeff T. Parsons - CPAN Author "CHOCOLATEBOY" - Robert Rotherberg - CPAN Author "PODMASTER" - Richard Soderberg - Nadim ibn Hamouda el Khemir - Graciliano M. P. - Leon Brocard - Jody Belka - Curtis Ovid - Yuval Kogman - Michael Schilli - Slaven Rezic - Lars Thegler - Tony Stubblebine - Tatsuhiko Miyagawa - CPAN Author "CHROMATIC" - Matisse Enzer - Roy Fulbright - Dan Brook - Johnny Lee - Johan Lindstrom And to single one person out, thanks go to Randal Schwartz who spent a great number of hours in IRC over a critical 6 month period explaining why Perl is impossibly unparsable and constantly shoving evil and ugly corner cases in my face. He remained a tireless devil's advocate, and without his support this project genuinely could never have been completed. So for my schooling in the Deep Magiks, you have my deepest gratitude Randal. COPYRIGHT Copyright 2001 - 2011 Adam Kennedy. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. The full text of the license can be found in the LICENSE file included with this module. PPI-1.215/inline2test.tpl0000644000175100017510000000046711532117301013524 0ustar adamadam#!/usr/bin/perl # Unit testing for PPI, generated by Test::Inline use strict; use File::Spec::Functions ':ALL'; BEGIN { $| = 1; $^W = 1; no warnings 'once'; $PPI::XS_DISABLE = 1; $PPI::Lexer::X_TOKENIZER ||= $ENV{X_TOKENIZER}; } use PPI; # Execute the tests use Test::More [% plan %]; [% tests %] 1; PPI-1.215/Changes0000644000175100017510000013170711532117301012040 0ustar adamadamRevision history for Perl extension PPI 1.215 Sat 26 Feb 2011 Summary: - No changes Details: - Confirmed new Perl::Critic works with 1.214_02, so we can release a new PPI now. 1.214_02 Mon 31 Jan 2011 Summary: - More minor fixes, preparing for production release Details: - Updated copyright year to 2011 (ADAMK) - Fixed RT #64247 bless {} probably contains a hash constructor (WYANT) - Backed out glob fix (WYANT) - Fixed RT #65199 Cast can trump braces in PPI::Token::Symbol->symbol (WYANT) 1.214_01 Thu 16 Dec 2010 Summary: - General fix release Details: - index_locations on an empty document no longer warns (WYANT) - Corrected a bug in line-spanning attribute support (WYANT) - Regression test for line-spanning attribute support (ADAMK) - Fixed #61305 return { foo => 1 } should parse curlys as hash constructor, not block (WYANT) - Fixed #63943 map and regexp confuse PPI? (ADAMK) 1.213 Tue 6 Jul 2010 Summary: - Targetted bug fix, no changes to parsing or normal usage Details: - Updated to Module::Install 1.00 - Updated module depednencies in xt author tests - Fixed extremely broken PPI::Token::Pod::merge and added test case 1.212 Sun 9 May 2010 Summary: - Minor bug fixes and development support Details: - Fixed #48819: Bug in ForLoop back-compatilbilty warning - Added support for $ENV{X_TOKENIZER} --> $PPI::Lexer::X_TOKENIZER 1.211_01 Sun 21 Feb 2010 Summary: - Experimentation support and bug fixes Details: - Upgraded to Module::Install 0.93 - Added support for $PPI::Lexer::X_TOKENIZER, so that alternate experimentatal tokenizers can be swapped in for testing. - Added an extra 14_charsets.t case to validate we handle byte order marks properly. - Moved author tests from t to xt to reduce spurious test failures in CPAN Testers, when the testing modules change across versions - Fixed #26082: scalar { %x } is misparsed - Fixed #26591: VMS patch for PPI 1.118 - Fixed #44862: PPI cannot parse "package Foo::100;" correctly - Fixed #54208: PPI::Token::Quote::Literal::literal is missing due to case-sensitivity error 1.210 Mon 15 Feb 2010 Summary: - Packaging fixes Details: - No functional changes - Upgrading to Module::Install 0.93 - Added missing test_requires dependency for Class::Inspector 1.209 Sat 6 Feb 2010 Summary: - Small optimisation release Details: - No functional changes - Upgrading to Module::Install 0.92 - Moved the Test::ClassAPI test to only run during RELEASE_TESTING to reduce the dependency load (and occasionally Test::ClassAPI seems to FAIL on CPAN Testers. 1.208 Thu 14 Jan 2010 Summary: - THIS IS THE 100TH RELEASE OF PPI! - Fixes some tiny issues, otherwise unchanged from 1.207_01 Details: - Don't assign '' to $^W, it generates a warning on Gentoo - Added missing PPI::Token::Regexp fix to Changes file - Updating Copyright to the new year (yet again) 1.207_01 Thu 10 Dec 2009 Summary: - This is a general bug fix and accuracy release Details: - Fixed #50309: literal() wrong result on "qw (a b c)" - PPI::Dumper no longer causes Elements to flush location data. Also it no longer disables location information for non-Documents. - +{ package => 1 } doesn't create a PPI::Statement::Package - PPI::Token::Regexp and PPI::Token::QuoteLike::Regexp how have methods for getting at the various components (delimiters, modifiers, match & substitution strings). 1.206 Sun 9 Aug 2009 Summary: - This is an optimisation release (1-2% speed up) (Using information uncovered by a Devel::NYTProf 3 alpha) Details: - Removing som superfluous 1; returns - Using defined and ref to avoid highly excessive calls to PPI::Util::TRUE 1.205 Mon 3 Aug 2009 Summary: - This is a production release Details: - No changes from 1.204_07 1.204_07 Fri 31 Jul 2009 Summary: - Minor tweaks Details: - Allow ::For and ::List to return true to ->isa(::ForLoop) and do a once-per-process warning when we do. - Fixed a bug in Class::XSAccessor prototype. 1.204_06 Wed 22 Jul 2009 Summary: - API Change Details: - Changing PPI::Structure::ForLoop to PPI::Structure::For 1.204_05 Tue 21 Jul 2009 Summary: - Bug fixes in preparation for production release Details: - There is no longer any real reason to bundle the testing modules except as a potential source of more bugs. - Removed quantifier ? on zero-length ^ in /^?for(?:each)?\z/ - Run-time load PPI::Document instal of compile-time loading it - Tweak a few load orders to get PPI::Util loaded earlier. - Fixed location access methods on PPI::Element - New PPI::Statement::Include::version_literal() method. 1.204_04 Thu 16 Jul 2009 Summary: - Dependency tweaks Details: - Because we bundle Test::ClassAPI, we need to explicitly match its dependencies. Bumped Params::Util to 1.00. - Bumped a couple of deps a couple of revisions to get better XS. 1.204_03 Tue 14 Jul 2009 Summary: - More bug fixing, clean up, and optimisation - Cleaning up contributed APIs - Adding some demonstration classes Details: - Implemented PPI::Transform::UpdateCopyright - Removed the use of 'use base' - Various minor simplifications - Renamed PPI::Statement::Switch to ::Given - Renamed PPI::Structure::WhenMatch to ::When - Converted the Lexer internals to use exception-based error handling. - Take advantage of the removal of all those "or return undef" to simplify the Lexer code, remove variable declarations, and inline calls to several hot-code-path functions. The Lexer should be significantly faster (FSDO "significant"). - The v6 key on Tokenizer broke support for Perl 5.6 (perl thought it was a numeric v-string) 1.204_02 Sun 10 May 2009 Summary: - Various bug fixing and stabilisation work - It's a perl 5.10 extravaganza! Details: - Updated Module::Install to 0.87 - Added Test::NoWarnings to the test suite - Added support for qw{foo} in addition to for ('foo') - Added support for vstrings again - Now supports the 5.10 "state" keyword. (As far as PPI is concerned it's a synonym for "my") - Now supports switch statements. - Now supports the smart match operator (~~). - Now supports keeping track of line numbers and file names as affected by the #line directive. - Now supports UNITCHECK blocks. - Statement::Include::module_version() implemented. - Statement::Include::arguments() implemented. - Statement::Variable::symbols() implemented. - Token::QuoteLike::Words::literal() implemented. - Token::Quote::Double::simplify() fixed. - Element line_number(), column_number(), visual_column_number(), logical_line_number(), and logical_filename() implemented. - Support for Unicode byte order marks (PPI::Token::BOM) added. - Token::Word::method_call() implemented. - Element::descendant_of() and Element::ancestor_of() implemented. - Statement::specialized() implemented. - Now can handle files named "0". (Perl::Critic got a complaint about this) - foreach loop variables can be declared using "our". - Much more comprehensive testing of compound statement detection. 1.204_01 Sun 18 May 2008 Summary: - Unicode cleanup and bug fixing - Taking the opportunity to do some house cleaning while the code base is relatively stable, before things get crazy again. Details: - For completeness sake, add support for empty documents - Moved capability detection into PPI::Util - POD test script now skips on install properly - Removed 200 lines of old dead "rawinput" code from PPI::Tokenizer - 100% of PPI::Tokenizer is now exception-driven - Workaround for "RT#35917 - charsets.t eats all available VM" (unicode bug in 5.8.6, works in 5.8.8) - Temporarily disable round-trip testing of 14_charset.t 1.203 Wed 14 May 2008 Summary: - No change, switching to production version 1.202_03 Wed 14 May 2008 Summary: - Initial Perl 6 support - Bug fixes and final 1.203 release candidate - I finally catch up with all the failing test cases that Chris Dolan keeps commiting :) Details: - Adding initial support for "use v6-alpha;" - Adding new class Perl::Statement::Include::Perl6 - Adding a test on the KindaPerl6::Grammar, which triggered a bug in the tokenizer during CPAN::Metrics tinderboxing. - All open() calls now use three-argument form - Upgrading explicit Perl dependency to 5.006, because of the previous item. - Better support for labels, including tricky ones like "BEGIN : { ... }" 1.202_02 Wed 2 Jan 2008 Summary: - Back-compatibility and 1.203 release candidate Details: - Removing the use of use base 'Exporter'; - Updating Test::SubCalls dep to 1.07 to get the use base 'Exporter' fix for that too. 1.202_01 Tue 20 Nov 2007 Summary: - Minor bug fix release Details: - RT #30469: calling length() on PPI::Token gives error - 14_charsets.t was incorrectly skipping in situations that it should have been running. 1.201 Mon 22 Oct 2007 Summary: - Minor bug fix release Details: - The internal exception class PPI::Exception::ParserTimeout was inheriting from itself. 1.200 Mon 15 Oct 2007 Summary: - Production Release Details: - Zero changes from 1.199_07 - Updated version from 1.199_07 to 1.200 1.199_07 Fri 12 Oct 2007 Summary: - This is the third release candidate for 1.200 - Minor tweak Details: - Changed the way to detect Perl 5.6 to ignore the 1_0e1_0 failure 1.199_06 Wed 10 Oct 2007 Summary: - This is the second release candidate for 1.200 - Some small bug fixes Details: - Remove -w from test scripts to allow taint'enabled testing - Skip the failing 1_0e1_0 test on Perl 5.6.2 1.199_05 Tue 9 Oct 2007 Summary: - This is the first release candidate for 1.200 - Fix some parser corner cases Details: - Fixed parsing of %!, $^\w, and %^H - Fixed parsing of @{$foo}-1 - Fixed parsing of <$fh1>, <$fh2> 1.199_04 Summary: - Build tweaks - More regression changes Details: - Increasing List::Util dependency to 1.19 (Removes a memory leak on Win32) 1.199_03 Thu 12 Jul 2007 Summary: - Support for a few more rare/legacy Perl syntax - Tokenizer simplification, optimization and exception'ification Details: - Added support for the <<\EOF heredoc style - Always create ->{type} in full-quote sections - Converted more of the Tokenizer to use exceptions - Optimized away a bunch of now-unneeded "or return undef" - Optimized _set_token_class down to a single statement - Inlined _set_token_class out of existance - Cache and fast-clone PPI::Token::Whitespace->null - Removed some superfluous parameter checks on private methods, for conditions that would cause explosions and be noticed anyway. - Removed the fancy options from PPI::Token::new - More consistent structure of incomplete quotes 1.199_02 Mon 5 Mar 2007 Summary: - Added parser timeout support - Fixing various regression cases - Adding some housekeeping tweaks Details: - Created PPI::Exception with an eye to moving towards using exceptions more for error handling (for speed). The goal is to get rid of the "or return undef"s. - Added the timeout param to the PPI::Document constructor which uses alarm to implement basic timeout support. This should help when parsing a large corpus on Unix. (Not available on Win32) - Fixed incorrect location() for PPI::Structure instances. - Adding better parsing of hash constructors. - Pushing Clone dependency to 0.22 to get closer to taint support) - Pushing deps on bundled test modules to prevent accidentally bundling old versions. 1.199_01 Tue 31 Oct 2006 Summary: - Improved lexing correctness - Partial implementation of literal - Initial implementation of Number classes (Chris Dolan) Details: - Split out PPI::Token::Number subclasses - Implement numbers with exponential notation - Implement literal() for ::Number classes (except ::Version) - Implement literal() for ::Token::Quote::Single - Added -T for inline tests - Add tests for nested statements and nested structures - Fixed some bugs as a result - Improved detection of the correct curly brace structure types 1.118 Fri 22 Sep 2006 Summary: - Better 5.10 support - Fixing various (mostly parsing) bugs Details: - Upgraded to Module::Install 0.64 - Improving support for dor and added //= operators - Fixed parsing of binary, octal and hex numbers - Fixed parsing of /= and *= - Fixed #21571 symbol() returns just sigil with adjacent braces - Fixed #21575 variables() chokes on list with whitespace - Fixed #20480 (Misparse of some floating-point numbers.) - Fixed #19999: Make test fails (undeclared global variable $document) under Perl 5.6.2 (or at least, I think I have. This needs double-checking on Perl 5.6.2) - Partially Fixed #16952: [PATCH] Speed up tokenizer char-by-char (Did not apply the patch, but fixed a bug noted as an aside in the report) - PPI::Document::File was returning a plain PPI::Document object, fixed. - FINALLY added some basic POD for PPI::Structure, the one class I somehow keep forgetting to do. 1.117 Sat 02 Sep 2006 Summary: - Fixing bugs introduced in 1.116 Details: - Simple compound statements "{ 1 }" were not end-detecting properly - The new handling for the "-" character was shortcutting naively - Labelled compound statements were not end-detecting properly - { package => 1 } was treating package incorrectly - Fixed bugs in test cases submitted by the Perl::Critic team - Added a number of extra test cases, and introduced Test::Object based testing for PPI::Document objects. 1.116 Thu 31 Aug 2006 Summary: - PPI::Document::File first release - Adding readonly attribute - Fixed various accumulated bugs Details: - Upgraded to Module::Install 0.63 - Add a new file-only subclass of PPI::Document - Added the readonly attribute to the PPI::Document->new constructor - Added method PPI::Document->readonly method - 'goto' is a PPI::Statement::Break - Re-fixed #19629: End of list mistakenly seen as end of statement - Applied #16892: [PATCH] docs and comments - Fixed #16815 (location of Structure::List is not defined.) - Fixed misparsing of C< 1-1 > - Fixed #18413: PPI::Node prune() implementation broken - Fixed #20428 (minor doc bug in PPI::Token::Symbol) - Resolved NOTABUG #20031 (PPI installation) - Resolved NOTABUG #20038 (PPI installation) - Fixed #19883: 'package' bareword used as hash key is detected as package statement - Fixed #19629: End of list mistakenly seen as end of statement - Fixed #15043: (no description) # He wanted PPI::Document::File 1.115 Sat 03 Jun 2006 Summary: - Fixing rt.cpan.org bugs Details: - Fixed #19614: Suspicious code in PPI::Structure - Fixed #16831: until () { } not parsed as compound statement - NOTABUG #16834: "$a = 1 if ($a == 2)" vs "$a = 1 if $a == 2" - Fixed #19629: End of list mistakenly seen as end of statement - Fixed #18413: PPI::Node prune() implementation broken 1.114 Thu 25 May 2006 Summary: - This release addresses only dependency issues Details: - Changed over from IO::Scalar to IO::String - Added a dependency on Task::Weaken so that we can make various not-so-clueful downstream packagers play nicely. 1.113 Wed 10 May 2006 Summary: - This release contains only build-time changes Details: - Upgraded to Module::Install 0.62 - No features() used in this dist, so removing auto_install 1.112 Mon 24 Apr 2006 Summary: - Emergency release to fix a bug that prevents install on perl > 5.8.4 Details: - Small typo in the unicode-specific section of 14_charsets.t prevents tests passing for anyone with a unicode-sane Perl version. - Added a test for strange locales that can't handle unicode, and skip the unicode tests. 1.111 Sat 22 Apr 2006 General - Moved from SourceForge CVS to new collaborative SVN repository - Fixed regressions other people had added since 1.110 - Upgraded to Module::Install 0.62 Details: - SourceForge was too hard to get into, so moved to specially designed new SVN repository to make it easy for others to help out. - Moved t.data to t/data in line with current style and to reduce complexity. - Fixed t/data/08_regression/11_multiply_vs_glob_cast (added by unknown) - Fixed t/data/08_regression/12_pow (added by unknown) - Removed every use of UNIVERSAL::isa in the tests - Upgraded to Module::Install 0.62 (my private prerelease) 1.110 Fri Jan 27 2005 General - Added test support for the third location component (Arjen Laarhoven) - Various bug fixes (Releasing early with only small changes at the request of Perl::Critic) Details: - Fixed CPAN #16924: PPI::Statement::Sub.pm fix to use Params::Util line to resolve _INSTANCE error - Fixed CPAN #16837: typo in PPI::Statement::Expression POD - Fixed CPAN #16973: PPI 1.109 shouldn't require List::Util 1.18 (We do need 1.18 to avoid a leak, but it doesn't work everywhere) - Fixed CPAN #16814: _INSTANCE method not defined in PPI::Statement::Sub (dupe) - Arjen Laarhoven added to CVS committers - Added a third element to ->location return arrayref that contains the visual starting column of the token, taking into account tabbing. 1.109 Fri Dec 30 2005 Summary: - Various bug fixes - Minor structural cleanup Details: - Removed every single use of UNIVERSAL::isa - PPI::Normal was quite broken, cleaned it up - Fixed PPI::Normal::Standard::remove_statement_seperator - Fixed CPAN #16674 PPI::Token::Quote::Double->interpolations (awigley) - Fixed CPAN #15131 PPI::Node->find() behavior not completely documented (Jeffrey Thalhammer) - Fixed CPAN 13743 PPI::Statement::Scheduled api (johanl) - PPI::Statement::Scheduled is now a subclass of PPI::Statement::Sub - Removed breaking circular include in PPI::Util - Removed an 'our' variable in t/04_element.t that created a 5.6.0 dependency - Only do the PPI::Cache tests that use Test::SubCalls if >= 5.006 - (Except for File::Remove, we should ACTUALLY depend on 5.005 now) - Fixed CPAN #16671 $_ is not localized (JPIERCE) (I missed an unlocaled $_ hiding in the Node object destructor) 1.108 Thu Dec 15 2005 Summary: - Fixing of some very minor bugs Details: - 8 wasn't an illegal character in an octal number (fixed) - Two <= 5.8.5) (not pre-checked and enforced yet, but will be) - Starting new generation of "exhaustive" testing Details: - Added 20_tokenizer_regressions, which tests all detectably-failing 3-or-less character long Perl programs (not inclusive of latin-1 or Unicode). (Audrey Tang) - Fixed bug for incomplete quotes at EOF (there may be a few more similar cases) - Fixed bug with $'0 (where 0 is only legal after ::) - No longer die for illegal chars in hex/bin number types (Attach the error to $token->{_warning} instead) - Caught a number of cases with trailing colons for $things (Both at EOF and end of token) - Convert [^\W\d]\w* to (?!\d)\w+ to improve unicode support in symbols etc (Audrey Tang) - Miscellaneous doc bugs in the SYNOPSIS (Audrey Tang) 1.104 Thu Nov 10 2005 General - No change to code - Both List::Util and List::MoreUtil contain memory leaks, and we use them extensively. Pushed the dependencies up to versions with the memory leaks fixed. 1.103 Thu Oct 6 2005 General - Small bug fix that shouldn't have escaped Details: - Changed md5hex_file to act more like the PPI::Documeny way. That is, localise and THEN convert to \015 1.102 Wed Oct 5 2005 General - Small things to support Perl::Metrics Details: - Added undocumented PPI::Util::md5hex_file function 1.101 Thu Sep 29 2005 General - Bug fix release Details: - Fixed CPAN bug #14436 and #14440, misparse for my ($foo) ... - Added an self-analysis test script for PPI-testable problems - Fixed some minor bugs it threw up. 1.100_03 General - Major bug fixing - Some additions to help simplify Perl::Metrics Details: - A whole bunch (practically all) of the sibling code was breaking under non-trivial use. Fixed, with a number of new tests added. - Added function PPI::Util::md5hex - Added method PPI::Document::hex_id 1.100_02 General - Various bug fixes - Completed the first version of PPI::Cache Details: - Expanded round-trip testing coverage to all the lexer and regression test files - 06_round_trip.t wasn't doing the round-trip test properly. Fortunately, this only resulted in false failures, so no actual damage was done as a result of this. 1.100_01 Sat Sep 03 2005 Summary: - Added integrated cache support Details: - Added PPI::Cache class - Removed warning in 99_pod.t - Added a common PPI::Util::_slurp function - PPI::Document can be given a cache to use 1.003 Tue Aug 18 2005 Summary: - Bug fix release Details: - Add support for 'for $foo () {}' - Add support for 'for my $foo () {}' - Fixed bug where "'Hello..." crashed the Tokenizer - Fixed bug where '"Hello...' crashed the Tokenizer - Fixed bug where 's' crashed the Tokenizer 1.002 Thu Jul 14 2005 Summary: - Bug fix release Details: - Fixed CPAN #13655 - insert_before and insert_after broken. 1.001 Tue Jul 12 2005 Summary: - Turning on Test::Inline scripts Details: - Bug fix: ->string returns wrong for qq and all braced quotes - Added Test::Inline 2.100-type inline2test.conf and inline2test.tpl files - Added t/ppi_token__quoteengine_full.t - Added t/ppi_token_quote_single.t - Added t/ppi_token_quote_double.t - Added t/ppi_token_quote_literal.t - Added t/ppi_token_quote_interpolate.t 1.000 Sat Jul 9 2005 Summary: - FIRST PRODUCTION RELEASE - Finalising POD, corrected the Copyright dates - Rewrote much of the main PPI.pm docs - Removing more unneeded dependencies - Added native Storable support Details: - Removed dependency on Class::Inspector - Added build dependency on Class::Inspector and include() it (although it's still needed at build time, this still does manage to reduce the number of files to download by one more) - Added PPI::Document::STORABLE_freeze and PPI::Document::STORABLE_thaw 0.996 Fri Jul 8 2005 Summary: - RELEASE CANDIDATE 2 - Clearing all remaining RT bugs - Removing and inlining dependencies Details: - Resolved PDOM bug CPAN #13454 ( while ( $s = $s->sprevious_sibling ) infinite loops ) Mental Note: Doing an auto-decrement in an array subscript is BAD - Resolved Lexer bug CPAN #13425 ( $p{package} creates a PPI::Statement::Package ) Added smarts to resolve word-started statements as ::Expression in subscripts - Resolved PDOM bug CPAN #13326 ( problems in index_locations ) Patch and comprehensive additional tests provided by johanl[ÄT]DarSerMan.com - Removed dependency on Class::Autouse. Just load Tokenizer and Lexer up front. - Removed dependency on File::Slurp. Only use it 3 times and it's not worth it when almost all the files we will read are under 50k. 0.995 Sun Jul 3 2005 Summary: - RELEASE CANDIDATE 1 - Added some internals to help with XML compatibility - Completed primary POD docs - Completed first versions of insert_before and insert_after - Removed last uses of _isa - Added final missing POD docs Details: - Added convenience method PPI::Element::class - Added docs for all PPI::Structure classes - Added additional tests to check for ::Unknown classes - Added PPI::Document::insert_before to return an error - Added PPI::Document::insert_after to return an error - Added PPI::Document::replace to return an error - Removed a number of unneeded UNIVERSAL::isa imports - Removed PPI::Token::_isa before anyone starts using it. It was hacky and unsuitable to a production release 0.994 skipped 0.993 Tue Jun 21 2005 Summary: - Various minor code, packaging and POD cleanups Details: - Corrected a POD bug in PPI::Dumper - Upgraded PPI::Dumper param checking to Params::Util - Restored PPI::Element->clone to using Clone::clone ( 0.17+ ) - Removed dependency on Storable - Until it fixes the problem, explicitly include ExtUtils::AutoInstall 0.992 Sun Jun 12 2005 Summary: - Added the PPI::Transform API 0.991 Fri Jun 10 2005 - Typo. I wasn't dieing on newlines to PPI::Document->new( string ) correctly, and thus dieing without the API CHANGE message. This was confusing people as to why. 0.990 Wed Jun 8 2005 Summary: - Last version (hopefully) to make API changes - Slight API shuffle in the constructors - Completed all PPI::Statement::* API documentation - Enabled latin-1 support in the appropriate places 0.906 Thu Apr 28 2005 Summary: - Completed location support and added related unit tests - Added API for future support of tab widths Details: - Removed PPI::Element::_line - Removed PPI::Element::_col - Fixed bugs in PPI::Document::index_location - Fixed bugs in PPI::Element::location - Added 12_location.t unit test - Added PPI::Document::tab_width method - Added PPI::Normal::Standard::remove_useless_attributes (to remove the ->{tab_width} attributes and later other things) 0.905 Wed Apr 20 2005 Summary: - Completely forgot to write unit tests for PPI::Util, and a bug slipped in. Fixed and added tests Details: - Fixed bug in PPI::Util::_Document - Added 11_util.t 0.904 Wed Apr 20 2005 Summary: - Improvements to PPI::Normal - Method renaming to parse-time PDOM private methods - Various bug fixes and POD tweaks - Added PPI::Util Details: - Partly added Layer 2 to PPI::Normal - Added function PPI::Normal::Standard::remove_useless_pragma - Added function PPI::Normal::Standard::remove_statement_seperator - Added function PPI::Normal::Standard::remove_useless_return - Renamed _on_line_start to __TOKENIZER__on_line_start - Renamed _on_line_end to __TOKENIZER__on_line_end - Renamed _on_char to __TOKENIZER__on_char - Renamed _scan_for_end to __TOKENIZER__scan_for_end - Renamed _commit to __TOKENIZER__commit - Renamed _is_an_attribute to __TOKENIZER__is_an_attribute - Renamed _literal to __TOKENIZER__literal - Renamed _opposite to __LEXER__opposite - Fixed bug in PPI::Statement::Package::namespace - Added unit tests for PPI::Statement::Package - Added (currently mostly internal) PPI::Util - Added exportable function PPI::Util::_Document 0.903 Fri Mar 25 2005 Summary: - PPI::Document and other PPI::Node-subclasses will now implicitly DESTROY correctly. - Now that PPI.pm is just a module loader, merge the main documentation from PPI::Manual back into it again. Details: - Added use of Scalar::Util::weaken for all %_PARENT writes - Uncovered critical bug in Clone, so we use Storable::dclone for now, until Clone is fixed. This resolves rt.cpan.org #11552 - Added dependency on Storable 1.13 - Moved all PPI::Manual content to PPI and relinked This resolves rt.cpan.org #11803 - Removed lib/PPI/Manual.pod - Added the standard 99_pod.t to check POD - Fixed a POD bug in Element.pm 0.902 Sun Feb 6 2005 Summary: - Added Document Normalization functions from old Perl::Compare (although it is very very limited in function at this point) Details: - Added class PPI::Normal - Added class PPI::Normal::Standard - Added class PPI::Document::Normalized - Added method PPI::Document->normalize - Bug: ->clone was going to all the trouble to build a clone, but then returning the original :( Fixed 0.901 Sat Jan 29 2005 Summary: - Moved all up-to-date code over to SourceForge - Various fixes to allow the release of File::Find::Rule::PPI Details: - Got all modules synchronising their versions correctly - Moved to SourceForge CVS repository - Changed all files over to the new CVS directory layout - Fixed bug in PPI::Node::find_first - Added unit tests for PPI::Node::find_first - Added unit tests for PPI::Node::find_any - Added a stub and docs for PPI::Statement::stable 0.900 Mon Jan 17 2005 Summary: - Final removal of PPI::Base - Completed majority of crash bugs in the Tokenizer Details: - Fixed Tokenizer Bug C< @foo = < seen as ::Readline - Fixed Tokenizer Bug C< (< seen as ::Readline - Fixed Tokenizer Bug C< q'foo bar' > parsed incorrectly - Fixed bug in PPI::Token::_QuoteEngine::_scan_quote_like_operator_gap - Fixed Tokenizer Bug C< $foo:'' > sees symbol $foo:' - Fixed Tokenizer Bug C< $#arrayindex > was seen as a Symbol - Fixed Tokenizer Bug C< %2 > was seen as a Symbol - Fixed Tokenizer Bug C< &64 > was seen as a Symbol - Fixed Tokenizer Bug C< $::| > is actually a Magic - Fixed Tokenizer Bug C< @0 > is a Magic - Deleted PPI::Base - Added $PPI::Element::errstr - Added basic private error methods to PPI::Element - PPI::Element::significant now returns '' as false - PPI::XS - Added all C methods 0.846 Mon Jan 17 2005 Summary: - Added proper support for - Last release before beta 1 if all looks good Details: - Added class PPI::Token::QuoteLike::Readline - Added t.data/05_lexer_practical/10_readline.code/dump - Added support for <> - A few other minor bug fixes 0.845 Sat Jan 15 2005 Summary: - Adding integration with PPI::XS, autoloading if installed Details: - Added $PPI::XS_COMPATIBLE and $PPI::XS_EXCLUDE variables to guide integration - Don't autoload PPI::Document, always load - Load in PPI::XS whenever it is installed - Loading and depending on Class::Inspector - PPI::Element::significant implemented in XS (as a trial) 0.844 Fri Jan 14 2005 Summary: - Found a massive performance bug when parsing large perl constructs - Fixed some install problems Details: - PPI::Node::schild was copying the entire of it's child array each call. This was causing massive slowdowns when ->{children} got large. Fixed. - The core tests still expect Transform to be in the core. Fixed. 0.843 Tue Jan 12 2005 Summary: - Starting the process of removing PPI::Base. It only does does error handling now, which will be split up. - Fixing some packaging and "play well with others" issues Details: - Randal Schwartz pointed out t/06... wouldn't working for him. It appears when Test::More bug CPAN #8385 was fixed, we broke. - We now include build-time-only dependencies in the installer - Although unusable, PPI::Document::Normalized's version fell out of sync with the rest of the distribution. Fixed. - PPI::Tokenizer no longer inherits from PPI::Base - Added class variable $PPI::Tokenizer::errstr - Added class method PPI::Tokenizer->errstr - Fixed Tokenizer Bug: C< y => 1 > was being seen as a regex - Fixed Tokenizer Bug: C< <<''; > was dying because I expected at least one character - Fixed Tokenizer Bug: C< $foo->{s} > was being seen as a regex 0.842 Tue Jan 11 2005 Summary: - Lots of debugging based on Tinderbox results Details: - Fixed MANIFEST.SKIP to removed PPI::Transform and PPI::Tinderbox from the core PPI distribution (like they should be) - Optimised the previous #9582 to not have to run for EVERY word, only those where it might be needed. - Corrected a use of QuoteLike::Execute to QuoteLike::Backtick - Fixed CPAN #9598 Tokenizer Bug: C< qx( $command ) > - Fixed CPAN #9614 Tokenizer Bug: C< $foo << 16 > - Set the properly includive regex for << '...' here-doc - Added an very early filter to prevent non-basic chars going in 0.841 Mon Jan 10 2005 Summary: - Completed much more documentation on the core classes - PPI::Tester back in sync again (seperate distribution) - PPI::Processor and PPI::Tinderbox completed (seperate distribution) Details: - Documented PPI::Tokenizer - PPI::Document->new( $source ) added as a convenience - PPI::Lexer::lex_file can now be called statically - PPI::Lexer::lex_source can now be called statically - PPI::Lexer::lex_tokenizer can now be called statically - Fixed a small bug in PPI::Dumper::print - Fixed CPAN #9582 Tokenizer Bug: C< sub y { } # Comment > - Fixed similar case with C< foo->y() > 0.840 Thu Dec 21 2004 Summary: - Changed the PPI summary to no longer use the devisive word "parse" Now: "PPI - Analyze and manipulate Perl code without using perl itself" - Total rewrite of all the ->location code - Upgrading MakeFile.PL to Module::Install - Fixed #CPAN 8752 (a round-trip edge case bug) - Added 08_regression.t to do code/dump regression testing for lexer bugs - Completed (hopefully) HereDocs conversion to a single complex token - PPI is now compatible with prefork.pm (although not dependant) Details: - Added PPI::Node::find_first object method - Changed PPI::Node::find_any to just call PPI::Node::find_first - Added PPI::Element::first_token object method - Added PPI::Element::last_token object method - Made a partial-removal-capable PPI::Element::_flush_locations - PPI::Document::flush_locations uses PPI::Element::_flush_locations - PPI::Document::index_locations is here-doc sane - Added PPI::Token::HereDoc::heredoc object method - Added PPI::Token::HereDoc::terminator object method - Documented PPI::Token::HereDoc - Added a HereDoc code/dump test to 05_lexer_practical.t - Added PPI::Document::serialize, which replaces the use of ->content for generating the actual string to write out to files when saving Documents. - File::Spec reduced from dependency to build dependency - Updated Test::ClassAPI dependency to newest version - Enabled API collision detection in 02_api.t - Updated Class::Autouse dependency to newest version 0.840_01 Tue Dec 21 2004 Summary: - Perl Foundation Funding Commences - Changes separated into General and Details from here on - Complete re-organisation of the quote-like token classes. Any and all code that works with quotes will be broken. - Gave up on the old PPI::Query code and wrote a complete new and much thinner implementation based roughly on the API of File::Find::Rule. PPI::Find uses the &wanted function (which also has a slightly different API to the old one) but has the ->in style search methods. It should be relatively easy for someone to write PPI::Find::Rule on top of it. - PPI::Transform is thus temporarily stale Details: - Introduced a bug for C< foreach $foo () > and caught/fixed it during the changeover. - Changed PPI::Lexer::Dump to PPI::Dumper - API Freeze PPI::Find - API Freeze PPI::Dumper - Documented PPI::Find - Documented PPI::Dumper 0.831 Fri Nov 5 2004 - Overloaded PPI::Document bool => true - Overloaded PPI::Document "" => content (That is, ::Documents stringify to their content) - Fixed PPI::Document::save - Merged Leon Brocard's docs patch - Cleaned up PPI::Node::_condition and documented conditions better (fixed #7799) - Allow dropping of the initial PPI:: in class search conditions - Fixed two instances of File::Slurp::read_file being called as a method 0.830 Mon Sep 27 2004 - Added PPI::Statement::Package::file_scoped object method - Handle potentially dangerous C< sub foo ($$ > safer - Resolve C< sub BEGIN { } > to PPI::Statement::Scheduled correctly - Resolve C< sub () { 1 }; > to PPI::Statement correctly - API Freeze PPI::Statement::Package - API Freeze PPI::Statement::Scheduled - API Freeze PPI::Statement::Sub - Documented PPI::Statement - Documented PPI::Statement::Package - Documented PPI::Statement::Scheduled - Documented PPI::Statement::Sub - Documented PPI::Document::Fragment 0.829 Sat Sep 25 2004 - BREAKS API COMPATIBILITY - Changed PPI::Token::SubPrototype to PPI::Token::Prototype - Added PPI::Token::Prototype::prototype object method - Added PPI::Statement::Sub::prototype object method - Added PPI::Statement::Sub::block object method - Fixed PPI::Statement::Include::version 0.828 Sun Aug 8 2004 - BREAKS API COMPATIBILITY - Changed PPI::Token::DashedBareword to PPI::Token::Quote::Dashed - Changed PPI::Token::Bareword to PPI::Token::Word - Vastly improved PPI::Manual 0.827 Thu Aug 5 2004 - Added PPI::Token::Seperator class ( for __DATA__ and __END__ ) - Added better Tokenizer handling of __DATA__ and __END__ - Added better Lexer handling of __DATA__ and __END__ - Fixed some version inconsistencies 0.826 Sat Jul 31 2004 - Added PPI::Element::statement object method - Added PPI::Transform abstract class - Sped up the 'bool' overload for PPI::Element - Added PPI::Element::snext_sibling object method - Added PPI::Element::sprevious_sibling object method - Added PPI::Element::insert_before object method placeholder - Added PPI::Element::insert_after object method placeholder - Changed {elements} to {children} to match PPI::Node definitions - Added PPI::Node::first_element object method - Added PPI::Node::last_element object method - Added PPI::Element::next_token object method - Added PPI::Element::previous_token object method - Added PPI::Token::Symbol::symbol object method 0.825 Mon Jul 26 2004 - Added PPI::Statement::Include::type object method - Added PPI::Statement::Include::module object method - Added PPI::Statement::Include::pragma object method - Added PPI::Statement::Include::version object method - Overloaded == as "the same object" for PPI::Element - Overloaded eq as "->content is the same" for PPI::Element - Overloaded bool as always true, to prevent an error - Added PPI::Statement::Package::namespace object method - 100% round-trip safe. What goes in, will come out. - Reduced leaks by 95%. Process size 30meg after 5000 files. Still some leaks remaining when Lexing errors out. - Seperated largest Tokens into their own files. This aligns token class structure with that of ::Statement and ::Structure - Rewrote PPI::Node::DESTROY several times while hunting down more leaks - Fixed Tokenizer crash on empty subroutine prototypes such as C< sub foo() {} > - Treat unexpected braces as an implicit close, to make the lexer more resilient - Added PPI::Statement::UnmatchedBrace (name suggested by Abhijit Menon-Sen) to handle closing braces found at the base of a Document. - Enabled foo'bar package notation again. - Getting close to the first 0.900 series beta release 0.824 Wed Jul 21 2004 - Removed a 6 meg tmon.out file I accidentally bundled 0.823 Wed Jul 21 2004 - Added PPI::Document::Fragment class - Added PPI::Node::schildren object method - Completed compound statement parsing - Lexer is now officially feature complete 0.822 Wed Jul 21 2004 - Filling out the API test as much as possible - Added PPI::Statement::label object method - Moved PPI::Structure::elements object method to PPI::Node::elements - Re-organised statement parsing to better implement ::Compound statements - Added PPI::Statement::Data class - Added PPI::Statement::End class - Re-organised the _lex_statement, _statement_continues stuff, ready for while - Added PPI::Lexer::_lex_statement_end to handle PPI::Statement::End properly - Organising 02_api.t was getting hard, so added implicit Module=class to Test::ClassAPI 0.821 Mon Jul 19 2004 - Cleaned up test data files directories - Added PPI::Statement::Variable::type object method - Added PPI::Statement::Variable::variables object method - Added some more classes to the API testing - Started 07_tokens.t for testing particular token classes - Added PPI::Token::Symbol::canonical object method (and tests) - PPI::Token::Magic now ISA PPI::Token::Symbol - PPI::Element::clone now fixes _PARENT links for Nodes 0.820 Mon Jul 19 2004 - Added Round-Trip-Safe testing for all PPI files - Added PPI::Node::find_any object method - Added PPI::Node::contains object method - Continuing the never ending addition of tests - Structure open and close brace tokens now see the Structure as their parent - Removed the sample application, to streamline the core install - Removed dependencies for the sample application - Removed custom META.yml, as now no longer needed 0.819 Mon Jul 14 2004 - Many parts of PPI are VASTLY changed in this revision - Breaks API compatibility heavily - Adds dependency on List::MoreUtils - Added PPI::Lexer support for CHECK blocks - Added PPI::Document::load method - Added PPI::Document::save method - Added PPI::Document::index_locations method - Added PPI::Document::flush_locations method - Added PPI::Element::top method - Added PPI::Element::document method - Renamed PPI::Element::extract -> PPI::Element::remove - Added test script for element-y stuff - Optimisation across the board using List::Any - Added PPI::Node::first_child method - Added PPI::Node::last_child method - Added PPI::Element::clone method - Removed Filehandle support from PPI::Tokenizer, to allow the ability to rollback source lines into the buffer if needed. - Added POD documentation for PPI::Element - Added POD documentation for PPI::Node - Added POD documentation for PPI::Document 0.818 Mon Jul 5 2004 - Changed lib/PPI/Manual.pm to lib/PPI/Manual.pod - Added documentation for PPI::Lexer - Fixed the misparsing of s{//}{\} - More clues added for deciding "slash or regex" - Removed PPI::Batch from the default distribution - Replaced File::Flat with File::Slurp to reduce dependencies 0.817 Thu Jul 1 2004 - Fixed the misparsing of $#{ } - Changed PPI::ParentElement to PPI::Node and moved it to it's own file - Changed PPI::Common to PPI::Base - Fixed PPI::Node::find - Added PPI::Node::prune - Started to add a little more class structure documentation - Tried to make the DESTROY sequence of events work better 0.816 Tue Jun 29 2004 - Solved the "last token in file parses wrong" bug 0.815 Sun Jun 27 2004 - Fixed a bug with the detection of @- and @+ - Added support for @* - Added missing classmap entry for ^ to ::Token::WhiteSpace - Added support for arcane "foo"x10 idiosyncracy 0.814 Sat Jun 26 2004 - Added the PPI tester, a desktop-based interactive debugger, which should greatly accelerate finding and fixing both ::Tokenizer and ::Lexer bugs. This will probably end up as a seperate distribution though, as it has a dependency on wxPerl. - Fixed the misparsing of Foo::Bar::Baz - Fixed the misparsing of *100 - Fixed the misparsing of Class::->method properly, or rather Foo:: - Tokenizer correctly identifies labels - Changed PPI::Statement::Flow to PPI::Statement::Compound - Removed the extra null whitespace token appearing after a bareword at the end of a file. - -X operator are recognised correctly, although not at end of file - Lexer detects subroutine and if () statement ends correctly 0.813 Sat Jun 26 2004 - PPI::Lexer is now structurally complete 0.812 Tue Jun 22 2004 - No changes to PPI itself. - With the addition of Test::ClassAPI 'complete' support, upgraded 02_api.t to use it. Fixed a few small house-keeping bugs. 0.811 Mon Jun 21 2004 - Added support for subroutine attributes - Fixed some problems with anonymous subroutines and prototypes - $#$foo parses as (Cast,Symbol) now, not (Magic,Symbol) 0.810 Mon Jun 14 2004 - Recognise the _ magic filehandle 0.809 Sat Apr 17 2004 - No changes to PPI itself. Set the correct number of tests to match changes to Test::ClassAPI 0.808 Sat Apr 17 2004 - No changes to PPI itself. Upgraded 02_api.t to match changes to Test::ClassAPI 0.807 Sat Apr 3 2004 - Added a manual META.yml file to stop the bundled private AppLib library from being indexed by CPAN 0.806 Mon Mar 22 2004 - The $} magic variable is now supported - Fixed a "tight sub property" bug ( sub foo:lvalue ) 0.805 Sun Sep 28 2003 - The maximum line length regressed, reseting it to 5000. - In PPI::Format::HTML, not any parsing error causing a premature end of tokenizer by adding it in a comment at the end of the file. 0.804 Sat Sep 06 2003 - Statement and Structure resolution preliminarily work. Some basic types of statements and structures are identified. - PPI::Format::Apache has been seperated into a different module 0.803 Sat Sep 06 2003 - Added very long line protection support. Maximum line length is now 5000. - Added bug fixes to the Lexer so that block tree building works mostly OK again, without adding broken duplicate tokens. - Added the PPI::Lexer::Dump module, to do Lexer object dumps. 0.802 Sat Aug 23 2003 - PPI::Format::HTML sends the correct content headers 0.801 Fri Aug 22 2003 - Moved to a new numbering scheme to get more room before 1.0 - Always fully load when called under mod_perl - Add mod_perl hook to PPI::Format::HTML 0.8 Fixes to the quote parsing engine 0.7 Fixed some minor bugs 0.6 Fixed POD, fixed version number, included $'a as a symbol 0.5 Missing 0.4 Mon Dec 23 10:24:21 - Some more minor parsing fixes in Tokenizer - Completely changed the API from doThis to do_this style - Changed API to indicate private methods properly 0.3 Tue Dec 17 10:29:27 - Restructured a little bit - Fixed some mis-parsing cases 0.2 Unknown - Added test script 0.1 Thu Dec 06 16:50:23 2002 - original version PPI-1.215/LICENSE0000644000175100017510000004737111532117301011555 0ustar adamadam Terms of Perl itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" ---------------------------------------------------------------------------- The General Public License (GPL) Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ---------------------------------------------------------------------------- The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End PPI-1.215/inline2test.conf0000644000175100017510000000003611532117301013642 0ustar adamadamreadonly=1 input=lib output=t PPI-1.215/MANIFEST0000644000175100017510000002217511532120243011673 0ustar adamadamChanges inc/Module/Install.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Win32.pm inc/Module/Install/With.pm inc/Module/Install/WriteAll.pm inline2test.conf inline2test.tpl lib/PPI.pm lib/PPI/Cache.pm lib/PPI/Document.pm lib/PPI/Document/File.pm lib/PPI/Document/Fragment.pm lib/PPI/Document/Normalized.pm lib/PPI/Dumper.pm lib/PPI/Element.pm lib/PPI/Exception.pm lib/PPI/Exception/ParserRejection.pm lib/PPI/Exception/ParserTimeout.pm lib/PPI/Find.pm lib/PPI/Lexer.pm lib/PPI/Node.pm lib/PPI/Normal.pm lib/PPI/Normal/Standard.pm lib/PPI/Statement.pm lib/PPI/Statement/Break.pm lib/PPI/Statement/Compound.pm lib/PPI/Statement/Data.pm lib/PPI/Statement/End.pm lib/PPI/Statement/Expression.pm lib/PPI/Statement/Given.pm lib/PPI/Statement/Include.pm lib/PPI/Statement/Include/Perl6.pm lib/PPI/Statement/Null.pm lib/PPI/Statement/Package.pm lib/PPI/Statement/Scheduled.pm lib/PPI/Statement/Sub.pm lib/PPI/Statement/Unknown.pm lib/PPI/Statement/UnmatchedBrace.pm lib/PPI/Statement/Variable.pm lib/PPI/Statement/When.pm lib/PPI/Structure.pm lib/PPI/Structure/Block.pm lib/PPI/Structure/Condition.pm lib/PPI/Structure/Constructor.pm lib/PPI/Structure/For.pm lib/PPI/Structure/Given.pm lib/PPI/Structure/List.pm lib/PPI/Structure/Subscript.pm lib/PPI/Structure/Unknown.pm lib/PPI/Structure/When.pm lib/PPI/Token.pm lib/PPI/Token/_QuoteEngine.pm lib/PPI/Token/_QuoteEngine/Full.pm lib/PPI/Token/_QuoteEngine/Simple.pm lib/PPI/Token/ArrayIndex.pm lib/PPI/Token/Attribute.pm lib/PPI/Token/BOM.pm lib/PPI/Token/Cast.pm lib/PPI/Token/Comment.pm lib/PPI/Token/DashedWord.pm lib/PPI/Token/Data.pm lib/PPI/Token/End.pm lib/PPI/Token/HereDoc.pm lib/PPI/Token/Label.pm lib/PPI/Token/Magic.pm lib/PPI/Token/Number.pm lib/PPI/Token/Number/Binary.pm lib/PPI/Token/Number/Exp.pm lib/PPI/Token/Number/Float.pm lib/PPI/Token/Number/Hex.pm lib/PPI/Token/Number/Octal.pm lib/PPI/Token/Number/Version.pm lib/PPI/Token/Operator.pm lib/PPI/Token/Pod.pm lib/PPI/Token/Prototype.pm lib/PPI/Token/Quote.pm lib/PPI/Token/Quote/Double.pm lib/PPI/Token/Quote/Interpolate.pm lib/PPI/Token/Quote/Literal.pm lib/PPI/Token/Quote/Single.pm lib/PPI/Token/QuoteLike.pm lib/PPI/Token/QuoteLike/Backtick.pm lib/PPI/Token/QuoteLike/Command.pm lib/PPI/Token/QuoteLike/Readline.pm lib/PPI/Token/QuoteLike/Regexp.pm lib/PPI/Token/QuoteLike/Words.pm lib/PPI/Token/Regexp.pm lib/PPI/Token/Regexp/Match.pm lib/PPI/Token/Regexp/Substitute.pm lib/PPI/Token/Regexp/Transliterate.pm lib/PPI/Token/Separator.pm lib/PPI/Token/Structure.pm lib/PPI/Token/Symbol.pm lib/PPI/Token/Unknown.pm lib/PPI/Token/Whitespace.pm lib/PPI/Token/Word.pm lib/PPI/Tokenizer.pm lib/PPI/Transform.pm lib/PPI/Transform/UpdateCopyright.pm lib/PPI/Util.pm lib/PPI/XSAccessor.pm LICENSE Makefile.PL MANIFEST This list of files META.yml README t/01_compile.t t/03_document.t t/04_element.t t/05_lexer.t t/06_round_trip.t t/07_token.t t/08_regression.t t/09_normal.t t/10_statement.t t/11_util.t t/12_location.t t/13_data.t t/14_charsets.t t/15_transform.t t/16_xml.t t/17_storable.t t/18_cache.t t/19_selftesting.t t/20_tokenizer_regression.t t/21_exhaustive.t t/22_readonly.t t/23_file.t t/24_v6.t t/25_increment.t t/26_bom.t t/27_complete.t t/28_foreach_qw.t t/data/03_document/empty.dat t/data/03_document/test.dat t/data/05_lexer/01_simpleassign.code t/data/05_lexer/01_simpleassign.dump t/data/05_lexer/02_END.code t/data/05_lexer/02_END.dump t/data/05_lexer/03_subroutine_attributes.code t/data/05_lexer/03_subroutine_attributes.dump t/data/05_lexer/04_anonymous_subroutines.code t/data/05_lexer/04_anonymous_subroutines.dump t/data/05_lexer/05_compound_loops.code t/data/05_lexer/05_compound_loops.dump t/data/05_lexer/06_subroutine_prototypes.code t/data/05_lexer/06_subroutine_prototypes.dump t/data/05_lexer/07_unmatched_braces.code t/data/05_lexer/07_unmatched_braces.dump t/data/05_lexer/08_subroutines.code t/data/05_lexer/08_subroutines.dump t/data/05_lexer/09_heredoc.code t/data/05_lexer/09_heredoc.dump t/data/05_lexer/10_readline.code t/data/05_lexer/10_readline.dump t/data/05_lexer/11_dor.code t/data/05_lexer/11_dor.dump t/data/05_lexer/12_switch.code t/data/05_lexer/12_switch.dump t/data/07_token/exp.code t/data/07_token/exp.dump t/data/07_token/hex.code t/data/07_token/hex.dump t/data/07_token/range_operator.code t/data/07_token/range_operator.dump t/data/07_token/smart_match.code t/data/07_token/smart_match.dump t/data/08_regression/01_rt_cpan_19629.code t/data/08_regression/01_rt_cpan_19629.dump t/data/08_regression/01_rt_cpan_19629b.code t/data/08_regression/01_rt_cpan_19629b.dump t/data/08_regression/02_rt_cpan_9582.code t/data/08_regression/02_rt_cpan_9582.dump t/data/08_regression/03_rt_cpan_9614.code t/data/08_regression/03_rt_cpan_9614.dump t/data/08_regression/04_tinderbox.code t/data/08_regression/04_tinderbox.dump t/data/08_regression/05_rt_cpan_13425.code t/data/08_regression/05_rt_cpan_13425.dump t/data/08_regression/06_partial_quote_double.code t/data/08_regression/06_partial_quote_double.dump t/data/08_regression/07_partial_quote_single.code t/data/08_regression/07_partial_quote_single.dump t/data/08_regression/08_partial_regex_substitution.code t/data/08_regression/08_partial_regex_substitution.dump t/data/08_regression/09_for_var.code t/data/08_regression/09_for_var.dump t/data/08_regression/10_leading_regexp.code t/data/08_regression/10_leading_regexp.dump t/data/08_regression/11_multiply_vs_glob_cast.code t/data/08_regression/11_multiply_vs_glob_cast.dump t/data/08_regression/12_pow.code t/data/08_regression/12_pow.dump t/data/08_regression/13_goto.code t/data/08_regression/13_goto.dump t/data/08_regression/14_minus.code t/data/08_regression/14_minus.dump t/data/08_regression/14b_minus.code t/data/08_regression/14b_minus.dump t/data/08_regression/15_dash_t.code t/data/08_regression/15_dash_t.dump t/data/08_regression/16_sub_declaration.code t/data/08_regression/16_sub_declaration.dump t/data/08_regression/17_scope.code t/data/08_regression/17_scope.dump t/data/08_regression/18_decimal_point.code t/data/08_regression/18_decimal_point.dump t/data/08_regression/19_long_operators.code t/data/08_regression/19_long_operators.dump t/data/08_regression/19_long_operators2.code t/data/08_regression/19_long_operators2.dump t/data/08_regression/20_hash_constructor.code t/data/08_regression/20_hash_constructor.dump t/data/08_regression/21_list_of_refs.code t/data/08_regression/21_list_of_refs.dump t/data/08_regression/22_hash_vs_brace.code t/data/08_regression/22_hash_vs_brace.dump t/data/08_regression/23_rt_cpan_8752.code t/data/08_regression/23_rt_cpan_8752.dump t/data/08_regression/24_compound.code t/data/08_regression/24_compound.dump t/data/08_regression/25_hash_block.code t/data/08_regression/25_hash_block.dump t/data/08_regression/26_rt_cpan_23253.code t/data/08_regression/26_rt_cpan_23253.dump t/data/08_regression/27_constant_hash.code t/data/08_regression/27_constant_hash.dump t/data/08_regression/28_backref_style_heredoc.code t/data/08_regression/28_backref_style_heredoc.dump t/data/08_regression/29_chained_casts.code t/data/08_regression/29_chained_casts.dump t/data/08_regression/29_magic_carat.code t/data/08_regression/29_magic_carat.dump t/data/08_regression/30_hash_bang.code t/data/08_regression/30_hash_bang.dump t/data/08_regression/31_hash_carat_H.code t/data/08_regression/31_hash_carat_H.dump t/data/08_regression/32_readline.code t/data/08_regression/32_readline.dump t/data/08_regression/33_magic_carat_long.code t/data/08_regression/33_magic_carat_long.dump t/data/08_regression/34_attr_whitespace.code t/data/08_regression/34_attr_whitespace.dump t/data/08_regression/35_attr_perlsub.code t/data/08_regression/35_attr_perlsub.dump t/data/08_regression/36_begin_label.code t/data/08_regression/36_begin_label.dump t/data/08_regression/37_partial_prototype.code t/data/08_regression/37_partial_prototype.dump t/data/08_regression/38_multiply.code t/data/08_regression/38_multiply.dump t/data/08_regression/39_foreach_our.code t/data/08_regression/39_foreach_our.dump t/data/08_regression/40_foreach_eval.code t/data/08_regression/40_foreach_eval.dump t/data/08_regression/41_scalar_hash.code t/data/08_regression/41_scalar_hash.dump t/data/08_regression/42_numeric_package.code t/data/08_regression/42_numeric_package.dump t/data/08_regression/43_nonblock_map.code t/data/08_regression/43_nonblock_map.dump t/data/11_util/test.pm t/data/13_data/Foo.pm t/data/15_transform/sample1.pm t/data/15_transform/sample1.pm_out t/data/24_v6/Grammar.pm t/data/24_v6/Simple.pm t/data/26_bom/utf8.code t/data/26_bom/utf8.dump t/data/27_complete/01y_helloworld.code t/data/27_complete/02n_helloworld.code t/data/basic.pl t/data/test2.txt t/interactive.t t/lib/PPI.pm t/ppi_element.t t/ppi_lexer.t t/ppi_node.t t/ppi_normal.t t/ppi_statement.t t/ppi_statement_compound.t t/ppi_statement_include.t t/ppi_statement_package.t t/ppi_statement_variable.t t/ppi_token__quoteengine_full.t t/ppi_token_dashedword.t t/ppi_token_magic.t t/ppi_token_number_version.t t/ppi_token_pod.t t/ppi_token_quote.t t/ppi_token_quote_double.t t/ppi_token_quote_interpolate.t t/ppi_token_quote_literal.t t/ppi_token_quote_single.t t/ppi_token_quotelike_words.t t/ppi_token_word.t xt/api.t xt/author.t xt/meta.t xt/pmv.t xt/pod.t PPI-1.215/Makefile.PL0000644000175100017510000000204311532117301012505 0ustar adamadamuse inc::Module::Install 1.00; all_from 'lib/PPI.pm'; requires 'File::Spec' => win32() ? '3.2701' : '0.84'; requires 'Clone' => '0.30'; requires 'List::Util' => '1.20'; requires 'List::MoreUtils' => '0.16'; requires 'Params::Util' => '1.00'; requires 'IO::String' => '1.07'; # Modules needed for PPI::Cache requires 'Digest::MD5' => '2.35'; requires 'Storable' => '2.17'; # Test-time dependencies (bundle as many as we can) test_requires 'Test::More' => '0.86'; test_requires 'Test::NoWarnings' => '0.084'; test_requires 'Test::Object' => '0.07'; test_requires 'Test::SubCalls' => '1.07'; test_requires 'File::Remove' => '1.42'; test_requires 'Class::Inspector' => '1.22'; # Force the existance of the weaken function # (which some distributions annoyingly don't have) requires 'Task::Weaken'; # Maintainers should also install this module # so that they can regenerate the inline tests # test_requires 'Test::Inline' => '2.203'; WriteAll; PPI-1.215/xt/0000755000175100017510000000000011532120507011171 5ustar adamadamPPI-1.215/xt/pmv.t0000644000175100017510000000164611532117301012165 0ustar adamadam#!/usr/bin/perl # Test that our declared minimum Perl version matches our syntax use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'File::Find::Rule 0.32', 'File::Find::Rule::Perl 1.09', 'Perl::MinimumVersion 1.25', 'Test::MinimumVersion 0.101080', ); # Don't run tests for installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_minimum_version_from_metayml_ok( { paths => [ grep { ! /14_charsets/ and ! /24_v6/ } File::Find::Rule->perl_file->in('.') ], } ); PPI-1.215/xt/api.t0000644000175100017510000001674011532117301012135 0ustar adamadam#!/usr/bin/perl # Basic first pass API testing for PPI use strict; use Test::More; BEGIN { $| = 1; $PPI::XS_DISABLE = 1; $PPI::XS_DISABLE = 1; # Prevent warning if ( $ENV{RELEASE_TESTING} ) { plan( tests => 2931 ); } else { plan( skip_all => 'Author tests not required for installation' ); } } use File::Spec::Functions ':ALL'; use Test::NoWarnings; use Test::ClassAPI; use PPI; use PPI::Dumper; use PPI::Find; use PPI::Transform; # Ignore various imported or special functions $Test::ClassAPI::IGNORE{'DESTROY'}++; $Test::ClassAPI::IGNORE{'refaddr'}++; $Test::ClassAPI::IGNORE{'reftype'}++; $Test::ClassAPI::IGNORE{'blessed'}++; # Execute the tests Test::ClassAPI->execute('complete', 'collisions'); exit(0); # Now, define the API for the classes __DATA__ # Explicitly list the core classes PPI=class PPI::Tokenizer=class PPI::Lexer=class PPI::Dumper=class PPI::Find=class PPI::Transform=abstract PPI::Normal=class # The abstract PDOM classes PPI::Element=abstract PPI::Node=abstract PPI::Token=abstract PPI::Token::_QuoteEngine=abstract PPI::Token::_QuoteEngine::Simple=abstract PPI::Token::_QuoteEngine::Full=abstract PPI::Token::Quote=abstract PPI::Token::QuoteLike=abstract PPI::Token::Regexp=abstract PPI::Structure=abstract PPI::Statement=abstract ##################################################################### # PDOM Classes [PPI::Element] new=method clone=method parent=method descendant_of=method ancestor_of=method top=method document=method statement=method next_sibling=method snext_sibling=method previous_sibling=method sprevious_sibling=method first_token=method last_token=method next_token=method previous_token=method insert_before=method insert_after=method remove=method delete=method replace=method content=method tokens=method significant=method location=method line_number=method column_number=method visual_column_number=method logical_line_number=method logical_filename=method class=method [PPI::Node] PPI::Element=isa scope=method add_element=method elements=method first_element=method last_element=method children=method schildren=method child=method schild=method contains=method find=method find_any=method find_first=method remove_child=method prune=method [PPI::Token] PPI::Element=isa new=method add_content=method set_class=method set_content=method length=method [PPI::Token::Whitespace] PPI::Token=isa null=method tidy=method [PPI::Token::Pod] PPI::Token=isa lines=method merge=method [PPI::Token::Data] PPI::Token=isa handle=method [PPI::Token::End] PPI::Token=isa [PPI::Token::Comment] PPI::Token=isa line=method [PPI::Token::Word] PPI::Token=isa literal=method method_call=method [PPI::Token::Separator] PPI::Token::Word=isa [PPI::Token::Label] PPI::Token=isa [PPI::Token::Structure] PPI::Token=isa [PPI::Token::Number] PPI::Token=isa base=method literal=method [PPI::Token::Symbol] PPI::Token=isa canonical=method symbol=method raw_type=method symbol_type=method [PPI::Token::ArrayIndex] PPI::Token=isa [PPI::Token::Operator] PPI::Token=isa [PPI::Token::Magic] PPI::Token=isa PPI::Token::Symbol=isa [PPI::Token::Cast] PPI::Token=isa [PPI::Token::Prototype] PPI::Token=isa prototype=method [PPI::Token::Attribute] PPI::Token=isa identifier=method parameters=method [PPI::Token::DashedWord] PPI::Token=isa literal=method [PPI::Token::HereDoc] PPI::Token=isa heredoc=method terminator=method [PPI::Token::_QuoteEngine] [PPI::Token::_QuoteEngine::Simple] PPI::Token::_QuoteEngine=isa [PPI::Token::_QuoteEngine::Full] PPI::Token::_QuoteEngine=isa [PPI::Token::Quote] PPI::Token=isa string=method [PPI::Token::Quote::Single] PPI::Token=isa PPI::Token::Quote=isa literal=method [PPI::Token::Quote::Double] PPI::Token=isa PPI::Token::Quote=isa interpolations=method simplify=method [PPI::Token::Quote::Literal] PPI::Token=isa literal=method [PPI::Token::Quote::Interpolate] PPI::Token=isa [PPI::Token::QuoteLike] PPI::Token=isa [PPI::Token::QuoteLike::Backtick] PPI::Token=isa PPI::Token::_QuoteEngine::Simple=isa [PPI::Token::QuoteLike::Command] PPI::Token=isa PPI::Token::_QuoteEngine::Full=isa [PPI::Token::QuoteLike::Words] PPI::Token=isa PPI::Token::_QuoteEngine::Full=isa literal=method [PPI::Token::QuoteLike::Regexp] PPI::Token=isa PPI::Token::_QuoteEngine::Full=isa get_match_string=method get_substitute_string=method get_modifiers=method get_delimiters=method [PPI::Token::QuoteLike::Readline] PPI::Token=isa PPI::Token::_QuoteEngine::Full=isa [PPI::Token::Regexp] PPI::Token=isa PPI::Token::_QuoteEngine::Full=isa get_match_string=method get_substitute_string=method get_modifiers=method get_delimiters=method [PPI::Token::Regexp::Match] PPI::Token=isa [PPI::Token::Regexp::Substitute] PPI::Token=isa [PPI::Token::Regexp::Transliterate] PPI::Token=isa [PPI::Statement] PPI::Node=isa label=method specialized=method stable=method [PPI::Statement::Expression] PPI::Statement=isa [PPI::Statement::Package] PPI::Statement=isa namespace=method file_scoped=method [PPI::Statement::Include] PPI::Statement=isa type=method arguments=method module=method module_version=method pragma=method version=method version_literal=method [PPI::Statement::Include::Perl6] PPI::Statement::Include=isa perl6=method [PPI::Statement::Sub] PPI::Statement=isa name=method prototype=method block=method forward=method reserved=method [PPI::Statement::Scheduled] PPI::Statement::Sub=isa PPI::Statement=isa type=method block=method [PPI::Statement::Variable] PPI::Statement=isa PPI::Statement::Expression=isa type=method variables=method symbols=method [PPI::Statement::Compound] PPI::Statement=isa type=method [PPI::Statement::Given] PPI::Statement=isa [PPI::Statement::When] PPI::Statement=isa [PPI::Statement::Break] PPI::Statement=isa [PPI::Statement::Null] PPI::Statement=isa [PPI::Statement::Data] PPI::Statement=isa [PPI::Statement::End] PPI::Statement=isa [PPI::Statement::Unknown] PPI::Statement=isa [PPI::Structure] PPI::Node=isa braces=method complete=method start=method finish=method [PPI::Structure::Block] PPI::Structure=isa [PPI::Structure::Subscript] PPI::Structure=isa [PPI::Structure::Constructor] PPI::Structure=isa [PPI::Structure::Condition] PPI::Structure=isa [PPI::Structure::List] PPI::Structure=isa [PPI::Structure::For] PPI::Structure=isa [PPI::Structure::Given] PPI::Structure=isa [PPI::Structure::When] PPI::Structure=isa [PPI::Structure::Unknown] PPI::Structure=isa [PPI::Document] PPI::Node=isa get_cache=method set_cache=method load=method save=method readonly=method tab_width=method serialize=method hex_id=method index_locations=method flush_locations=method normalized=method complete=method errstr=method STORABLE_freeze=method STORABLE_thaw=method [PPI::Document::Fragment] PPI::Document=isa ##################################################################### # Non-PDOM Classes [PPI] [PPI::Tokenizer] new=method get_token=method all_tokens=method increment_cursor=method decrement_cursor=method [PPI::Lexer] new=method lex_file=method lex_source=method lex_tokenizer=method errstr=method [PPI::Dumper] new=method print=method string=method list=method [PPI::Find] new=method clone=method in=method start=method match=method finish=method errstr=method [PPI::Transform] new=method document=method apply=method file=method [PPI::Normal] register=method new=method layer=method process=method [PPI::Normal::Standard] import=method remove_insignificant_elements=method remove_useless_attributes=method remove_useless_pragma=method remove_statement_separator=method remove_useless_return=method [PPI::Document::Normalized] new=method version=method functions=method equal=method PPI-1.215/xt/author.t0000644000175100017510000000253411532117301012662 0ustar adamadam#!/usr/bin/perl use strict; BEGIN { $| = 1; $^W = 1; } my $MODULE = 'Test::Pod 1.44'; # Don't run tests for installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing module eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } ##################################################################### # BEGIN BLACK MAGIC ##################################################################### # Hack Pod::Simple::BlackBox to ignore the Test::Inline "=begin has more than one word errors" my $begin = \&Pod::Simple::BlackBox::_ponder_begin; sub mybegin { my $para = $_[1]; my $content = join ' ', splice @$para, 2; $content =~ s/^\s+//s; $content =~ s/\s+$//s; my @words = split /\s+/, $content; if ( $words[0] =~ /^test(?:ing)?\z/s ) { foreach ( 2 .. $#$para ) { $para->[$_] = ''; } $para->[2] = $words[0]; } # Continue as normal return &$begin(@_); } local $^W = 0; *Pod::Simple::BlackBox::_ponder_begin = \&mybegin; ##################################################################### # END BLACK MAGIC ##################################################################### all_pod_files_ok(); PPI-1.215/xt/meta.t0000644000175100017510000000107311532117301012303 0ustar adamadam#!/usr/bin/perl # Test that our META.yml file matches the current specification. use strict; BEGIN { $| = 1; $^W = 1; } my $MODULE = 'Test::CPAN::Meta 0.17'; # Don't run tests for installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing module eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } meta_yaml_ok(); PPI-1.215/xt/pod.t0000644000175100017510000000116711532117301012143 0ustar adamadam#!/usr/bin/perl # Test that the syntax of our POD documentation is valid use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Pod::Simple 3.14', 'Test::Pod 1.44', ); # Don't run tests for installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_pod_files_ok(); PPI-1.215/inc/0000755000175100017510000000000011532120507011307 5ustar adamadamPPI-1.215/inc/Module/0000755000175100017510000000000011532120507012534 5ustar adamadamPPI-1.215/inc/Module/Install.pm0000644000175100017510000003013511532120242014476 0ustar adamadam#line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.005; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.00'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::cwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::cwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($subpath . '.pm'); my $in_pod = 0; foreach ( split //, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_NEW sub _read { local *FH; open( FH, "< $_[0]" ) or die "open($_[0]): $!"; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_OLD sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_NEW sub _write { local *FH; open( FH, "> $_[0]" ) or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_OLD # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version ($) { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp ($$) { _version($_[0]) <=> _version($_[1]); } # Cloned from Params::Util::_CLASS sub _CLASS ($) { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2010 Adam Kennedy. PPI-1.215/inc/Module/Install/0000755000175100017510000000000011532120507014142 5ustar adamadamPPI-1.215/inc/Module/Install/Can.pm0000644000175100017510000000333311532120243015200 0ustar adamadam#line 1 package Module::Install::Can; use strict; use Config (); use File::Spec (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.00'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; my $abs = File::Spec->catfile($dir, $_[1]); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # can we locate a (the) C compiler sub can_cc { my $self = shift; my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 156 PPI-1.215/inc/Module/Install/Fetch.pm0000644000175100017510000000462711532120243015537 0ustar adamadam#line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.00'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; PPI-1.215/inc/Module/Install/WriteAll.pm0000644000175100017510000000237611532120243016230 0ustar adamadam#line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.00'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1; PPI-1.215/inc/Module/Install/With.pm0000644000175100017510000000224611532120243015414 0ustar adamadam#line 1 package Module::Install::With; # See POD at end for docs use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.00'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } ##################################################################### # Installer Target # Are we targeting ExtUtils::MakeMaker (running as Makefile.PL) sub eumm { !! ($0 =~ /Makefile.PL$/i); } # You should not be using this, but we'll keep the hook anyways sub mb { !! ($0 =~ /Build.PL$/i); } ##################################################################### # Testing and Configuration Contexts #line 49 sub interactive { # Treat things interactively ONLY based on input !! (-t STDIN and ! automated_testing()); } #line 67 sub automated_testing { !! $ENV{AUTOMATED_TESTING}; } #line 86 sub release_testing { !! $ENV{RELEASE_TESTING}; } sub author_context { !! $Module::Install::AUTHOR; } ##################################################################### # Operating System Convenience #line 114 sub win32 { !! ($^O eq 'MSWin32'); } #line 131 sub winlike { !! ($^O eq 'MSWin32' or $^O eq 'cygwin'); } 1; #line 159 PPI-1.215/inc/Module/Install/Win32.pm0000644000175100017510000000340311532120243015377 0ustar adamadam#line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.00'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; PPI-1.215/inc/Module/Install/Base.pm0000644000175100017510000000214711532120243015353 0ustar adamadam#line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.00'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 PPI-1.215/inc/Module/Install/Metadata.pm0000644000175100017510000004302011532120243016214 0ustar adamadam#line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.00'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; unless ( @_ ) { warn "You MUST provide an explicit true/false value to dynamic_config\n"; return $self; } $self->{values}->{dynamic_config} = $_[0] ? 1 : 0; return 1; } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the reall old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) \s* ; /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( \Qhttp://rt.cpan.org/\E[^>]+| \Qhttp://github.com/\E[\w_]+/[\w_]+/issues| \Qhttp://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashs delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; PPI-1.215/inc/Module/Install/Makefile.pm0000644000175100017510000002703211532120243016216 0ustar adamadam#line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.00'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-seperated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # MakeMaker can complain about module versions that include # an underscore, even though its own version may contain one! # Hence the funny regexp to get rid of it. See RT #35800 # for details. my $v = $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/; $self->build_requires( 'ExtUtils::MakeMaker' => $v ); $self->configure_requires( 'ExtUtils::MakeMaker' => $v ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.42 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.42 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT $DB::single = 1; if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 541 PPI-1.215/lib/0000755000175100017510000000000011532120507011304 5ustar adamadamPPI-1.215/lib/PPI.pm0000644000175100017510000007512011532117301012275 0ustar adamadampackage PPI; # See POD at end for documentation use 5.006; use strict; # Set the version for CPAN use vars qw{$VERSION $XS_COMPATIBLE @XS_EXCLUDE}; BEGIN { $VERSION = '1.215'; $XS_COMPATIBLE = '0.845'; @XS_EXCLUDE = (); } # Load everything use PPI::Util (); use PPI::Exception (); use PPI::Element (); use PPI::Token (); use PPI::Statement (); use PPI::Structure (); use PPI::Document (); use PPI::Document::File (); use PPI::Document::Fragment (); use PPI::Document::Normalized (); use PPI::Normal (); use PPI::Tokenizer (); use PPI::Lexer (); # If it is installed, load in PPI::XS unless ( $PPI::XS_DISABLE ) { eval { require PPI::XS }; # Only ignore the failure to load PPI::XS if not installed die if $@ && $@ !~ /^Can't locate .*? at /; } 1; __END__ =pod =head1 NAME PPI - Parse, Analyze and Manipulate Perl (without perl) =head1 SYNOPSIS use PPI; # Create a new empty document my $Document = PPI::Document->new; # Create a document from source $Document = PPI::Document->new(\'print "Hello World!\n"'); # Load a Document from a file $Document = PPI::Document->new('Module.pm'); # Does it contain any POD? if ( $Document->find_any('PPI::Token::Pod') ) { print "Module contains POD\n"; } # Get the name of the main package $pkg = $Document->find_first('PPI::Statement::Package')->namespace; # Remove all that nasty documentation $Document->prune('PPI::Token::Pod'); $Document->prune('PPI::Token::Comment'); # Save the file $Document->save('Module.pm.stripped'); =head1 DESCRIPTION =head2 About this Document This is the PPI manual. It describes its reason for existing, its general structure, its use, an overview of the API, and provides a few implementation samples. =head2 Background The ability to read, and manipulate Perl (the language) programmatically other than with perl (the application) was one that caused difficulty for a long time. The cause of this problem was Perl's complex and dynamic grammar. Although there is typically not a huge diversity in the grammar of most Perl code, certain issues cause large problems when it comes to parsing. Indeed, quite early in Perl's history Tom Christenson introduced the Perl community to the quote I<"Nothing but perl can parse Perl">, or as it is more often stated now as a truism: B<"Only perl can parse Perl"> One example of the sorts of things the prevent Perl being easily parsed are function signatures, as demonstrated by the following. @result = (dothis $foo, $bar); # Which of the following is it equivalent to? @result = (dothis($foo), $bar); @result = dothis($foo, $bar); The first line above can be interpreted in two different ways, depending on whether the C<&dothis> function is expecting one argument, or two, or several. A "code parser" (something that parses for the purpose of execution) such as perl needs information that is not found in the immediate vicinity of the statement being parsed. The information might not just be elsewhere in the file, it might not even be in the same file at all. It might also not be able to determine this information without the prior execution of a C block, or the loading and execution of one or more external modules. Or worse the &dothis function may not even have been written yet. B Even perl itself never really fully understands the structure of the source code after and indeed B it processes it, and in that sense doesn't "parse" Perl source into anything remotely like a structured document. This makes it of no real use for any task that needs to treat the source code as a document, and do so reliably and robustly. For more information on why it is impossible to parse perl, see Randal Schwartz's seminal response to the question of "Why can't you parse Perl". L The purpose of PPI is B to parse Perl I, but to parse Perl I. By treating the problem this way, we are able to parse a single file containing Perl source code "isolated" from any other resources, such as libraries upon which the code may depend, and without needing to run an instance of perl alongside or inside the parser. Historically, using an embedded perl parser was widely considered to be the most likely avenue for finding a solution to C. It was investigated from time to time and attempts have generally failed or suffered from sufficiently bad corner cases that they were abandoned. =head2 What Does PPI Stand For? C is an acronym for the longer original module name C. And in the spirit or the silly acronym games played by certain unnamed Open Source projects you may have I of, it also a reverse backronym of "I Parse Perl". Of course, I could just be lying and have just made that second bit up 10 minutes before the release of PPI 1.000. Besides, B the cool Perl packages have TLAs (Three Letter Acronyms). It's a rule or something. Why don't you just think of it as the B for simplicity. The original name was shortened to prevent the author (and you the users) from contracting RSI by having to type crazy things like C 100 times a day. In acknowledgment that someone may some day come up with a valid solution for the grammar problem it was decided at the commencement of the project to leave the C namespace free for any such effort. Since that time I've been able to prove to my own satisfaction that it B truly impossible to accurately parse Perl as both code and document at once. For the academics, parsing Perl suffers from the "Halting Problem". With this in mind C has now been co-opted as the title for the SourceForge project that publishes PPI and a large collection of other applications and modules related to the (document) parsing of Perl source code. You can find this project at L, however we no longer use the SourceForge CVS server. Instead, the current development version of PPI is available via SVN at L. =head2 Why Parse Perl? Once you can accept that we will never be able to parse Perl well enough to meet the standards of things that treat Perl as code, it is worth re-examining C we want to "parse" Perl at all. What are the things that people might want a "Perl parser" for. =over 4 =item Documentation Analyzing the contents of a Perl document to automatically generate documentation, in parallel to, or as a replacement for, POD documentation. Allow an indexer to to locate and process all the comments and documentation from code for "full text search" applications. =item Structural and Quality Analysis Determine quality or other metrics across a body of code, and identify situations relating to particular phrases, techniques or locations. Index functions, variables and packages within Perl code, and doing search and graph (in the node/edge sense) analysis of large code bases. =item Refactoring Make structural, syntax, or other changes to code in an automated manner, either independently or in assistance to an editor. This sort of task list includes backporting, forward porting, partial evaluation, "improving" code, or whatever. All the sort of things you'd want from a L. =item Layout Change the layout of code without changing its meaning. This includes techniques such as tidying (like L), obfuscation, compressing and "squishing", or to implement formatting preferences or policies. =item Presentation This includes methods of improving the presentation of code, without changing the content of the code. Modify, improve, syntax colour etc the presentation of a Perl document. Generating "IntelliText"-like functions. =back If we treat this as a baseline for the sort of things we are going to have to build on top of Perl, then it becomes possible to identify a standard for how good a Perl parser needs to be. =head2 How good is Good Enough(TM) PPI seeks to be good enough to achieve all of the above tasks, or to provide a sufficiently good API on which to allow others to implement modules in these and related areas. However, there are going to be limits to this process. Because PPI cannot adapt to changing grammars, any code written using source filters should not be assumed to be parsable. At one extreme, this includes anything munged by L, as well as (arguably) more common cases like L. We do not pretend to be able to always parse code using these modules, although as long as it still follows a format that looks like Perl syntax, it may be possible to extend the lexer to handle them. The ability to extend PPI to handle lexical additions to the language is on the drawing board to be done some time post-1.0 The goal for success was originally to be able to successfully parse 99% of all Perl documents contained in CPAN. This means the entire file in each case. PPI has succeeded in this goal far beyond the expectations of even the author. At time of writing there are only 28 non-Acme Perl modules in CPAN that PPI is incapable of parsing. Most of these are so badly broken they do not compile as Perl code anyway. So unless you are actively going out of your way to break PPI, you should expect that it will handle your code just fine. =head2 Internationalisation PPI provides partial support for internationalisation and localisation. Specifically, it allows the use characters from the Latin-1 character set to be used in quotes, comments, and POD. Primarily, this covers languages from Europe and South America. PPI does B currently provide support for Unicode, although there is an initial implementation available in a development branch from CVS. If you need Unicode support, and would like to help stress test the Unicode support so we can move it to the main branch and enable it in the main release should contact the author. (contact details below) =head2 Round Trip Safe When PPI parses a file it builds B into the model, including whitespace. This is needed in order to make the Document fully "Round Trip" safe. The general concept behind a "Round Trip" parser is that it knows what it is parsing is somewhat uncertain, and so B to get things wrong from time to time. In the cases where it parses code wrongly the tree will serialize back out to the same string of code that was read in, repairing the parser's mistake as it heads back out to the file. The end result is that if you parse in a file and serialize it back out without changing the tree, you are guaranteed to get the same file you started with. PPI does this correctly and reliably for 100% of all known cases. B The one minor exception at this time is that if the newlines for your file are wrong (meaning not matching the platform newline format), PPI will localise them for you. (It isn't to be convenient, supporting arbitrary newlines would make some of the code more complicated) Better control of the newline type is on the wish list though, and anyone wanting to help out is encouraged to contact the author. =head1 IMPLEMENTATION =head2 General Layout PPI is built upon two primary "parsing" components, L and L, and a large tree of about 50 classes which implement the various the I (PDOM). The PDOM is conceptually similar in style and intent to the regular DOM or other code Abstract Syntax Trees (ASTs), but contains some differences to handle perl-specific cases, and to assist in treating the code as a document. Please note that it is B an implementation of the official Document Object Model specification, only somewhat similar to it. On top of the Tokenizer, Lexer and the classes of the PDOM, sit a number of classes intended to make life a little easier when dealing with PDOM trees. Both the major parsing components were hand-coded from scratch with only plain Perl code and a few small utility modules. There are no grammar or patterns mini-languages, no YACC or LEX style tools and only a small number of regular expressions. This is primarily because of the sheer volume of accumulated cruft that exists in Perl. Not even perl itself is capable of parsing Perl documents (remember, it just parses and executes it as code). As a result, PPI needed to be cruftier than perl itself. Feel free to shudder at this point, and hope you never have to understand the Tokenizer codebase. Speaking of which... =head2 The Tokenizer The Tokenizer takes source code and converts it into a series of tokens. It does this using a slow but thorough character by character manual process, rather than using a pattern system or complex regexes. Or at least it does so conceptually. If you were to actually trace the code you would find it's not truly character by character due to a number of regexps and optimisations throughout the code. This lets the Tokenizer "skip ahead" when it can find shortcuts, so it tends to jump around a line a bit wildly at times. In practice, the number of times the Tokenizer will B move the character cursor itself is only about 5% - 10% higher than the number of tokens contained in the file. This makes it about as optimal as it can be made without implementing it in something other than Perl. In 2001 when PPI was started, this structure made PPI quite slow, and not really suitable for interactive tasks. This situation has improved greatly with multi-gigahertz processors, but can still be painful when working with very large files. The target parsing rate for PPI is about 5000 lines per gigacycle. It is currently believed to be at about 1500, and main avenue for making it to the target speed has now become L, a drop-in XS accelerator for PPI. Since L has only just gotten off the ground and is currently only at proof-of-concept stage, this may take a little while. Anyone interested in helping out with L is B encouraged to contact the author. In fact, the design of L means it's possible to port one function at a time safely and reliably. So every little bit will help. =head2 The Lexer The Lexer takes a token stream, and converts it to a lexical tree. Because we are parsing Perl B this includes whitespace, comments, and all number of weird things that have no relevance when code is actually executed. An instantiated L consumes L objects and produces L objects. However you should probably never be working with the Lexer directly. You should just be able to create L objects and work with them directly. =head2 The Perl Document Object Model The PDOM is a structured collection of data classes that together provide a correct and scalable model for documents that follow the standard Perl syntax. =head2 The PDOM Class Tree The following lists all of the 67 current PDOM classes, listing with indentation based on inheritance. PPI::Element PPI::Node PPI::Document PPI::Document::Fragment PPI::Statement PPI::Statement::Package PPI::Statement::Include PPI::Statement::Sub PPI::Statement::Scheduled PPI::Statement::Compound PPI::Statement::Break PPI::Statement::Given PPI::Statement::When PPI::Statement::Data PPI::Statement::End PPI::Statement::Expression PPI::Statement::Variable PPI::Statement::Null PPI::Statement::UnmatchedBrace PPI::Statement::Unknown PPI::Structure PPI::Structure::Block PPI::Structure::Subscript PPI::Structure::Constructor PPI::Structure::Condition PPI::Structure::List PPI::Structure::For PPI::Structure::Given PPI::Structure::When PPI::Structure::Unknown PPI::Token PPI::Token::Whitespace PPI::Token::Comment PPI::Token::Pod PPI::Token::Number PPI::Token::Number::Binary PPI::Token::Number::Octal PPI::Token::Number::Hex PPI::Token::Number::Float PPI::Token::Number::Exp PPI::Token::Number::Version PPI::Token::Word PPI::Token::DashedWord PPI::Token::Symbol PPI::Token::Magic PPI::Token::ArrayIndex PPI::Token::Operator PPI::Token::Quote PPI::Token::Quote::Single PPI::Token::Quote::Double PPI::Token::Quote::Literal PPI::Token::Quote::Interpolate PPI::Token::QuoteLike PPI::Token::QuoteLike::Backtick PPI::Token::QuoteLike::Command PPI::Token::QuoteLike::Regexp PPI::Token::QuoteLike::Words PPI::Token::QuoteLike::Readline PPI::Token::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute PPI::Token::Regexp::Transliterate PPI::Token::HereDoc PPI::Token::Cast PPI::Token::Structure PPI::Token::Label PPI::Token::Separator PPI::Token::Data PPI::Token::End PPI::Token::Prototype PPI::Token::Attribute PPI::Token::Unknown To summarize the above layout, all PDOM objects inherit from the L class. Under this are L, strings of content with a known type, and L, syntactically significant containers that hold other Elements. The three most important of these are the L, the L and the L classes. =head2 The Document, Statement and Structure At the top of all complete PDOM trees is a L object. It represents a complete file of Perl source code as you might find it on disk. There are some specialised types of document, such as L and L but for the purposes of the PDOM they are all just considered to be the same thing. Each Document will contain a number of B, B and B. A L is any series of Tokens and Structures that are treated as a single contiguous statement by perl itself. You should note that a Statement is as close as PPI can get to "parsing" the code in the sense that perl-itself parses Perl code when it is building the op-tree. Because of the isolation and Perl's syntax, it is provably impossible for PPI to accurately determine precedence of operators or which tokens are implicit arguments to a sub call. So rather than lead you on with a bad guess that has a strong chance of being wrong, PPI does not attempt to determine precedence or sub parameters at all. At a fundamental level, it only knows that this series of elements represents a single Statement as perl sees it, but it can do so with enough certainty that it can be trusted. However, for specific Statement types the PDOM is able to derive additional useful information about their meaning. For the best, most useful, and most heavily used example, see L. A L is any series of tokens contained within matching braces. This includes code blocks, conditions, function argument braces, anonymous array and hash constructors, lists, scoping braces and all other syntactic structures represented by a matching pair of braces, including (although it may not seem obvious at first) CREADLINEE> braces. Each Structure contains none, one, or many Tokens and Structures (the rules for which vary for the different Structure subclasses) Under the PDOM structure rules, a Statement can B directly contain another child Statement, a Structure can B directly contain another child Structure, and a Document can B contain another Document anywhere in the tree. Aside from these three rules, the PDOM tree is extremely flexible. =head2 The PDOM at Work To demonstrate the PDOM in use lets start with an example showing how the tree might look for the following chunk of simple Perl code. #!/usr/bin/perl print( "Hello World!" ); exit(); Translated into a PDOM tree it would have the following structure (as shown via the included L). PPI::Document PPI::Token::Comment '#!/usr/bin/perl\n' PPI::Token::Whitespace '\n' PPI::Statement::Expression PPI::Token::Bareword 'print' PPI::Structure::List ( ... ) PPI::Token::Whitespace ' ' PPI::Statement::Expression PPI::Token::Quote::Double '"Hello World!"' PPI::Token::Whitespace ' ' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement::Expression PPI::Token::Bareword 'exit' PPI::Structure::List ( ... ) PPI::Token::Structure ';' PPI::Token::Whitespace '\n' Please note that in this this example, strings are only listed for the B L that contains that string. Structures are listed with the type of brace characters it represents noted. The L module can be used to generate similar trees yourself. We can make that PDOM dump a little easier to read if we strip out all the whitespace. Here it is again, sans the distracting whitespace tokens. PPI::Document PPI::Token::Comment '#!/usr/bin/perl\n' PPI::Statement::Expression PPI::Token::Bareword 'print' PPI::Structure::List ( ... ) PPI::Statement::Expression PPI::Token::Quote::Double '"Hello World!"' PPI::Token::Structure ';' PPI::Statement::Expression PPI::Token::Bareword 'exit' PPI::Structure::List ( ... ) PPI::Token::Structure ';' As you can see, the tree can get fairly deep at time, especially when every isolated token in a bracket becomes its own statement. This is needed to allow anything inside the tree the ability to grow. It also makes the search and analysis algorithms much more flexible. Because of the depth and complexity of PDOM trees, a vast number of very easy to use methods have been added wherever possible to help people working with PDOM trees do normal tasks relatively quickly and efficiently. =head2 Overview of the Primary Classes The main PPI classes, and links to their own documentation, are listed here in alphabetical order. =over 4 =item L The Document object, the root of the PDOM. =item L A cohesive fragment of a larger Document. Although not of any real current use, it is needed for use in certain internal tree manipulation algorithms. For example, doing things like cut/copy/paste etc. Very similar to a L, but has some additional methods and does not represent a lexical scope boundary. A document fragment is also non-serializable, and so cannot be written out to a file. =item L A simple class for dumping readable debugging versions of PDOM structures, such as in the demonstration above. =item L The Element class is the abstract base class for all objects within the PDOM =item L Implements an instantiable object form of a PDOM tree search. =item L The PPI Lexer. Converts Token streams into PDOM trees. =item L The Node object, the abstract base class for all PDOM objects that can contain other Elements, such as the Document, Statement and Structure objects. =item L The base class for all Perl statements. Generic "evaluate for side-effects" statements are of this actual type. Other more interesting statement types belong to one of its children. See it's own documentation for a longer description and list of all of the different statement types and sub-classes. =item L The abstract base class for all structures. A Structure is a language construct consisting of matching braces containing a set of other elements. See the L documentation for a description and list of all of the different structure types and sub-classes. =item L A token is the basic unit of content. At its most basic, a Token is just a string tagged with metadata (its class, and some additional flags in some cases). =item L The L and L classes provide abstract base classes for the many and varied types of quote and quote-like things in Perl. However, much of the actual quote login is implemented in a separate quote engine, based at L. Classes that inherit from L, L and L are generally parsed only by the Quote Engine. =item L The PPI Tokenizer. One Tokenizer consumes a chunk of text and provides access to a stream of L objects. The Tokenizer is very very complicated, to the point where even the author treads carefully when working with it. Most of the complication is the result of optimizations which have tripled the tokenization speed, at the expense of maintainability. We cope with the spaghetti by heavily commenting everything. =item L The Perl Document Transformation API. Provides a standard interface and abstract base class for objects and classes that manipulate Documents. =back =head1 INSTALLING The core PPI distribution is pure Perl and has been kept as tight as possible and with as few dependencies as possible. It should download and install normally on any platform from within the CPAN and CPANPLUS applications, or directly using the distribution tarball. If installing by hand, you may need to install a few small utility modules first. The exact ones will depend on your version of perl. There are no special install instructions for PPI, and the normal C, C, C, C instructions apply. =head1 EXTENDING The PPI namespace itself is reserved for the sole use of the modules under the umbrella of the C SourceForge project. L You are recommended to use the PPIx:: namespace for PPI-specific modifications or prototypes thereof, or Perl:: for modules which provide a general Perl language-related functions. If what you wish to implement looks like it fits into PPIx:: namespace, you should consider contacting the C mailing list (detailed on the SourceForge site) first, as what you want may already be in progress, or you may wish to consider joining the team and doing it within the C project itself. =head1 TO DO - Many more analysis and utility methods for PDOM classes - Creation of a PPI::Tutorial document - Add many more key functions to PPI::XS - We can B write more and better unit tests - Complete the full implementation of -Eliteral (1.200) - Full understanding of scoping (due 1.300) =head1 SUPPORT This module is stored in an Open Repository at the following address. L Write access to the repository is made available automatically to any published CPAN author, and to most other volunteers on request. If you are able to submit your bug report in the form of new (failing) unit tests, or can apply your fix directly instead of submitting a patch, you are B encouraged to do so, as the author currently maintains over 100 modules and it can take some time to deal with non-"Critical" bug reports or patches. This will also guarentee that your issue will be addressed in the next release of the module. For large changes though, please consider creating a branch so that they can be properly reviewed and trialed before being applied to the trunk. If you cannot provide a direct test or fix, or don't have time to do so, then regular bug reports are still accepted and appreciated via the CPAN bug tracker. L For other issues or questions, contact the C project mailing list. For commercial or media-related enquiries, or to have your SVN commit bit enabled, contact the author. =head1 AUTHOR Adam Kennedy Eadamk@cpan.orgE =head1 ACKNOWLEDGMENTS A huge thank you to Phase N Australia (L) for permitting the original open sourcing and release of this distribution from what was originally several thousand hours of commercial work. Another big thank you to The Perl Foundation (L) for funding for the final big refactoring and completion run. Also, to the various co-maintainers that have contributed both large and small with tests and patches and especially to those rare few who have deep-dived into the guts to (gasp) add a feature. - Dan Brook : PPIx::XPath, Acme::PerlML - Audrey Tang : "Line Noise" Testing - Arjen Laarhoven : Three-element ->location support - Elliot Shank : Perl 5.10 support, five-element ->location And finally, thanks to those brave ( and foolish :) ) souls willing to dive in and use, test drive and provide feedback on PPI before version 1.000, in some cases before it made it to beta quality, and still did extremely distasteful things (like eating 50 meg of RAM a second). I owe you all a beer. Corner me somewhere and collect at your convenience. If I missed someone who wasn't in my email history, thank you too :) # In approximate order of appearance - Claes Jacobsson - Michael Schwern - Jeff T. Parsons - CPAN Author "CHOCOLATEBOY" - Robert Rotherberg - CPAN Author "PODMASTER" - Richard Soderberg - Nadim ibn Hamouda el Khemir - Graciliano M. P. - Leon Brocard - Jody Belka - Curtis Ovid - Yuval Kogman - Michael Schilli - Slaven Rezic - Lars Thegler - Tony Stubblebine - Tatsuhiko Miyagawa - CPAN Author "CHROMATIC" - Matisse Enzer - Roy Fulbright - Dan Brook - Johnny Lee - Johan Lindstrom And to single one person out, thanks go to Randal Schwartz who spent a great number of hours in IRC over a critical 6 month period explaining why Perl is impossibly unparsable and constantly shoving evil and ugly corner cases in my face. He remained a tireless devil's advocate, and without his support this project genuinely could never have been completed. So for my schooling in the Deep Magiks, you have my deepest gratitude Randal. =head1 COPYRIGHT Copyright 2001 - 2011 Adam Kennedy. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. The full text of the license can be found in the LICENSE file included with this module. =cut PPI-1.215/lib/PPI/0000755000175100017510000000000011532120507011734 5ustar adamadamPPI-1.215/lib/PPI/Structure.pm0000644000175100017510000002127411532117301014276 0ustar adamadampackage PPI::Structure; =pod =head1 NAME PPI::Structure - The base class for Perl braced structures =head1 INHERITANCE PPI::Structure isa PPI::Node isa PPI::Element =head1 DESCRIPTION PPI::Structure is the root class for all Perl bracing structures. This covers all forms of C< [ ... ] >, C< { ... } >, and C< ( ... ) > brace types, and includes cases where only one half of the pair exist. The class PPI::Structure itself is full abstract and no objects of that type should actually exist in the tree. =head2 Elements vs Children A B has an unusual existance. Unlike a L or L, which both simply contain other elements, a structure B contains and consists of content. That is, the brace tokens are B considered to be "children" of the structure, but are part of it. In practice, this will mean that while the -Eelements and -Etokens methods (and related) B return a list with the brace tokens at either end, the -Echildren method explicitly will B return the brace. =head1 STRUCTURE CLASSES Excluding the transient L that exists briefly inside the parser, there are eight types of structure. =head2 L This covers all round braces used for function arguments, in C loops, literal lists, and braces used for precedence-ordering purposes. =head2 L Although B used for the C loop list, this B used for the special case of the round-brace three-part semicolon-seperated C loop expression (the traditional C style for loop). =head2 L This is for the expression being matched in switch statements. =head2 L This is for the matching expression in "when" statements. =head2 L This round-brace structure covers boolean conditional braces, such as for C and C blocks. =head2 L This curly-brace and common structure is used for all form of code blocks. This includes those for C, C and similar, as well as C, C, C, C and (labelled or anonymous) scoping blocks. =head2 L This class covers brace structures used for the construction of anonymous C and C references. =head2 L This class covers square-braces and curly-braces used after a -E pointer to access the subscript of an C or C. =head1 METHODS C itself has very few methods. Most of the time, you will be working with the more generic L or L methods, or one of the methods that are subclass-specific. =cut use strict; use Scalar::Util (); use Params::Util qw{_INSTANCE}; use PPI::Node (); use PPI::Exception (); use vars qw{$VERSION @ISA *_PARENT}; BEGIN { $VERSION = '1.215'; @ISA = 'PPI::Node'; *_PARENT = *PPI::Element::_PARENT; } use PPI::Structure::Block (); use PPI::Structure::Condition (); use PPI::Structure::Constructor (); use PPI::Structure::For (); use PPI::Structure::Given (); use PPI::Structure::List (); use PPI::Structure::Subscript (); use PPI::Structure::Unknown (); use PPI::Structure::When (); ##################################################################### # Constructor sub new { my $class = shift; my $Token = PPI::Token::__LEXER__opens($_[0]) ? shift : return undef; # Create the object my $self = bless { children => [], start => $Token, }, $class; # Set the start braces parent link Scalar::Util::weaken( $_PARENT{Scalar::Util::refaddr $Token} = $self ); $self; } ##################################################################### # PPI::Structure API methods =pod =head2 start For lack of better terminology (like "open" and "close") that has not already in use for some other more important purpose, the two individual braces for the structure are known within PPI as the "start" and "finish" braces (at least for method purposes). The C method returns the start brace for the structure (i.e. the opening brace). Returns the brace as a L or C if the structure does not have a starting brace. Under normal parsing circumstances this should never occur, but may happen due to manipulation of the PDOM tree. =cut sub start { $_[0]->{start} } =pod =head2 finish The C method returns the finish brace for the structure (i.e. the closing brace). Returns the brace as a L or C if the structure does not have a finishing brace. This can be quite common if the document is not complete (for example, from an editor where the user may be halfway through typeing a subroutine). =cut sub finish { $_[0]->{finish} } =pod =head2 braces The C method is a utility method which returns the brace type, regardless of whether has both braces defined, or just the starting brace, or just the ending brace. Returns on of the three strings C<'[]'>, C<'{}'>, or C<'()'>, or C on error (primarily not having a start brace, as mentioned above). =cut sub braces { my $self = $_[0]->{start} ? shift : return undef; return { '[' => '[]', '(' => '()', '{' => '{}', }->{ $self->{start}->{content} }; } =pod =head1 complete The C method is a convenience method that returns true if the both braces are defined for the structure, or false if only one brace is defined. Unlike the top level C method which checks for completeness in depth, the structure complete method ONLY confirms completeness for the braces, and does not recurse downwards. =cut sub complete { !! ($_[0]->{start} and $_[0]->{finish}); } ##################################################################### # PPI::Node overloaded methods # For us, the "elements" concept includes the brace tokens sub elements { my $self = shift; if ( wantarray ) { # Return a list in array context return ( $self->{start} || (), @{$self->{children}}, $self->{finish} || () ); } else { # Return the number of elements in scalar context. # This is memory-cheaper than creating another big array return scalar(@{$self->{children}}) + ($self->{start} ? 1 : 0) + ($self->{finish} ? 1 : 0); } } # For us, the first element is probably the opening brace sub first_element { # Technically, if we have no children and no opening brace, # then the first element is the closing brace. $_[0]->{start} or $_[0]->{children}->[0] or $_[0]->{finish}; } # For us, the last element is probably the closing brace sub last_element { # Technically, if we have no children and no closing brace, # then the last element is the opening brace $_[0]->{finish} or $_[0]->{children}->[-1] or $_[0]->{start}; } # Location is same as the start token, if any sub location { my $self = shift; my $first = $self->first_element or return undef; $first->location; } ##################################################################### # PPI::Element overloaded methods # Get the full set of tokens, including start and finish sub tokens { my $self = shift; my @tokens = ( $self->{start} || (), $self->SUPER::tokens(@_), $self->{finish} || (), ); @tokens; } # Like the token method ->content, get our merged contents. # This will recurse downwards through everything ### Reimplement this using List::Utils stuff sub content { my $self = shift; my $content = $self->{start} ? $self->{start}->content : ''; foreach my $child ( @{$self->{children}} ) { $content .= $child->content; } $content .= $self->{finish}->content if $self->{finish}; $content; } # Is the structure completed sub _complete { !! ( defined $_[0]->{finish} ); } # You can insert either another structure, or a token sub insert_before { my $self = shift; my $Element = _INSTANCE(shift, 'PPI::Element') or return undef; if ( $Element->isa('PPI::Structure') ) { return $self->__insert_before($Element); } elsif ( $Element->isa('PPI::Token') ) { return $self->__insert_before($Element); } ''; } # As above, you can insert either another structure, or a token sub insert_after { my $self = shift; my $Element = _INSTANCE(shift, 'PPI::Element') or return undef; if ( $Element->isa('PPI::Structure') ) { return $self->__insert_after($Element); } elsif ( $Element->isa('PPI::Token') ) { return $self->__insert_after($Element); } ''; } 1; =pod =head1 SUPPORT See the L in the main module. =head1 AUTHOR Adam Kennedy Eadamk@cpan.orgE =head1 COPYRIGHT Copyright 2001 - 2011 Adam Kennedy. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. The full text of the license can be found in the LICENSE file included with this module. =cut PPI-1.215/lib/PPI/Statement.pm0000644000175100017510000002613311532117301014241 0ustar adamadampackage PPI::Statement; =pod =head1 NAME PPI::Statement - The base class for Perl statements =head1 INHERITANCE PPI::Statement isa PPI::Node isa PPI::Element =head1 DESCRIPTION PPI::Statement is the root class for all Perl statements. This includes (from L) "Declarations", "Simple Statements" and "Compound Statements". The class PPI::Statement itself represents a "Simple Statement" as defined in the L manpage. =head1 STATEMENT CLASSES Please note that unless documented themselves, these classes are yet to be frozen/finalised. Names may change slightly or be added or removed. =head2 L This covers all "scheduled" blocks, chunks of code that are executed separately from the main body of the code, at a particular time. This includes all C, C, C, C and C blocks. =head2 L A package declaration, as defined in L. =head2 L A statement that loads or unloads another module. This includes 'use', 'no', and 'require' statements. =head2 L A named subroutine declaration, or forward declaration =head2 L A variable declaration statement. This could be either a straight declaration or also be an expression. This includes all 'my', 'state', 'local' and 'our' statements. =head2 L This covers the whole family of 'compound' statements, as described in L. This includes all statements starting with 'if', 'unless', 'for', 'foreach' and 'while'. Note that this does NOT include 'do', as it is treated differently. All compound statements have implicit ends. That is, they do not end with a ';' statement terminator. =head2 L A statement that breaks out of a structure. This includes all of 'redo', 'next', 'last' and 'return' statements. =head2 L The kind of statement introduced in Perl 5.10 that starts with 'given'. This has an implicit end. =head2 L The kind of statement introduced in Perl 5.10 that starts with 'when' or 'default'. This also has an implicit end. =head2 L A special statement which encompasses an entire C<__DATA__> block, including the initial C<'__DATA__'> token itself and the entire contents. =head2 L A special statement which encompasses an entire __END__ block, including the initial '__END__' token itself and the entire contents, including any parsed PPI::Token::POD that may occur in it. =head2 L L is a little more speculative, and is intended to help represent the special rules relating to "expressions" such as in: # Several examples of expression statements # Boolean conditions if ( expression ) { ... } # Lists, such as for arguments Foo->bar( expression ) =head2 L A null statement is a special case for where we encounter two consecutive statement terminators. ( ;; ) The second terminator is given an entire statement of its own, but one that serves no purpose. Hence a 'null' statement. Theoretically, assuming a correct parsing of a perl file, all null statements are superfluous and should be able to be removed without damage to the file. But don't do that, in case PPI has parsed something wrong. =head2 L Because L is intended for use when parsing incorrect or incomplete code, the problem arises of what to do with a stray closing brace. Rather than die, it is allocated its own "unmatched brace" statement, which really means "unmatched closing brace". An unmatched open brace at the end of a file would become a structure with no contents and no closing brace. If the document loaded is intended to be correct and valid, finding a L in the PDOM is generally indicative of a misparse. =head2 L This is used temporarily mid-parsing to hold statements for which the lexer cannot yet determine what class it should be, usually because there are insufficient clues, or it might be more than one thing. You should never encounter these in a fully parsed PDOM tree. =head1 METHODS C itself has very few methods. Most of the time, you will be working with the more generic L or L methods, or one of the methods that are subclass-specific. =cut use strict; use Scalar::Util (); use Params::Util qw{_INSTANCE}; use PPI::Node (); use PPI::Exception (); use vars qw{$VERSION @ISA *_PARENT}; BEGIN { $VERSION = '1.215'; @ISA = 'PPI::Node'; *_PARENT = *PPI::Element::_PARENT; } use PPI::Statement::Break (); use PPI::Statement::Compound (); use PPI::Statement::Data (); use PPI::Statement::End (); use PPI::Statement::Expression (); use PPI::Statement::Include (); use PPI::Statement::Null (); use PPI::Statement::Package (); use PPI::Statement::Scheduled (); use PPI::Statement::Sub (); use PPI::Statement::Given (); use PPI::Statement::UnmatchedBrace (); use PPI::Statement::Unknown (); use PPI::Statement::Variable (); use PPI::Statement::When (); # "Normal" statements end at a statement terminator ; # Some are not, and need the more rigorous _continues to see # if we are at an implicit statement boundary. sub __LEXER__normal { 1 } ##################################################################### # Constructor sub new { my $class = shift; if ( ref $class ) { PPI::Exception->throw; } # Create the object my $self = bless { children => [], }, $class; # If we have been passed what should be an initial token, add it my $token = shift; if ( _INSTANCE($token, 'PPI::Token') ) { # Inlined $self->__add_element(shift); Scalar::Util::weaken( $_PARENT{Scalar::Util::refaddr $token} = $self ); push @{$self->{children}}, $token; } $self; } =pod =head2 label One factor common to most statements is their ability to be labeled. The C